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