]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/deletion/undo_delete.rs
Upgrade activitypub_federation to 0.2.0, add setting federation.debug (#2300)
[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_api_common::utils::blocking;
14 use lemmy_db_schema::{
15   source::{
16     comment::Comment,
17     community::Community,
18     moderator::{
19       ModRemoveComment,
20       ModRemoveCommentForm,
21       ModRemoveCommunity,
22       ModRemoveCommunityForm,
23       ModRemovePost,
24       ModRemovePostForm,
25     },
26     post::Post,
27   },
28   traits::Crud,
29 };
30 use lemmy_utils::error::LemmyError;
31 use lemmy_websocket::{
32   send::{send_comment_ws_message_simple, send_community_ws_message, send_post_ws_message},
33   LemmyContext,
34   UserOperationCrud,
35 };
36 use url::Url;
37
38 #[async_trait::async_trait(?Send)]
39 impl ActivityHandler for UndoDelete {
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     self.object.verify(context, request_counter).await?;
58     verify_delete_activity(
59       &self.object,
60       self.object.summary.is_some(),
61       context,
62       request_counter,
63     )
64     .await?;
65     Ok(())
66   }
67
68   #[tracing::instrument(skip_all)]
69   async fn receive(
70     self,
71     context: &Data<LemmyContext>,
72     request_counter: &mut i32,
73   ) -> Result<(), LemmyError> {
74     if self.object.summary.is_some() {
75       UndoDelete::receive_undo_remove_action(
76         &self
77           .actor
78           .dereference(context, local_instance(context), request_counter)
79           .await?,
80         self.object.object.id(),
81         context,
82       )
83       .await
84     } else {
85       receive_delete_action(
86         self.object.object.id(),
87         &self.actor,
88         false,
89         context,
90         request_counter,
91       )
92       .await
93     }
94   }
95 }
96
97 impl UndoDelete {
98   #[tracing::instrument(skip_all)]
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<UndoDelete, LemmyError> {
107     let object = Delete::new(actor, object, to.clone(), community, summary, context)?;
108
109     let id = generate_activity_id(
110       UndoType::Undo,
111       &context.settings().get_protocol_and_hostname(),
112     )?;
113     let cc: Option<Url> = community.map(|c| c.actor_id.clone().into());
114     Ok(UndoDelete {
115       actor: ObjectId::new(actor.actor_id.clone()),
116       to: vec![to],
117       object,
118       cc: cc.into_iter().collect(),
119       kind: UndoType::Undo,
120       id,
121       unparsed: Default::default(),
122     })
123   }
124
125   #[tracing::instrument(skip_all)]
126   pub(in crate::activities) async fn receive_undo_remove_action(
127     actor: &ApubPerson,
128     object: &Url,
129     context: &LemmyContext,
130   ) -> Result<(), LemmyError> {
131     use UserOperationCrud::*;
132     match DeletableObjects::read_from_db(object, context).await? {
133       DeletableObjects::Community(community) => {
134         if community.local {
135           return Err(LemmyError::from_message(
136             "Only local admin can restore community",
137           ));
138         }
139         let form = ModRemoveCommunityForm {
140           mod_person_id: actor.id,
141           community_id: community.id,
142           removed: Some(false),
143           reason: None,
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, false)
152         })
153         .await??;
154         send_community_ws_message(deleted_community.id, EditCommunity, None, None, context).await?;
155       }
156       DeletableObjects::Post(post) => {
157         let form = ModRemovePostForm {
158           mod_person_id: actor.id,
159           post_id: post.id,
160           removed: Some(false),
161           reason: None,
162         };
163         blocking(context.pool(), move |conn| {
164           ModRemovePost::create(conn, &form)
165         })
166         .await??;
167         let removed_post = blocking(context.pool(), move |conn| {
168           Post::update_removed(conn, post.id, false)
169         })
170         .await??;
171         send_post_ws_message(removed_post.id, EditPost, None, None, context).await?;
172       }
173       DeletableObjects::Comment(comment) => {
174         let form = ModRemoveCommentForm {
175           mod_person_id: actor.id,
176           comment_id: comment.id,
177           removed: Some(false),
178           reason: None,
179         };
180         blocking(context.pool(), move |conn| {
181           ModRemoveComment::create(conn, &form)
182         })
183         .await??;
184         let removed_comment = blocking(context.pool(), move |conn| {
185           Comment::update_removed(conn, comment.id, false)
186         })
187         .await??;
188         send_comment_ws_message_simple(removed_comment.id, EditComment, context).await?;
189       }
190       DeletableObjects::PrivateMessage(_) => unimplemented!(),
191     }
192     Ok(())
193   }
194 }
195
196 #[async_trait::async_trait(?Send)]
197 impl GetCommunity for UndoDelete {
198   #[tracing::instrument(skip_all)]
199   async fn get_community(
200     &self,
201     context: &LemmyContext,
202     request_counter: &mut i32,
203   ) -> Result<ApubCommunity, LemmyError> {
204     self.object.get_community(context, request_counter).await
205   }
206 }