]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/deletion/undo_delete.rs
Rewrite delete activities (#1699)
[lemmy.git] / crates / apub / src / activities / deletion / undo_delete.rs
1 use crate::{
2   activities::{
3     community::announce::AnnouncableActivities,
4     deletion::{
5       delete::Delete,
6       receive_delete_action,
7       verify_delete_activity,
8       DeletableObjects,
9       WebsocketMessages,
10     },
11     generate_activity_id,
12     verify_activity,
13   },
14   activity_queue::send_to_community_new,
15   extensions::context::lemmy_context,
16   ActorType,
17 };
18 use activitystreams::activity::kind::{DeleteType, UndoType};
19 use anyhow::anyhow;
20 use lemmy_api_common::blocking;
21 use lemmy_apub_lib::{values::PublicUrl, ActivityCommonFields, ActivityHandler};
22 use lemmy_db_queries::source::{comment::Comment_, community::Community_, post::Post_};
23 use lemmy_db_schema::source::{comment::Comment, community::Community, person::Person, post::Post};
24 use lemmy_utils::LemmyError;
25 use lemmy_websocket::{
26   send::{send_comment_ws_message_simple, send_community_ws_message, send_post_ws_message},
27   LemmyContext,
28   UserOperationCrud,
29 };
30 use url::Url;
31
32 #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
33 #[serde(rename_all = "camelCase")]
34 pub struct UndoDelete {
35   to: PublicUrl,
36   object: Delete,
37   cc: [Url; 1],
38   #[serde(rename = "type")]
39   kind: UndoType,
40   #[serde(flatten)]
41   common: ActivityCommonFields,
42 }
43
44 #[async_trait::async_trait(?Send)]
45 impl ActivityHandler for UndoDelete {
46   async fn verify(
47     &self,
48     context: &LemmyContext,
49     request_counter: &mut i32,
50   ) -> Result<(), LemmyError> {
51     verify_activity(self.common())?;
52     self.object.verify(context, request_counter).await?;
53     verify_delete_activity(
54       &self.object.object,
55       &self.cc[0],
56       &self.common,
57       self.object.summary.is_some(),
58       context,
59       request_counter,
60     )
61     .await?;
62     Ok(())
63   }
64
65   async fn receive(
66     self,
67     context: &LemmyContext,
68     request_counter: &mut i32,
69   ) -> Result<(), LemmyError> {
70     if self.object.summary.is_some() {
71       UndoDelete::receive_undo_remove_action(&self.object.object, context).await
72     } else {
73       receive_delete_action(
74         &self.object.object,
75         &self.common.actor,
76         WebsocketMessages {
77           community: UserOperationCrud::EditCommunity,
78           post: UserOperationCrud::EditPost,
79           comment: UserOperationCrud::EditComment,
80         },
81         false,
82         context,
83         request_counter,
84       )
85       .await
86     }
87   }
88
89   fn common(&self) -> &ActivityCommonFields {
90     &self.common
91   }
92 }
93
94 impl UndoDelete {
95   pub(in crate::activities::deletion) async fn send(
96     actor: &Person,
97     community: &Community,
98     object_id: Url,
99     summary: Option<String>,
100     context: &LemmyContext,
101   ) -> Result<(), LemmyError> {
102     let delete = Delete {
103       to: PublicUrl::Public,
104       object: object_id,
105       cc: [community.actor_id()],
106       kind: DeleteType::Delete,
107       summary,
108       common: ActivityCommonFields {
109         context: lemmy_context(),
110         id: generate_activity_id(DeleteType::Delete)?,
111         actor: actor.actor_id(),
112         unparsed: Default::default(),
113       },
114     };
115
116     let id = generate_activity_id(UndoType::Undo)?;
117     let undo = UndoDelete {
118       to: PublicUrl::Public,
119       object: delete,
120       cc: [community.actor_id()],
121       kind: UndoType::Undo,
122       common: ActivityCommonFields {
123         context: lemmy_context(),
124         id: id.clone(),
125         actor: actor.actor_id(),
126         unparsed: Default::default(),
127       },
128     };
129
130     let activity = AnnouncableActivities::UndoDelete(undo);
131     send_to_community_new(activity, &id, actor, community, vec![], context).await
132   }
133
134   pub(in crate::activities) async fn receive_undo_remove_action(
135     object: &Url,
136     context: &LemmyContext,
137   ) -> Result<(), LemmyError> {
138     use UserOperationCrud::*;
139     match DeletableObjects::read_from_db(object, context).await? {
140       DeletableObjects::Community(community) => {
141         if community.local {
142           return Err(anyhow!("Only local admin can restore community").into());
143         }
144         let deleted_community = blocking(context.pool(), move |conn| {
145           Community::update_removed(conn, community.id, false)
146         })
147         .await??;
148         send_community_ws_message(deleted_community.id, EditCommunity, None, None, context).await?;
149       }
150       DeletableObjects::Post(post) => {
151         let removed_post = blocking(context.pool(), move |conn| {
152           Post::update_removed(conn, post.id, false)
153         })
154         .await??;
155         send_post_ws_message(removed_post.id, EditPost, None, None, context).await?;
156       }
157       DeletableObjects::Comment(comment) => {
158         let removed_comment = blocking(context.pool(), move |conn| {
159           Comment::update_removed(conn, comment.id, false)
160         })
161         .await??;
162         send_comment_ws_message_simple(removed_comment.id, EditComment, context).await?;
163       }
164     }
165     Ok(())
166   }
167 }