]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/community/announce.rs
Move @context out of object/activity definitions
[lemmy.git] / crates / apub / src / activities / community / announce.rs
1 use crate::{
2   activities::{
3     comment::create_or_update::CreateOrUpdateComment,
4     community::{
5       add_mod::AddMod,
6       block_user::BlockUserFromCommunity,
7       list_community_follower_inboxes,
8       remove_mod::RemoveMod,
9       undo_block_user::UndoBlockUserFromCommunity,
10       update::UpdateCommunity,
11     },
12     deletion::{delete::Delete, undo_delete::UndoDelete},
13     generate_activity_id,
14     post::create_or_update::CreateOrUpdatePost,
15     send_lemmy_activity,
16     verify_activity,
17     verify_is_public,
18     voting::{undo_vote::UndoVote, vote::Vote},
19   },
20   fetcher::object_id::ObjectId,
21   http::is_activity_already_known,
22   insert_activity,
23   objects::community::ApubCommunity,
24 };
25 use activitystreams::{activity::kind::AnnounceType, public, unparsed::Unparsed};
26 use lemmy_apub_lib::{
27   data::Data,
28   traits::{ActivityFields, ActivityHandler, ActorType},
29   verify::verify_urls_match,
30 };
31 use lemmy_utils::LemmyError;
32 use lemmy_websocket::LemmyContext;
33 use serde::{Deserialize, Serialize};
34 use url::Url;
35
36 #[derive(Clone, Debug, Deserialize, Serialize, ActivityHandler, ActivityFields)]
37 #[serde(untagged)]
38 #[activity_handler(LemmyContext)]
39 pub enum AnnouncableActivities {
40   CreateOrUpdateComment(CreateOrUpdateComment),
41   CreateOrUpdatePost(Box<CreateOrUpdatePost>),
42   Vote(Vote),
43   UndoVote(UndoVote),
44   Delete(Delete),
45   UndoDelete(UndoDelete),
46   UpdateCommunity(Box<UpdateCommunity>),
47   BlockUserFromCommunity(BlockUserFromCommunity),
48   UndoBlockUserFromCommunity(UndoBlockUserFromCommunity),
49   AddMod(AddMod),
50   RemoveMod(RemoveMod),
51 }
52
53 #[async_trait::async_trait(?Send)]
54 pub(crate) trait GetCommunity {
55   async fn get_community(
56     &self,
57     context: &LemmyContext,
58     request_counter: &mut i32,
59   ) -> Result<ApubCommunity, LemmyError>;
60 }
61
62 #[async_trait::async_trait(?Send)]
63 impl GetCommunity for AnnouncableActivities {
64   async fn get_community(
65     &self,
66     context: &LemmyContext,
67     request_counter: &mut i32,
68   ) -> Result<ApubCommunity, LemmyError> {
69     use AnnouncableActivities::*;
70     let community = match self {
71       CreateOrUpdateComment(a) => a.get_community(context, request_counter).await?,
72       CreateOrUpdatePost(a) => a.get_community(context, request_counter).await?,
73       Vote(a) => a.get_community(context, request_counter).await?,
74       UndoVote(a) => a.get_community(context, request_counter).await?,
75       Delete(a) => a.get_community(context, request_counter).await?,
76       UndoDelete(a) => a.get_community(context, request_counter).await?,
77       UpdateCommunity(a) => a.get_community(context, request_counter).await?,
78       BlockUserFromCommunity(a) => a.get_community(context, request_counter).await?,
79       UndoBlockUserFromCommunity(a) => a.get_community(context, request_counter).await?,
80       AddMod(a) => a.get_community(context, request_counter).await?,
81       RemoveMod(a) => a.get_community(context, request_counter).await?,
82     };
83     verify_urls_match(self.actor(), &community.actor_id())?;
84     Ok(community)
85   }
86 }
87
88 #[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
89 #[serde(rename_all = "camelCase")]
90 pub struct AnnounceActivity {
91   actor: ObjectId<ApubCommunity>,
92   to: Vec<Url>,
93   object: AnnouncableActivities,
94   cc: Vec<Url>,
95   #[serde(rename = "type")]
96   kind: AnnounceType,
97   id: Url,
98   #[serde(flatten)]
99   unparsed: Unparsed,
100 }
101
102 impl AnnounceActivity {
103   pub async fn send(
104     object: AnnouncableActivities,
105     community: &ApubCommunity,
106     additional_inboxes: Vec<Url>,
107     context: &LemmyContext,
108   ) -> Result<(), LemmyError> {
109     let announce = AnnounceActivity {
110       actor: ObjectId::new(community.actor_id()),
111       to: vec![public()],
112       object,
113       cc: vec![community.followers_url.clone().into_inner()],
114       kind: AnnounceType::Announce,
115       id: generate_activity_id(
116         &AnnounceType::Announce,
117         &context.settings().get_protocol_and_hostname(),
118       )?,
119       unparsed: Default::default(),
120     };
121     let inboxes = list_community_follower_inboxes(community, additional_inboxes, context).await?;
122     send_lemmy_activity(context, &announce, &announce.id, community, inboxes, false).await
123   }
124 }
125
126 #[async_trait::async_trait(?Send)]
127 impl ActivityHandler for AnnounceActivity {
128   type DataType = LemmyContext;
129   async fn verify(
130     &self,
131     context: &Data<LemmyContext>,
132     request_counter: &mut i32,
133   ) -> Result<(), LemmyError> {
134     verify_is_public(&self.to)?;
135     verify_activity(self, &context.settings())?;
136     self.object.verify(context, request_counter).await?;
137     Ok(())
138   }
139
140   async fn receive(
141     self,
142     context: &Data<LemmyContext>,
143     request_counter: &mut i32,
144   ) -> Result<(), LemmyError> {
145     if is_activity_already_known(context.pool(), self.object.id_unchecked()).await? {
146       return Ok(());
147     }
148     insert_activity(
149       self.object.id_unchecked(),
150       self.object.clone(),
151       false,
152       true,
153       context.pool(),
154     )
155     .await?;
156     self.object.receive(context, request_counter).await
157   }
158 }