From c1ba45fcd83aecdecbdb05a60e412dc1f448ae1c Mon Sep 17 00:00:00 2001 From: xphoniex Date: Sat, 4 Feb 2023 17:16:26 +0330 Subject: [PATCH] httpd: Extract `issue` json response Signed-off-by: xphoniex --- radicle-httpd/src/api/json.rs | 55 ++++++++++++++++++++++++ radicle-httpd/src/api/v1/projects.rs | 63 ++-------------------------- 2 files changed, 58 insertions(+), 60 deletions(-) diff --git a/radicle-httpd/src/api/json.rs b/radicle-httpd/src/api/json.rs index 9de6bf17..00b8e8bf 100644 --- a/radicle-httpd/src/api/json.rs +++ b/radicle-httpd/src/api/json.rs @@ -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::(), + "tags": issue.tags().collect::>(), + }) +} + /// 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, +} + +#[derive(Serialize)] +struct Comments(Vec); + +impl<'a> FromIterator<(&'a CommentId, &'a thread::Comment)> for Comments { + fn from_iter>(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) + } +} diff --git a/radicle-httpd/src/api/v1/projects.rs b/radicle-httpd/src/api/v1/projects.rs index dc7afc3c..0a21a8da 100644 --- a/radicle-httpd/src/api/v1/projects.rs +++ b/radicle-httpd/src/api/v1/projects.rs @@ -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::(), - "tags": issue.tags().collect::>(), - }) - }) + .map(|(id, issue, _)| api::json::issue(id, issue)) .skip(page * per_page) .take(per_page) .collect::>(); @@ -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::(), - "tags": issue.tags().collect::>(), - }); - 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, -} - -#[derive(Serialize)] -struct Comments(Vec); - -impl<'a> FromIterator<(&'a CommentId, &'a thread::Comment)> for Comments { - fn from_iter>(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;