]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/deletion/undo_delete.rs
Change activity.cc to Vec<Url> in public activities
[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: Vec<Url>,
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     let community = self.get_community(context, request_counter).await?;
73     verify_delete_activity(
74       &self.object.object,
75       self,
76       &community,
77       self.object.summary.is_some(),
78       context,
79       request_counter,
80     )
81     .await?;
82     Ok(())
83   }
84
85   async fn receive(
86     self,
87     context: &Data<LemmyContext>,
88     request_counter: &mut i32,
89   ) -> Result<(), LemmyError> {
90     if self.object.summary.is_some() {
91       UndoDelete::receive_undo_remove_action(&self.object.object, context).await
92     } else {
93       receive_delete_action(
94         &self.object.object,
95         &self.actor,
96         WebsocketMessages {
97           community: UserOperationCrud::EditCommunity,
98           post: UserOperationCrud::EditPost,
99           comment: UserOperationCrud::EditComment,
100         },
101         false,
102         context,
103         request_counter,
104       )
105       .await
106     }
107   }
108 }
109
110 impl UndoDelete {
111   pub(in crate::activities::deletion) async fn send(
112     actor: &ApubPerson,
113     community: &ApubCommunity,
114     object_id: Url,
115     summary: Option<String>,
116     context: &LemmyContext,
117   ) -> Result<(), LemmyError> {
118     let object = Delete::new(actor, community, object_id, summary, context)?;
119
120     let id = generate_activity_id(
121       UndoType::Undo,
122       &context.settings().get_protocol_and_hostname(),
123     )?;
124     let undo = UndoDelete {
125       actor: ObjectId::new(actor.actor_id()),
126       to: vec![public()],
127       object,
128       cc: vec![community.actor_id()],
129       kind: UndoType::Undo,
130       id: id.clone(),
131       context: lemmy_context(),
132       unparsed: Default::default(),
133     };
134
135     let activity = AnnouncableActivities::UndoDelete(undo);
136     send_to_community(activity, &id, actor, community, vec![], context).await
137   }
138
139   pub(in crate::activities) async fn receive_undo_remove_action(
140     object: &Url,
141     context: &LemmyContext,
142   ) -> Result<(), LemmyError> {
143     use UserOperationCrud::*;
144     match DeletableObjects::read_from_db(object, context).await? {
145       DeletableObjects::Community(community) => {
146         if community.local {
147           return Err(anyhow!("Only local admin can restore community").into());
148         }
149         let deleted_community = blocking(context.pool(), move |conn| {
150           Community::update_removed(conn, community.id, false)
151         })
152         .await??;
153         send_community_ws_message(deleted_community.id, EditCommunity, None, None, context).await?;
154       }
155       DeletableObjects::Post(post) => {
156         let removed_post = blocking(context.pool(), move |conn| {
157           Post::update_removed(conn, post.id, false)
158         })
159         .await??;
160         send_post_ws_message(removed_post.id, EditPost, None, None, context).await?;
161       }
162       DeletableObjects::Comment(comment) => {
163         let removed_comment = blocking(context.pool(), move |conn| {
164           Comment::update_removed(conn, comment.id, false)
165         })
166         .await??;
167         send_comment_ws_message_simple(removed_comment.id, EditComment, context).await?;
168       }
169     }
170     Ok(())
171   }
172 }
173
174 #[async_trait::async_trait(?Send)]
175 impl GetCommunity for UndoDelete {
176   async fn get_community(
177     &self,
178     context: &LemmyContext,
179     request_counter: &mut i32,
180   ) -> Result<ApubCommunity, LemmyError> {
181     self.object.get_community(context, request_counter).await
182   }
183 }