httpd: Add reactions to issue and patch json
Signed-off-by: Sebastian Martinez <me@sebastinez.dev>
This commit is contained in:
parent
6b62f5bb28
commit
a5746b4f08
|
|
@ -8,8 +8,9 @@ use serde_json::{json, Value};
|
||||||
|
|
||||||
use radicle::cob::issue::{Issue, IssueId};
|
use radicle::cob::issue::{Issue, IssueId};
|
||||||
use radicle::cob::patch::{Patch, PatchId};
|
use radicle::cob::patch::{Patch, PatchId};
|
||||||
use radicle::cob::thread::{self, CommentId};
|
use radicle::cob::thread;
|
||||||
use radicle::cob::{ActorId, Author, Timestamp};
|
use radicle::cob::thread::{CommentId, Thread};
|
||||||
|
use radicle::cob::{ActorId, Author, Reaction, Timestamp};
|
||||||
use radicle::git::RefString;
|
use radicle::git::RefString;
|
||||||
use radicle::storage::{git, refs, ReadRepository};
|
use radicle::storage::{git, refs, ReadRepository};
|
||||||
use radicle_surf::blob::Blob;
|
use radicle_surf::blob::Blob;
|
||||||
|
|
@ -98,7 +99,10 @@ pub(crate) fn issue(id: IssueId, issue: Issue) -> Value {
|
||||||
"title": issue.title(),
|
"title": issue.title(),
|
||||||
"state": issue.state(),
|
"state": issue.state(),
|
||||||
"assignees": issue.assigned().collect::<Vec<_>>(),
|
"assignees": issue.assigned().collect::<Vec<_>>(),
|
||||||
"discussion": issue.comments().collect::<Comments>(),
|
"discussion": issue
|
||||||
|
.comments()
|
||||||
|
.map(|(id, comment)| Comment::new(id, comment, issue.thread()))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
"tags": issue.tags().collect::<Vec<_>>(),
|
"tags": issue.tags().collect::<Vec<_>>(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -121,7 +125,10 @@ pub(crate) fn patch(id: PatchId, patch: Patch, repo: &git::Repository) -> Value
|
||||||
"oid": rev.oid,
|
"oid": rev.oid,
|
||||||
"refs": get_refs(repo, patch.author().id(), &rev.oid).unwrap_or(vec![]),
|
"refs": get_refs(repo, patch.author().id(), &rev.oid).unwrap_or(vec![]),
|
||||||
"merges": rev.merges().collect::<Vec<_>>(),
|
"merges": rev.merges().collect::<Vec<_>>(),
|
||||||
"discussions": rev.discussion.comments().collect::<Comments>(),
|
"discussions": rev.discussion
|
||||||
|
.comments()
|
||||||
|
.map(|(id, comment)| Comment::new(id, comment, &rev.discussion))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
"timestamp": rev.timestamp,
|
"timestamp": rev.timestamp,
|
||||||
"reviews": rev.reviews().collect::<Vec<_>>(),
|
"reviews": rev.reviews().collect::<Vec<_>>(),
|
||||||
})
|
})
|
||||||
|
|
@ -160,33 +167,24 @@ fn get_refs(
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
struct Comment {
|
struct Comment<'a> {
|
||||||
id: CommentId,
|
id: CommentId,
|
||||||
author: Author,
|
author: Author,
|
||||||
body: String,
|
body: &'a str,
|
||||||
reactions: [String; 0],
|
reactions: Vec<(&'a ActorId, &'a Reaction)>,
|
||||||
timestamp: Timestamp,
|
timestamp: Timestamp,
|
||||||
reply_to: Option<CommentId>,
|
reply_to: Option<CommentId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
impl<'a> Comment<'a> {
|
||||||
struct Comments(Vec<Comment>);
|
fn new(id: &'a CommentId, comment: &'a thread::Comment, thread: &'a Thread) -> Self {
|
||||||
|
Self {
|
||||||
impl<'a> FromIterator<(&'a CommentId, &'a thread::Comment)> for Comments {
|
id: *id,
|
||||||
fn from_iter<I: IntoIterator<Item = (&'a CommentId, &'a thread::Comment)>>(iter: I) -> Self {
|
author: Author::new(comment.author()),
|
||||||
let mut comments = Vec::new();
|
body: comment.body(),
|
||||||
|
reactions: thread.reactions(id).collect::<Vec<_>>(),
|
||||||
for (id, comment) in iter {
|
timestamp: comment.timestamp(),
|
||||||
comments.push(Comment {
|
reply_to: comment.reply_to(),
|
||||||
id: id.to_owned(),
|
|
||||||
author: comment.author().into(),
|
|
||||||
body: comment.body().to_owned(),
|
|
||||||
reactions: [],
|
|
||||||
timestamp: comment.timestamp(),
|
|
||||||
reply_to: comment.reply_to(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Comments(comments)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1523,6 +1523,24 @@ mod routes {
|
||||||
assert_eq!(response.status(), StatusCode::OK);
|
assert_eq!(response.status(), StatusCode::OK);
|
||||||
assert_eq!(response.json().await, json!({ "success": true }));
|
assert_eq!(response.json().await, json!({ "success": true }));
|
||||||
|
|
||||||
|
let body = serde_json::to_vec(&json!({
|
||||||
|
"type": "thread",
|
||||||
|
"action": {
|
||||||
|
"type": "react",
|
||||||
|
"to": "9685b141c2e939c3d60f8ca34f8c7bf01a609af1",
|
||||||
|
"reaction": "🚀",
|
||||||
|
"active": true,
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.unwrap();
|
||||||
|
patch(
|
||||||
|
&app,
|
||||||
|
format!("/projects/{CONTRIBUTOR_RID}/issues/{CONTRIBUTOR_ISSUE_ID}"),
|
||||||
|
Some(Body::from(body)),
|
||||||
|
Some(SESSION_ID.to_string()),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
let response = get(
|
let response = get(
|
||||||
&app,
|
&app,
|
||||||
format!("/projects/{CONTRIBUTOR_RID}/issues/{CONTRIBUTOR_ISSUE_ID}"),
|
format!("/projects/{CONTRIBUTOR_RID}/issues/{CONTRIBUTOR_ISSUE_ID}"),
|
||||||
|
|
@ -1536,11 +1554,11 @@ mod routes {
|
||||||
"author": {
|
"author": {
|
||||||
"id": CONTRIBUTOR_DID,
|
"id": CONTRIBUTOR_DID,
|
||||||
},
|
},
|
||||||
"assignees": [],
|
|
||||||
"title": "Issue #1",
|
"title": "Issue #1",
|
||||||
"state": {
|
"state": {
|
||||||
"status": "open",
|
"status": "open",
|
||||||
},
|
},
|
||||||
|
"assignees": [],
|
||||||
"discussion": [
|
"discussion": [
|
||||||
{
|
{
|
||||||
"id": ISSUE_DISCUSSION_ID,
|
"id": ISSUE_DISCUSSION_ID,
|
||||||
|
|
@ -1558,7 +1576,12 @@ mod routes {
|
||||||
"id": CONTRIBUTOR_DID,
|
"id": CONTRIBUTOR_DID,
|
||||||
},
|
},
|
||||||
"body": "This is first-level comment",
|
"body": "This is first-level comment",
|
||||||
"reactions": [],
|
"reactions": [
|
||||||
|
[
|
||||||
|
"z6Mkk7oqY4pPxhMmGEotDYsFo97vhCj85BLY1H256HrJmjN8",
|
||||||
|
"🚀",
|
||||||
|
],
|
||||||
|
],
|
||||||
"timestamp": TIMESTAMP,
|
"timestamp": TIMESTAMP,
|
||||||
"replyTo": null,
|
"replyTo": null,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -80,10 +80,15 @@ impl State {
|
||||||
/// Issue state. Accumulates [`Action`].
|
/// Issue state. Accumulates [`Action`].
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Issue {
|
pub struct Issue {
|
||||||
|
/// Actors assigned to this issue.
|
||||||
assignees: LWWSet<ActorId>,
|
assignees: LWWSet<ActorId>,
|
||||||
|
/// Title of the issue.
|
||||||
title: LWWReg<Max<String>, clock::Lamport>,
|
title: LWWReg<Max<String>, clock::Lamport>,
|
||||||
|
/// Current state of the issue.
|
||||||
state: LWWReg<Max<State>, clock::Lamport>,
|
state: LWWReg<Max<State>, clock::Lamport>,
|
||||||
|
/// Associated tags.
|
||||||
tags: LWWSet<Tag>,
|
tags: LWWSet<Tag>,
|
||||||
|
/// Discussion around this issue.
|
||||||
thread: Thread,
|
thread: Thread,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -195,6 +200,10 @@ impl Issue {
|
||||||
self.thread.comments().next().map(|(_, c)| c.body())
|
self.thread.comments().next().map(|(_, c)| c.body())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn thread(&self) -> &Thread {
|
||||||
|
&self.thread
|
||||||
|
}
|
||||||
|
|
||||||
pub fn comments(&self) -> impl Iterator<Item = (&CommentId, &thread::Comment)> {
|
pub fn comments(&self) -> impl Iterator<Item = (&CommentId, &thread::Comment)> {
|
||||||
self.thread.comments()
|
self.thread.comments()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue