httpd: Cleaning up `api::json` and review comments

This commit is contained in:
Sebastian Martinez 2023-12-12 15:23:31 +01:00 committed by cloudhead
parent cc380532c6
commit 53c08f5d26
No known key found for this signature in database
3 changed files with 125 additions and 147 deletions

View File

@ -4,16 +4,13 @@ use std::path::Path;
use std::str; use std::str;
use base64::prelude::{Engine, BASE64_STANDARD}; use base64::prelude::{Engine, BASE64_STANDARD};
use serde::Serialize; use radicle::patch::CodeLocation;
use serde_json::{json, Value}; use serde_json::{json, Value};
use radicle::cob::issue::{Issue, IssueId}; use radicle::cob::issue::{Issue, IssueId};
use radicle::cob::patch::Merge; use radicle::cob::patch::{Merge, Patch, PatchId, Review};
use radicle::cob::patch::Review; use radicle::cob::thread::{Comment, CommentId};
use radicle::cob::patch::{Patch, PatchId}; use radicle::cob::{ActorId, Author};
use radicle::cob::thread;
use radicle::cob::thread::CommentId;
use radicle::cob::{ActorId, Author, Embed, Reaction, Timestamp, Uri};
use radicle::git::RefString; use radicle::git::RefString;
use radicle::node::{Alias, AliasStore}; use radicle::node::{Alias, AliasStore};
use radicle::prelude::NodeId; use radicle::prelude::NodeId;
@ -106,10 +103,7 @@ pub(crate) fn issue(id: IssueId, issue: Issue, aliases: &impl AliasStore) -> Val
"title": issue.title(), "title": issue.title(),
"state": issue.state(), "state": issue.state(),
"assignees": issue.assignees().collect::<Vec<_>>(), "assignees": issue.assignees().collect::<Vec<_>>(),
"discussion": issue "discussion": issue.comments().map(|(id, c)| comment(id, c, aliases)).collect::<Vec<_>>(),
.comments()
.map(|(id, comment)| Comment::new(id, comment, aliases))
.collect::<Vec<_>>(),
"labels": issue.labels().collect::<Vec<_>>(), "labels": issue.labels().collect::<Vec<_>>(),
}) })
} }
@ -128,7 +122,7 @@ pub(crate) fn patch(
"state": patch.state(), "state": patch.state(),
"target": patch.target(), "target": patch.target(),
"labels": patch.labels().collect::<Vec<_>>(), "labels": patch.labels().collect::<Vec<_>>(),
"merges": patch.merges().map(|(nid, m)| merge(m, nid, aliases.alias(nid))).collect::<Vec<_>>(), "merges": patch.merges().map(|(nid, m)| merge(nid, m, aliases)).collect::<Vec<_>>(),
"assignees": patch.assignees().collect::<Vec<_>>(), "assignees": patch.assignees().collect::<Vec<_>>(),
"revisions": patch.revisions().map(|(id, rev)| { "revisions": patch.revisions().map(|(id, rev)| {
json!({ json!({
@ -138,11 +132,9 @@ pub(crate) fn patch(
"base": rev.base(), "base": rev.base(),
"oid": rev.head(), "oid": rev.head(),
"refs": get_refs(repo, patch.author().id(), &rev.head()).unwrap_or_default(), "refs": get_refs(repo, patch.author().id(), &rev.head()).unwrap_or_default(),
"discussions": rev.discussion().comments() "discussions": rev.discussion().comments().map(|(id, c)| comment(id, c, aliases)).collect::<Vec<_>>(),
.map(|(id, comment)| Comment::new(id, comment, aliases))
.collect::<Vec<_>>(),
"timestamp": rev.timestamp().as_secs(), "timestamp": rev.timestamp().as_secs(),
"reviews": rev.reviews().map(|(nid, _review)| review(nid, aliases.alias(nid), _review)).collect::<Vec<_>>(), "reviews": rev.reviews().map(|(nid, r)| review(nid, r, aliases)).collect::<Vec<_>>(),
}) })
}).collect::<Vec<_>>(), }).collect::<Vec<_>>(),
}) })
@ -160,51 +152,73 @@ fn author(author: &Author, alias: Option<Alias>) -> Value {
} }
/// Returns JSON for a patch `Merge` and fills in `alias` when present. /// Returns JSON for a patch `Merge` and fills in `alias` when present.
fn merge(merge: &Merge, nid: &NodeId, alias: Option<Alias>) -> Value { fn merge(nid: &NodeId, merge: &Merge, aliases: &impl AliasStore) -> Value {
match alias { json!({
Some(alias) => json!({ "author": author(&Author::from(*nid), aliases.alias(nid)),
"author": { "commit": merge.commit,
"id": nid, "timestamp": merge.timestamp.as_secs(),
"alias": alias, "revision": merge.revision,
}, })
"commit": merge.commit,
"timestamp": merge.timestamp.as_secs(),
"revision": merge.revision,
}),
None => json!({
"author": {
"id": nid,
},
"commit": merge.commit,
"timestamp": merge.timestamp.as_secs(),
"revision": merge.revision,
}),
}
} }
/// Returns JSON for a patch `Review` and fills in `alias` when present. /// Returns JSON for a patch `Review` and fills in `alias` when present.
fn review(nid: &NodeId, alias: Option<Alias>, review: &Review) -> Value { fn review(nid: &NodeId, review: &Review, aliases: &impl AliasStore) -> Value {
match alias { json!({
Some(alias) => json!({ "author": author(&Author::from(*nid), aliases.alias(nid)),
"author": { "verdict": review.verdict(),
"id": nid, "summary": review.summary(),
"alias": alias, "comments": review.comments().map(|(id, c)| review_comment(id, c, aliases)).collect::<Vec<_>>(),
}, "timestamp": review.timestamp().as_secs(),
"verdict": review.verdict(), })
"summary": review.summary(), }
"comments": review.comments().collect::<Vec<_>>(),
"timestamp": review.timestamp().as_secs(), /// Returns JSON for a `Comment`.
}), fn comment(id: &CommentId, comment: &Comment, aliases: &impl AliasStore) -> Value {
None => json!({ json!({
"author": { "id": *id,
"id": nid, "author": author(&Author::from(comment.author()), aliases.alias(&comment.author())),
}, "body": comment.body(),
"verdict": review.verdict(), "edits": comment.edits().map(|edit| {
"summary": review.summary(), json!({
"comments": review.comments().collect::<Vec<_>>(), "author": author(&Author::from(edit.author), aliases.alias(&edit.author)),
"timestamp": review.timestamp().as_secs(), "body": edit.body,
}), "timestamp": edit.timestamp.as_secs(),
} "embeds": edit.embeds,
})
}).collect::<Vec<_>>(),
"embeds": comment.embeds().to_vec(),
"reactions": comment.reactions().collect::<Vec<_>>(),
"timestamp": comment.timestamp().as_secs(),
"replyTo": comment.reply_to(),
"resolved": comment.resolved(),
})
}
/// Returns JSON for a `Review`.
fn review_comment(
id: &CommentId,
comment: &Comment<CodeLocation>,
aliases: &impl AliasStore,
) -> Value {
json!({
"id": *id,
"author": author(&Author::from(comment.author()), aliases.alias(&comment.author())),
"body": comment.body(),
"edits": comment.edits().map(|edit| {
json!({
"author": author(&Author::from(edit.author), aliases.alias(&edit.author)),
"body": edit.body,
"timestamp": edit.timestamp.as_secs(),
"embeds": edit.embeds,
})
}).collect::<Vec<_>>(),
"embeds": comment.embeds().to_vec(),
"reactions": comment.reactions().collect::<Vec<_>>(),
"timestamp": comment.timestamp().as_secs(),
"replyTo": comment.reply_to(),
"location": comment.location(),
"resolved": comment.resolved(),
})
} }
/// Returns the name part of a path string. /// Returns the name part of a path string.
@ -235,45 +249,3 @@ fn get_refs(
Ok(refs) Ok(refs)
} }
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct Comment<'a> {
id: CommentId,
author: Value,
body: &'a str,
edits: Vec<Value>,
embeds: Vec<Embed<Uri>>,
reactions: Vec<(&'a ActorId, &'a Reaction)>,
#[serde(with = "radicle::serde_ext::localtime::time")]
timestamp: Timestamp,
reply_to: Option<CommentId>,
resolved: bool,
}
impl<'a> Comment<'a> {
fn new(id: &'a CommentId, comment: &'a thread::Comment, aliases: &impl AliasStore) -> Self {
let comment_author = Author::new(comment.author());
Self {
id: *id,
author: author(&comment_author, aliases.alias(comment_author.id())),
body: comment.body(),
edits: comment
.edits()
.map(|edit| {
json!({
"author": author(&Author::from(edit.author), aliases.alias(&edit.author)),
"body": edit.body,
"timestamp": edit.timestamp,
"embeds": edit.embeds,
})
})
.collect::<Vec<_>>(),
embeds: comment.embeds().to_vec(),
reactions: comment.reactions().collect::<Vec<_>>(),
timestamp: comment.timestamp(),
reply_to: comment.reply_to(),
resolved: comment.resolved(),
}
}
}

