]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/deletion/undo_delete.rs
Make verify apub url function async (#2514)
[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, CommentUpdateForm},
17     community::{Community, CommunityUpdateForm},
18     moderator::{
19       ModRemoveComment,
20       ModRemoveCommentForm,
21       ModRemoveCommunity,
22       ModRemoveCommunityForm,
23       ModRemovePost,
24       ModRemovePostForm,
25     },
26     post::{Post, PostUpdateForm},
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(
152             conn,
153             community.id,
154             &CommunityUpdateForm::builder().removed(Some(false)).build(),
155           )
156         })
157         .await??;
158         send_community_ws_message(deleted_community.id, EditCommunity, None, None, context).await?;
159       }
160       DeletableObjects::Post(post) => {
161         let form = ModRemovePostForm {
162           mod_person_id: actor.id,
163           post_id: post.id,
164           removed: Some(false),
165           reason: None,
166         };
167         blocking(context.pool(), move |conn| {
168           ModRemovePost::create(conn, &form)
169         })
170         .await??;
171         let removed_post = blocking(context.pool(), move |conn| {
172           Post::update(
173             conn,
174             post.id,
175             &PostUpdateForm::builder().removed(Some(false)).build(),
176           )
177         })
178         .await??;
179         send_post_ws_message(removed_post.id, EditPost, None, None, context).await?;
180       }
181       DeletableObjects::Comment(comment) => {
182         let form = ModRemoveCommentForm {
183           mod_person_id: actor.id,
184           comment_id: comment.id,
185           removed: Some(false),
186           reason: None,
187         };
188         blocking(context.pool(), move |conn| {
189           ModRemoveComment::create(conn, &form)
190         })
191         .await??;
192         let removed_comment = blocking(context.pool(), move |conn| {
193           Comment::update(
194             conn,
195             comment.id,
196             &CommentUpdateForm::builder().removed(Some(false)).build(),
197           )
198         })
199         .await??;
200         send_comment_ws_message_simple(removed_comment.id, EditComment, context).await?;
201       }
202       DeletableObjects::PrivateMessage(_) => unimplemented!(),
203     }
204     Ok(())
205   }
206 }
207
208 #[async_trait::async_trait(?Send)]
209 impl GetCommunity for UndoDelete {
210   #[tracing::instrument(skip_all)]
211   async fn get_community(
212     &self,
213     context: &LemmyContext,
214     request_counter: &mut i32,
215   ) -> Result<ApubCommunity, LemmyError> {
216     self.object.get_community(context, request_counter).await
217   }
218 }