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