248 lines
7.3 KiB
Rust
248 lines
7.3 KiB
Rust
use super::*;
|
|
|
|
static ISSUES_BASE_URL: &'static str = "{base_url}/api/v1/repos/{repo}/issues";
|
|
static ISSUES_COMMENTS_URL: &'static str = "{base_url}/api/v1/repos/{repo}/issues/{index}/comments";
|
|
|
|
use serde::Serialize;
|
|
|
|
#[derive(Serialize, Default)]
|
|
struct CreateIssueOption {
|
|
assignee: String,
|
|
assignees: Vec<String>,
|
|
body: String,
|
|
closed: bool,
|
|
title: String,
|
|
}
|
|
|
|
pub fn new_issue(
|
|
conn: &Connection,
|
|
title: String,
|
|
body: String,
|
|
anonymous: bool,
|
|
submitter: Address,
|
|
conf: &Config,
|
|
) -> Result<(Password, i64)> {
|
|
let issue = CreateIssueOption {
|
|
title,
|
|
body: format!(
|
|
"{} reports:\n\n{}",
|
|
if anonymous {
|
|
"Anonymous".to_string()
|
|
} else {
|
|
submitter.to_string()
|
|
},
|
|
body
|
|
),
|
|
..CreateIssueOption::default()
|
|
};
|
|
let client = reqwest::Client::new();
|
|
let res = client
|
|
.post(
|
|
&ISSUES_BASE_URL
|
|
.replace("{base_url}", &conf.base_url)
|
|
.replace("{repo}", &conf.repo),
|
|
)
|
|
.header("authorization", &conf.auth_token)
|
|
.json(&issue)
|
|
.send()
|
|
.unwrap()
|
|
.text()
|
|
.unwrap();
|
|
|
|
let map: serde_json::map::Map<String, serde_json::Value> = serde_json::from_str(&res).unwrap();
|
|
let issue = Issue {
|
|
id: map["number"].as_i64().unwrap(),
|
|
submitter,
|
|
password: Uuid::new_v4(),
|
|
time_created: time::get_time(),
|
|
anonymous,
|
|
subscribed: true,
|
|
title: issue.title,
|
|
last_update: map["created_at"].to_string(),
|
|
};
|
|
conn.execute(
|
|
"INSERT INTO issue (id, submitter, password, time_created, anonymous, subscribed, title, last_update)
|
|
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)",
|
|
&[
|
|
&issue.id,
|
|
&issue.submitter.to_string() as &dyn ToSql,
|
|
&issue.password.as_bytes().to_vec(),
|
|
&issue.time_created,
|
|
&issue.anonymous,
|
|
&issue.subscribed,
|
|
&issue.title,
|
|
&issue.last_update,
|
|
],
|
|
)
|
|
.unwrap();
|
|
Ok((issue.password, issue.id))
|
|
}
|
|
|
|
#[derive(Serialize, Default)]
|
|
struct CreateIssueCommentOption {
|
|
body: String,
|
|
}
|
|
|
|
pub fn new_reply(
|
|
conn: &Connection,
|
|
body: String,
|
|
password: Password,
|
|
submitter: Address,
|
|
conf: &Config,
|
|
) -> Result<(String, i64, bool)> {
|
|
let mut stmt =
|
|
conn.prepare("SELECT id, title, subscribed, anonymous FROM issue WHERE password = ?")?;
|
|
let mut results = stmt
|
|
.query_map(&[password.as_bytes().to_vec()], |row| {
|
|
Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
|
|
})?
|
|
.map(|r| r.unwrap())
|
|
.collect::<Vec<(i64, String, bool, bool)>>();
|
|
if results.is_empty() {
|
|
return Err(IssueError::new("Not found".to_string()));
|
|
}
|
|
let client = reqwest::Client::new();
|
|
let response = client
|
|
.post(
|
|
&ISSUES_COMMENTS_URL
|
|
.replace("{base_url}", &conf.base_url)
|
|
.replace("{repo}", &conf.repo)
|
|
.replace("{index}", &results[0].0.to_string()),
|
|
)
|
|
.header("authorization", &conf.auth_token)
|
|
.json(&CreateIssueCommentOption {
|
|
body: format!(
|
|
"{} replies:\n\n{}",
|
|
if results[0].3 {
|
|
"Anonymous".to_string()
|
|
} else {
|
|
submitter.to_string()
|
|
},
|
|
body
|
|
),
|
|
})
|
|
.send()?;
|
|
if response.status().is_success() {
|
|
let (issue_id, title, is_subscribed, _) = results.remove(0);
|
|
Ok((title, issue_id, is_subscribed))
|
|
} else {
|
|
eprintln!(
|
|
"New reply could not be created: {:?}\npassword: {}\nsubmitter: {}\nbody: {}",
|
|
response.status(),
|
|
password.to_string(),
|
|
submitter.to_string(),
|
|
body
|
|
);
|
|
Err(IssueError::new(
|
|
"You can not reply to this issue due to an internal error.",
|
|
))
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Default)]
|
|
struct EditIssueOption {
|
|
state: String,
|
|
}
|
|
|
|
pub fn close(conn: &Connection, password: Password, conf: &Config) -> Result<(String, i64, bool)> {
|
|
let mut stmt = conn.prepare("SELECT id, title, subscribed FROM issue WHERE password = ?")?;
|
|
let mut results = stmt
|
|
.query_map(&[password.as_bytes().to_vec()], |row| {
|
|
Ok((row.get(0)?, row.get(1)?, row.get(2)?))
|
|
})?
|
|
.map(|r| r.unwrap())
|
|
.collect::<Vec<(i64, String, bool)>>();
|
|
if results.is_empty() {
|
|
return Err(IssueError::new("Not found".to_string()));
|
|
}
|
|
let client = reqwest::Client::new();
|
|
let res = client
|
|
.patch(&format!(
|
|
"{}/{}",
|
|
ISSUES_BASE_URL
|
|
.replace("{base_url}", &conf.base_url)
|
|
.replace("{repo}", &conf.repo),
|
|
&results[0].0.to_string()
|
|
))
|
|
.header("authorization", &conf.auth_token)
|
|
.json(&EditIssueOption {
|
|
state: "closed".to_string(),
|
|
})
|
|
.send()?
|
|
.text()?;
|
|
|
|
let map: serde_json::map::Map<String, serde_json::Value> = serde_json::from_str(&res).unwrap();
|
|
if map["state"] == "closed" {
|
|
let (issue_id, title, is_subscribed) = results.remove(0);
|
|
Ok((title, issue_id, is_subscribed))
|
|
} else {
|
|
eprintln!("Issue could not be closed: {:#?}", map);
|
|
Err(IssueError::new(
|
|
"Issue cannot be closed due to an internal error.",
|
|
))
|
|
}
|
|
}
|
|
|
|
pub fn change_subscription(
|
|
conn: &Connection,
|
|
password: Password,
|
|
new_val: bool,
|
|
) -> Result<(String, i64, bool)> {
|
|
let mut stmt = conn.prepare("SELECT id, title, subscribed FROM issue WHERE password = ?")?;
|
|
let mut results = stmt
|
|
.query_map(&[password.as_bytes().to_vec()], |row| {
|
|
Ok((row.get(0)?, row.get(1)?, row.get(2)?))
|
|
})?
|
|
.map(|r| r.unwrap())
|
|
.collect::<Vec<(i64, String, bool)>>();
|
|
if results.is_empty() {
|
|
return Err(IssueError::new("Issue not found".to_string()));
|
|
}
|
|
let (issue_id, title, is_subscribed) = results.remove(0);
|
|
if !is_subscribed && !new_val {
|
|
return Err(IssueError::new(format!(
|
|
"You are not subscribed to issue `{}`",
|
|
&title
|
|
)));
|
|
} else if is_subscribed && new_val {
|
|
return Err(IssueError::new(format!(
|
|
"You are already subscribed to issue `{}`",
|
|
&title
|
|
)));
|
|
}
|
|
|
|
let mut stmt =
|
|
conn.prepare("UPDATE issue SET subscribed = (:subscribed) WHERE password = (:password)")?;
|
|
assert_eq!(
|
|
stmt.execute_named(&[
|
|
(":subscribed", &new_val),
|
|
(":password", &password.as_bytes().to_vec())
|
|
])?,
|
|
1
|
|
);
|
|
Ok((title, issue_id, is_subscribed))
|
|
}
|
|
|
|
pub fn comments(
|
|
id: i64,
|
|
since: &str,
|
|
conf: &Config,
|
|
) -> Vec<serde_json::map::Map<String, serde_json::Value>> {
|
|
let client = reqwest::Client::new();
|
|
let result = client
|
|
.get(
|
|
&ISSUES_COMMENTS_URL
|
|
.replace("{base_url}", &conf.base_url)
|
|
.replace("{repo}", &conf.repo)
|
|
.replace("{index}", &id.to_string()),
|
|
)
|
|
.header("authorization", &conf.auth_token)
|
|
.query(&[("since", since)])
|
|
.send()
|
|
.unwrap()
|
|
.text()
|
|
.unwrap();
|
|
let result: Vec<_> = serde_json::from_str(&result).unwrap();
|
|
result
|
|
}
|