]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/removal/undo_remove.rs
Fix changelog links
[lemmy.git] / crates / apub / src / activities / removal / undo_remove.rs
1 use crate::{
2   activities::{
3     comment::send_websocket_message as send_comment_message,
4     community::send_websocket_message as send_community_message,
5     post::send_websocket_message as send_post_message,
6     removal::remove::RemovePostCommentCommunityOrMod,
7     verify_activity,
8     verify_mod_action,
9     verify_person_in_community,
10   },
11   fetcher::{
12     community::get_or_fetch_and_upsert_community,
13     objects::get_or_fetch_and_insert_post_or_comment,
14   },
15   PostOrComment,
16 };
17 use activitystreams::activity::kind::UndoType;
18 use anyhow::anyhow;
19 use lemmy_api_common::blocking;
20 use lemmy_apub_lib::{ActivityCommonFields, ActivityHandler, PublicUrl};
21 use lemmy_db_queries::source::{comment::Comment_, community::Community_, post::Post_};
22 use lemmy_db_schema::source::{comment::Comment, community::Community, post::Post};
23 use lemmy_utils::LemmyError;
24 use lemmy_websocket::{LemmyContext, UserOperationCrud};
25 use url::Url;
26
27 #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
28 #[serde(rename_all = "camelCase")]
29 pub struct UndoRemovePostCommentOrCommunity {
30   to: PublicUrl,
31   object: RemovePostCommentCommunityOrMod,
32   cc: [Url; 1],
33   #[serde(rename = "type")]
34   kind: UndoType,
35   #[serde(flatten)]
36   common: ActivityCommonFields,
37 }
38
39 #[async_trait::async_trait(?Send)]
40 impl ActivityHandler for UndoRemovePostCommentOrCommunity {
41   async fn verify(
42     &self,
43     context: &LemmyContext,
44     request_counter: &mut i32,
45   ) -> Result<(), LemmyError> {
46     verify_activity(self.common())?;
47     let object_community =
48       get_or_fetch_and_upsert_community(&self.object.object, context, request_counter).await;
49     // removing a community
50     if object_community.is_ok() {
51       verify_mod_action(&self.common.actor, self.object.object.clone(), context).await?;
52     }
53     // removing a post or comment
54     else {
55       verify_person_in_community(&self.common.actor, &self.cc, context, request_counter).await?;
56       verify_mod_action(&self.common.actor, self.cc[0].clone(), context).await?;
57     }
58     self.object.verify(context, request_counter).await?;
59     // dont check that actor and object.actor are identical, so that one mod can
60     // undo the action of another
61     Ok(())
62   }
63
64   async fn receive(
65     &self,
66     context: &LemmyContext,
67     request_counter: &mut i32,
68   ) -> Result<(), LemmyError> {
69     let object_community =
70       get_or_fetch_and_upsert_community(&self.object.object, context, request_counter).await;
71     // restoring a community
72     if let Ok(community) = object_community {
73       if community.local {
74         return Err(anyhow!("Only local admin can undo remove community").into());
75       }
76       let deleted_community = blocking(context.pool(), move |conn| {
77         Community::update_removed(conn, community.id, false)
78       })
79       .await??;
80
81       send_community_message(
82         deleted_community.id,
83         UserOperationCrud::EditCommunity,
84         context,
85       )
86       .await
87     }
88     // restoring a post or comment
89     else {
90       match get_or_fetch_and_insert_post_or_comment(&self.object.object, context, request_counter)
91         .await?
92       {
93         PostOrComment::Post(post) => {
94           let removed_post = blocking(context.pool(), move |conn| {
95             Post::update_removed(conn, post.id, false)
96           })
97           .await??;
98           send_post_message(removed_post.id, UserOperationCrud::EditPost, context).await
99         }
100         PostOrComment::Comment(comment) => {
101           let removed_comment = blocking(context.pool(), move |conn| {
102             Comment::update_removed(conn, comment.id, false)
103           })
104           .await??;
105           send_comment_message(
106             removed_comment.id,
107             vec![],
108             UserOperationCrud::EditComment,
109             context,
110           )
111           .await
112         }
113       }
114     }
115   }
116
117   fn common(&self) -> &ActivityCommonFields {
118     &self.common
119   }
120 }