]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/deletion/delete.rs
Use audience field to federate items in groups (fixes #2464) (#2584)
[lemmy.git] / crates / apub / src / activities / deletion / delete.rs
1 use crate::{
2   activities::{
3     deletion::{receive_delete_action, verify_delete_activity, DeletableObjects},
4     generate_activity_id,
5   },
6   local_instance,
7   objects::{community::ApubCommunity, person::ApubPerson},
8   protocol::{activities::deletion::delete::Delete, IdOrNestedObject},
9 };
10 use activitypub_federation::{core::object_id::ObjectId, data::Data, traits::ActivityHandler};
11 use activitystreams_kinds::activity::DeleteType;
12 use lemmy_db_schema::{
13   source::{
14     comment::{Comment, CommentUpdateForm},
15     community::{Community, CommunityUpdateForm},
16     moderator::{
17       ModRemoveComment,
18       ModRemoveCommentForm,
19       ModRemoveCommunity,
20       ModRemoveCommunityForm,
21       ModRemovePost,
22       ModRemovePostForm,
23     },
24     post::{Post, PostUpdateForm},
25   },
26   traits::Crud,
27 };
28 use lemmy_utils::error::LemmyError;
29 use lemmy_websocket::{
30   send::{send_comment_ws_message_simple, send_community_ws_message, send_post_ws_message},
31   LemmyContext,
32   UserOperationCrud,
33 };
34 use url::Url;
35
36 #[async_trait::async_trait(?Send)]
37 impl ActivityHandler for Delete {
38   type DataType = LemmyContext;
39   type Error = LemmyError;
40
41   fn id(&self) -> &Url {
42     &self.id
43   }
44
45   fn actor(&self) -> &Url {
46     self.actor.inner()
47   }
48
49   #[tracing::instrument(skip_all)]
50   async fn verify(
51     &self,
52     context: &Data<LemmyContext>,
53     request_counter: &mut i32,
54   ) -> Result<(), LemmyError> {
55     verify_delete_activity(self, self.summary.is_some(), context, request_counter).await?;
56     Ok(())
57   }
58
59   #[tracing::instrument(skip_all)]
60   async fn receive(
61     self,
62     context: &Data<LemmyContext>,
63     request_counter: &mut i32,
64   ) -> Result<(), LemmyError> {
65     if let Some(reason) = self.summary {
66       // We set reason to empty string if it doesn't exist, to distinguish between delete and
67       // remove. Here we change it back to option, so we don't write it to db.
68       let reason = if reason.is_empty() {
69         None
70       } else {
71         Some(reason)
72       };
73       receive_remove_action(
74         &self
75           .actor
76           .dereference(context, local_instance(context).await, request_counter)
77           .await?,
78         self.object.id(),
79         reason,
80         context,
81       )
82       .await
83     } else {
84       receive_delete_action(
85         self.object.id(),
86         &self.actor,
87         true,
88         context,
89         request_counter,
90       )
91       .await
92     }
93   }
94 }
95
96 impl Delete {
97   pub(in crate::activities::deletion) fn new(
98     actor: &ApubPerson,
99     object: DeletableObjects,
100     to: Url,
101     community: Option<&Community>,
102     summary: Option<String>,
103     context: &LemmyContext,
104   ) -> Result<Delete, LemmyError> {
105     let id = generate_activity_id(
106       DeleteType::Delete,
107       &context.settings().get_protocol_and_hostname(),
108     )?;
109     let cc: Option<Url> = community.map(|c| c.actor_id.clone().into());
110     Ok(Delete {
111       actor: ObjectId::new(actor.actor_id.clone()),
112       to: vec![to],
113       object: IdOrNestedObject::Id(object.id()),
114       cc: cc.into_iter().collect(),
115       kind: DeleteType::Delete,
116       summary,
117       id,
118       audience: community.map(|c| ObjectId::<ApubCommunity>::new(c.actor_id.clone())),
119     })
120   }
121 }
122
123 #[tracing::instrument(skip_all)]
124 pub(in crate::activities) async fn receive_remove_action(
125   actor: &ApubPerson,
126   object: &Url,
127   reason: Option<String>,
128   context: &LemmyContext,
129 ) -> Result<(), LemmyError> {
130   use UserOperationCrud::*;
131   match DeletableObjects::read_from_db(object, context).await? {
132     DeletableObjects::Community(community) => {
133       if community.local {
134         return Err(LemmyError::from_message(
135           "Only local admin can remove community",
136         ));
137       }
138       let form = ModRemoveCommunityForm {
139         mod_person_id: actor.id,
140         community_id: community.id,
141         removed: Some(true),
142         reason,
143         expires: None,
144       };
145       ModRemoveCommunity::create(context.pool(), &form).await?;
146       let deleted_community = Community::update(
147         context.pool(),
148         community.id,
149         &CommunityUpdateForm::builder().removed(Some(true)).build(),
150       )
151       .await?;
152
153       send_community_ws_message(deleted_community.id, RemoveCommunity, None, None, context).await?;
154     }
155     DeletableObjects::Post(post) => {
156       let form = ModRemovePostForm {
157         mod_person_id: actor.id,
158         post_id: post.id,
159         removed: Some(true),
160         reason,
161       };
162       ModRemovePost::create(context.pool(), &form).await?;
163       let removed_post = Post::update(
164         context.pool(),
165         post.id,
166         &PostUpdateForm::builder().removed(Some(true)).build(),
167       )
168       .await?;
169
170       send_post_ws_message(removed_post.id, RemovePost, None, None, context).await?;
171     }
172     DeletableObjects::Comment(comment) => {
173       let form = ModRemoveCommentForm {
174         mod_person_id: actor.id,
175         comment_id: comment.id,
176         removed: Some(true),
177         reason,
178       };
179       ModRemoveComment::create(context.pool(), &form).await?;
180       let removed_comment = Comment::update(
181         context.pool(),
182         comment.id,
183         &CommentUpdateForm::builder().removed(Some(true)).build(),
184       )
185       .await?;
186
187       send_comment_ws_message_simple(removed_comment.id, RemoveComment, context).await?;
188     }
189     DeletableObjects::PrivateMessage(_) => unimplemented!(),
190   }
191   Ok(())
192 }