View File

@ -2001,7 +2001,7 @@ mod routes {
"id": DID, "id": DID,
}, },
"body": "Change 'hello world' to 'hello everyone'", "body": "Change 'hello world' to 'hello everyone'",
"timestamp": COMMENT_TIMESTAMP, "timestamp": TIMESTAMP,
"embeds": [], "embeds": [],
}, },
], ],
@ -2086,7 +2086,7 @@ mod routes {
"id": CONTRIBUTOR_DID, "id": CONTRIBUTOR_DID,
}, },
"body": "Change 'hello world' to 'hello everyone'", "body": "Change 'hello world' to 'hello everyone'",
"timestamp": COMMENT_TIMESTAMP, "timestamp": TIMESTAMP,
"embeds": [ "embeds": [
{ {
"name": "example.html", "name": "example.html",
@ -2234,7 +2234,7 @@ mod routes {
"id": CONTRIBUTOR_DID, "id": CONTRIBUTOR_DID,
}, },
"body": "Change 'hello world' to 'hello everyone'", "body": "Change 'hello world' to 'hello everyone'",
"timestamp": COMMENT_TIMESTAMP, "timestamp": TIMESTAMP,
"embeds": [], "embeds": [],
}, },
{ {
@ -2242,7 +2242,7 @@ mod routes {
"id": CONTRIBUTOR_DID, "id": CONTRIBUTOR_DID,
}, },
"body": "EDIT: Change 'hello world' to 'hello anyone'", "body": "EDIT: Change 'hello world' to 'hello anyone'",
"timestamp": COMMENT_TIMESTAMP, "timestamp": TIMESTAMP,
"embeds": [ "embeds": [
{ {
"name": "image.jpg", "name": "image.jpg",
@ -2337,7 +2337,7 @@ mod routes {
"id": CONTRIBUTOR_DID, "id": CONTRIBUTOR_DID,
}, },
"body": "Change 'hello world' to 'hello everyone'", "body": "Change 'hello world' to 'hello everyone'",
"timestamp": COMMENT_TIMESTAMP, "timestamp": TIMESTAMP,
"embeds": [], "embeds": [],
}, },
], ],
@ -2359,7 +2359,7 @@ mod routes {
"id": CONTRIBUTOR_DID, "id": CONTRIBUTOR_DID,
}, },
"body": "This is a reply to the first comment", "body": "This is a reply to the first comment",
"timestamp": COMMENT_TIMESTAMP, "timestamp": TIMESTAMP,
"embeds": [ "embeds": [
{ {
"name": "image.jpg", "name": "image.jpg",
@ -3010,7 +3010,7 @@ mod routes {
"id": CONTRIBUTOR_DID, "id": CONTRIBUTOR_DID,
}, },
"body": "This is a root level comment", "body": "This is a root level comment",
"timestamp": COMMENT_TIMESTAMP, "timestamp": TIMESTAMP,
"embeds": [ "embeds": [
{ {
"name": "image.jpg", "name": "image.jpg",
@ -3023,7 +3023,7 @@ mod routes {
"id": CONTRIBUTOR_DID, "id": CONTRIBUTOR_DID,
}, },
"body": "EDIT: This is a root level comment", "body": "EDIT: This is a root level comment",
"timestamp": COMMENT_TIMESTAMP, "timestamp": TIMESTAMP,
"embeds": [ "embeds": [
{ {
"name": "image.jpg", "name": "image.jpg",
@ -3055,7 +3055,7 @@ mod routes {
"id": CONTRIBUTOR_DID, "id": CONTRIBUTOR_DID,
}, },
"body": "This is a root level comment", "body": "This is a root level comment",
"timestamp": COMMENT_TIMESTAMP, "timestamp": TIMESTAMP,
"embeds": [], "embeds": [],
}, },
], ],
@ -3216,49 +3216,37 @@ mod routes {
"reviews": [ "reviews": [
{ {
"author": { "author": {
"id": CONTRIBUTOR_NID, "id": CONTRIBUTOR_DID,
}, },
"verdict": "accept", "verdict": "accept",
"summary": "A small review", "summary": "A small review",
"comments": [[ "comments": [
comment_id,
{ {
"author": CONTRIBUTOR_NID, "id": "b108acfd2117480fd87012a5ab7cb69a0651d933",
"location": { "author": {
"path": "README.md", "id": "did:key:z6Mkk7oqY4pPxhMmGEotDYsFo97vhCj85BLY1H256HrJmjN8",
"old": null,
"new": {
"type": "lines",
"range": {
"start": 2,
"end": 4,
}
}
}, },
"reactions": [
[
"z6Mkk7oqY4pPxhMmGEotDYsFo97vhCj85BLY1H256HrJmjN8",
"🚀",
],
],
"resolved": true,
"body": "EDIT: This is a comment on a review", "body": "EDIT: This is a comment on a review",
"edits": [ "edits": [
{ {
"author": "z6Mkk7oqY4pPxhMmGEotDYsFo97vhCj85BLY1H256HrJmjN8", "author": {
"timestamp": COMMENT_TIMESTAMP, "id": "did:key:z6Mkk7oqY4pPxhMmGEotDYsFo97vhCj85BLY1H256HrJmjN8",
},
"body": "This is a comment on a review", "body": "This is a comment on a review",
"timestamp": 1671125284,
"embeds": [ "embeds": [
{ {
"name": "image.jpg", "name": "image.jpg",
"content": "git:94381b429d7f7fe87e1bade52d893ab348ae29cc", "content": "git:94381b429d7f7fe87e1bade52d893ab348ae29cc",
}, },
], ],
}, },
{ {
"author": "z6Mkk7oqY4pPxhMmGEotDYsFo97vhCj85BLY1H256HrJmjN8", "author": {
"timestamp": COMMENT_TIMESTAMP, "id": "did:key:z6Mkk7oqY4pPxhMmGEotDYsFo97vhCj85BLY1H256HrJmjN8",
},
"body": "EDIT: This is a comment on a review", "body": "EDIT: This is a comment on a review",
"timestamp": 1671125284,
"embeds": [ "embeds": [
{ {
"name": "image.jpg", "name": "image.jpg",
@ -3271,11 +3259,31 @@ mod routes {
{ {
"name": "image.jpg", "name": "image.jpg",
"content": "git:94381b429d7f7fe87e1bade52d893ab348ae29cc", "content": "git:94381b429d7f7fe87e1bade52d893ab348ae29cc",
} },
], ],
}, "reactions": [
]], [
"timestamp": TIMESTAMP, "z6Mkk7oqY4pPxhMmGEotDYsFo97vhCj85BLY1H256HrJmjN8",
"🚀",
],
],
"timestamp": 1671125284,
"replyTo": null,
"location": {
"path": "README.md",
"old": null,
"new": {
"type": "lines",
"range": {
"start": 2,
"end": 4,
},
},
},
"resolved": true,
}
],
"timestamp": 1671125284,
}, },
], ],
}, },
@ -3329,20 +3337,20 @@ mod routes {
"labels": [], "labels": [],
"merges": [{ "merges": [{
"author": { "author": {
"id": CONTRIBUTOR_NID, "id": CONTRIBUTOR_DID,
}, },
"revision": CONTRIBUTOR_PATCH_ID,
"commit": PARENT, "commit": PARENT,
"timestamp": TIMESTAMP, "timestamp": TIMESTAMP,
"revision": CONTRIBUTOR_PATCH_ID,
}], }],
"assignees": [], "assignees": [],
"revisions": [ "revisions": [
{ {
"id": CONTRIBUTOR_PATCH_ID, "id": CONTRIBUTOR_PATCH_ID,
"description": "change `hello world` in README to something else",
"author": { "author": {
"id": CONTRIBUTOR_DID, "id": CONTRIBUTOR_DID,
}, },
"description": "change `hello world` in README to something else",
"base": PARENT, "base": PARENT,
"oid": HEAD, "oid": HEAD,
"refs": [ "refs": [

View File

@ -37,10 +37,8 @@ pub const ISSUE_DISCUSSION_ID: &str = "d11b03464c9bf58b09460713c8e2c74f0725d3bd"
pub const ISSUE_COMMENT_ID: &str = "e3aa754cb47d2299781fed49cc91c4b41e06c219"; pub const ISSUE_COMMENT_ID: &str = "e3aa754cb47d2299781fed49cc91c4b41e06c219";
pub const SESSION_ID: &str = "u9MGAkkfkMOv0uDDB2WeUHBT7HbsO2Dy"; pub const SESSION_ID: &str = "u9MGAkkfkMOv0uDDB2WeUHBT7HbsO2Dy";
pub const TIMESTAMP: u64 = 1671125284; pub const TIMESTAMP: u64 = 1671125284;
pub const COMMENT_TIMESTAMP: u64 = 1671125284000;
pub const CONTRIBUTOR_RID: &str = "rad:z4XaCmN3jLSeiMvW15YTDpNbDHFhG"; pub const CONTRIBUTOR_RID: &str = "rad:z4XaCmN3jLSeiMvW15YTDpNbDHFhG";
pub const CONTRIBUTOR_DID: &str = "did:key:z6Mkk7oqY4pPxhMmGEotDYsFo97vhCj85BLY1H256HrJmjN8"; pub const CONTRIBUTOR_DID: &str = "did:key:z6Mkk7oqY4pPxhMmGEotDYsFo97vhCj85BLY1H256HrJmjN8";
pub const CONTRIBUTOR_NID: &str = "z6Mkk7oqY4pPxhMmGEotDYsFo97vhCj85BLY1H256HrJmjN8";
pub const CONTRIBUTOR_PATCH_ID: &str = "0867c6389ee073304da0854a83885f47b1d7f5ed"; pub const CONTRIBUTOR_PATCH_ID: &str = "0867c6389ee073304da0854a83885f47b1d7f5ed";
/// Create a new profile. /// Create a new profile.