From bc6294a834fc06dc118ed1bc9c39724484a1efd7 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Thu, 12 Aug 2021 22:24:36 +0200 Subject: [PATCH] Rewrite delete activities --- crates/api_crud/src/comment/delete.rs | 53 +++--- crates/api_crud/src/community/delete.rs | 37 ++-- crates/api_crud/src/post/delete.rs | 49 ++--- .../apub/src/activities/community/announce.rs | 16 +- crates/apub/src/activities/deletion/delete.rs | 179 ++++++++++++++++-- crates/apub/src/activities/deletion/mod.rs | 84 +++++++- .../src/activities/deletion/undo_delete.rs | 125 ++++++++++-- crates/apub/src/activities/removal/remove.rs | 112 +++-------- .../src/activities/removal/undo_remove.rs | 100 ++-------- crates/apub/src/activities/send/comment.rs | 153 --------------- crates/apub/src/activities/send/community.rs | 118 +----------- crates/apub/src/activities/send/mod.rs | 2 - crates/apub/src/activities/send/post.rs | 139 -------------- crates/apub/src/http/inbox_enums.rs | 19 +- crates/apub/src/lib.rs | 24 --- crates/apub/src/migrations.rs | 12 ++ 16 files changed, 501 insertions(+), 721 deletions(-) delete mode 100644 crates/apub/src/activities/send/comment.rs delete mode 100644 crates/apub/src/activities/send/post.rs diff --git a/crates/api_crud/src/comment/delete.rs b/crates/api_crud/src/comment/delete.rs index e2ec3080e..4bbd8ca68 100644 --- a/crates/api_crud/src/comment/delete.rs +++ b/crates/api_crud/src/comment/delete.rs @@ -8,9 +8,9 @@ use lemmy_api_common::{ is_mod_or_admin, send_local_notifs, }; -use lemmy_apub::ApubObjectType; +use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove}; use lemmy_db_queries::{source::comment::Comment_, Crud, DeleteableOrRemoveable}; -use lemmy_db_schema::source::{comment::*, moderator::*}; +use lemmy_db_schema::source::{comment::*, community::Community, moderator::*}; use lemmy_db_views::comment_view::CommentView; use lemmy_utils::{ApiError, ConnectionId, LemmyError}; use lemmy_websocket::{messages::SendComment, LemmyContext, UserOperationCrud}; @@ -47,23 +47,25 @@ impl PerformCrud for DeleteComment { // Do the delete let deleted = data.deleted; - let mut updated_comment = blocking(context.pool(), move |conn| { + let updated_comment = blocking(context.pool(), move |conn| { Comment::update_deleted(conn, comment_id, deleted) }) .await? .map_err(|_| ApiError::err("couldnt_update_comment"))?; // Send the apub message - if deleted { - updated_comment = updated_comment.blank_out_deleted_or_removed_info(); - updated_comment - .send_delete(&local_user_view.person, context) - .await?; - } else { - updated_comment - .send_undo_delete(&local_user_view.person, context) - .await?; - } + let community = blocking(context.pool(), move |conn| { + Community::read(conn, orig_comment.post.community_id) + }) + .await??; + send_apub_delete( + &local_user_view.person, + &community, + updated_comment.ap_id.clone().into(), + deleted, + context, + ) + .await?; // Refetch it let comment_id = data.comment_id; @@ -142,7 +144,7 @@ impl PerformCrud for RemoveComment { // Do the remove let removed = data.removed; - let mut updated_comment = blocking(context.pool(), move |conn| { + let updated_comment = blocking(context.pool(), move |conn| { Comment::update_removed(conn, comment_id, removed) }) .await? @@ -161,16 +163,19 @@ impl PerformCrud for RemoveComment { .await??; // Send the apub message - if removed { - updated_comment = updated_comment.blank_out_deleted_or_removed_info(); - updated_comment - .send_remove(&local_user_view.person, context) - .await?; - } else { - updated_comment - .send_undo_remove(&local_user_view.person, context) - .await?; - } + let community = blocking(context.pool(), move |conn| { + Community::read(conn, orig_comment.post.community_id) + }) + .await??; + send_apub_remove( + &local_user_view.person, + &community, + updated_comment.ap_id.clone().into(), + data.reason.clone().unwrap_or_else(|| "".to_string()), + removed, + context, + ) + .await?; // Refetch it let comment_id = data.comment_id; diff --git a/crates/api_crud/src/community/delete.rs b/crates/api_crud/src/community/delete.rs index 62fb0f38f..747a46e3d 100644 --- a/crates/api_crud/src/community/delete.rs +++ b/crates/api_crud/src/community/delete.rs @@ -1,7 +1,7 @@ use crate::{community::send_community_websocket, PerformCrud}; use actix_web::web::Data; use lemmy_api_common::{blocking, community::*, get_local_user_view_from_jwt, is_admin}; -use lemmy_apub::CommunityType; +use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove}; use lemmy_db_queries::{source::community::Community_, Crud, DeleteableOrRemoveable}; use lemmy_db_schema::source::{ community::*, @@ -48,16 +48,14 @@ impl PerformCrud for DeleteCommunity { .map_err(|_| ApiError::err("couldnt_update_community"))?; // Send apub messages - if deleted { - updated_community - .blank_out_deleted_or_removed_info() - .send_delete(local_user_view.person.to_owned(), context) - .await?; - } else { - updated_community - .send_undo_delete(local_user_view.person.to_owned(), context) - .await?; - } + send_apub_delete( + &local_user_view.person, + &updated_community, + updated_community.actor_id.clone().into(), + deleted, + context, + ) + .await?; let community_id = data.community_id; let person_id = local_user_view.person.id; @@ -123,14 +121,15 @@ impl PerformCrud for RemoveCommunity { .await??; // Apub messages - if removed { - updated_community - .blank_out_deleted_or_removed_info() - .send_remove(context) - .await?; - } else { - updated_community.send_undo_remove(context).await?; - } + send_apub_remove( + &local_user_view.person, + &updated_community, + updated_community.actor_id.clone().into(), + data.reason.clone().unwrap_or_else(|| "".to_string()), + removed, + context, + ) + .await?; let community_id = data.community_id; let person_id = local_user_view.person.id; diff --git a/crates/api_crud/src/post/delete.rs b/crates/api_crud/src/post/delete.rs index cf48757d3..5deca1c85 100644 --- a/crates/api_crud/src/post/delete.rs +++ b/crates/api_crud/src/post/delete.rs @@ -7,9 +7,9 @@ use lemmy_api_common::{ is_mod_or_admin, post::*, }; -use lemmy_apub::ApubObjectType; +use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove}; use lemmy_db_queries::{source::post::Post_, Crud, DeleteableOrRemoveable}; -use lemmy_db_schema::source::{moderator::*, post::*}; +use lemmy_db_schema::source::{community::Community, moderator::*, post::*}; use lemmy_db_views::post_view::PostView; use lemmy_utils::{ApiError, ConnectionId, LemmyError}; use lemmy_websocket::{messages::SendPost, LemmyContext, UserOperationCrud}; @@ -50,16 +50,18 @@ impl PerformCrud for DeletePost { .await??; // apub updates - if deleted { - updated_post - .blank_out_deleted_or_removed_info() - .send_delete(&local_user_view.person, context) - .await?; - } else { - updated_post - .send_undo_delete(&local_user_view.person, context) - .await?; - } + let community = blocking(context.pool(), move |conn| { + Community::read(conn, orig_post.community_id) + }) + .await??; + send_apub_delete( + &local_user_view.person, + &community, + updated_post.ap_id.into(), + deleted, + context, + ) + .await?; // Refetch the post let post_id = data.post_id; @@ -135,16 +137,19 @@ impl PerformCrud for RemovePost { .await??; // apub updates - if removed { - updated_post - .blank_out_deleted_or_removed_info() - .send_remove(&local_user_view.person, context) - .await?; - } else { - updated_post - .send_undo_remove(&local_user_view.person, context) - .await?; - } + let community = blocking(context.pool(), move |conn| { + Community::read(conn, orig_post.community_id) + }) + .await??; + send_apub_remove( + &local_user_view.person, + &community, + updated_post.ap_id.into(), + data.reason.clone().unwrap_or_else(|| "".to_string()), + removed, + context, + ) + .await?; // Refetch the post let post_id = data.post_id; diff --git a/crates/apub/src/activities/community/announce.rs b/crates/apub/src/activities/community/announce.rs index fc3bebfed..734fed00e 100644 --- a/crates/apub/src/activities/community/announce.rs +++ b/crates/apub/src/activities/community/announce.rs @@ -7,16 +7,10 @@ use crate::{ list_community_follower_inboxes, undo_block_user::UndoBlockUserFromCommunity, }, - deletion::{ - delete::DeletePostCommentOrCommunity, - undo_delete::UndoDeletePostCommentOrCommunity, - }, + deletion::{delete::Delete, undo_delete::UndoDelete}, generate_activity_id, post::create_or_update::CreateOrUpdatePost, - removal::{ - remove::RemovePostCommentCommunityOrMod, - undo_remove::UndoRemovePostCommentOrCommunity, - }, + removal::{remove::RemoveMod, undo_remove::UndoRemovePostCommentOrCommunity}, verify_activity, verify_community, voting::{undo_vote::UndoVote, vote::Vote}, @@ -43,13 +37,13 @@ pub enum AnnouncableActivities { CreateOrUpdatePost(Box), Vote(Vote), UndoVote(UndoVote), - DeletePostCommentOrCommunity(DeletePostCommentOrCommunity), - UndoDeletePostCommentOrCommunity(UndoDeletePostCommentOrCommunity), - RemovePostCommentCommunityOrMod(RemovePostCommentCommunityOrMod), + Delete(Delete), + UndoDelete(UndoDelete), UndoRemovePostCommentOrCommunity(UndoRemovePostCommentOrCommunity), BlockUserFromCommunity(BlockUserFromCommunity), UndoBlockUserFromCommunity(UndoBlockUserFromCommunity), AddMod(AddMod), + RemoveMod(RemoveMod), } #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] diff --git a/crates/apub/src/activities/deletion/delete.rs b/crates/apub/src/activities/deletion/delete.rs index 2539327b0..feca495ef 100644 --- a/crates/apub/src/activities/deletion/delete.rs +++ b/crates/apub/src/activities/deletion/delete.rs @@ -1,19 +1,42 @@ use crate::{ activities::{ comment::send_websocket_message as send_comment_message, - community::send_websocket_message as send_community_message, - deletion::{verify_delete_activity, DeletableObjects}, + community::{ + announce::AnnouncableActivities, + send_websocket_message as send_community_message, + }, + deletion::{send_apub_delete, verify_delete_activity, DeletableObjects}, + generate_activity_id, post::send_websocket_message as send_post_message, verify_activity, }, + activity_queue::send_to_community_new, + extensions::context::lemmy_context, fetcher::person::get_or_fetch_and_upsert_person, - CommunityType, + ActorType, }; use activitystreams::activity::kind::DeleteType; +use anyhow::anyhow; use lemmy_api_common::blocking; use lemmy_apub_lib::{values::PublicUrl, ActivityCommonFields, ActivityHandler}; -use lemmy_db_queries::source::{comment::Comment_, community::Community_, post::Post_}; -use lemmy_db_schema::source::{comment::Comment, community::Community, post::Post}; +use lemmy_db_queries::{ + source::{comment::Comment_, community::Community_, post::Post_}, + Crud, +}; +use lemmy_db_schema::source::{ + comment::Comment, + community::Community, + moderator::{ + ModRemoveComment, + ModRemoveCommentForm, + ModRemoveCommunity, + ModRemoveCommunityForm, + ModRemovePost, + ModRemovePostForm, + }, + person::Person, + post::Post, +}; use lemmy_utils::LemmyError; use lemmy_websocket::{LemmyContext, UserOperationCrud}; use url::Url; @@ -28,18 +51,21 @@ use url::Url; /// wrapping it in an announce just like other activities, instead of having the community send it. #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] -pub struct DeletePostCommentOrCommunity { - to: PublicUrl, +pub struct Delete { + pub(in crate::activities::deletion) to: PublicUrl, pub(in crate::activities::deletion) object: Url, - cc: [Url; 1], + pub(in crate::activities::deletion) cc: [Url; 1], #[serde(rename = "type")] - kind: DeleteType, + pub(in crate::activities::deletion) kind: DeleteType, + /// If summary is present, this is a mod action (Remove in Lemmy terms). Otherwise, its a user + /// deleting their own content. + pub(in crate::activities::deletion) summary: Option, #[serde(flatten)] - common: ActivityCommonFields, + pub(in crate::activities::deletion) common: ActivityCommonFields, } #[async_trait::async_trait(?Send)] -impl ActivityHandler for DeletePostCommentOrCommunity { +impl ActivityHandler for Delete { async fn verify( &self, context: &LemmyContext, @@ -50,6 +76,7 @@ impl ActivityHandler for DeletePostCommentOrCommunity { &self.object, &self.cc[0], &self.common, + self.summary.is_some(), context, request_counter, ) @@ -61,6 +88,59 @@ impl ActivityHandler for DeletePostCommentOrCommunity { self, context: &LemmyContext, request_counter: &mut i32, + ) -> Result<(), LemmyError> { + if let Some(reason) = self.summary { + receive_remove_action( + &self.common.actor, + &self.object, + Some(reason), + context, + request_counter, + ) + .await + } else { + self.receive_delete_action(context, request_counter).await + } + } + + fn common(&self) -> &ActivityCommonFields { + &self.common + } +} + +impl Delete { + pub(in crate::activities::deletion) async fn send( + actor: &Person, + community: &Community, + object_id: Url, + summary: Option, + context: &LemmyContext, + ) -> Result<(), LemmyError> { + let id = generate_activity_id(DeleteType::Delete)?; + let delete = Delete { + to: PublicUrl::Public, + object: object_id, + cc: [community.actor_id()], + kind: DeleteType::Delete, + summary, + common: ActivityCommonFields { + context: lemmy_context(), + id: id.clone(), + actor: actor.actor_id(), + unparsed: Default::default(), + }, + }; + + let activity = AnnouncableActivities::Delete(delete); + send_to_community_new(activity, &id, actor, community, vec![], context).await + } + + // TODO: would be nice if we could merge this and receive_delete_action() into a single method + // (or merge with receive_undo_delete_action() instead) + async fn receive_delete_action( + &self, + context: &LemmyContext, + request_counter: &mut i32, ) -> Result<(), LemmyError> { use UserOperationCrud::*; match DeletableObjects::read_from_db(&self.object, context).await? { @@ -68,7 +148,8 @@ impl ActivityHandler for DeletePostCommentOrCommunity { if community.local { let mod_ = get_or_fetch_and_upsert_person(&self.common.actor, context, request_counter).await?; - community.send_delete(mod_, context).await?; + let object = community.actor_id(); + send_apub_delete(&mod_, &community.clone(), object, true, context).await?; } let deleted_community = blocking(context.pool(), move |conn| { @@ -82,19 +163,85 @@ impl ActivityHandler for DeletePostCommentOrCommunity { Post::update_deleted(conn, post.id, true) }) .await??; - send_post_message(deleted_post.id, EditPost, context).await + send_post_message(deleted_post.id, DeletePost, context).await } DeletableObjects::Comment(comment) => { let deleted_comment = blocking(context.pool(), move |conn| { Comment::update_deleted(conn, comment.id, true) }) .await??; - send_comment_message(deleted_comment.id, vec![], EditComment, context).await + send_comment_message(deleted_comment.id, vec![], DeleteComment, context).await } } } +} - fn common(&self) -> &ActivityCommonFields { - &self.common +// TODO: reason is optional for compat with v0.11, make it mandatory after removing the migration +pub(in crate::activities) async fn receive_remove_action( + actor: &Url, + object: &Url, + reason: Option, + context: &LemmyContext, + request_counter: &mut i32, +) -> Result<(), LemmyError> { + let actor = get_or_fetch_and_upsert_person(actor, context, request_counter).await?; + use UserOperationCrud::*; + match DeletableObjects::read_from_db(object, context).await? { + DeletableObjects::Community(community) => { + if community.local { + return Err(anyhow!("Only local admin can remove community").into()); + } + let form = ModRemoveCommunityForm { + mod_person_id: actor.id, + community_id: community.id, + removed: Some(true), + reason, + expires: None, + }; + blocking(context.pool(), move |conn| { + ModRemoveCommunity::create(conn, &form) + }) + .await??; + let deleted_community = blocking(context.pool(), move |conn| { + Community::update_removed(conn, community.id, true) + }) + .await??; + + send_community_message(deleted_community.id, RemoveCommunity, context).await + } + DeletableObjects::Post(post) => { + let form = ModRemovePostForm { + mod_person_id: actor.id, + post_id: post.id, + removed: Some(true), + reason, + }; + blocking(context.pool(), move |conn| { + ModRemovePost::create(conn, &form) + }) + .await??; + let removed_post = blocking(context.pool(), move |conn| { + Post::update_removed(conn, post.id, true) + }) + .await??; + send_post_message(removed_post.id, RemovePost, context).await + } + DeletableObjects::Comment(comment) => { + let form = ModRemoveCommentForm { + mod_person_id: actor.id, + comment_id: comment.id, + removed: Some(true), + reason, + }; + blocking(context.pool(), move |conn| { + ModRemoveComment::create(conn, &form) + }) + .await??; + let removed_comment = blocking(context.pool(), move |conn| { + Comment::update_removed(conn, comment.id, true) + }) + .await??; + send_comment_message(removed_comment.id, vec![], RemoveComment, context).await + } } } diff --git a/crates/apub/src/activities/deletion/mod.rs b/crates/apub/src/activities/deletion/mod.rs index c486310a1..dc08ccde6 100644 --- a/crates/apub/src/activities/deletion/mod.rs +++ b/crates/apub/src/activities/deletion/mod.rs @@ -1,12 +1,16 @@ use crate::{ - activities::{verify_mod_action, verify_person_in_community}, + activities::{ + deletion::{delete::Delete, undo_delete::UndoDelete}, + verify_mod_action, + verify_person_in_community, + }, ActorType, }; use lemmy_api_common::blocking; use lemmy_apub_lib::{verify_domains_match, ActivityCommonFields}; use lemmy_db_queries::ApubObject; use lemmy_db_schema::{ - source::{comment::Comment, community::Community, post::Post}, + source::{comment::Comment, community::Community, person::Person, post::Post}, DbUrl, }; use lemmy_utils::LemmyError; @@ -16,6 +20,37 @@ use url::Url; pub mod delete; pub mod undo_delete; +pub async fn send_apub_delete( + actor: &Person, + community: &Community, + object_id: Url, + deleted: bool, + context: &LemmyContext, +) -> Result<(), LemmyError> { + if deleted { + Delete::send(actor, community, object_id, None, context).await + } else { + UndoDelete::send(actor, community, object_id, None, context).await + } +} + +// TODO: remove reason is actually optional in lemmy. we set an empty string in that case, but its +// ugly +pub async fn send_apub_remove( + actor: &Person, + community: &Community, + object_id: Url, + reason: String, + removed: bool, + context: &LemmyContext, +) -> Result<(), LemmyError> { + if removed { + Delete::send(actor, community, object_id, Some(reason), context).await + } else { + UndoDelete::send(actor, community, object_id, Some(reason), context).await + } +} + pub enum DeletableObjects { Community(Box), Comment(Box), @@ -53,10 +88,11 @@ impl DeletableObjects { } } -pub(in crate::activities::deletion) async fn verify_delete_activity( +pub(in crate::activities) async fn verify_delete_activity( object: &Url, cc: &Url, common: &ActivityCommonFields, + is_mod_action: bool, context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { @@ -68,17 +104,49 @@ pub(in crate::activities::deletion) async fn verify_delete_activity( // deleted community (which fails) verify_person_in_community(&common.actor, cc, context, request_counter).await?; } + // community deletion is always a mod (or admin) action verify_mod_action(&common.actor, c.actor_id(), context).await?; } DeletableObjects::Post(p) => { - verify_person_in_community(&common.actor, cc, context, request_counter).await?; - // domain of post ap_id and post.creator ap_id are identical, so we just check the former - verify_domains_match(&common.actor, &p.ap_id.into())?; + verify_delete_activity_post_or_comment( + cc, + common, + &p.ap_id.into(), + is_mod_action, + context, + request_counter, + ) + .await?; } DeletableObjects::Comment(c) => { - verify_person_in_community(&common.actor, cc, context, request_counter).await?; - verify_domains_match(&common.actor, &c.ap_id.into())?; + verify_delete_activity_post_or_comment( + cc, + common, + &c.ap_id.into(), + is_mod_action, + context, + request_counter, + ) + .await?; } } Ok(()) } + +async fn verify_delete_activity_post_or_comment( + cc: &Url, + common: &ActivityCommonFields, + object_id: &Url, + is_mod_action: bool, + context: &LemmyContext, + request_counter: &mut i32, +) -> Result<(), LemmyError> { + verify_person_in_community(&common.actor, cc, context, request_counter).await?; + if is_mod_action { + verify_mod_action(&common.actor, cc.clone(), context).await?; + } else { + // domain of post ap_id and post.creator ap_id are identical, so we just check the former + verify_domains_match(&common.actor, object_id)?; + } + Ok(()) +} diff --git a/crates/apub/src/activities/deletion/undo_delete.rs b/crates/apub/src/activities/deletion/undo_delete.rs index 65530abb9..b754231c8 100644 --- a/crates/apub/src/activities/deletion/undo_delete.rs +++ b/crates/apub/src/activities/deletion/undo_delete.rs @@ -1,28 +1,35 @@ use crate::{ activities::{ comment::send_websocket_message as send_comment_message, - community::send_websocket_message as send_community_message, - deletion::{delete::DeletePostCommentOrCommunity, verify_delete_activity, DeletableObjects}, + community::{ + announce::AnnouncableActivities, + send_websocket_message as send_community_message, + }, + deletion::{delete::Delete, send_apub_delete, verify_delete_activity, DeletableObjects}, + generate_activity_id, post::send_websocket_message as send_post_message, verify_activity, }, + activity_queue::send_to_community_new, + extensions::context::lemmy_context, fetcher::person::get_or_fetch_and_upsert_person, - CommunityType, + ActorType, }; -use activitystreams::activity::kind::UndoType; +use activitystreams::activity::kind::{DeleteType, UndoType}; +use anyhow::anyhow; use lemmy_api_common::blocking; use lemmy_apub_lib::{values::PublicUrl, ActivityCommonFields, ActivityHandler}; use lemmy_db_queries::source::{comment::Comment_, community::Community_, post::Post_}; -use lemmy_db_schema::source::{comment::Comment, community::Community, post::Post}; +use lemmy_db_schema::source::{comment::Comment, community::Community, person::Person, post::Post}; use lemmy_utils::LemmyError; use lemmy_websocket::{LemmyContext, UserOperationCrud}; use url::Url; #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] -pub struct UndoDeletePostCommentOrCommunity { +pub struct UndoDelete { to: PublicUrl, - object: DeletePostCommentOrCommunity, + object: Delete, cc: [Url; 1], #[serde(rename = "type")] kind: UndoType, @@ -31,7 +38,7 @@ pub struct UndoDeletePostCommentOrCommunity { } #[async_trait::async_trait(?Send)] -impl ActivityHandler for UndoDeletePostCommentOrCommunity { +impl ActivityHandler for UndoDelete { async fn verify( &self, context: &LemmyContext, @@ -43,6 +50,7 @@ impl ActivityHandler for UndoDeletePostCommentOrCommunity { &self.object.object, &self.cc[0], &self.common, + self.object.summary.is_some(), context, request_counter, ) @@ -54,6 +62,64 @@ impl ActivityHandler for UndoDeletePostCommentOrCommunity { self, context: &LemmyContext, request_counter: &mut i32, + ) -> Result<(), LemmyError> { + if self.object.summary.is_some() { + UndoDelete::receive_undo_remove_action(&self.object.object, context).await + } else { + self + .receive_undo_delete_action(context, request_counter) + .await + } + } + + fn common(&self) -> &ActivityCommonFields { + &self.common + } +} + +impl UndoDelete { + pub(in crate::activities::deletion) async fn send( + actor: &Person, + community: &Community, + object_id: Url, + summary: Option, + context: &LemmyContext, + ) -> Result<(), LemmyError> { + let delete = Delete { + to: PublicUrl::Public, + object: object_id, + cc: [community.actor_id()], + kind: DeleteType::Delete, + summary, + common: ActivityCommonFields { + context: lemmy_context(), + id: generate_activity_id(DeleteType::Delete)?, + actor: actor.actor_id(), + unparsed: Default::default(), + }, + }; + + let id = generate_activity_id(UndoType::Undo)?; + let undo = UndoDelete { + to: PublicUrl::Public, + object: delete, + cc: [community.actor_id()], + kind: UndoType::Undo, + common: ActivityCommonFields { + context: lemmy_context(), + id: id.clone(), + actor: actor.actor_id(), + unparsed: Default::default(), + }, + }; + + let activity = AnnouncableActivities::UndoDelete(undo); + send_to_community_new(activity, &id, actor, community, vec![], context).await + } + async fn receive_undo_delete_action( + &self, + context: &LemmyContext, + request_counter: &mut i32, ) -> Result<(), LemmyError> { use UserOperationCrud::*; let object = DeletableObjects::read_from_db(&self.object.object, context).await?; @@ -62,7 +128,14 @@ impl ActivityHandler for UndoDeletePostCommentOrCommunity { if community.local { let mod_ = get_or_fetch_and_upsert_person(&self.common.actor, context, request_counter).await?; - community.send_undo_delete(mod_, context).await?; + send_apub_delete( + &mod_, + &community.clone(), + community.actor_id(), + false, + context, + ) + .await?; } let deleted_community = blocking(context.pool(), move |conn| { @@ -88,7 +161,37 @@ impl ActivityHandler for UndoDeletePostCommentOrCommunity { } } - fn common(&self) -> &ActivityCommonFields { - &self.common + pub(in crate::activities) async fn receive_undo_remove_action( + object: &Url, + context: &LemmyContext, + ) -> Result<(), LemmyError> { + use UserOperationCrud::*; + match DeletableObjects::read_from_db(object, context).await? { + DeletableObjects::Community(community) => { + if community.local { + return Err(anyhow!("Only local admin can restore community").into()); + } + let deleted_community = blocking(context.pool(), move |conn| { + Community::update_removed(conn, community.id, false) + }) + .await??; + + send_community_message(deleted_community.id, EditCommunity, context).await + } + DeletableObjects::Post(post) => { + let removed_post = blocking(context.pool(), move |conn| { + Post::update_removed(conn, post.id, false) + }) + .await??; + send_post_message(removed_post.id, EditPost, context).await + } + DeletableObjects::Comment(comment) => { + let removed_comment = blocking(context.pool(), move |conn| { + Comment::update_removed(conn, comment.id, false) + }) + .await??; + send_comment_message(removed_comment.id, vec![], EditComment, context).await + } + } } } diff --git a/crates/apub/src/activities/removal/remove.rs b/crates/apub/src/activities/removal/remove.rs index 83aaabc6f..1bd6e0a03 100644 --- a/crates/apub/src/activities/removal/remove.rs +++ b/crates/apub/src/activities/removal/remove.rs @@ -1,77 +1,59 @@ use crate::{ activities::{ - comment::send_websocket_message as send_comment_message, - community::send_websocket_message as send_community_message, - post::send_websocket_message as send_post_message, + deletion::{delete::receive_remove_action, verify_delete_activity}, verify_activity, verify_add_remove_moderator_target, verify_mod_action, verify_person_in_community, }, - fetcher::{ - community::get_or_fetch_and_upsert_community, - objects::get_or_fetch_and_insert_post_or_comment, - person::get_or_fetch_and_upsert_person, - }, + fetcher::{community::get_or_fetch_and_upsert_community, person::get_or_fetch_and_upsert_person}, CommunityType, - PostOrComment, }; use activitystreams::{activity::kind::RemoveType, base::AnyBase}; -use anyhow::anyhow; use lemmy_api_common::blocking; use lemmy_apub_lib::{values::PublicUrl, ActivityCommonFields, ActivityHandler}; -use lemmy_db_queries::{ - source::{comment::Comment_, community::Community_, post::Post_}, - Joinable, -}; -use lemmy_db_schema::source::{ - comment::Comment, - community::{Community, CommunityModerator, CommunityModeratorForm}, - post::Post, -}; +use lemmy_db_queries::Joinable; +use lemmy_db_schema::source::community::{CommunityModerator, CommunityModeratorForm}; use lemmy_utils::LemmyError; -use lemmy_websocket::{LemmyContext, UserOperationCrud}; +use lemmy_websocket::LemmyContext; use url::Url; -// TODO: we can probably deduplicate a bunch of code between this and DeletePostCommentOrCommunity #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] -pub struct RemovePostCommentCommunityOrMod { +pub struct RemoveMod { to: PublicUrl, pub(in crate::activities::removal) object: Url, cc: [Url; 1], #[serde(rename = "type")] kind: RemoveType, // if target is set, this is means remove mod from community - target: Option, + pub(in crate::activities::removal) target: Option, #[serde(flatten)] common: ActivityCommonFields, } #[async_trait::async_trait(?Send)] -impl ActivityHandler for RemovePostCommentCommunityOrMod { +impl ActivityHandler for RemoveMod { async fn verify( &self, context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { verify_activity(self.common())?; - let object_community = - get_or_fetch_and_upsert_community(&self.object, context, request_counter).await; - // removing a community - if object_community.is_ok() { - verify_mod_action(&self.common.actor, self.object.clone(), context).await?; - } - // removing community mod - else if let Some(target) = &self.target { + if let Some(target) = &self.target { verify_person_in_community(&self.common.actor, &self.cc[0], context, request_counter).await?; verify_mod_action(&self.common.actor, self.cc[0].clone(), context).await?; verify_add_remove_moderator_target(target, self.cc[0].clone())?; - } - // removing a post or comment - else { - verify_person_in_community(&self.common.actor, &self.cc[0], context, request_counter).await?; - verify_mod_action(&self.common.actor, self.cc[0].clone(), context).await?; + } else { + verify_delete_activity( + &self.object, + &self.cc[0], + self.common(), + true, + context, + request_counter, + ) + .await?; } Ok(()) } @@ -81,27 +63,7 @@ impl ActivityHandler for RemovePostCommentCommunityOrMod { context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { - let object_community = - get_or_fetch_and_upsert_community(&self.object, context, request_counter).await; - // removing a community - if let Ok(community) = object_community { - if community.local { - return Err(anyhow!("Only local admin can remove community").into()); - } - let deleted_community = blocking(context.pool(), move |conn| { - Community::update_removed(conn, community.id, true) - }) - .await??; - - send_community_message( - deleted_community.id, - UserOperationCrud::RemoveCommunity, - context, - ) - .await - } - // removing community mod - else if self.target.is_some() { + if self.target.is_some() { let community = get_or_fetch_and_upsert_community(&self.cc[0], context, request_counter).await?; let remove_mod = @@ -121,31 +83,15 @@ impl ActivityHandler for RemovePostCommentCommunityOrMod { .await?; // TODO: send websocket notification about removed mod Ok(()) - } - // removing a post or comment - else { - match get_or_fetch_and_insert_post_or_comment(&self.object, context, request_counter).await? { - PostOrComment::Post(post) => { - let removed_post = blocking(context.pool(), move |conn| { - Post::update_removed(conn, post.id, true) - }) - .await??; - send_post_message(removed_post.id, UserOperationCrud::EditPost, context).await - } - PostOrComment::Comment(comment) => { - let removed_comment = blocking(context.pool(), move |conn| { - Comment::update_removed(conn, comment.id, true) - }) - .await??; - send_comment_message( - removed_comment.id, - vec![], - UserOperationCrud::EditComment, - context, - ) - .await - } - } + } else { + receive_remove_action( + &self.common.actor, + &self.object, + None, + context, + request_counter, + ) + .await } } diff --git a/crates/apub/src/activities/removal/undo_remove.rs b/crates/apub/src/activities/removal/undo_remove.rs index 003eb4aaa..e2c7ef76f 100644 --- a/crates/apub/src/activities/removal/undo_remove.rs +++ b/crates/apub/src/activities/removal/undo_remove.rs @@ -1,34 +1,20 @@ -use crate::{ - activities::{ - comment::send_websocket_message as send_comment_message, - community::send_websocket_message as send_community_message, - post::send_websocket_message as send_post_message, - removal::remove::RemovePostCommentCommunityOrMod, - verify_activity, - verify_mod_action, - verify_person_in_community, - }, - fetcher::{ - community::get_or_fetch_and_upsert_community, - objects::get_or_fetch_and_insert_post_or_comment, - }, - PostOrComment, +use crate::activities::{ + deletion::{undo_delete::UndoDelete, verify_delete_activity}, + removal::remove::RemoveMod, + verify_activity, }; use activitystreams::activity::kind::UndoType; -use anyhow::anyhow; -use lemmy_api_common::blocking; use lemmy_apub_lib::{values::PublicUrl, ActivityCommonFields, ActivityHandler}; -use lemmy_db_queries::source::{comment::Comment_, community::Community_, post::Post_}; -use lemmy_db_schema::source::{comment::Comment, community::Community, post::Post}; use lemmy_utils::LemmyError; -use lemmy_websocket::{LemmyContext, UserOperationCrud}; +use lemmy_websocket::LemmyContext; use url::Url; #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct UndoRemovePostCommentOrCommunity { to: PublicUrl, - object: RemovePostCommentCommunityOrMod, + // Note, there is no such thing as Undo/Remove/Mod, so we ignore that + object: RemoveMod, cc: [Url; 1], #[serde(rename = "type")] kind: UndoType, @@ -44,74 +30,26 @@ impl ActivityHandler for UndoRemovePostCommentOrCommunity { request_counter: &mut i32, ) -> Result<(), LemmyError> { verify_activity(self.common())?; - let object_community = - get_or_fetch_and_upsert_community(&self.object.object, context, request_counter).await; - // removing a community - if object_community.is_ok() { - verify_mod_action(&self.common.actor, self.object.object.clone(), context).await?; - } - // removing a post or comment - else { - verify_person_in_community(&self.common.actor, &self.cc[0], context, request_counter).await?; - verify_mod_action(&self.common.actor, self.cc[0].clone(), context).await?; - } self.object.verify(context, request_counter).await?; - // dont check that actor and object.actor are identical, so that one mod can - // undo the action of another + + verify_delete_activity( + &self.object.object, + &self.cc[0], + self.common(), + true, + context, + request_counter, + ) + .await?; Ok(()) } async fn receive( self, context: &LemmyContext, - request_counter: &mut i32, + _request_counter: &mut i32, ) -> Result<(), LemmyError> { - let object_community = - get_or_fetch_and_upsert_community(&self.object.object, context, request_counter).await; - // restoring a community - if let Ok(community) = object_community { - if community.local { - return Err(anyhow!("Only local admin can undo remove community").into()); - } - let deleted_community = blocking(context.pool(), move |conn| { - Community::update_removed(conn, community.id, false) - }) - .await??; - - send_community_message( - deleted_community.id, - UserOperationCrud::EditCommunity, - context, - ) - .await - } - // restoring a post or comment - else { - match get_or_fetch_and_insert_post_or_comment(&self.object.object, context, request_counter) - .await? - { - PostOrComment::Post(post) => { - let removed_post = blocking(context.pool(), move |conn| { - Post::update_removed(conn, post.id, false) - }) - .await??; - send_post_message(removed_post.id, UserOperationCrud::EditPost, context).await - } - PostOrComment::Comment(comment) => { - let removed_comment = blocking(context.pool(), move |conn| { - Comment::update_removed(conn, comment.id, false) - }) - .await??; - send_comment_message( - removed_comment.id, - vec![], - UserOperationCrud::EditComment, - context, - ) - .await - } - } - } + UndoDelete::receive_undo_remove_action(&self.object.object, context).await } fn common(&self) -> &ActivityCommonFields { diff --git a/crates/apub/src/activities/send/comment.rs b/crates/apub/src/activities/send/comment.rs deleted file mode 100644 index 8b446860a..000000000 --- a/crates/apub/src/activities/send/comment.rs +++ /dev/null @@ -1,153 +0,0 @@ -use crate::{ - activities::generate_activity_id, - activity_queue::send_to_community, - extensions::context::lemmy_context, - ActorType, - ApubObjectType, -}; -use activitystreams::{ - activity::{ - kind::{DeleteType, RemoveType, UndoType}, - Delete, - Remove, - Undo, - }, - prelude::*, - public, -}; -use lemmy_api_common::blocking; -use lemmy_db_queries::Crud; -use lemmy_db_schema::source::{comment::Comment, community::Community, person::Person, post::Post}; -use lemmy_utils::LemmyError; -use lemmy_websocket::LemmyContext; - -#[async_trait::async_trait(?Send)] -impl ApubObjectType for Comment { - async fn send_delete(&self, creator: &Person, context: &LemmyContext) -> Result<(), LemmyError> { - let post_id = self.post_id; - let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; - - let community_id = post.community_id; - let community = blocking(context.pool(), move |conn| { - Community::read(conn, community_id) - }) - .await??; - - let mut delete = Delete::new( - creator.actor_id.to_owned().into_inner(), - self.ap_id.to_owned().into_inner(), - ); - delete - .set_many_contexts(lemmy_context()) - .set_id(generate_activity_id(DeleteType::Delete)?) - .set_to(public()) - .set_many_ccs(vec![community.actor_id()]); - - send_to_community(delete, creator, &community, None, context).await?; - Ok(()) - } - - async fn send_undo_delete( - &self, - creator: &Person, - context: &LemmyContext, - ) -> Result<(), LemmyError> { - let post_id = self.post_id; - let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; - - let community_id = post.community_id; - let community = blocking(context.pool(), move |conn| { - Community::read(conn, community_id) - }) - .await??; - - // Generate a fake delete activity, with the correct object - let mut delete = Delete::new( - creator.actor_id.to_owned().into_inner(), - self.ap_id.to_owned().into_inner(), - ); - delete - .set_many_contexts(lemmy_context()) - .set_id(generate_activity_id(DeleteType::Delete)?) - .set_to(public()) - .set_many_ccs(vec![community.actor_id()]); - - // Undo that fake activity - let mut undo = Undo::new( - creator.actor_id.to_owned().into_inner(), - delete.into_any_base()?, - ); - undo - .set_many_contexts(lemmy_context()) - .set_id(generate_activity_id(UndoType::Undo)?) - .set_to(public()) - .set_many_ccs(vec![community.actor_id()]); - - send_to_community(undo, creator, &community, None, context).await?; - Ok(()) - } - - async fn send_remove(&self, mod_: &Person, context: &LemmyContext) -> Result<(), LemmyError> { - let post_id = self.post_id; - let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; - - let community_id = post.community_id; - let community = blocking(context.pool(), move |conn| { - Community::read(conn, community_id) - }) - .await??; - - let mut remove = Remove::new( - mod_.actor_id.to_owned().into_inner(), - self.ap_id.to_owned().into_inner(), - ); - remove - .set_many_contexts(lemmy_context()) - .set_id(generate_activity_id(RemoveType::Remove)?) - .set_to(public()) - .set_many_ccs(vec![community.actor_id()]); - - send_to_community(remove, mod_, &community, None, context).await?; - Ok(()) - } - - async fn send_undo_remove( - &self, - mod_: &Person, - context: &LemmyContext, - ) -> Result<(), LemmyError> { - let post_id = self.post_id; - let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; - - let community_id = post.community_id; - let community = blocking(context.pool(), move |conn| { - Community::read(conn, community_id) - }) - .await??; - - // Generate a fake delete activity, with the correct object - let mut remove = Remove::new( - mod_.actor_id.to_owned().into_inner(), - self.ap_id.to_owned().into_inner(), - ); - remove - .set_many_contexts(lemmy_context()) - .set_id(generate_activity_id(RemoveType::Remove)?) - .set_to(public()) - .set_many_ccs(vec![community.actor_id()]); - - // Undo that fake activity - let mut undo = Undo::new( - mod_.actor_id.to_owned().into_inner(), - remove.into_any_base()?, - ); - undo - .set_many_contexts(lemmy_context()) - .set_id(generate_activity_id(UndoType::Undo)?) - .set_to(public()) - .set_many_ccs(vec![community.actor_id()]); - - send_to_community(undo, mod_, &community, None, context).await?; - Ok(()) - } -} diff --git a/crates/apub/src/activities/send/community.rs b/crates/apub/src/activities/send/community.rs index 6f88dd36f..a103f95c6 100644 --- a/crates/apub/src/activities/send/community.rs +++ b/crates/apub/src/activities/send/community.rs @@ -12,20 +12,10 @@ use crate::{ }; use activitystreams::{ activity::{ - kind::{ - AddType, - AnnounceType, - BlockType, - DeleteType, - LikeType, - RemoveType, - UndoType, - UpdateType, - }, + kind::{AddType, AnnounceType, BlockType, RemoveType, UndoType, UpdateType}, Add, Announce, Block, - Delete, OptTargetRefExt, Remove, Undo, @@ -97,112 +87,6 @@ impl CommunityType for Community { Ok(()) } - /// If the creator of a community deletes the community, send this to all followers. - /// - /// We need to handle deletion by a remote mod separately. - async fn send_delete(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError> { - // Local mod, send directly from community to followers - if self.local { - let mut delete = Delete::new(self.actor_id(), self.actor_id()); - delete - .set_many_contexts(lemmy_context()) - .set_id(generate_activity_id(DeleteType::Delete)?) - .set_to(public()) - .set_many_ccs(vec![self.followers_url()]); - - send_to_community_followers(delete, self, None, context).await?; - } - // Remote mod, send from mod to community - else { - let mut delete = Delete::new(mod_.actor_id(), self.actor_id()); - delete - .set_many_contexts(lemmy_context()) - .set_id(generate_activity_id(DeleteType::Delete)?) - .set_to(public()) - .set_many_ccs(vec![self.actor_id()]); - - send_to_community(delete, &mod_, self, None, context).await?; - } - Ok(()) - } - - /// If the creator of a community reverts the deletion of a community, send this to all followers. - /// - /// We need to handle undelete by a remote mod separately. - async fn send_undo_delete(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError> { - // Local mod, send directly from community to followers - if self.local { - let mut delete = Delete::new(self.actor_id(), self.actor_id()); - delete - .set_many_contexts(lemmy_context()) - .set_id(generate_activity_id(DeleteType::Delete)?) - .set_to(public()) - .set_many_ccs(vec![self.followers_url()]); - - let mut undo = Undo::new(self.actor_id(), delete.into_any_base()?); - undo - .set_many_contexts(lemmy_context()) - .set_id(generate_activity_id(UndoType::Undo)?) - .set_to(public()) - .set_many_ccs(vec![self.followers_url()]); - - send_to_community_followers(undo, self, None, context).await?; - } - // Remote mod, send from mod to community - else { - let mut delete = Delete::new(mod_.actor_id(), self.actor_id()); - delete - .set_many_contexts(lemmy_context()) - .set_id(generate_activity_id(DeleteType::Delete)?) - .set_to(public()) - .set_many_ccs(vec![self.actor_id()]); - - let mut undo = Undo::new(mod_.actor_id(), delete.into_any_base()?); - undo - .set_many_contexts(lemmy_context()) - .set_id(generate_activity_id(UndoType::Undo)?) - .set_to(public()) - .set_many_ccs(vec![self.actor_id()]); - - send_to_community(undo, &mod_, self, None, context).await?; - } - Ok(()) - } - - /// If an admin removes a community, send this to all followers. - async fn send_remove(&self, context: &LemmyContext) -> Result<(), LemmyError> { - let mut remove = Remove::new(self.actor_id(), self.actor_id()); - remove - .set_many_contexts(lemmy_context()) - .set_id(generate_activity_id(RemoveType::Remove)?) - .set_to(public()) - .set_many_ccs(vec![self.followers_url()]); - - send_to_community_followers(remove, self, None, context).await?; - Ok(()) - } - - /// If an admin reverts the removal of a community, send this to all followers. - async fn send_undo_remove(&self, context: &LemmyContext) -> Result<(), LemmyError> { - let mut remove = Remove::new(self.actor_id(), self.actor_id()); - remove - .set_many_contexts(lemmy_context()) - .set_id(generate_activity_id(RemoveType::Remove)?) - .set_to(public()) - .set_many_ccs(vec![self.followers_url()]); - - // Undo that fake activity - let mut undo = Undo::new(self.actor_id(), remove.into_any_base()?); - undo - .set_many_contexts(lemmy_context()) - .set_id(generate_activity_id(LikeType::Like)?) - .set_to(public()) - .set_many_ccs(vec![self.followers_url()]); - - send_to_community_followers(undo, self, None, context).await?; - Ok(()) - } - /// Wraps an activity sent to the community in an announce, and then sends the announce to all /// community followers. /// diff --git a/crates/apub/src/activities/send/mod.rs b/crates/apub/src/activities/send/mod.rs index c00ecb1a7..a01cddd6d 100644 --- a/crates/apub/src/activities/send/mod.rs +++ b/crates/apub/src/activities/send/mod.rs @@ -1,4 +1,2 @@ -pub(crate) mod comment; pub(crate) mod community; pub(crate) mod person; -pub(crate) mod post; diff --git a/crates/apub/src/activities/send/post.rs b/crates/apub/src/activities/send/post.rs deleted file mode 100644 index b9713661b..000000000 --- a/crates/apub/src/activities/send/post.rs +++ /dev/null @@ -1,139 +0,0 @@ -use crate::{ - activities::generate_activity_id, - activity_queue::send_to_community, - extensions::context::lemmy_context, - ActorType, - ApubObjectType, -}; -use activitystreams::{ - activity::{ - kind::{DeleteType, RemoveType, UndoType}, - Delete, - Remove, - Undo, - }, - prelude::*, - public, -}; -use lemmy_api_common::blocking; -use lemmy_db_queries::Crud; -use lemmy_db_schema::source::{community::Community, person::Person, post::Post}; -use lemmy_utils::LemmyError; -use lemmy_websocket::LemmyContext; - -#[async_trait::async_trait(?Send)] -impl ApubObjectType for Post { - async fn send_delete(&self, creator: &Person, context: &LemmyContext) -> Result<(), LemmyError> { - let community_id = self.community_id; - let community = blocking(context.pool(), move |conn| { - Community::read(conn, community_id) - }) - .await??; - - let mut delete = Delete::new( - creator.actor_id.to_owned().into_inner(), - self.ap_id.to_owned().into_inner(), - ); - delete - .set_many_contexts(lemmy_context()) - .set_id(generate_activity_id(DeleteType::Delete)?) - .set_to(public()) - .set_many_ccs(vec![community.actor_id()]); - - send_to_community(delete, creator, &community, None, context).await?; - Ok(()) - } - - async fn send_undo_delete( - &self, - creator: &Person, - context: &LemmyContext, - ) -> Result<(), LemmyError> { - let community_id = self.community_id; - let community = blocking(context.pool(), move |conn| { - Community::read(conn, community_id) - }) - .await??; - - let mut delete = Delete::new( - creator.actor_id.to_owned().into_inner(), - self.ap_id.to_owned().into_inner(), - ); - delete - .set_many_contexts(lemmy_context()) - .set_id(generate_activity_id(DeleteType::Delete)?) - .set_to(public()) - .set_many_ccs(vec![community.actor_id()]); - - // Undo that fake activity - let mut undo = Undo::new( - creator.actor_id.to_owned().into_inner(), - delete.into_any_base()?, - ); - undo - .set_many_contexts(lemmy_context()) - .set_id(generate_activity_id(UndoType::Undo)?) - .set_to(public()) - .set_many_ccs(vec![community.actor_id()]); - - send_to_community(undo, creator, &community, None, context).await?; - Ok(()) - } - - async fn send_remove(&self, mod_: &Person, context: &LemmyContext) -> Result<(), LemmyError> { - let community_id = self.community_id; - let community = blocking(context.pool(), move |conn| { - Community::read(conn, community_id) - }) - .await??; - - let mut remove = Remove::new( - mod_.actor_id.to_owned().into_inner(), - self.ap_id.to_owned().into_inner(), - ); - remove - .set_many_contexts(lemmy_context()) - .set_id(generate_activity_id(RemoveType::Remove)?) - .set_to(public()) - .set_many_ccs(vec![community.actor_id()]); - - send_to_community(remove, mod_, &community, None, context).await?; - Ok(()) - } - - async fn send_undo_remove( - &self, - mod_: &Person, - context: &LemmyContext, - ) -> Result<(), LemmyError> { - let community_id = self.community_id; - let community = blocking(context.pool(), move |conn| { - Community::read(conn, community_id) - }) - .await??; - - let mut remove = Remove::new( - mod_.actor_id.to_owned().into_inner(), - self.ap_id.to_owned().into_inner(), - ); - remove - .set_many_contexts(lemmy_context()) - .set_id(generate_activity_id(RemoveType::Remove)?) - .set_to(public()) - .set_many_ccs(vec![community.actor_id()]); - - // Undo that fake activity - let mut undo = Undo::new( - mod_.actor_id.to_owned().into_inner(), - remove.into_any_base()?, - ); - undo - .set_many_contexts(lemmy_context()) - .set_id(generate_activity_id(UndoType::Undo)?) - .set_to(public()) - .set_many_ccs(vec![community.actor_id()]); - - send_to_community(undo, mod_, &community, None, context).await?; - Ok(()) - } -} diff --git a/crates/apub/src/http/inbox_enums.rs b/crates/apub/src/http/inbox_enums.rs index 034048777..1ed210bb5 100644 --- a/crates/apub/src/http/inbox_enums.rs +++ b/crates/apub/src/http/inbox_enums.rs @@ -7,7 +7,7 @@ use crate::activities::{ undo_block_user::UndoBlockUserFromCommunity, update::UpdateCommunity, }, - deletion::{delete::DeletePostCommentOrCommunity, undo_delete::UndoDeletePostCommentOrCommunity}, + deletion::{delete::Delete, undo_delete::UndoDelete}, following::{accept::AcceptFollowCommunity, follow::FollowCommunity, undo::UndoFollowCommunity}, post::create_or_update::CreateOrUpdatePost, private_message::{ @@ -15,10 +15,7 @@ use crate::activities::{ delete::DeletePrivateMessage, undo_delete::UndoDeletePrivateMessage, }, - removal::{ - remove::RemovePostCommentCommunityOrMod, - undo_remove::UndoRemovePostCommentOrCommunity, - }, + removal::{remove::RemoveMod, undo_remove::UndoRemovePostCommentOrCommunity}, voting::{undo_vote::UndoVote, vote::Vote}, }; use lemmy_apub_lib::{ActivityCommonFields, ActivityHandler}; @@ -45,14 +42,14 @@ pub enum GroupInboxActivities { CreateOrUpdatePost(Box), Vote(Vote), UndoVote(UndoVote), - DeletePostCommentOrCommunity(DeletePostCommentOrCommunity), - UndoDeletePostCommentOrCommunity(UndoDeletePostCommentOrCommunity), - RemovePostCommentOrCommunity(RemovePostCommentCommunityOrMod), + DeletePostCommentOrCommunity(Delete), + UndoDeletePostCommentOrCommunity(UndoDelete), UndoRemovePostCommentOrCommunity(UndoRemovePostCommentOrCommunity), UpdateCommunity(Box), BlockUserFromCommunity(BlockUserFromCommunity), UndoBlockUserFromCommunity(UndoBlockUserFromCommunity), AddMod(AddMod), + RemoveMod(RemoveMod), } #[derive(Clone, Debug, Deserialize, Serialize, ActivityHandler)] @@ -65,14 +62,14 @@ pub enum SharedInboxActivities { CreateOrUpdatePost(Box), Vote(Vote), UndoVote(UndoVote), - DeletePostCommentOrCommunity(DeletePostCommentOrCommunity), - UndoDeletePostCommentOrCommunity(UndoDeletePostCommentOrCommunity), - RemovePostCommentOrCommunity(RemovePostCommentCommunityOrMod), + Delete(Delete), + UndoDelete(UndoDelete), UndoRemovePostCommentOrCommunity(UndoRemovePostCommentOrCommunity), UpdateCommunity(Box), BlockUserFromCommunity(BlockUserFromCommunity), UndoBlockUserFromCommunity(UndoBlockUserFromCommunity), AddMod(AddMod), + RemoveMod(RemoveMod), // received by person AcceptFollowCommunity(AcceptFollowCommunity), // Note, pm activities need to be at the end, otherwise comments will end up here. We can probably diff --git a/crates/apub/src/lib.rs b/crates/apub/src/lib.rs index 5bbf8bb55..477143009 100644 --- a/crates/apub/src/lib.rs +++ b/crates/apub/src/lib.rs @@ -102,25 +102,6 @@ pub(crate) fn check_is_apub_id_valid( Ok(()) } -/// Common functions for ActivityPub objects, which are implemented by most (but not all) objects -/// and actors in Lemmy. -#[async_trait::async_trait(?Send)] -pub trait ApubObjectType { - async fn send_delete(&self, creator: &DbPerson, context: &LemmyContext) - -> Result<(), LemmyError>; - async fn send_undo_delete( - &self, - creator: &DbPerson, - context: &LemmyContext, - ) -> Result<(), LemmyError>; - async fn send_remove(&self, mod_: &DbPerson, context: &LemmyContext) -> Result<(), LemmyError>; - async fn send_undo_remove( - &self, - mod_: &DbPerson, - context: &LemmyContext, - ) -> Result<(), LemmyError>; -} - /// Common methods provided by ActivityPub actors (community and person). Not all methods are /// implemented by all actors. trait ActorType { @@ -160,11 +141,6 @@ pub trait CommunityType { async fn get_follower_inboxes(&self, pool: &DbPool) -> Result, LemmyError>; async fn send_update(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError>; - async fn send_delete(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError>; - async fn send_undo_delete(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError>; - - async fn send_remove(&self, context: &LemmyContext) -> Result<(), LemmyError>; - async fn send_undo_remove(&self, context: &LemmyContext) -> Result<(), LemmyError>; async fn send_announce( &self, diff --git a/crates/apub/src/migrations.rs b/crates/apub/src/migrations.rs index 0f18d2f37..59eeacce9 100644 --- a/crates/apub/src/migrations.rs +++ b/crates/apub/src/migrations.rs @@ -15,3 +15,15 @@ pub enum CommentInReplyToMigration { Old(Vec), New(Url), } + +// Another migration we are doing is to handle all deletions and removals using Delete activity. +// This is because Remove is for removing an object from a collection, so using it that way doesn't +// really make sense. It is also a problem because we have a RemoveMod activity, which was awkward +// to handle together with removing posts etc. +// +// v0.11: send and receive mod removals as Remove +// v0.12: receive removals as Remove, send as Delete (compatible with v0.11) +// v0.13: send and receive mod removals as Delete (compatible with v0.12) +// +// For v0.13, delete [`UndoRemovePostCommentOrCommunity`], and don't handle object deletion in +// [`RemoveMod`] handler.