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