From: Nutomic Date: Mon, 14 Feb 2022 15:14:24 +0000 (+0000) Subject: Merge different delete activities for better compatibility (fixes #2066) (#2073) X-Git-Url: http://these/git/readmes/%7B%60%24%7BarchiveTodayUrl%7D/static/%7Bthis.getImage%28%29%7D?a=commitdiff_plain;h=788924d7ff5640babe6c508b6ec4c2a46b57f77b;p=lemmy.git Merge different delete activities for better compatibility (fixes #2066) (#2073) --- diff --git a/crates/api_crud/src/comment/delete.rs b/crates/api_crud/src/comment/delete.rs index 84be30fa..adbc3cc5 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, DeletableObjects}; +use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects}; use lemmy_db_schema::{ source::{ comment::Comment, @@ -83,30 +83,34 @@ impl PerformCrud for DeleteComment { ) .await?; + let res = send_comment_ws_message( + data.comment_id, + UserOperationCrud::DeleteComment, + websocket_id, + None, // TODO a comment delete might clear forms? + Some(local_user_view.person.id), + recipient_ids, + context, + ) + .await?; + // Send the apub message let community = blocking(context.pool(), move |conn| { Community::read(conn, orig_comment.post.community_id) }) .await??; - send_apub_delete( - &local_user_view.person.clone().into(), - &community.clone().into(), - DeletableObjects::Comment(Box::new(updated_comment.into())), + let deletable = DeletableObjects::Comment(Box::new(updated_comment.clone().into())); + send_apub_delete_in_community( + local_user_view.person, + community, + deletable, + None, deleted, context, ) .await?; - send_comment_ws_message( - data.comment_id, - UserOperationCrud::DeleteComment, - websocket_id, - None, // TODO a comment delete might clear forms? - Some(local_user_view.person.id), - recipient_ids, - context, - ) - .await + Ok(res) } } @@ -178,30 +182,33 @@ impl PerformCrud for RemoveComment { ) .await?; + let res = send_comment_ws_message( + data.comment_id, + UserOperationCrud::RemoveComment, + websocket_id, + None, // TODO maybe this might clear other forms + Some(local_user_view.person.id), + recipient_ids, + context, + ) + .await?; + // Send the apub message let community = blocking(context.pool(), move |conn| { Community::read(conn, orig_comment.post.community_id) }) .await??; - send_apub_remove( - &local_user_view.person.clone().into(), - &community.into(), - DeletableObjects::Comment(Box::new(updated_comment.into())), - data.reason.clone().unwrap_or_else(|| "".to_string()), + let deletable = DeletableObjects::Comment(Box::new(updated_comment.clone().into())); + send_apub_delete_in_community( + local_user_view.person, + community, + deletable, + data.reason.clone().or_else(|| Some("".to_string())), removed, context, ) .await?; - send_comment_ws_message( - data.comment_id, - UserOperationCrud::RemoveComment, - websocket_id, - None, // TODO maybe this might clear other forms - Some(local_user_view.person.id), - recipient_ids, - context, - ) - .await + Ok(res) } } diff --git a/crates/api_crud/src/community/delete.rs b/crates/api_crud/src/community/delete.rs index 5769bc53..17ad7003 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, DeletableObjects}; +use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects}; use lemmy_db_schema::{ source::{ community::Community, @@ -49,24 +49,28 @@ impl PerformCrud for DeleteCommunity { .map_err(LemmyError::from) .map_err(|e| e.with_message("couldnt_update_community"))?; - // Send apub messages - send_apub_delete( - &local_user_view.person.clone().into(), - &updated_community.clone().into(), - DeletableObjects::Community(Box::new(updated_community.into())), - deleted, - context, - ) - .await?; - - send_community_ws_message( + let res = send_community_ws_message( data.community_id, UserOperationCrud::DeleteCommunity, websocket_id, Some(local_user_view.person.id), context, ) - .await + .await?; + + // Send apub messages + let deletable = DeletableObjects::Community(Box::new(updated_community.clone().into())); + send_apub_delete_in_community( + local_user_view.person, + updated_community, + deletable, + None, + deleted, + context, + ) + .await?; + + Ok(res) } } @@ -111,24 +115,26 @@ impl PerformCrud for RemoveCommunity { }) .await??; - // Apub messages - send_apub_remove( - &local_user_view.person.clone().into(), - &updated_community.clone().into(), - DeletableObjects::Community(Box::new(updated_community.into())), - data.reason.clone().unwrap_or_else(|| "".to_string()), - removed, - context, - ) - .await?; - - send_community_ws_message( + let res = send_community_ws_message( data.community_id, UserOperationCrud::RemoveCommunity, websocket_id, Some(local_user_view.person.id), context, ) - .await + .await?; + + // Apub messages + let deletable = DeletableObjects::Community(Box::new(updated_community.clone().into())); + send_apub_delete_in_community( + local_user_view.person, + updated_community, + deletable, + data.reason.clone().or_else(|| Some("".to_string())), + removed, + context, + ) + .await?; + Ok(res) } } diff --git a/crates/api_crud/src/post/delete.rs b/crates/api_crud/src/post/delete.rs index 0777153b..05c395b5 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, DeletableObjects}; +use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects}; use lemmy_db_schema::{ source::{ community::Community, @@ -63,28 +63,31 @@ impl PerformCrud for DeletePost { }) .await??; + let res = send_post_ws_message( + data.post_id, + UserOperationCrud::DeletePost, + websocket_id, + Some(local_user_view.person.id), + context, + ) + .await?; + // apub updates let community = blocking(context.pool(), move |conn| { Community::read(conn, orig_post.community_id) }) .await??; - send_apub_delete( - &local_user_view.person.clone().into(), - &community.into(), - DeletableObjects::Post(Box::new(updated_post.into())), + let deletable = DeletableObjects::Post(Box::new(updated_post.into())); + send_apub_delete_in_community( + local_user_view.person, + community, + deletable, + None, deleted, context, ) .await?; - - send_post_ws_message( - data.post_id, - UserOperationCrud::DeletePost, - websocket_id, - Some(local_user_view.person.id), - context, - ) - .await + Ok(res) } } @@ -140,28 +143,30 @@ impl PerformCrud for RemovePost { }) .await??; + let res = send_post_ws_message( + data.post_id, + UserOperationCrud::RemovePost, + websocket_id, + Some(local_user_view.person.id), + context, + ) + .await?; + // apub updates let community = blocking(context.pool(), move |conn| { Community::read(conn, orig_post.community_id) }) .await??; - send_apub_remove( - &local_user_view.person.clone().into(), - &community.into(), - DeletableObjects::Post(Box::new(updated_post.into())), - data.reason.clone().unwrap_or_else(|| "".to_string()), + let deletable = DeletableObjects::Post(Box::new(updated_post.into())); + send_apub_delete_in_community( + local_user_view.person, + community, + deletable, + data.reason.clone().or_else(|| Some("".to_string())), removed, context, ) .await?; - - send_post_ws_message( - data.post_id, - UserOperationCrud::RemovePost, - websocket_id, - Some(local_user_view.person.id), - context, - ) - .await + Ok(res) } } diff --git a/crates/api_crud/src/private_message/create.rs b/crates/api_crud/src/private_message/create.rs index 54edc240..3eddf0a5 100644 --- a/crates/api_crud/src/private_message/create.rs +++ b/crates/api_crud/src/private_message/create.rs @@ -10,7 +10,7 @@ use lemmy_api_common::{ use lemmy_apub::{ generate_local_apub_endpoint, protocol::activities::{ - private_message::create_or_update::CreateOrUpdatePrivateMessage, + create_or_update::private_message::CreateOrUpdatePrivateMessage, CreateOrUpdateType, }, EndpointType, diff --git a/crates/api_crud/src/private_message/delete.rs b/crates/api_crud/src/private_message/delete.rs index e28712cf..f11e9657 100644 --- a/crates/api_crud/src/private_message/delete.rs +++ b/crates/api_crud/src/private_message/delete.rs @@ -5,14 +5,8 @@ use lemmy_api_common::{ get_local_user_view_from_jwt, person::{DeletePrivateMessage, PrivateMessageResponse}, }; -use lemmy_apub::protocol::activities::private_message::{ - delete::DeletePrivateMessage as DeletePrivateMessageApub, - undo_delete::UndoDeletePrivateMessage, -}; -use lemmy_db_schema::{ - source::private_message::PrivateMessage, - traits::{Crud, DeleteableOrRemoveable}, -}; +use lemmy_apub::activities::deletion::send_apub_delete_private_message; +use lemmy_db_schema::{source::private_message::PrivateMessage, traits::Crud}; use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud}; @@ -51,23 +45,13 @@ impl PerformCrud for DeletePrivateMessage { .map_err(|e| e.with_message("couldnt_update_private_message"))?; // Send the apub update - if data.deleted { - DeletePrivateMessageApub::send( - &local_user_view.person.into(), - &updated_private_message - .blank_out_deleted_or_removed_info() - .into(), - context, - ) - .await?; - } else { - UndoDeletePrivateMessage::send( - &local_user_view.person.into(), - &updated_private_message.into(), - context, - ) - .await?; - } + send_apub_delete_private_message( + &local_user_view.person.into(), + updated_private_message, + data.deleted, + context, + ) + .await?; let op = UserOperationCrud::DeletePrivateMessage; send_pm_ws_message(data.private_message_id, op, websocket_id, context).await diff --git a/crates/api_crud/src/private_message/update.rs b/crates/api_crud/src/private_message/update.rs index 83e75687..15e84f2c 100644 --- a/crates/api_crud/src/private_message/update.rs +++ b/crates/api_crud/src/private_message/update.rs @@ -6,7 +6,7 @@ use lemmy_api_common::{ person::{EditPrivateMessage, PrivateMessageResponse}, }; use lemmy_apub::protocol::activities::{ - private_message::create_or_update::CreateOrUpdatePrivateMessage, + create_or_update::private_message::CreateOrUpdatePrivateMessage, CreateOrUpdateType, }; use lemmy_db_schema::{source::private_message::PrivateMessage, traits::Crud}; diff --git a/crates/apub/assets/lemmy/activities/private_message/create.json b/crates/apub/assets/lemmy/activities/create_or_update/create_private_message.json similarity index 100% rename from crates/apub/assets/lemmy/activities/private_message/create.json rename to crates/apub/assets/lemmy/activities/create_or_update/create_private_message.json diff --git a/crates/apub/assets/lemmy/activities/deletion/delete_page.json b/crates/apub/assets/lemmy/activities/deletion/delete_page.json index 6b2aba37..8dd26a10 100644 --- a/crates/apub/assets/lemmy/activities/deletion/delete_page.json +++ b/crates/apub/assets/lemmy/activities/deletion/delete_page.json @@ -3,10 +3,7 @@ "to": [ "https://www.w3.org/ns/activitystreams#Public" ], - "object": { - "id": "http://ds9.lemmy.ml/post/1", - "type": "Tombstone" - }, + "object": "http://ds9.lemmy.ml/post/1", "cc": [ "http://enterprise.lemmy.ml/c/main" ], diff --git a/crates/apub/assets/lemmy/activities/private_message/delete.json b/crates/apub/assets/lemmy/activities/deletion/delete_private_message.json similarity index 100% rename from crates/apub/assets/lemmy/activities/private_message/delete.json rename to crates/apub/assets/lemmy/activities/deletion/delete_private_message.json diff --git a/crates/apub/assets/lemmy/activities/deletion/remove_note.json b/crates/apub/assets/lemmy/activities/deletion/remove_note.json index 07ca4e5c..8ea35404 100644 --- a/crates/apub/assets/lemmy/activities/deletion/remove_note.json +++ b/crates/apub/assets/lemmy/activities/deletion/remove_note.json @@ -3,10 +3,7 @@ "to": [ "https://www.w3.org/ns/activitystreams#Public" ], - "object": { - "id": "http://ds9.lemmy.ml/comment/1", - "type": "Tombstone" - }, + "object": "http://ds9.lemmy.ml/comment/1", "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 d2d5533f..9f824fa1 100644 --- a/crates/apub/assets/lemmy/activities/deletion/undo_delete_page.json +++ b/crates/apub/assets/lemmy/activities/deletion/undo_delete_page.json @@ -8,10 +8,7 @@ "to": [ "https://www.w3.org/ns/activitystreams#Public" ], - "object": { - "id": "http://ds9.lemmy.ml/post/1", - "type": "Tombstone" - }, + "object": "http://ds9.lemmy.ml/post/1", "cc": [ "http://enterprise.lemmy.ml/c/main" ], diff --git a/crates/apub/assets/lemmy/activities/private_message/undo_delete.json b/crates/apub/assets/lemmy/activities/deletion/undo_delete_private_message.json similarity index 100% rename from crates/apub/assets/lemmy/activities/private_message/undo_delete.json rename to crates/apub/assets/lemmy/activities/deletion/undo_delete_private_message.json 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 e4c9ee26..413cf16b 100644 --- a/crates/apub/assets/lemmy/activities/deletion/undo_remove_note.json +++ b/crates/apub/assets/lemmy/activities/deletion/undo_remove_note.json @@ -8,10 +8,7 @@ "to": [ "https://www.w3.org/ns/activitystreams#Public" ], - "object": { - "id": "http://ds9.lemmy.ml/comment/1", - "type": "Tombstone" - }, + "object": "http://ds9.lemmy.ml/comment/1", "cc": [ "http://enterprise.lemmy.ml/c/main" ], diff --git a/crates/apub/assets/mastodon/activities/delete.json b/crates/apub/assets/mastodon/activities/delete.json new file mode 100644 index 00000000..dec21ca4 --- /dev/null +++ b/crates/apub/assets/mastodon/activities/delete.json @@ -0,0 +1,26 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + { + "ostatus": "http://ostatus.org#", + "atomUri": "ostatus:atomUri" + } + ], + "id": "https://mastodon.madrid/users/felix/statuses/107773559874184870#delete", + "type": "Delete", + "actor": "https://mastodon.madrid/users/felix", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "object": { + "id": "https://mastodon.madrid/users/felix/statuses/107773559874184870", + "type": "Tombstone", + "atomUri": "https://mastodon.madrid/users/felix/statuses/107773559874184870" + }, + "signature": { + "type": "RsaSignature2017", + "creator": "https://mastodon.madrid/users/felix#main-key", + "created": "2022-02-10T11:54:18Z", + "signatureValue": "NjGnbkvouSP/cSusR7+sz39iEYxWXCu6nFmBXU3t8ETPkmbpMF5ASeJixXvpTOqbOfkMoWfXncw+jDsbqZ3ELaHGG1gZ5wHWym7mk7YCjQokpF3oPhTWmlEJCVKgewXMrfI4Ok8GGsUMGzuki9EyBDGc/UNBMEAhcxV5Huu7QSQDowcbIwxS3ImxFmtKFceh6mv/kMiXUerCgkYSm6rYZeXZGMTUpvcn9gP6X6Ed6UsrLjCSb3Fj0Naz7LHtzZXRSZDZF/SX2Vw/xKJIgEGzSCv+LKZGvEEkK8PPfMJJhi8cBJebkqOnBGtE6gYK2z2cm/oGorZtXU2L05pXmLAlYQ==" + } +} \ No newline at end of file diff --git a/crates/apub/assets/pleroma/activities/delete.json b/crates/apub/assets/pleroma/activities/delete.json new file mode 100644 index 00000000..b5aa08ef --- /dev/null +++ b/crates/apub/assets/pleroma/activities/delete.json @@ -0,0 +1,35 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://greenish.red/schemas/litepub-0.1.jsonld", + { + "@language": "und" + } + ], + "actor": "https://greenish.red/users/vpzom", + "attachment": [], + "attributedTo": "https://greenish.red/users/vpzom", + "cc": [], + "conversation": null, + "id": "https://greenish.red/activities/52f0b259-596e-429f-8a1b-c0b455f8932b", + "object": "https://greenish.red/objects/38e2b983-ebf5-4387-9bc2-3b80305469c9", + "tag": [ + { + "href": "https://voyager.lemmy.ml/c/main", + "name": "@main@voyager.lemmy.ml", + "type": "Mention" + }, + { + "href": "https://voyager.lemmy.ml/u/dess_voy_41u2", + "name": "@dess_voy_41u2@voyager.lemmy.ml", + "type": "Mention" + } + ], + "to": [ + "https://greenish.red/users/vpzom/followers", + "https://voyager.lemmy.ml/c/main", + "https://voyager.lemmy.ml/u/dess_voy_41u2", + "https://www.w3.org/ns/activitystreams#Public" + ], + "type": "Delete" +} \ No newline at end of file diff --git a/crates/apub/src/activities/comment/create_or_update.rs b/crates/apub/src/activities/create_or_update/comment.rs similarity index 97% rename from crates/apub/src/activities/comment/create_or_update.rs rename to crates/apub/src/activities/create_or_update/comment.rs index b0894ab1..7d6d8904 100644 --- a/crates/apub/src/activities/comment/create_or_update.rs +++ b/crates/apub/src/activities/create_or_update/comment.rs @@ -1,8 +1,8 @@ use crate::{ activities::{ check_community_deleted_or_removed, - comment::get_notif_recipients, community::{announce::GetCommunity, send_activity_in_community}, + create_or_update::get_comment_notif_recipients, generate_activity_id, verify_activity, verify_is_public, @@ -114,7 +114,7 @@ impl ActivityHandler for CreateOrUpdateComment { ) -> Result<(), LemmyError> { let comment = ApubComment::from_apub(self.object, context, request_counter).await?; let do_send_email = self.kind == CreateOrUpdateType::Create; - let recipients = get_notif_recipients( + let recipients = get_comment_notif_recipients( &self.actor, &comment, do_send_email, diff --git a/crates/apub/src/activities/comment/mod.rs b/crates/apub/src/activities/create_or_update/mod.rs similarity index 92% rename from crates/apub/src/activities/comment/mod.rs rename to crates/apub/src/activities/create_or_update/mod.rs index e26bdc06..3cdac71b 100644 --- a/crates/apub/src/activities/comment/mod.rs +++ b/crates/apub/src/activities/create_or_update/mod.rs @@ -9,10 +9,12 @@ use lemmy_db_schema::{ use lemmy_utils::{utils::scrape_text_for_mentions, LemmyError}; use lemmy_websocket::{send::send_local_notifs, LemmyContext}; -pub mod create_or_update; +pub mod comment; +pub mod post; +pub mod private_message; #[tracing::instrument(skip_all)] -async fn get_notif_recipients( +async fn get_comment_notif_recipients( actor: &ObjectId, comment: &Comment, do_send_email: bool, diff --git a/crates/apub/src/activities/post/create_or_update.rs b/crates/apub/src/activities/create_or_update/post.rs similarity index 100% rename from crates/apub/src/activities/post/create_or_update.rs rename to crates/apub/src/activities/create_or_update/post.rs diff --git a/crates/apub/src/activities/private_message/create_or_update.rs b/crates/apub/src/activities/create_or_update/private_message.rs similarity index 97% rename from crates/apub/src/activities/private_message/create_or_update.rs rename to crates/apub/src/activities/create_or_update/private_message.rs index 3374f224..bae43047 100644 --- a/crates/apub/src/activities/private_message/create_or_update.rs +++ b/crates/apub/src/activities/create_or_update/private_message.rs @@ -2,7 +2,7 @@ use crate::{ activities::{generate_activity_id, send_lemmy_activity, verify_activity, verify_person}, objects::{person::ApubPerson, private_message::ApubPrivateMessage}, protocol::activities::{ - private_message::create_or_update::CreateOrUpdatePrivateMessage, + create_or_update::private_message::CreateOrUpdatePrivateMessage, CreateOrUpdateType, }, }; diff --git a/crates/apub/src/activities/deletion/delete.rs b/crates/apub/src/activities/deletion/delete.rs index 774582b1..e141fcad 100644 --- a/crates/apub/src/activities/deletion/delete.rs +++ b/crates/apub/src/activities/deletion/delete.rs @@ -1,22 +1,17 @@ use crate::{ activities::{ - community::{announce::GetCommunity, send_activity_in_community}, + community::announce::GetCommunity, deletion::{receive_delete_action, verify_delete_activity, DeletableObjects}, generate_activity_id, verify_activity, - verify_is_public, }, - activity_lists::AnnouncableActivities, objects::{community::ApubCommunity, person::ApubPerson}, - protocol::activities::deletion::delete::Delete, + protocol::activities::deletion::delete::{Delete, IdOrNestedObject}, }; -use activitystreams_kinds::{activity::DeleteType, public}; +use activitystreams_kinds::activity::DeleteType; +use anyhow::anyhow; use lemmy_api_common::blocking; -use lemmy_apub_lib::{ - data::Data, - object_id::ObjectId, - traits::{ActivityHandler, ActorType}, -}; +use lemmy_apub_lib::{data::Data, object_id::ObjectId, traits::ActivityHandler}; use lemmy_db_schema::{ source::{ comment::Comment, @@ -29,6 +24,7 @@ use lemmy_db_schema::{ ModRemovePost, ModRemovePostForm, }, + person::Person, post::Post, }, traits::Crud, @@ -51,18 +47,8 @@ impl ActivityHandler for Delete { context: &Data, request_counter: &mut i32, ) -> Result<(), LemmyError> { - 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.id, - &self.actor, - &community, - self.summary.is_some(), - context, - request_counter, - ) - .await?; + verify_delete_activity(self, self.summary.is_some(), context, request_counter).await?; Ok(()) } @@ -82,53 +68,50 @@ impl ActivityHandler for Delete { }; receive_remove_action( &self.actor, - &self.object.id, + self.object.id(), reason, context, request_counter, ) .await } else { - receive_delete_action(&self.object.id, &self.actor, true, context, request_counter).await + receive_delete_action( + self.object.id(), + &self.actor, + true, + context, + request_counter, + ) + .await } } } impl Delete { pub(in crate::activities::deletion) fn new( - actor: &ApubPerson, + actor: &Person, object: DeletableObjects, + to: Url, + community: Option<&Community>, summary: Option, context: &LemmyContext, ) -> Result { + let id = generate_activity_id( + DeleteType::Delete, + &context.settings().get_protocol_and_hostname(), + )?; + let cc: Option = community.map(|c| c.actor_id.clone().into()); Ok(Delete { - actor: ObjectId::new(actor.actor_id()), - to: vec![public()], - object: object.to_tombstone()?, + actor: ObjectId::new(actor.actor_id.clone()), + to: vec![to], + object: IdOrNestedObject::Id(object.id()), + cc: cc.into_iter().collect(), kind: DeleteType::Delete, summary, - id: generate_activity_id( - DeleteType::Delete, - &context.settings().get_protocol_and_hostname(), - )?, + id, unparsed: Default::default(), }) } - - #[tracing::instrument(skip_all)] - pub(in crate::activities::deletion) async fn send( - actor: &ApubPerson, - community: &ApubCommunity, - object: DeletableObjects, - summary: Option, - context: &LemmyContext, - ) -> Result<(), LemmyError> { - let delete = Delete::new(actor, object, summary, context)?; - let delete_id = delete.id.clone(); - - let activity = AnnouncableActivities::Delete(delete); - send_activity_in_community(activity, &delete_id, actor, community, vec![], context).await - } } #[tracing::instrument(skip_all)] @@ -204,6 +187,7 @@ pub(in crate::activities) async fn receive_remove_action( send_comment_ws_message_simple(removed_comment.id, RemoveComment, context).await?; } + DeletableObjects::PrivateMessage(_) => unimplemented!(), } Ok(()) } @@ -216,13 +200,16 @@ impl GetCommunity for Delete { context: &LemmyContext, _request_counter: &mut i32, ) -> Result { - let community_id = match DeletableObjects::read_from_db(&self.object.id, 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??; post.community_id } DeletableObjects::Post(p) => p.community_id, + DeletableObjects::PrivateMessage(_) => { + return Err(anyhow!("Private message is not part of community").into()) + } }; let community = blocking(context.pool(), move |conn| { Community::read(conn, community_id) diff --git a/crates/apub/src/activities/deletion/mod.rs b/crates/apub/src/activities/deletion/mod.rs index 419469c9..cc8319e8 100644 --- a/crates/apub/src/activities/deletion/mod.rs +++ b/crates/apub/src/activities/deletion/mod.rs @@ -1,62 +1,117 @@ 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}, - objects::tombstone::Tombstone, + activities::{ + community::{announce::GetCommunity, send_activity_in_community}, + send_lemmy_activity, + verify_is_public, + verify_mod_action, + verify_person, + verify_person_in_community, }, + activity_lists::AnnouncableActivities, + objects::{ + comment::ApubComment, + community::ApubCommunity, + person::ApubPerson, + post::ApubPost, + private_message::ApubPrivateMessage, + }, + protocol::activities::deletion::{delete::Delete, undo_delete::UndoDelete}, }; +use activitystreams_kinds::public; use lemmy_api_common::blocking; -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_apub_lib::{ + object_id::ObjectId, + traits::{ActorType, ApubObject}, + verify::verify_domains_match, +}; +use lemmy_db_schema::{ + source::{ + comment::Comment, + community::Community, + person::Person, + post::Post, + private_message::PrivateMessage, + }, + traits::Crud, +}; use lemmy_utils::LemmyError; use lemmy_websocket::{ - send::{send_comment_ws_message_simple, send_community_ws_message, send_post_ws_message}, + send::{ + send_comment_ws_message_simple, + send_community_ws_message, + send_pm_ws_message, + send_post_ws_message, + }, LemmyContext, UserOperationCrud, }; +use std::ops::Deref; use url::Url; pub mod delete; pub mod undo_delete; +/// Parameter `reason` being set indicates that this is a removal by a mod. If its unset, this +/// action was done by a normal user. #[tracing::instrument(skip_all)] -pub async fn send_apub_delete( - actor: &ApubPerson, - community: &ApubCommunity, +pub async fn send_apub_delete_in_community( + actor: Person, + community: Community, object: DeletableObjects, + reason: Option, deleted: bool, context: &LemmyContext, ) -> Result<(), LemmyError> { - if deleted { - Delete::send(actor, community, object, None, context).await + let (id, activity) = if deleted { + let delete = Delete::new(&actor, object, public(), Some(&community), reason, context)?; + (delete.id.clone(), AnnouncableActivities::Delete(delete)) } else { - UndoDelete::send(actor, community, object, None, context).await - } + let undo = UndoDelete::new(&actor, object, public(), Some(&community), reason, context)?; + (undo.id.clone(), AnnouncableActivities::UndoDelete(undo)) + }; + send_activity_in_community( + activity, + &id, + &ApubPerson::from(actor), + &community.into(), + vec![], + context, + ) + .await } -// TODO: remove reason is actually optional in lemmy. we set an empty string in that case, but its -// ugly #[tracing::instrument(skip_all)] -pub async fn send_apub_remove( +pub async fn send_apub_delete_private_message( actor: &ApubPerson, - community: &ApubCommunity, - object: DeletableObjects, - reason: String, - removed: bool, + pm: PrivateMessage, + deleted: bool, context: &LemmyContext, ) -> Result<(), LemmyError> { - if removed { - Delete::send(actor, community, object, Some(reason), context).await + let recipient_id = pm.recipient_id; + let recipient: ApubPerson = + blocking(context.pool(), move |conn| Person::read(conn, recipient_id)) + .await?? + .into(); + + let deletable = DeletableObjects::PrivateMessage(Box::new(pm.into())); + let inbox = vec![recipient.shared_inbox_or_inbox_url()]; + if deleted { + let delete = Delete::new(actor, deletable, recipient.actor_id(), None, None, context)?; + let id = delete.id.clone(); + send_lemmy_activity(context, &delete, &id, actor, inbox, true).await?; } else { - UndoDelete::send(actor, community, object, Some(reason), context).await - } + let undo = UndoDelete::new(actor, deletable, recipient.actor_id(), None, None, context)?; + let id = undo.id.clone(); + send_lemmy_activity(context, &undo, &id, actor, inbox, true).await?; + }; + Ok(()) } pub enum DeletableObjects { Community(Box), Comment(Box), Post(Box), + PrivateMessage(Box), } impl DeletableObjects { @@ -74,43 +129,47 @@ impl DeletableObjects { if let Some(c) = ApubComment::read_from_apub_id(ap_id.clone(), context).await? { return Ok(DeletableObjects::Comment(Box::new(c))); } + if let Some(p) = ApubPrivateMessage::read_from_apub_id(ap_id.clone(), context).await? { + return Ok(DeletableObjects::PrivateMessage(Box::new(p))); + } Err(diesel::NotFound.into()) } - pub(crate) fn to_tombstone(&self) -> Result { + pub(crate) fn id(&self) -> Url { match self { - DeletableObjects::Community(c) => c.to_tombstone(), - DeletableObjects::Comment(c) => c.to_tombstone(), - DeletableObjects::Post(p) => p.to_tombstone(), + DeletableObjects::Community(c) => c.actor_id(), + DeletableObjects::Comment(c) => c.ap_id.clone().into(), + DeletableObjects::Post(p) => p.ap_id.clone().into(), + DeletableObjects::PrivateMessage(p) => p.ap_id.clone().into(), } } } #[tracing::instrument(skip_all)] pub(in crate::activities) async fn verify_delete_activity( - object: &Url, - actor: &ObjectId, - community: &ApubCommunity, + activity: &Delete, is_mod_action: bool, context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { - let object = DeletableObjects::read_from_db(object, context).await?; + let object = DeletableObjects::read_from_db(activity.object.id(), context).await?; match object { DeletableObjects::Community(community) => { + verify_is_public(&activity.to, &[])?; if community.local { // can only do this check for local community, in remote case it would try to fetch the // deleted community (which fails) - verify_person_in_community(actor, &community, context, request_counter).await?; + verify_person_in_community(&activity.actor, &community, context, request_counter).await?; } // community deletion is always a mod (or admin) action - verify_mod_action(actor, &community, context, request_counter).await?; + verify_mod_action(&activity.actor, &community, context, request_counter).await?; } DeletableObjects::Post(p) => { - verify_delete_activity_post_or_comment( - actor, + verify_is_public(&activity.to, &[])?; + verify_delete_post_or_comment( + &activity.actor, &p.ap_id.clone().into(), - community, + &activity.get_community(context, request_counter).await?, is_mod_action, context, request_counter, @@ -118,22 +177,27 @@ pub(in crate::activities) async fn verify_delete_activity( .await?; } DeletableObjects::Comment(c) => { - verify_delete_activity_post_or_comment( - actor, + verify_is_public(&activity.to, &[])?; + verify_delete_post_or_comment( + &activity.actor, &c.ap_id.clone().into(), - community, + &activity.get_community(context, request_counter).await?, is_mod_action, context, request_counter, ) .await?; } + DeletableObjects::PrivateMessage(_) => { + verify_person(&activity.actor, context, request_counter).await?; + verify_domains_match(activity.actor.inner(), activity.object.id())?; + } } Ok(()) } #[tracing::instrument(skip_all)] -async fn verify_delete_activity_post_or_comment( +async fn verify_delete_post_or_comment( actor: &ObjectId, object_id: &Url, community: &ApubCommunity, @@ -152,8 +216,6 @@ async fn verify_delete_activity_post_or_comment( } /// Write deletion or restoring of an object to the database, and send websocket message. -/// TODO: we should do something similar for receive_remove_action(), but its much more complicated -/// because of the mod log #[tracing::instrument(skip_all)] async fn receive_delete_action( object: &Url, @@ -165,11 +227,14 @@ async fn receive_delete_action( match DeletableObjects::read_from_db(object, context).await? { DeletableObjects::Community(community) => { if community.local { - let mod_ = actor + let mod_: Person = actor .dereference(context, context.client(), request_counter) - .await?; + .await? + .deref() + .clone(); let object = DeletableObjects::Community(community.clone()); - send_apub_delete(&mod_, &community.clone(), object, true, context).await?; + let c: Community = community.deref().deref().clone(); + send_apub_delete_in_community(mod_, c, object, None, true, context).await?; } let community = blocking(context.pool(), move |conn| { @@ -215,6 +280,20 @@ async fn receive_delete_action( .await?; } } + DeletableObjects::PrivateMessage(pm) => { + let deleted_private_message = blocking(context.pool(), move |conn| { + PrivateMessage::update_deleted(conn, pm.id, deleted) + }) + .await??; + + send_pm_ws_message( + deleted_private_message.id, + UserOperationCrud::DeletePrivateMessage, + None, + context, + ) + .await?; + } } Ok(()) } diff --git a/crates/apub/src/activities/deletion/undo_delete.rs b/crates/apub/src/activities/deletion/undo_delete.rs index 167f8961..7ee90b6e 100644 --- a/crates/apub/src/activities/deletion/undo_delete.rs +++ b/crates/apub/src/activities/deletion/undo_delete.rs @@ -1,23 +1,17 @@ use crate::{ activities::{ - community::{announce::GetCommunity, send_activity_in_community}, + community::announce::GetCommunity, deletion::{receive_delete_action, verify_delete_activity, DeletableObjects}, generate_activity_id, verify_activity, - verify_is_public, }, - activity_lists::AnnouncableActivities, - objects::{community::ApubCommunity, person::ApubPerson}, + objects::community::ApubCommunity, protocol::activities::deletion::{delete::Delete, undo_delete::UndoDelete}, }; -use activitystreams_kinds::{activity::UndoType, public}; +use activitystreams_kinds::activity::UndoType; use lemmy_api_common::blocking; -use lemmy_apub_lib::{ - data::Data, - object_id::ObjectId, - traits::{ActivityHandler, ActorType}, -}; -use lemmy_db_schema::source::{comment::Comment, community::Community, post::Post}; +use lemmy_apub_lib::{data::Data, object_id::ObjectId, traits::ActivityHandler}; +use lemmy_db_schema::source::{comment::Comment, community::Community, person::Person, post::Post}; use lemmy_utils::LemmyError; use lemmy_websocket::{ send::{send_comment_ws_message_simple, send_community_ws_message, send_post_ws_message}, @@ -36,14 +30,10 @@ impl ActivityHandler for UndoDelete { context: &Data, request_counter: &mut i32, ) -> Result<(), LemmyError> { - verify_is_public(&self.to, &self.cc)?; verify_activity(&self.id, self.actor.inner(), &context.settings())?; self.object.verify(context, request_counter).await?; - let community = self.get_community(context, request_counter).await?; verify_delete_activity( - &self.object.object.id, - &self.actor, - &community, + &self.object, self.object.summary.is_some(), context, request_counter, @@ -59,10 +49,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.id, context).await + UndoDelete::receive_undo_remove_action(self.object.object.id(), context).await } else { receive_delete_action( - &self.object.object.id, + self.object.object.id(), &self.actor, false, context, @@ -75,31 +65,30 @@ impl ActivityHandler for UndoDelete { impl UndoDelete { #[tracing::instrument(skip_all)] - pub(in crate::activities::deletion) async fn send( - actor: &ApubPerson, - community: &ApubCommunity, + pub(in crate::activities::deletion) fn new( + actor: &Person, object: DeletableObjects, + to: Url, + community: Option<&Community>, summary: Option, context: &LemmyContext, - ) -> Result<(), LemmyError> { - let object = Delete::new(actor, object, summary, context)?; + ) -> Result { + let object = Delete::new(actor, object, to.clone(), community, summary, context)?; let id = generate_activity_id( UndoType::Undo, &context.settings().get_protocol_and_hostname(), )?; - let undo = UndoDelete { - actor: ObjectId::new(actor.actor_id()), - to: vec![public()], + let cc: Option = community.map(|c| c.actor_id.clone().into()); + Ok(UndoDelete { + actor: ObjectId::new(actor.actor_id.clone()), + to: vec![to], object, - cc: vec![community.actor_id()], + cc: cc.into_iter().collect(), kind: UndoType::Undo, - id: id.clone(), + id, unparsed: Default::default(), - }; - - let activity = AnnouncableActivities::UndoDelete(undo); - send_activity_in_community(activity, &id, actor, community, vec![], context).await + }) } #[tracing::instrument(skip_all)] @@ -135,6 +124,7 @@ impl UndoDelete { .await??; send_comment_ws_message_simple(removed_comment.id, EditComment, context).await?; } + DeletableObjects::PrivateMessage(_) => unimplemented!(), } Ok(()) } diff --git a/crates/apub/src/activities/mod.rs b/crates/apub/src/activities/mod.rs index 343633c8..0624b32f 100644 --- a/crates/apub/src/activities/mod.rs +++ b/crates/apub/src/activities/mod.rs @@ -26,12 +26,10 @@ use url::{ParseError, Url}; use uuid::Uuid; pub mod block; -pub mod comment; pub mod community; +pub mod create_or_update; pub mod deletion; pub mod following; -pub mod post; -pub mod private_message; pub mod voting; /// Checks that the specified Url actually identifies a Person (by fetching it), and that the person diff --git a/crates/apub/src/activities/post/mod.rs b/crates/apub/src/activities/post/mod.rs deleted file mode 100644 index e903f52f..00000000 --- a/crates/apub/src/activities/post/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod create_or_update; diff --git a/crates/apub/src/activities/private_message/delete.rs b/crates/apub/src/activities/private_message/delete.rs deleted file mode 100644 index af81db0e..00000000 --- a/crates/apub/src/activities/private_message/delete.rs +++ /dev/null @@ -1,97 +0,0 @@ -use crate::{ - activities::{generate_activity_id, send_lemmy_activity, verify_activity, verify_person}, - objects::{person::ApubPerson, private_message::ApubPrivateMessage}, - protocol::activities::private_message::delete::DeletePrivateMessage, -}; -use activitystreams_kinds::activity::DeleteType; -use lemmy_api_common::blocking; -use lemmy_apub_lib::{ - data::Data, - object_id::ObjectId, - traits::{ActivityHandler, ActorType}, - verify::verify_domains_match, -}; -use lemmy_db_schema::{ - source::{person::Person, private_message::PrivateMessage}, - traits::Crud, -}; -use lemmy_utils::LemmyError; -use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud}; - -impl DeletePrivateMessage { - pub(in crate::activities::private_message) fn new( - actor: &ApubPerson, - pm: &PrivateMessage, - context: &LemmyContext, - ) -> Result { - Ok(DeletePrivateMessage { - actor: ObjectId::new(actor.actor_id()), - to: [ObjectId::new(actor.actor_id())], - object: ObjectId::new(pm.ap_id.clone()), - kind: DeleteType::Delete, - id: generate_activity_id( - DeleteType::Delete, - &context.settings().get_protocol_and_hostname(), - )?, - unparsed: Default::default(), - }) - } - - #[tracing::instrument(skip_all)] - pub async fn send( - actor: &ApubPerson, - pm: &ApubPrivateMessage, - context: &LemmyContext, - ) -> Result<(), LemmyError> { - let delete = DeletePrivateMessage::new(actor, pm, context)?; - let delete_id = delete.id.clone(); - - let recipient_id = pm.recipient_id; - let recipient: ApubPerson = - blocking(context.pool(), move |conn| Person::read(conn, recipient_id)) - .await?? - .into(); - let inbox = vec![recipient.shared_inbox_or_inbox_url()]; - send_lemmy_activity(context, &delete, &delete_id, actor, inbox, true).await - } -} - -#[async_trait::async_trait(?Send)] -impl ActivityHandler for DeletePrivateMessage { - type DataType = LemmyContext; - - #[tracing::instrument(skip_all)] - async fn verify( - &self, - context: &Data, - request_counter: &mut i32, - ) -> Result<(), LemmyError> { - verify_activity(&self.id, self.actor.inner(), &context.settings())?; - verify_person(&self.actor, context, request_counter).await?; - verify_domains_match(self.actor.inner(), self.object.inner())?; - Ok(()) - } - - #[tracing::instrument(skip_all)] - async fn receive( - self, - context: &Data, - _request_counter: &mut i32, - ) -> Result<(), LemmyError> { - let private_message = self.object.dereference_local(context).await?; - let deleted_private_message = blocking(context.pool(), move |conn| { - PrivateMessage::update_deleted(conn, private_message.id, true) - }) - .await??; - - send_pm_ws_message( - deleted_private_message.id, - UserOperationCrud::DeletePrivateMessage, - None, - context, - ) - .await?; - - Ok(()) - } -} diff --git a/crates/apub/src/activities/private_message/mod.rs b/crates/apub/src/activities/private_message/mod.rs deleted file mode 100644 index 4bcda7c7..00000000 --- a/crates/apub/src/activities/private_message/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod create_or_update; -pub mod delete; -pub mod undo_delete; diff --git a/crates/apub/src/activities/private_message/undo_delete.rs b/crates/apub/src/activities/private_message/undo_delete.rs deleted file mode 100644 index dbd84bd5..00000000 --- a/crates/apub/src/activities/private_message/undo_delete.rs +++ /dev/null @@ -1,97 +0,0 @@ -use crate::{ - activities::{generate_activity_id, send_lemmy_activity, verify_activity, verify_person}, - objects::{person::ApubPerson, private_message::ApubPrivateMessage}, - protocol::activities::private_message::{ - delete::DeletePrivateMessage, - undo_delete::UndoDeletePrivateMessage, - }, -}; -use activitystreams_kinds::activity::UndoType; -use lemmy_api_common::blocking; -use lemmy_apub_lib::{ - data::Data, - object_id::ObjectId, - traits::{ActivityHandler, ActorType}, - verify::{verify_domains_match, verify_urls_match}, -}; -use lemmy_db_schema::{ - source::{person::Person, private_message::PrivateMessage}, - traits::Crud, -}; -use lemmy_utils::LemmyError; -use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud}; - -impl UndoDeletePrivateMessage { - #[tracing::instrument(skip_all)] - pub async fn send( - actor: &ApubPerson, - pm: &ApubPrivateMessage, - context: &LemmyContext, - ) -> Result<(), LemmyError> { - let recipient_id = pm.recipient_id; - let recipient: ApubPerson = - blocking(context.pool(), move |conn| Person::read(conn, recipient_id)) - .await?? - .into(); - - let object = DeletePrivateMessage::new(actor, pm, context)?; - let id = generate_activity_id( - UndoType::Undo, - &context.settings().get_protocol_and_hostname(), - )?; - let undo = UndoDeletePrivateMessage { - actor: ObjectId::new(actor.actor_id()), - to: [ObjectId::new(recipient.actor_id())], - object, - kind: UndoType::Undo, - id: id.clone(), - unparsed: Default::default(), - }; - let inbox = vec![recipient.shared_inbox_or_inbox_url()]; - send_lemmy_activity(context, &undo, &id, actor, inbox, true).await - } -} - -#[async_trait::async_trait(?Send)] -impl ActivityHandler for UndoDeletePrivateMessage { - type DataType = LemmyContext; - - #[tracing::instrument(skip_all)] - async fn verify( - &self, - context: &Data, - request_counter: &mut i32, - ) -> Result<(), LemmyError> { - verify_activity(&self.id, self.actor.inner(), &context.settings())?; - verify_person(&self.actor, context, request_counter).await?; - verify_urls_match(self.actor.inner(), self.object.actor.inner())?; - verify_domains_match(self.actor.inner(), self.object.object.inner())?; - self.object.verify(context, request_counter).await?; - Ok(()) - } - - #[tracing::instrument(skip_all)] - async fn receive( - self, - context: &Data, - _request_counter: &mut i32, - ) -> Result<(), LemmyError> { - let ap_id = self.object.object.clone(); - let private_message = ap_id.dereference_local(context).await?; - - let deleted_private_message = blocking(context.pool(), move |conn| { - PrivateMessage::update_deleted(conn, private_message.id, false) - }) - .await??; - - send_pm_ws_message( - deleted_private_message.id, - UserOperationCrud::EditPrivateMessage, - None, - context, - ) - .await?; - - Ok(()) - } -} diff --git a/crates/apub/src/activity_lists.rs b/crates/apub/src/activity_lists.rs index c8666b93..a24ac8e4 100644 --- a/crates/apub/src/activity_lists.rs +++ b/crates/apub/src/activity_lists.rs @@ -11,18 +11,17 @@ use crate::{ report::Report, update::UpdateCommunity, }, - create_or_update::{comment::CreateOrUpdateComment, post::CreateOrUpdatePost}, + create_or_update::{ + comment::CreateOrUpdateComment, + post::CreateOrUpdatePost, + private_message::CreateOrUpdatePrivateMessage, + }, deletion::{delete::Delete, undo_delete::UndoDelete}, following::{ accept::AcceptFollowCommunity, follow::FollowCommunity, undo_follow::UndoFollowCommunity, }, - private_message::{ - create_or_update::CreateOrUpdatePrivateMessage, - delete::DeletePrivateMessage, - undo_delete::UndoDeletePrivateMessage, - }, voting::{undo_vote::UndoVote, vote::Vote}, }, objects::page::Page, @@ -61,8 +60,8 @@ pub enum PersonInboxActivities { /// Some activities can also be sent from user to user, eg a comment with mentions AnnouncableActivities(AnnouncableActivities), CreateOrUpdatePrivateMessage(CreateOrUpdatePrivateMessage), - DeletePrivateMessage(DeletePrivateMessage), - UndoDeletePrivateMessage(UndoDeletePrivateMessage), + Delete(Delete), + UndoDelete(UndoDelete), AnnounceActivity(AnnounceActivity), } diff --git a/crates/apub/src/http/community.rs b/crates/apub/src/http/community.rs index 5483d58d..c049c6ae 100644 --- a/crates/apub/src/http/community.rs +++ b/crates/apub/src/http/community.rs @@ -84,10 +84,14 @@ pub(in crate::http) async fn receive_group_inbox( let res = receive_activity(request, activity.clone(), activity_data, context).await?; if let GroupInboxActivities::AnnouncableActivities(announcable) = activity { - let community = announcable.get_community(context, &mut 0).await?; - verify_person_in_community(&actor_id, &community, context, &mut 0).await?; - if community.local { - AnnounceActivity::send(*announcable, &community, context).await?; + // Ignore failures in get_community(). those happen because Delete/PrivateMessage is not in a + // community, but looks identical to Delete/Post or Delete/Comment which are in a community. + let community = announcable.get_community(context, &mut 0).await; + if let Ok(community) = community { + if community.local { + verify_person_in_community(&actor_id, &community, context, &mut 0).await?; + AnnounceActivity::send(*announcable, &community, context).await?; + } } } diff --git a/crates/apub/src/protocol/activities/create_or_update/mod.rs b/crates/apub/src/protocol/activities/create_or_update/mod.rs index 2ce70333..ff03c5a0 100644 --- a/crates/apub/src/protocol/activities/create_or_update/mod.rs +++ b/crates/apub/src/protocol/activities/create_or_update/mod.rs @@ -1,5 +1,6 @@ pub mod comment; pub mod post; +pub mod private_message; #[cfg(test)] mod tests { @@ -7,7 +8,11 @@ mod tests { context::WithContext, objects::tests::file_to_json_object, protocol::{ - activities::create_or_update::{comment::CreateOrUpdateComment, post::CreateOrUpdatePost}, + activities::create_or_update::{ + comment::CreateOrUpdateComment, + post::CreateOrUpdatePost, + private_message::CreateOrUpdatePrivateMessage, + }, tests::test_parse_lemmy_item, }, }; @@ -26,6 +31,10 @@ mod tests { "assets/lemmy/activities/create_or_update/create_note.json", ) .unwrap(); + test_parse_lemmy_item::( + "assets/lemmy/activities/create_or_update/create_private_message.json", + ) + .unwrap(); file_to_json_object::>( "assets/pleroma/activities/create_note.json", diff --git a/crates/apub/src/protocol/activities/private_message/create_or_update.rs b/crates/apub/src/protocol/activities/create_or_update/private_message.rs similarity index 100% rename from crates/apub/src/protocol/activities/private_message/create_or_update.rs rename to crates/apub/src/protocol/activities/create_or_update/private_message.rs diff --git a/crates/apub/src/protocol/activities/deletion/delete.rs b/crates/apub/src/protocol/activities/deletion/delete.rs index a999e58e..70b38af6 100644 --- a/crates/apub/src/protocol/activities/deletion/delete.rs +++ b/crates/apub/src/protocol/activities/deletion/delete.rs @@ -1,7 +1,4 @@ -use crate::{ - objects::person::ApubPerson, - protocol::{objects::tombstone::Tombstone, Unparsed}, -}; +use crate::{objects::person::ApubPerson, protocol::Unparsed}; use activitystreams_kinds::activity::DeleteType; use lemmy_apub_lib::object_id::ObjectId; use serde::{Deserialize, Serialize}; @@ -15,7 +12,11 @@ pub struct Delete { pub(crate) actor: ObjectId, #[serde(deserialize_with = "crate::deserialize_one_or_many")] pub(crate) to: Vec, - pub(crate) object: Tombstone, + pub(crate) object: IdOrNestedObject, + #[serde(deserialize_with = "crate::deserialize_one_or_many")] + #[serde(default)] + #[serde(skip_serializing_if = "Vec::is_empty")] + pub(crate) cc: Vec, #[serde(rename = "type")] pub(crate) kind: DeleteType, /// If summary is present, this is a mod action (Remove in Lemmy terms). Otherwise, its a user @@ -25,3 +26,26 @@ pub struct Delete { #[serde(flatten)] pub(crate) unparsed: Unparsed, } + +/// Instead of a simple ID string as object, Mastodon sends a nested tombstone for some reason, +/// so we need to handle that as well. +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(untagged)] +pub(crate) enum IdOrNestedObject { + Id(Url), + NestedObject(NestedObject), +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub(crate) struct NestedObject { + id: Url, +} + +impl IdOrNestedObject { + pub(crate) fn id(&self) -> &Url { + match self { + IdOrNestedObject::Id(i) => i, + IdOrNestedObject::NestedObject(n) => &n.id, + } + } +} diff --git a/crates/apub/src/protocol/activities/deletion/mod.rs b/crates/apub/src/protocol/activities/deletion/mod.rs index 80254834..9ecb65c4 100644 --- a/crates/apub/src/protocol/activities/deletion/mod.rs +++ b/crates/apub/src/protocol/activities/deletion/mod.rs @@ -3,13 +3,17 @@ pub mod undo_delete; #[cfg(test)] mod tests { - use crate::protocol::{ - activities::deletion::{delete::Delete, undo_delete::UndoDelete}, - tests::test_parse_lemmy_item, + use crate::{ + context::WithContext, + objects::tests::file_to_json_object, + protocol::{ + activities::deletion::{delete::Delete, undo_delete::UndoDelete}, + tests::test_parse_lemmy_item, + }, }; #[actix_rt::test] - async fn test_parse_lemmy_deletion() { + async fn test_parse_deletion() { test_parse_lemmy_item::("assets/lemmy/activities/deletion/remove_note.json").unwrap(); test_parse_lemmy_item::("assets/lemmy/activities/deletion/delete_page.json").unwrap(); @@ -17,5 +21,14 @@ mod tests { .unwrap(); test_parse_lemmy_item::("assets/lemmy/activities/deletion/undo_delete_page.json") .unwrap(); + test_parse_lemmy_item::("assets/lemmy/activities/deletion/delete_private_message.json") + .unwrap(); + test_parse_lemmy_item::( + "assets/lemmy/activities/deletion/undo_delete_private_message.json", + ) + .unwrap(); + + file_to_json_object::>("assets/pleroma/activities/delete.json").unwrap(); + file_to_json_object::>("assets/mastodon/activities/delete.json").unwrap(); } } diff --git a/crates/apub/src/protocol/activities/deletion/undo_delete.rs b/crates/apub/src/protocol/activities/deletion/undo_delete.rs index ebd51f96..f2f2d764 100644 --- a/crates/apub/src/protocol/activities/deletion/undo_delete.rs +++ b/crates/apub/src/protocol/activities/deletion/undo_delete.rs @@ -15,6 +15,8 @@ pub struct UndoDelete { pub(crate) to: Vec, pub(crate) object: Delete, #[serde(deserialize_with = "crate::deserialize_one_or_many")] + #[serde(default)] + #[serde(skip_serializing_if = "Vec::is_empty")] pub(crate) cc: Vec, #[serde(rename = "type")] pub(crate) kind: UndoType, diff --git a/crates/apub/src/protocol/activities/mod.rs b/crates/apub/src/protocol/activities/mod.rs index 47b01b24..9279cab1 100644 --- a/crates/apub/src/protocol/activities/mod.rs +++ b/crates/apub/src/protocol/activities/mod.rs @@ -6,7 +6,6 @@ pub mod community; pub mod create_or_update; pub mod deletion; pub mod following; -pub mod private_message; pub mod voting; #[derive(Clone, Debug, Display, Deserialize, Serialize, PartialEq)] diff --git a/crates/apub/src/protocol/activities/private_message/delete.rs b/crates/apub/src/protocol/activities/private_message/delete.rs deleted file mode 100644 index 7d28e1c4..00000000 --- a/crates/apub/src/protocol/activities/private_message/delete.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::{ - objects::{person::ApubPerson, private_message::ApubPrivateMessage}, - protocol::Unparsed, -}; -use activitystreams_kinds::activity::DeleteType; -use lemmy_apub_lib::object_id::ObjectId; -use serde::{Deserialize, Serialize}; -use url::Url; - -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DeletePrivateMessage { - pub(crate) actor: ObjectId, - #[serde(deserialize_with = "crate::deserialize_one")] - pub(crate) to: [ObjectId; 1], - pub(crate) object: ObjectId, - #[serde(rename = "type")] - pub(crate) kind: DeleteType, - pub(crate) id: Url, - #[serde(flatten)] - pub(crate) unparsed: Unparsed, -} diff --git a/crates/apub/src/protocol/activities/private_message/mod.rs b/crates/apub/src/protocol/activities/private_message/mod.rs deleted file mode 100644 index 04be31b1..00000000 --- a/crates/apub/src/protocol/activities/private_message/mod.rs +++ /dev/null @@ -1,31 +0,0 @@ -pub mod create_or_update; -pub mod delete; -pub mod undo_delete; - -#[cfg(test)] -mod tests { - use crate::protocol::{ - activities::private_message::{ - create_or_update::CreateOrUpdatePrivateMessage, - delete::DeletePrivateMessage, - undo_delete::UndoDeletePrivateMessage, - }, - tests::test_parse_lemmy_item, - }; - - #[actix_rt::test] - async fn test_parse_lemmy_private_message() { - test_parse_lemmy_item::( - "assets/lemmy/activities/private_message/create.json", - ) - .unwrap(); - test_parse_lemmy_item::( - "assets/lemmy/activities/private_message/delete.json", - ) - .unwrap(); - test_parse_lemmy_item::( - "assets/lemmy/activities/private_message/undo_delete.json", - ) - .unwrap(); - } -} diff --git a/crates/apub/src/protocol/activities/private_message/undo_delete.rs b/crates/apub/src/protocol/activities/private_message/undo_delete.rs deleted file mode 100644 index 605938c4..00000000 --- a/crates/apub/src/protocol/activities/private_message/undo_delete.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::{ - objects::person::ApubPerson, - protocol::{activities::private_message::delete::DeletePrivateMessage, Unparsed}, -}; -use activitystreams_kinds::activity::UndoType; -use lemmy_apub_lib::object_id::ObjectId; -use serde::{Deserialize, Serialize}; -use url::Url; - -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct UndoDeletePrivateMessage { - pub(crate) actor: ObjectId, - #[serde(deserialize_with = "crate::deserialize_one")] - pub(crate) to: [ObjectId; 1], - pub(crate) object: DeletePrivateMessage, - #[serde(rename = "type")] - pub(crate) kind: UndoType, - pub(crate) id: Url, - #[serde(flatten)] - pub(crate) unparsed: Unparsed, -}