]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/deletion/undo_delete.rs
Activitypub crate rewrite (#2782)
[lemmy.git] / crates / apub / src / activities / deletion / undo_delete.rs
1 use crate::{
2   activities::{
3     deletion::{receive_delete_action, verify_delete_activity, DeletableObjects},
4     generate_activity_id,
5   },
6   insert_activity,
7   objects::person::ApubPerson,
8   protocol::activities::deletion::{delete::Delete, undo_delete::UndoDelete},
9 };
10 use activitypub_federation::{config::Data, kinds::activity::UndoType, traits::ActivityHandler};
11 use lemmy_api_common::{
12   context::LemmyContext,
13   websocket::{
14     send::{send_comment_ws_message_simple, send_community_ws_message, send_post_ws_message},
15     UserOperationCrud,
16   },
17 };
18 use lemmy_db_schema::{
19   source::{
20     comment::{Comment, CommentUpdateForm},
21     community::{Community, CommunityUpdateForm},
22     moderator::{
23       ModRemoveComment,
24       ModRemoveCommentForm,
25       ModRemoveCommunity,
26       ModRemoveCommunityForm,
27       ModRemovePost,
28       ModRemovePostForm,
29     },
30     post::{Post, PostUpdateForm},
31   },
32   traits::Crud,
33 };
34 use lemmy_utils::error::LemmyError;
35 use url::Url;
36
37 #[async_trait::async_trait]
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   async fn verify(&self, data: &Data<Self::DataType>) -> Result<(), Self::Error> {
51     self.object.verify(data).await?;
52     verify_delete_activity(&self.object, self.object.summary.is_some(), data).await?;
53     Ok(())
54   }
55
56   #[tracing::instrument(skip_all)]
57   async fn receive(self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
58     insert_activity(&self.id, &self, false, false, context).await?;
59     if self.object.summary.is_some() {
60       UndoDelete::receive_undo_remove_action(
61         &self.actor.dereference(context).await?,
62         self.object.object.id(),
63         context,
64       )
65       .await
66     } else {
67       receive_delete_action(self.object.object.id(), &self.actor, false, context).await
68     }
69   }
70 }
71
72 impl UndoDelete {
73   #[tracing::instrument(skip_all)]
74   pub(in crate::activities::deletion) fn new(
75     actor: &ApubPerson,
76     object: DeletableObjects,
77     to: Url,
78     community: Option<&Community>,
79     summary: Option<String>,
80     context: &Data<LemmyContext>,
81   ) -> Result<UndoDelete, LemmyError> {
82     let object = Delete::new(actor, object, to.clone(), community, summary, context)?;
83
84     let id = generate_activity_id(
85       UndoType::Undo,
86       &context.settings().get_protocol_and_hostname(),
87     )?;
88     let cc: Option<Url> = community.map(|c| c.actor_id.clone().into());
89     Ok(UndoDelete {
90       actor: actor.actor_id.clone().into(),
91       to: vec![to],
92       object,
93       cc: cc.into_iter().collect(),
94       kind: UndoType::Undo,
95       id,
96       audience: community.map(|c| c.actor_id.clone().into()),
97     })
98   }
99
100   #[tracing::instrument(skip_all)]
101   pub(in crate::activities) async fn receive_undo_remove_action(
102     actor: &ApubPerson,
103     object: &Url,
104     context: &Data<LemmyContext>,
105   ) -> Result<(), LemmyError> {
106     use UserOperationCrud::*;
107     match DeletableObjects::read_from_db(object, context).await? {
108       DeletableObjects::Community(community) => {
109         if community.local {
110           return Err(LemmyError::from_message(
111             "Only local admin can restore community",
112           ));
113         }
114         let form = ModRemoveCommunityForm {
115           mod_person_id: actor.id,
116           community_id: community.id,
117           removed: Some(false),
118           reason: None,
119           expires: None,
120         };
121         ModRemoveCommunity::create(context.pool(), &form).await?;
122         let deleted_community = Community::update(
123           context.pool(),
124           community.id,
125           &CommunityUpdateForm::builder().removed(Some(false)).build(),
126         )
127         .await?;
128         send_community_ws_message(deleted_community.id, EditCommunity, None, None, context).await?;
129       }
130       DeletableObjects::Post(post) => {
131         let form = ModRemovePostForm {
132           mod_person_id: actor.id,
133           post_id: post.id,
134           removed: Some(false),
135           reason: None,
136         };
137         ModRemovePost::create(context.pool(), &form).await?;
138         let removed_post = Post::update(
139           context.pool(),
140           post.id,
141           &PostUpdateForm::builder().removed(Some(false)).build(),
142         )
143         .await?;
144         send_post_ws_message(removed_post.id, EditPost, None, None, context).await?;
145       }
146       DeletableObjects::Comment(comment) => {
147         let form = ModRemoveCommentForm {
148           mod_person_id: actor.id,
149           comment_id: comment.id,
150           removed: Some(false),
151           reason: None,
152         };
153         ModRemoveComment::create(context.pool(), &form).await?;
154         let removed_comment = Comment::update(
155           context.pool(),
156           comment.id,
157           &CommentUpdateForm::builder().removed(Some(false)).build(),
158         )
159         .await?;
160         send_comment_ws_message_simple(removed_comment.id, EditComment, context).await?;
161       }
162       DeletableObjects::PrivateMessage(_) => unimplemented!(),
163     }
164     Ok(())
165   }
166 }