httpd: Add comment edits to serialized json
This allows the display of any edits done to comments, replies and issue descriptions. This commit doesn't remove the body property which is the latest comment body but adds a edits property. Also adds an author property to the `Edit` struct, which allows us to see the author of an edit action.
This commit is contained in:
parent
924a2624a4
commit
f8005c74c6
|
|
@ -242,6 +242,7 @@ 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")]
|
||||
|
|
@ -257,6 +258,17 @@ impl<'a> Comment<'a> {
|
|||
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(),
|
||||
|
|
|
|||
|
|
@ -1995,6 +1995,16 @@ mod routes {
|
|||
"id": DID
|
||||
},
|
||||
"body": "Change 'hello world' to 'hello everyone'",
|
||||
"edits": [
|
||||
{
|
||||
"author": {
|
||||
"id": DID,
|
||||
},
|
||||
"body": "Change 'hello world' to 'hello everyone'",
|
||||
"timestamp": COMMENT_TIMESTAMP,
|
||||
"embeds": [],
|
||||
},
|
||||
],
|
||||
"embeds": [],
|
||||
"reactions": [],
|
||||
"timestamp": TIMESTAMP,
|
||||
|
|
@ -2070,6 +2080,21 @@ mod routes {
|
|||
"id": CONTRIBUTOR_DID,
|
||||
},
|
||||
"body": "Change 'hello world' to 'hello everyone'",
|
||||
"edits": [
|
||||
{
|
||||
"author": {
|
||||
"id": CONTRIBUTOR_DID,
|
||||
},
|
||||
"body": "Change 'hello world' to 'hello everyone'",
|
||||
"timestamp": COMMENT_TIMESTAMP,
|
||||
"embeds": [
|
||||
{
|
||||
"name": "example.html",
|
||||
"content": "git:b62df2ec90365e3749cd4fa431cb844492908b84",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
"embeds": [
|
||||
{
|
||||
"name": "example.html",
|
||||
|
|
@ -2203,6 +2228,29 @@ mod routes {
|
|||
"id": CONTRIBUTOR_DID,
|
||||
},
|
||||
"body": "EDIT: Change 'hello world' to 'hello anyone'",
|
||||
"edits": [
|
||||
{
|
||||
"author": {
|
||||
"id": CONTRIBUTOR_DID,
|
||||
},
|
||||
"body": "Change 'hello world' to 'hello everyone'",
|
||||
"timestamp": COMMENT_TIMESTAMP,
|
||||
"embeds": [],
|
||||
},
|
||||
{
|
||||
"author": {
|
||||
"id": CONTRIBUTOR_DID,
|
||||
},
|
||||
"body": "EDIT: Change 'hello world' to 'hello anyone'",
|
||||
"timestamp": COMMENT_TIMESTAMP,
|
||||
"embeds": [
|
||||
{
|
||||
"name": "image.jpg",
|
||||
"content": "git:94381b429d7f7fe87e1bade52d893ab348ae29cc",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
"embeds": [
|
||||
{
|
||||
"name": "image.jpg",
|
||||
|
|
@ -2271,11 +2319,11 @@ mod routes {
|
|||
"author": {
|
||||
"id": CONTRIBUTOR_DID,
|
||||
},
|
||||
"assignees": [],
|
||||
"title": "Issue #1",
|
||||
"state": {
|
||||
"status": "open",
|
||||
},
|
||||
"assignees": [],
|
||||
"discussion": [
|
||||
{
|
||||
"id": ISSUE_DISCUSSION_ID,
|
||||
|
|
@ -2283,6 +2331,16 @@ mod routes {
|
|||
"id": CONTRIBUTOR_DID,
|
||||
},
|
||||
"body": "Change 'hello world' to 'hello everyone'",
|
||||
"edits": [
|
||||
{
|
||||
"author": {
|
||||
"id": CONTRIBUTOR_DID,
|
||||
},
|
||||
"body": "Change 'hello world' to 'hello everyone'",
|
||||
"timestamp": COMMENT_TIMESTAMP,
|
||||
"embeds": [],
|
||||
},
|
||||
],
|
||||
"embeds": [],
|
||||
"reactions": [],
|
||||
"timestamp": TIMESTAMP,
|
||||
|
|
@ -2295,6 +2353,21 @@ mod routes {
|
|||
"id": CONTRIBUTOR_DID,
|
||||
},
|
||||
"body": "This is a reply to the first comment",
|
||||
"edits": [
|
||||
{
|
||||
"author": {
|
||||
"id": CONTRIBUTOR_DID,
|
||||
},
|
||||
"body": "This is a reply to the first comment",
|
||||
"timestamp": COMMENT_TIMESTAMP,
|
||||
"embeds": [
|
||||
{
|
||||
"name": "image.jpg",
|
||||
"content": "git:94381b429d7f7fe87e1bade52d893ab348ae29cc",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
"embeds": [
|
||||
{
|
||||
"name": "image.jpg",
|
||||
|
|
@ -2931,6 +3004,34 @@ mod routes {
|
|||
"id": CONTRIBUTOR_DID,
|
||||
},
|
||||
"body": "EDIT: This is a root level comment",
|
||||
"edits": [
|
||||
{
|
||||
"author": {
|
||||
"id": CONTRIBUTOR_DID,
|
||||
},
|
||||
"body": "This is a root level comment",
|
||||
"timestamp": COMMENT_TIMESTAMP,
|
||||
"embeds": [
|
||||
{
|
||||
"name": "image.jpg",
|
||||
"content": "git:94381b429d7f7fe87e1bade52d893ab348ae29cc",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"author": {
|
||||
"id": CONTRIBUTOR_DID,
|
||||
},
|
||||
"body": "EDIT: This is a root level comment",
|
||||
"timestamp": COMMENT_TIMESTAMP,
|
||||
"embeds": [
|
||||
{
|
||||
"name": "image.jpg",
|
||||
"content": "git:94381b429d7f7fe87e1bade52d893ab348ae29cc",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
"embeds": [
|
||||
{
|
||||
"name": "image.jpg",
|
||||
|
|
@ -2948,6 +3049,16 @@ mod routes {
|
|||
"id": CONTRIBUTOR_DID,
|
||||
},
|
||||
"body": "This is a root level comment",
|
||||
"edits": [
|
||||
{
|
||||
"author": {
|
||||
"id": CONTRIBUTOR_DID,
|
||||
},
|
||||
"body": "This is a root level comment",
|
||||
"timestamp": COMMENT_TIMESTAMP,
|
||||
"embeds": [],
|
||||
},
|
||||
],
|
||||
"embeds": [],
|
||||
"reactions": [],
|
||||
"timestamp": TIMESTAMP,
|
||||
|
|
@ -3132,6 +3243,30 @@ mod routes {
|
|||
],
|
||||
"resolved": true,
|
||||
"body": "EDIT: This is a comment on a review",
|
||||
"edits": [
|
||||
{
|
||||
"author": "z6Mkk7oqY4pPxhMmGEotDYsFo97vhCj85BLY1H256HrJmjN8",
|
||||
"timestamp": COMMENT_TIMESTAMP,
|
||||
"body": "This is a comment on a review",
|
||||
"embeds": [
|
||||
{
|
||||
"name": "image.jpg",
|
||||
"content": "git:94381b429d7f7fe87e1bade52d893ab348ae29cc",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"author": "z6Mkk7oqY4pPxhMmGEotDYsFo97vhCj85BLY1H256HrJmjN8",
|
||||
"timestamp": COMMENT_TIMESTAMP,
|
||||
"body": "EDIT: This is a comment on a review",
|
||||
"embeds": [
|
||||
{
|
||||
"name": "image.jpg",
|
||||
"content": "git:94381b429d7f7fe87e1bade52d893ab348ae29cc",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
"embeds": [
|
||||
{
|
||||
"name": "image.jpg",
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ pub const ISSUE_DISCUSSION_ID: &str = "d11b03464c9bf58b09460713c8e2c74f0725d3bd"
|
|||
pub const ISSUE_COMMENT_ID: &str = "e3aa754cb47d2299781fed49cc91c4b41e06c219";
|
||||
pub const SESSION_ID: &str = "u9MGAkkfkMOv0uDDB2WeUHBT7HbsO2Dy";
|
||||
pub const TIMESTAMP: u64 = 1671125284;
|
||||
pub const COMMENT_TIMESTAMP: u64 = 1671125284000;
|
||||
pub const CONTRIBUTOR_RID: &str = "rad:z4XaCmN3jLSeiMvW15YTDpNbDHFhG";
|
||||
pub const CONTRIBUTOR_DID: &str = "did:key:z6Mkk7oqY4pPxhMmGEotDYsFo97vhCj85BLY1H256HrJmjN8";
|
||||
pub const CONTRIBUTOR_NID: &str = "z6Mkk7oqY4pPxhMmGEotDYsFo97vhCj85BLY1H256HrJmjN8";
|
||||
|
|
|
|||
|
|
@ -356,7 +356,7 @@ impl Issue {
|
|||
)?;
|
||||
}
|
||||
Action::CommentEdit { id, body, embeds } => {
|
||||
thread::edit(&mut self.thread, entry, id, timestamp, body, embeds)?;
|
||||
thread::edit(&mut self.thread, entry, author, id, timestamp, body, embeds)?;
|
||||
}
|
||||
Action::CommentRedact { id } => {
|
||||
let (root, _) = self.root();
|
||||
|
|
|
|||
|
|
@ -881,6 +881,7 @@ impl Patch {
|
|||
thread::edit(
|
||||
&mut review.comments,
|
||||
entry,
|
||||
author,
|
||||
comment,
|
||||
timestamp,
|
||||
body,
|
||||
|
|
@ -1036,6 +1037,7 @@ impl Patch {
|
|||
thread::edit(
|
||||
&mut revision.discussion,
|
||||
entry,
|
||||
author,
|
||||
comment,
|
||||
timestamp,
|
||||
body,
|
||||
|
|
|
|||
|
|
@ -53,8 +53,10 @@ pub type CommentId = EntryId;
|
|||
pub type Reactions = BTreeSet<(ActorId, Reaction)>;
|
||||
|
||||
/// A comment edit is just some text and an edit time.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize)]
|
||||
pub struct Edit {
|
||||
/// Edit author.
|
||||
pub author: ActorId,
|
||||
/// When the edit was made.
|
||||
pub timestamp: Timestamp,
|
||||
/// Edit contents. Replaces previous edits.
|
||||
|
|
@ -86,7 +88,7 @@ impl<T: Serialize> Serialize for Comment<T> {
|
|||
where
|
||||
S: serde::ser::Serializer,
|
||||
{
|
||||
let mut state = serializer.serialize_struct("Comment", 8)?;
|
||||
let mut state = serializer.serialize_struct("Comment", 9)?;
|
||||
state.serialize_field("author", &self.author())?;
|
||||
if let Some(loc) = &self.location {
|
||||
state.serialize_field("location", loc)?;
|
||||
|
|
@ -97,6 +99,7 @@ impl<T: Serialize> Serialize for Comment<T> {
|
|||
state.serialize_field("reactions", &self.reactions)?;
|
||||
state.serialize_field("resolved", &self.resolved)?;
|
||||
state.serialize_field("body", self.body())?;
|
||||
state.serialize_field("edits", &self.edits)?;
|
||||
if let Some(location) = self.location() {
|
||||
state.serialize_field("location", &location)?;
|
||||
}
|
||||
|
|
@ -120,6 +123,7 @@ impl<L> Comment<L> {
|
|||
timestamp: Timestamp,
|
||||
) -> Self {
|
||||
let edit = Edit {
|
||||
author,
|
||||
body,
|
||||
embeds,
|
||||
timestamp,
|
||||
|
|
@ -168,8 +172,15 @@ impl<L> Comment<L> {
|
|||
}
|
||||
|
||||
/// Add an edit.
|
||||
pub fn edit(&mut self, body: String, embeds: Vec<Embed<Uri>>, timestamp: Timestamp) {
|
||||
pub fn edit(
|
||||
&mut self,
|
||||
author: ActorId,
|
||||
body: String,
|
||||
embeds: Vec<Embed<Uri>>,
|
||||
timestamp: Timestamp,
|
||||
) {
|
||||
self.edits.push(Edit {
|
||||
author,
|
||||
body,
|
||||
embeds,
|
||||
timestamp,
|
||||
|
|
@ -336,7 +347,7 @@ impl Thread {
|
|||
comment(self, entry, author, timestamp, body, reply_to, None, vec![])?;
|
||||
}
|
||||
Action::Edit { id, body } => {
|
||||
edit(self, entry, id, timestamp, body, vec![])?;
|
||||
edit(self, entry, author, id, timestamp, body, vec![])?;
|
||||
}
|
||||
Action::Redact { id } => {
|
||||
redact(self, entry, id)?;
|
||||
|
|
@ -471,6 +482,7 @@ pub fn comment<L>(
|
|||
pub fn edit<L>(
|
||||
thread: &mut Thread<Comment<L>>,
|
||||
id: EntryId,
|
||||
author: ActorId,
|
||||
comment: EntryId,
|
||||
timestamp: Timestamp,
|
||||
body: String,
|
||||
|
|
@ -489,7 +501,7 @@ pub fn edit<L>(
|
|||
// that as an error.
|
||||
if let Some(comment) = thread.comments.get_mut(&comment) {
|
||||
if let Some(comment) = comment {
|
||||
comment.edit(body, embeds, timestamp);
|
||||
comment.edit(author, body, embeds, timestamp);
|
||||
}
|
||||
} else {
|
||||
return Err(Error::Missing(comment));
|
||||
|
|
@ -785,7 +797,18 @@ mod tests {
|
|||
let (second_id, second) = thread.comments().nth(2).unwrap();
|
||||
|
||||
assert!(first_id != second_id); // The ids are not the same,
|
||||
assert_eq!(first.edits, second.edits); // despite the content being the same.
|
||||
assert_eq!(
|
||||
first
|
||||
.edits
|
||||
.iter()
|
||||
.map(|e| (&e.body, e.timestamp))
|
||||
.collect::<Vec<_>>(),
|
||||
second
|
||||
.edits
|
||||
.iter()
|
||||
.map(|e| (&e.body, e.timestamp))
|
||||
.collect::<Vec<_>>(),
|
||||
); // despite the content being the same.
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
|
|
|
|||
Loading…
Reference in New Issue