use axum::{
extract::{Path, Query, State},
Json,
};
use serde::Deserialize;
use crate::web::github::{self, Refusal};
use crate::web::state::WebState;
use wsb_github::client::{CreateIssueRequest, GitHubComment, GitHubIssue, UpdateIssueRequest};
use wsb_github::service::IssueState;
#[derive(Deserialize)]
pub struct ListIssuesQuery {
pub state: Option<String>,
pub repo: Option<String>,
}
fn issue_state(query: &ListIssuesQuery) -> Result<IssueState, Refusal> {
query
.state
.as_deref()
.unwrap_or("open")
.parse()
.map_err(|error: String| github::failure(wsb_github::Failure::Invalid(error)))
}
pub async fn list_issues(
State(state): State<WebState>,
Query(query): Query<ListIssuesQuery>,
) -> Result<Json<wsb_github::service::IssueList>, Refusal> {
let wanted = issue_state(&query)?;
let service = github::of(&state)?.service.clone();
let mut repos = github::repository_names(&state).await?;
if let Some(repo) = &query.repo {
repos.retain(|held| held == repo);
}
github::blocking(move || service.issues(&repos, wanted))
.await
.map(Json)
}
pub async fn list_repo_issues(
State(state): State<WebState>,
Path((owner, repo)): Path<(String, String)>,
Query(query): Query<ListIssuesQuery>,
) -> Result<Json<serde_json::Value>, Refusal> {
let wanted = issue_state(&query)?;
let service = github::of(&state)?.service.clone();
let name = format!("{owner}/{repo}");
let repos = vec![name.clone()];
let mut list = github::blocking(move || service.issues(&repos, wanted)).await?;
Ok(Json(serde_json::json!({
"repo": name,
"issues": list.issues,
"sync": list.sync.remove(&name),
})))
}
pub async fn create_issue(
State(state): State<WebState>,
Path((owner, repo)): Path<(String, String)>,
Json(body): Json<CreateIssueRequest>,
) -> Result<Json<GitHubIssue>, Refusal> {
let github = github::of(&state)?;
let client = github::client(github)?;
github
.service
.create_issue(&client, &owner, &repo, &body)
.await
.map(Json)
.map_err(github::failure)
}
pub async fn update_issue(
State(state): State<WebState>,
Path((owner, repo, number)): Path<(String, String, i64)>,
Json(body): Json<UpdateIssueRequest>,
) -> Result<Json<GitHubIssue>, Refusal> {
let github = github::of(&state)?;
let client = github::client(github)?;
github
.service
.update_issue(&client, &owner, &repo, number, &body)
.await
.map(Json)
.map_err(github::failure)
}
#[derive(Deserialize)]
pub struct CommentRequest {
pub body: String,
}
pub async fn list_comments(
State(state): State<WebState>,
Path((owner, repo, number)): Path<(String, String, i64)>,
) -> Result<Json<serde_json::Value>, Refusal> {
let github = github::of(&state)?;
let client = github::client(github).ok();
let listed = github
.service
.comments(client.as_ref(), &format!("{owner}/{repo}"), number)
.await
.map_err(github::failure)?;
Ok(Json(serde_json::json!({ "comments": listed.items, "sync": listed.sync })))
}
pub async fn add_comment(
State(state): State<WebState>,
Path((owner, repo, number)): Path<(String, String, i64)>,
Json(body): Json<CommentRequest>,
) -> Result<Json<GitHubComment>, Refusal> {
let github = github::of(&state)?;
let client = github::client(github)?;
github
.service
.add_comment(&client, &owner, &repo, number, &body.body)
.await
.map(Json)
.map_err(github::failure)
}