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