From: Aode (lion) Date: Tue, 16 Nov 2021 00:58:15 +0000 (-0600) Subject: Support mastodon deletes X-Git-Url: http://these/git/%7B%60%24%7BwebArchiveUrl%7D/%22%7B%7D/%22https:/nerdica.net/static/sneer-club-logo.svg?a=commitdiff_plain;h=20cddf5e81da48f083f3ead6b90c74b4d431e3b6;p=lemmy.git Support mastodon deletes --- diff --git a/crates/api_crud/src/comment/delete.rs b/crates/api_crud/src/comment/delete.rs index f55119f7..7e920882 100644 --- a/crates/api_crud/src/comment/delete.rs +++ b/crates/api_crud/src/comment/delete.rs @@ -7,7 +7,7 @@ use lemmy_api_common::{ get_local_user_view_from_jwt, is_mod_or_admin, }; -use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove}; +use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove, DeletableObjects}; use lemmy_db_schema::{ source::{ comment::Comment, @@ -69,6 +69,18 @@ impl PerformCrud for DeleteComment { .await? .map_err(|e| ApiError::err("couldnt_update_comment", e))?; + let post_id = updated_comment.post_id; + let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; + let recipient_ids = send_local_notifs( + vec![], + &updated_comment, + &local_user_view.person, + &post, + false, + context, + ) + .await?; + // Send the apub message let community = blocking(context.pool(), move |conn| { Community::read(conn, orig_comment.post.community_id) @@ -77,24 +89,12 @@ impl PerformCrud for DeleteComment { send_apub_delete( &local_user_view.person.clone().into(), &community.clone().into(), - updated_comment.ap_id.clone().into(), + DeletableObjects::Comment(Box::new(updated_comment.into())), deleted, context, ) .await?; - let post_id = updated_comment.post_id; - let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; - let recipient_ids = send_local_notifs( - vec![], - &updated_comment, - &local_user_view.person, - &post, - false, - context, - ) - .await?; - send_comment_ws_message( data.comment_id, UserOperationCrud::DeleteComment, @@ -162,6 +162,18 @@ impl PerformCrud for RemoveComment { }) .await??; + let post_id = updated_comment.post_id; + let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; + let recipient_ids = send_local_notifs( + vec![], + &updated_comment, + &local_user_view.person.clone(), + &post, + false, + context, + ) + .await?; + // Send the apub message let community = blocking(context.pool(), move |conn| { Community::read(conn, orig_comment.post.community_id) @@ -170,25 +182,13 @@ impl PerformCrud for RemoveComment { send_apub_remove( &local_user_view.person.clone().into(), &community.into(), - updated_comment.ap_id.clone().into(), + DeletableObjects::Comment(Box::new(updated_comment.into())), data.reason.clone().unwrap_or_else(|| "".to_string()), removed, context, ) .await?; - let post_id = updated_comment.post_id; - let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; - let recipient_ids = send_local_notifs( - vec![], - &updated_comment, - &local_user_view.person.clone(), - &post, - false, - context, - ) - .await?; - send_comment_ws_message( data.comment_id, UserOperationCrud::RemoveComment, diff --git a/crates/api_crud/src/community/delete.rs b/crates/api_crud/src/community/delete.rs index bf59e786..aec45192 100644 --- a/crates/api_crud/src/community/delete.rs +++ b/crates/api_crud/src/community/delete.rs @@ -1,7 +1,7 @@ use crate::PerformCrud; use actix_web::web::Data; use lemmy_api_common::{blocking, community::*, get_local_user_view_from_jwt, is_admin}; -use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove}; +use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove, DeletableObjects}; use lemmy_db_schema::{ source::{ community::Community, @@ -51,7 +51,7 @@ impl PerformCrud for DeleteCommunity { send_apub_delete( &local_user_view.person.clone().into(), &updated_community.clone().into(), - updated_community.actor_id.clone().into(), + DeletableObjects::Community(Box::new(updated_community.into())), deleted, context, ) @@ -111,7 +111,7 @@ impl PerformCrud for RemoveCommunity { send_apub_remove( &local_user_view.person.clone().into(), &updated_community.clone().into(), - updated_community.actor_id.clone().into(), + DeletableObjects::Community(Box::new(updated_community.into())), data.reason.clone().unwrap_or_else(|| "".to_string()), removed, context, diff --git a/crates/api_crud/src/post/delete.rs b/crates/api_crud/src/post/delete.rs index af699934..a974feb1 100644 --- a/crates/api_crud/src/post/delete.rs +++ b/crates/api_crud/src/post/delete.rs @@ -8,7 +8,7 @@ use lemmy_api_common::{ is_mod_or_admin, post::*, }; -use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove}; +use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove, DeletableObjects}; use lemmy_db_schema::{ source::{ community::Community, @@ -70,7 +70,7 @@ impl PerformCrud for DeletePost { send_apub_delete( &local_user_view.person.clone().into(), &community.into(), - updated_post.ap_id.into(), + DeletableObjects::Post(Box::new(updated_post.into())), deleted, context, ) @@ -146,7 +146,7 @@ impl PerformCrud for RemovePost { send_apub_remove( &local_user_view.person.clone().into(), &community.into(), - updated_post.ap_id.into(), + DeletableObjects::Post(Box::new(updated_post.into())), data.reason.clone().unwrap_or_else(|| "".to_string()), removed, context, diff --git a/crates/apub/assets/lemmy/activities/deletion/delete_page.json b/crates/apub/assets/lemmy/activities/deletion/delete_page.json index 8dd26a10..6b2aba37 100644 --- a/crates/apub/assets/lemmy/activities/deletion/delete_page.json +++ b/crates/apub/assets/lemmy/activities/deletion/delete_page.json @@ -3,7 +3,10 @@ "to": [ "https://www.w3.org/ns/activitystreams#Public" ], - "object": "http://ds9.lemmy.ml/post/1", + "object": { + "id": "http://ds9.lemmy.ml/post/1", + "type": "Tombstone" + }, "cc": [ "http://enterprise.lemmy.ml/c/main" ], diff --git a/crates/apub/assets/lemmy/activities/deletion/remove_note.json b/crates/apub/assets/lemmy/activities/deletion/remove_note.json index 8ea35404..07ca4e5c 100644 --- a/crates/apub/assets/lemmy/activities/deletion/remove_note.json +++ b/crates/apub/assets/lemmy/activities/deletion/remove_note.json @@ -3,7 +3,10 @@ "to": [ "https://www.w3.org/ns/activitystreams#Public" ], - "object": "http://ds9.lemmy.ml/comment/1", + "object": { + "id": "http://ds9.lemmy.ml/comment/1", + "type": "Tombstone" + }, "cc": [ "http://enterprise.lemmy.ml/c/main" ], diff --git a/crates/apub/assets/lemmy/activities/deletion/undo_delete_page.json b/crates/apub/assets/lemmy/activities/deletion/undo_delete_page.json index 9f824fa1..d2d5533f 100644 --- a/crates/apub/assets/lemmy/activities/deletion/undo_delete_page.json +++ b/crates/apub/assets/lemmy/activities/deletion/undo_delete_page.json @@ -8,7 +8,10 @@ "to": [ "https://www.w3.org/ns/activitystreams#Public" ], - "object": "http://ds9.lemmy.ml/post/1", + "object": { + "id": "http://ds9.lemmy.ml/post/1", + "type": "Tombstone" + }, "cc": [ "http://enterprise.lemmy.ml/c/main" ], diff --git a/crates/apub/assets/lemmy/activities/deletion/undo_remove_note.json b/crates/apub/assets/lemmy/activities/deletion/undo_remove_note.json index 413cf16b..e4c9ee26 100644 --- a/crates/apub/assets/lemmy/activities/deletion/undo_remove_note.json +++ b/crates/apub/assets/lemmy/activities/deletion/undo_remove_note.json @@ -8,7 +8,10 @@ "to": [ "https://www.w3.org/ns/activitystreams#Public" ], - "object": "http://ds9.lemmy.ml/comment/1", + "object": { + "id": "http://ds9.lemmy.ml/comment/1", + "type": "Tombstone" + }, "cc": [ "http://enterprise.lemmy.ml/c/main" ], diff --git a/crates/apub/src/activities/deletion/delete.rs b/crates/apub/src/activities/deletion/delete.rs index cec8ab9a..b976a1b4 100644 --- a/crates/apub/src/activities/deletion/delete.rs +++ b/crates/apub/src/activities/deletion/delete.rs @@ -50,11 +50,11 @@ impl ActivityHandler for Delete { context: &Data, request_counter: &mut i32, ) -> Result<(), LemmyError> { - verify_is_public(&self.to, &self.cc)?; + verify_is_public(&self.to, &[])?; verify_activity(&self.id, self.actor.inner(), &context.settings())?; let community = self.get_community(context, request_counter).await?; verify_delete_activity( - &self.object, + &self.object.id, &self.actor, &community, self.summary.is_some(), @@ -78,9 +78,16 @@ impl ActivityHandler for Delete { } else { Some(reason) }; - receive_remove_action(&self.actor, &self.object, reason, context, request_counter).await + receive_remove_action( + &self.actor, + &self.object.id, + reason, + context, + request_counter, + ) + .await } else { - receive_delete_action(&self.object, &self.actor, true, context, request_counter).await + receive_delete_action(&self.object.id, &self.actor, true, context, request_counter).await } } } @@ -88,16 +95,14 @@ impl ActivityHandler for Delete { impl Delete { pub(in crate::activities::deletion) fn new( actor: &ApubPerson, - community: &ApubCommunity, - object_id: Url, + object: DeletableObjects, summary: Option, context: &LemmyContext, ) -> Result { Ok(Delete { actor: ObjectId::new(actor.actor_id()), to: vec![public()], - object: object_id, - cc: vec![community.actor_id()], + object: object.to_tombstone()?, kind: DeleteType::Delete, summary, id: generate_activity_id( @@ -110,11 +115,11 @@ impl Delete { pub(in crate::activities::deletion) async fn send( actor: &ApubPerson, community: &ApubCommunity, - object_id: Url, + object: DeletableObjects, summary: Option, context: &LemmyContext, ) -> Result<(), LemmyError> { - let delete = Delete::new(actor, community, object_id, summary, context)?; + let delete = Delete::new(actor, object, summary, context)?; let delete_id = delete.id.clone(); let activity = AnnouncableActivities::Delete(delete); @@ -201,7 +206,7 @@ impl GetCommunity for Delete { context: &LemmyContext, _request_counter: &mut i32, ) -> Result { - let community_id = match DeletableObjects::read_from_db(&self.object, context).await? { + let community_id = match DeletableObjects::read_from_db(&self.object.id, context).await? { DeletableObjects::Community(c) => c.id, DeletableObjects::Comment(c) => { let post = blocking(context.pool(), move |conn| Post::read(conn, c.post_id)).await??; diff --git a/crates/apub/src/activities/deletion/mod.rs b/crates/apub/src/activities/deletion/mod.rs index ddd607a7..ab2e7a0b 100644 --- a/crates/apub/src/activities/deletion/mod.rs +++ b/crates/apub/src/activities/deletion/mod.rs @@ -1,14 +1,13 @@ use crate::{ activities::{verify_mod_action, verify_person_in_community}, objects::{comment::ApubComment, community::ApubCommunity, person::ApubPerson, post::ApubPost}, - protocol::activities::deletion::{delete::Delete, undo_delete::UndoDelete}, + protocol::{ + activities::deletion::{delete::Delete, undo_delete::UndoDelete}, + objects::tombstone::Tombstone, + }, }; use lemmy_api_common::blocking; -use lemmy_apub_lib::{ - object_id::ObjectId, - traits::{ActorType, ApubObject}, - verify::verify_domains_match, -}; +use lemmy_apub_lib::{object_id::ObjectId, traits::ApubObject, verify::verify_domains_match}; use lemmy_db_schema::source::{comment::Comment, community::Community, post::Post}; use lemmy_utils::LemmyError; use lemmy_websocket::{ @@ -24,14 +23,14 @@ pub mod undo_delete; pub async fn send_apub_delete( actor: &ApubPerson, community: &ApubCommunity, - object_id: Url, + object: DeletableObjects, deleted: bool, context: &LemmyContext, ) -> Result<(), LemmyError> { if deleted { - Delete::send(actor, community, object_id, None, context).await + Delete::send(actor, community, object, None, context).await } else { - UndoDelete::send(actor, community, object_id, None, context).await + UndoDelete::send(actor, community, object, None, context).await } } @@ -40,15 +39,15 @@ pub async fn send_apub_delete( pub async fn send_apub_remove( actor: &ApubPerson, community: &ApubCommunity, - object_id: Url, + object: DeletableObjects, reason: String, removed: bool, context: &LemmyContext, ) -> Result<(), LemmyError> { if removed { - Delete::send(actor, community, object_id, Some(reason), context).await + Delete::send(actor, community, object, Some(reason), context).await } else { - UndoDelete::send(actor, community, object_id, Some(reason), context).await + UndoDelete::send(actor, community, object, Some(reason), context).await } } @@ -74,6 +73,14 @@ impl DeletableObjects { } Err(diesel::NotFound.into()) } + + pub(crate) fn to_tombstone(&self) -> Result { + match self { + DeletableObjects::Community(c) => c.to_tombstone(), + DeletableObjects::Comment(c) => c.to_tombstone(), + DeletableObjects::Post(p) => p.to_tombstone(), + } + } } pub(in crate::activities) async fn verify_delete_activity( @@ -153,7 +160,7 @@ async fn receive_delete_action( DeletableObjects::Community(community) => { if community.local { let mod_ = actor.dereference(context, request_counter).await?; - let object = community.actor_id(); + let object = DeletableObjects::Community(community.clone()); send_apub_delete(&mod_, &community.clone(), object, true, context).await?; } diff --git a/crates/apub/src/activities/deletion/undo_delete.rs b/crates/apub/src/activities/deletion/undo_delete.rs index c6e5ddfc..28ad0f5a 100644 --- a/crates/apub/src/activities/deletion/undo_delete.rs +++ b/crates/apub/src/activities/deletion/undo_delete.rs @@ -40,7 +40,7 @@ impl ActivityHandler for UndoDelete { self.object.verify(context, request_counter).await?; let community = self.get_community(context, request_counter).await?; verify_delete_activity( - &self.object.object, + &self.object.object.id, &self.actor, &community, self.object.summary.is_some(), @@ -57,10 +57,10 @@ impl ActivityHandler for UndoDelete { request_counter: &mut i32, ) -> Result<(), LemmyError> { if self.object.summary.is_some() { - UndoDelete::receive_undo_remove_action(&self.object.object, context).await + UndoDelete::receive_undo_remove_action(&self.object.object.id, context).await } else { receive_delete_action( - &self.object.object, + &self.object.object.id, &self.actor, false, context, @@ -75,11 +75,11 @@ impl UndoDelete { pub(in crate::activities::deletion) async fn send( actor: &ApubPerson, community: &ApubCommunity, - object_id: Url, + object: DeletableObjects, summary: Option, context: &LemmyContext, ) -> Result<(), LemmyError> { - let object = Delete::new(actor, community, object_id, summary, context)?; + let object = Delete::new(actor, object, summary, context)?; let id = generate_activity_id( UndoType::Undo, diff --git a/crates/apub/src/activities/mod.rs b/crates/apub/src/activities/mod.rs index b75d37e4..cac5d6e1 100644 --- a/crates/apub/src/activities/mod.rs +++ b/crates/apub/src/activities/mod.rs @@ -117,7 +117,7 @@ fn verify_add_remove_moderator_target( } pub(crate) fn verify_is_public(to: &[Url], cc: &[Url]) -> Result<(), LemmyError> { - if !to.contains(&public()) && !cc.contains(&public()) { + if ![to, cc].iter().any(|set| set.contains(&public())) { return Err(anyhow!("Object is not public").into()); } Ok(()) diff --git a/crates/apub/src/objects/comment.rs b/crates/apub/src/objects/comment.rs index 40683818..a3840e10 100644 --- a/crates/apub/src/objects/comment.rs +++ b/crates/apub/src/objects/comment.rs @@ -132,10 +132,7 @@ impl ApubObject for ApubComment { } fn to_tombstone(&self) -> Result { - Ok(Tombstone::new( - NoteType::Note, - self.updated.unwrap_or(self.published), - )) + Ok(Tombstone::new(self.ap_id.clone().into())) } async fn verify( diff --git a/crates/apub/src/objects/community.rs b/crates/apub/src/objects/community.rs index 87fca8d3..f37d82d8 100644 --- a/crates/apub/src/objects/community.rs +++ b/crates/apub/src/objects/community.rs @@ -118,10 +118,7 @@ impl ApubObject for ApubCommunity { } fn to_tombstone(&self) -> Result { - Ok(Tombstone::new( - GroupType::Group, - self.updated.unwrap_or(self.published), - )) + Ok(Tombstone::new(self.actor_id())) } async fn verify( diff --git a/crates/apub/src/objects/post.rs b/crates/apub/src/objects/post.rs index 4e34fc88..44dbe73b 100644 --- a/crates/apub/src/objects/post.rs +++ b/crates/apub/src/objects/post.rs @@ -128,10 +128,7 @@ impl ApubObject for ApubPost { } fn to_tombstone(&self) -> Result { - Ok(Tombstone::new( - PageType::Page, - self.updated.unwrap_or(self.published), - )) + Ok(Tombstone::new(self.ap_id.clone().into())) } async fn verify( diff --git a/crates/apub/src/protocol/activities/deletion/delete.rs b/crates/apub/src/protocol/activities/deletion/delete.rs index 7e227515..26aee276 100644 --- a/crates/apub/src/protocol/activities/deletion/delete.rs +++ b/crates/apub/src/protocol/activities/deletion/delete.rs @@ -1,4 +1,4 @@ -use crate::objects::person::ApubPerson; +use crate::{objects::person::ApubPerson, protocol::objects::tombstone::Tombstone}; use activitystreams::{activity::kind::DeleteType, unparsed::Unparsed}; use lemmy_apub_lib::object_id::ObjectId; use serde::{Deserialize, Serialize}; @@ -11,8 +11,7 @@ use url::Url; pub struct Delete { pub(crate) actor: ObjectId, pub(crate) to: Vec, - pub(crate) object: Url, - pub(crate) cc: Vec, + pub(crate) object: Tombstone, #[serde(rename = "type")] pub(crate) kind: DeleteType, /// If summary is present, this is a mod action (Remove in Lemmy terms). Otherwise, its a user diff --git a/crates/apub/src/protocol/activities/deletion/mod.rs b/crates/apub/src/protocol/activities/deletion/mod.rs index c77492a3..647c3d50 100644 --- a/crates/apub/src/protocol/activities/deletion/mod.rs +++ b/crates/apub/src/protocol/activities/deletion/mod.rs @@ -11,7 +11,7 @@ mod tests { #[actix_rt::test] #[serial] - async fn test_parse_lemmy_voting() { + async fn test_parse_lemmy_deletion() { test_parse_lemmy_item::("assets/lemmy/activities/deletion/remove_note.json"); test_parse_lemmy_item::("assets/lemmy/activities/deletion/delete_page.json"); diff --git a/crates/apub/src/protocol/objects/tombstone.rs b/crates/apub/src/protocol/objects/tombstone.rs index 2746c5ae..152066cb 100644 --- a/crates/apub/src/protocol/objects/tombstone.rs +++ b/crates/apub/src/protocol/objects/tombstone.rs @@ -1,25 +1,22 @@ use activitystreams::object::kind::TombstoneType; -use chrono::{DateTime, FixedOffset, NaiveDateTime}; -use lemmy_utils::utils::convert_datetime; use serde::{Deserialize, Serialize}; use serde_with::skip_serializing_none; +use url::Url; #[skip_serializing_none] #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct Tombstone { + pub(crate) id: Url, #[serde(rename = "type")] kind: TombstoneType, - former_type: String, - deleted: DateTime, } impl Tombstone { - pub fn new(former_type: T, updated_time: NaiveDateTime) -> Tombstone { + pub fn new(id: Url) -> Tombstone { Tombstone { + id, kind: TombstoneType::Tombstone, - former_type: former_type.to_string(), - deleted: convert_datetime(updated_time), } } }