]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/deletion/delete.rs
Move ObjectId to library
[lemmy.git] / crates / apub / src / activities / deletion / delete.rs
1 use crate::{
2   activities::{
3     community::{announce::GetCommunity, send_to_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::{activity::kind::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,
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(&self.actor, &self.object, reason, context, request_counter).await
82     } else {
83       receive_delete_action(&self.object, &self.actor, true, context, request_counter).await
84     }
85   }
86 }
87
88 impl Delete {
89   pub(in crate::activities::deletion) fn new(
90     actor: &ApubPerson,
91     community: &ApubCommunity,
92     object_id: Url,
93     summary: Option<String>,
94     context: &LemmyContext,
95   ) -> Result<Delete, LemmyError> {
96     Ok(Delete {
97       actor: ObjectId::new(actor.actor_id()),
98       to: vec![public()],
99       object: object_id,
100       cc: vec![community.actor_id()],
101       kind: DeleteType::Delete,
102       summary,
103       id: generate_activity_id(
104         DeleteType::Delete,
105         &context.settings().get_protocol_and_hostname(),
106       )?,
107       unparsed: Default::default(),
108     })
109   }
110   pub(in crate::activities::deletion) async fn send(
111     actor: &ApubPerson,
112     community: &ApubCommunity,
113     object_id: Url,
114     summary: Option<String>,
115     context: &LemmyContext,
116   ) -> Result<(), LemmyError> {
117     let delete = Delete::new(actor, community, object_id, summary, context)?;
118     let delete_id = delete.id.clone();
119
120     let activity = AnnouncableActivities::Delete(delete);
121     send_to_community(activity, &delete_id, actor, community, vec![], context).await
122   }
123 }
124
125 pub(in crate::activities) async fn receive_remove_action(
126   actor: &ObjectId<ApubPerson>,
127   object: &Url,
128   reason: Option<String>,
129   context: &LemmyContext,
130   request_counter: &mut i32,
131 ) -> Result<(), LemmyError> {
132   let actor = actor.dereference(context, request_counter).await?;
133   use UserOperationCrud::*;
134   match DeletableObjects::read_from_db(object, context).await? {
135     DeletableObjects::Community(community) => {
136       if community.local {
137         return Err(anyhow!("Only local admin can remove community").into());
138       }
139       let form = ModRemoveCommunityForm {
140         mod_person_id: actor.id,
141         community_id: community.id,
142         removed: Some(true),
143         reason,
144         expires: None,
145       };
146       blocking(context.pool(), move |conn| {
147         ModRemoveCommunity::create(conn, &form)
148       })
149       .await??;
150       let deleted_community = blocking(context.pool(), move |conn| {
151         Community::update_removed(conn, community.id, true)
152       })
153       .await??;
154
155       send_community_ws_message(deleted_community.id, RemoveCommunity, None, None, context).await?;
156     }
157     DeletableObjects::Post(post) => {
158       let form = ModRemovePostForm {
159         mod_person_id: actor.id,
160         post_id: post.id,
161         removed: Some(true),
162         reason,
163       };
164       blocking(context.pool(), move |conn| {
165         ModRemovePost::create(conn, &form)
166       })
167       .await??;
168       let removed_post = blocking(context.pool(), move |conn| {
169         Post::update_removed(conn, post.id, true)
170       })
171       .await??;
172
173       send_post_ws_message(removed_post.id, RemovePost, None, None, context).await?;
174     }
175     DeletableObjects::Comment(comment) => {
176       let form = ModRemoveCommentForm {
177         mod_person_id: actor.id,
178         comment_id: comment.id,
179         removed: Some(true),
180         reason,
181       };
182       blocking(context.pool(), move |conn| {
183         ModRemoveComment::create(conn, &form)
184       })
185       .await??;
186       let removed_comment = blocking(context.pool(), move |conn| {
187         Comment::update_removed(conn, comment.id, true)
188       })
189       .await??;
190
191       send_comment_ws_message_simple(removed_comment.id, RemoveComment, context).await?;
192     }
193   }
194   Ok(())
195 }
196
197 #[async_trait::async_trait(?Send)]
198 impl GetCommunity for Delete {
199   async fn get_community(
200     &self,
201     context: &LemmyContext,
202     _request_counter: &mut i32,
203   ) -> Result<ApubCommunity, LemmyError> {
204     let community_id = match DeletableObjects::read_from_db(&self.object, context).await? {
205       DeletableObjects::Community(c) => c.id,
206       DeletableObjects::Comment(c) => {
207         let post = blocking(context.pool(), move |conn| Post::read(conn, c.post_id)).await??;
208         post.community_id
209       }
210       DeletableObjects::Post(p) => p.community_id,
211     };
212     let community = blocking(context.pool(), move |conn| {
213       Community::read(conn, community_id)
214     })
215     .await??;
216     Ok(community.into())
217   }
218 }