]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/deletion/delete.rs
Replace activitystreams crate with activitystreams-kinds
[lemmy.git] / crates / apub / src / activities / deletion / delete.rs
1 use crate::{
2   activities::{
3     community::{announce::GetCommunity, send_activity_in_community},
4     deletion::{receive_delete_action, verify_delete_activity, DeletableObjects},
5     generate_activity_id,
6     verify_activity,
7     verify_is_public,
8   },
9   activity_lists::AnnouncableActivities,
10   objects::{community::ApubCommunity, person::ApubPerson},
11   protocol::activities::deletion::delete::Delete,
12 };
13 use activitystreams_kinds::{activity::DeleteType, public};
14 use anyhow::anyhow;
15 use lemmy_api_common::blocking;
16 use lemmy_apub_lib::{
17   data::Data,
18   object_id::ObjectId,
19   traits::{ActivityHandler, ActorType},
20 };
21 use lemmy_db_schema::{
22   source::{
23     comment::Comment,
24     community::Community,
25     moderator::{
26       ModRemoveComment,
27       ModRemoveCommentForm,
28       ModRemoveCommunity,
29       ModRemoveCommunityForm,
30       ModRemovePost,
31       ModRemovePostForm,
32     },
33     post::Post,
34   },
35   traits::Crud,
36 };
37 use lemmy_utils::LemmyError;
38 use lemmy_websocket::{
39   send::{send_comment_ws_message_simple, send_community_ws_message, send_post_ws_message},
40   LemmyContext,
41   UserOperationCrud,
42 };
43 use url::Url;
44
45 #[async_trait::async_trait(?Send)]
46 impl ActivityHandler for Delete {
47   type DataType = LemmyContext;
48   async fn verify(
49     &self,
50     context: &Data<LemmyContext>,
51     request_counter: &mut i32,
52   ) -> Result<(), LemmyError> {
53     verify_is_public(&self.to, &[])?;
54     verify_activity(&self.id, self.actor.inner(), &context.settings())?;
55     let community = self.get_community(context, request_counter).await?;
56     verify_delete_activity(
57       &self.object.id,
58       &self.actor,
59       &community,
60       self.summary.is_some(),
61       context,
62       request_counter,
63     )
64     .await?;
65     Ok(())
66   }
67
68   async fn receive(
69     self,
70     context: &Data<LemmyContext>,
71     request_counter: &mut i32,
72   ) -> Result<(), LemmyError> {
73     if let Some(reason) = self.summary {
74       // We set reason to empty string if it doesn't exist, to distinguish between delete and
75       // remove. Here we change it back to option, so we don't write it to db.
76       let reason = if reason.is_empty() {
77         None
78       } else {
79         Some(reason)
80       };
81       receive_remove_action(
82         &self.actor,
83         &self.object.id,
84         reason,
85         context,
86         request_counter,
87       )
88       .await
89     } else {
90       receive_delete_action(&self.object.id, &self.actor, true, context, request_counter).await
91     }
92   }
93 }
94
95 impl Delete {
96   pub(in crate::activities::deletion) fn new(
97     actor: &ApubPerson,
98     object: DeletableObjects,
99     summary: Option<String>,
100     context: &LemmyContext,
101   ) -> Result<Delete, LemmyError> {
102     Ok(Delete {
103       actor: ObjectId::new(actor.actor_id()),
104       to: vec![public()],
105       object: object.to_tombstone()?,
106       kind: DeleteType::Delete,
107       summary,
108       id: generate_activity_id(
109         DeleteType::Delete,
110         &context.settings().get_protocol_and_hostname(),
111       )?,
112       unparsed: Default::default(),
113     })
114   }
115   pub(in crate::activities::deletion) async fn send(
116     actor: &ApubPerson,
117     community: &ApubCommunity,
118     object: DeletableObjects,
119     summary: Option<String>,
120     context: &LemmyContext,
121   ) -> Result<(), LemmyError> {
122     let delete = Delete::new(actor, object, summary, context)?;
123     let delete_id = delete.id.clone();
124
125     let activity = AnnouncableActivities::Delete(delete);
126     send_activity_in_community(activity, &delete_id, actor, community, vec![], context).await
127   }
128 }
129
130 pub(in crate::activities) async fn receive_remove_action(
131   actor: &ObjectId<ApubPerson>,
132   object: &Url,
133   reason: Option<String>,
134   context: &LemmyContext,
135   request_counter: &mut i32,
136 ) -> Result<(), LemmyError> {
137   let actor = actor.dereference(context, request_counter).await?;
138   use UserOperationCrud::*;
139   match DeletableObjects::read_from_db(object, context).await? {
140     DeletableObjects::Community(community) => {
141       if community.local {
142         return Err(anyhow!("Only local admin can remove community").into());
143       }
144       let form = ModRemoveCommunityForm {
145         mod_person_id: actor.id,
146         community_id: community.id,
147         removed: Some(true),
148         reason,
149         expires: None,
150       };
151       blocking(context.pool(), move |conn| {
152         ModRemoveCommunity::create(conn, &form)
153       })
154       .await??;
155       let deleted_community = blocking(context.pool(), move |conn| {
156         Community::update_removed(conn, community.id, true)
157       })
158       .await??;
159
160       send_community_ws_message(deleted_community.id, RemoveCommunity, None, None, context).await?;
161     }
162     DeletableObjects::Post(post) => {
163       let form = ModRemovePostForm {
164         mod_person_id: actor.id,
165         post_id: post.id,
166         removed: Some(true),
167         reason,
168       };
169       blocking(context.pool(), move |conn| {
170         ModRemovePost::create(conn, &form)
171       })
172       .await??;
173       let removed_post = blocking(context.pool(), move |conn| {
174         Post::update_removed(conn, post.id, true)
175       })
176       .await??;
177
178       send_post_ws_message(removed_post.id, RemovePost, None, None, context).await?;
179     }
180     DeletableObjects::Comment(comment) => {
181       let form = ModRemoveCommentForm {
182         mod_person_id: actor.id,
183         comment_id: comment.id,
184         removed: Some(true),
185         reason,
186       };
187       blocking(context.pool(), move |conn| {
188         ModRemoveComment::create(conn, &form)
189       })
190       .await??;
191       let removed_comment = blocking(context.pool(), move |conn| {
192         Comment::update_removed(conn, comment.id, true)
193       })
194       .await??;
195
196       send_comment_ws_message_simple(removed_comment.id, RemoveComment, context).await?;
197     }
198   }
199   Ok(())
200 }
201
202 #[async_trait::async_trait(?Send)]
203 impl GetCommunity for Delete {
204   async fn get_community(
205     &self,
206     context: &LemmyContext,
207     _request_counter: &mut i32,
208   ) -> Result<ApubCommunity, LemmyError> {
209     let community_id = match DeletableObjects::read_from_db(&self.object.id, context).await? {
210       DeletableObjects::Community(c) => c.id,
211       DeletableObjects::Comment(c) => {
212         let post = blocking(context.pool(), move |conn| Post::read(conn, c.post_id)).await??;
213         post.community_id
214       }
215       DeletableObjects::Post(p) => p.community_id,
216     };
217     let community = blocking(context.pool(), move |conn| {
218       Community::read(conn, community_id)
219     })
220     .await??;
221     Ok(community.into())
222   }
223 }