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