httpd: Extract `issue` json response

Signed-off-by: xphoniex <dj.2dixx@gmail.com>
This commit is contained in:
xphoniex 2023-02-04 17:16:26 +03:30
parent 4552c1f296
commit c1ba45fcd8
No known key found for this signature in database
GPG Key ID: 9FACFECE1E3B3994
2 changed files with 58 additions and 60 deletions

View File

@ -2,9 +2,14 @@
use std::path::Path;
use serde::Serialize;
use serde_json::{json, Value};
use radicle::cob::issue::{Issue, IssueId};
use radicle::cob::patch::{Patch, PatchId};
use radicle::cob::thread::{self, CommentId};
use radicle::cob::Timestamp;
use radicle::identity::PublicKey;
use radicle_surf::blob::Blob;
use radicle_surf::tree::Tree;
use radicle_surf::{Commit, Stats};
@ -62,6 +67,18 @@ pub(crate) fn tree(tree: &Tree, path: &str, stats: &Stats) -> Value {
})
}
/// Returns JSON for an `issue`.
pub(crate) fn issue(id: IssueId, issue: Issue) -> Value {
json!({
"id": id.to_string(),
"author": issue.author(),
"title": issue.title(),
"state": issue.state(),
"discussion": issue.comments().collect::<Comments>(),
"tags": issue.tags().collect::<Vec<_>>(),
})
}
/// Returns JSON for a `patch`.
pub(crate) fn patch(id: PatchId, patch: Patch) -> Value {
json!({
@ -89,3 +106,41 @@ fn name_in_path(path: &str) -> &str {
None => path,
}
}
#[derive(Serialize)]
struct Author {
id: PublicKey,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct Comment {
author: Author,
body: String,
reactions: [String; 0],
timestamp: Timestamp,
reply_to: Option<CommentId>,
}
#[derive(Serialize)]
struct Comments(Vec<Comment>);
impl<'a> FromIterator<(&'a CommentId, &'a thread::Comment)> for Comments {
fn from_iter<I: IntoIterator<Item = (&'a CommentId, &'a thread::Comment)>>(iter: I) -> Self {
let mut comments = Vec::new();
for (_, comment) in iter {
comments.push(Comment {
author: Author {
id: comment.author(),
},
body: comment.body().to_owned(),
reactions: [],
timestamp: comment.timestamp(),
reply_to: comment.reply_to(),
});
}
Comments(comments)
}
}

View File

@ -13,9 +13,7 @@ use tower_http::set_header::SetResponseHeaderLayer;
use radicle::cob::issue::Issues;
use radicle::cob::patch::Patches;
use radicle::cob::thread::{self, CommentId};
use radicle::cob::Timestamp;
use radicle::identity::{Id, PublicKey};
use radicle::identity::Id;
use radicle::node::NodeId;
use radicle::storage::{git::paths, ReadRepository, WriteStorage};
use radicle_surf::{Glob, Oid, Repository};
@ -385,16 +383,7 @@ async fn issues_handler(
.all()?
.into_iter()
.filter_map(|r| r.ok())
.map(|(id, issue, _)| {
json!({
"id": id.to_string(),
"author": issue.author(),
"title": issue.title(),
"state": issue.state(),
"discussion": issue.comments().collect::<Comments>(),
"tags": issue.tags().collect::<Vec<_>>(),
})
})
.map(|(id, issue, _)| api::json::issue(id, issue))
.skip(page * per_page)
.take(per_page)
.collect::<Vec<_>>();
@ -413,16 +402,8 @@ async fn issue_handler(
let issue = Issues::open(ctx.profile.public_key, &repo)?
.get(&issue_id.into())?
.ok_or(Error::NotFound)?;
let issue = json!({
"id": issue_id,
"author": issue.author(),
"title": issue.title(),
"state": issue.state(),
"discussion": issue.comments().collect::<Comments>(),
"tags": issue.tags().collect::<Vec<_>>(),
});
Ok::<_, Error>(Json(issue))
Ok::<_, Error>(Json(api::json::issue(issue_id.into(), issue)))
}
/// Get project patches list.
@ -465,44 +446,6 @@ async fn patch_handler(
Ok::<_, Error>(Json(api::json::patch(patch_id.into(), patch)))
}
#[derive(Serialize)]
struct Author {
id: PublicKey,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct Comment {
author: Author,
body: String,
reactions: [String; 0],
timestamp: Timestamp,
reply_to: Option<CommentId>,
}
#[derive(Serialize)]
struct Comments(Vec<Comment>);
impl<'a> FromIterator<(&'a CommentId, &'a thread::Comment)> for Comments {
fn from_iter<I: IntoIterator<Item = (&'a CommentId, &'a thread::Comment)>>(iter: I) -> Self {
let mut comments = Vec::new();
for (_, comment) in iter {
comments.push(Comment {
author: Author {
id: comment.author(),
},
body: comment.body().to_owned(),
reactions: [],
timestamp: comment.timestamp(),
reply_to: comment.reply_to(),
});
}
Comments(comments)
}
}
#[cfg(test)]
mod routes {
use axum::http::StatusCode;