]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/community/announce.rs
Breaking apub changes (#1859)
[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     verify_activity,
16     verify_community,
17     voting::{undo_vote::UndoVote, vote::Vote},
18   },
19   context::lemmy_context,
20   fetcher::object_id::ObjectId,
21   http::is_activity_already_known,
22   insert_activity,
23   objects::community::ApubCommunity,
24   send_lemmy_activity,
25   CommunityType,
26 };
27 use activitystreams::{
28   activity::kind::AnnounceType,
29   base::AnyBase,
30   primitives::OneOrMany,
31   unparsed::Unparsed,
32 };
33 use lemmy_apub_lib::{
34   data::Data,
35   traits::{ActivityFields, ActivityHandler, ActorType},
36   values::PublicUrl,
37 };
38 use lemmy_utils::LemmyError;
39 use lemmy_websocket::LemmyContext;
40 use serde::{Deserialize, Serialize};
41 use url::Url;
42
43 #[derive(Clone, Debug, Deserialize, Serialize, ActivityHandler, ActivityFields)]
44 #[serde(untagged)]
45 #[activity_handler(LemmyContext)]
46 pub enum AnnouncableActivities {
47   CreateOrUpdateComment(CreateOrUpdateComment),
48   CreateOrUpdatePost(Box<CreateOrUpdatePost>),
49   Vote(Vote),
50   UndoVote(UndoVote),
51   Delete(Delete),
52   UndoDelete(UndoDelete),
53   UpdateCommunity(Box<UpdateCommunity>),
54   BlockUserFromCommunity(BlockUserFromCommunity),
55   UndoBlockUserFromCommunity(UndoBlockUserFromCommunity),
56   AddMod(AddMod),
57   RemoveMod(RemoveMod),
58 }
59
60 #[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
61 #[serde(rename_all = "camelCase")]
62 pub struct AnnounceActivity {
63   actor: ObjectId<ApubCommunity>,
64   to: [PublicUrl; 1],
65   object: AnnouncableActivities,
66   cc: Vec<Url>,
67   #[serde(rename = "type")]
68   kind: AnnounceType,
69   id: Url,
70   #[serde(rename = "@context")]
71   context: OneOrMany<AnyBase>,
72   #[serde(flatten)]
73   unparsed: Unparsed,
74 }
75
76 impl AnnounceActivity {
77   pub async fn send(
78     object: AnnouncableActivities,
79     community: &ApubCommunity,
80     additional_inboxes: Vec<Url>,
81     context: &LemmyContext,
82   ) -> Result<(), LemmyError> {
83     let announce = AnnounceActivity {
84       actor: ObjectId::new(community.actor_id()),
85       to: [PublicUrl::Public],
86       object,
87       cc: vec![community.followers_url()],
88       kind: AnnounceType::Announce,
89       id: generate_activity_id(
90         &AnnounceType::Announce,
91         &context.settings().get_protocol_and_hostname(),
92       )?,
93       context: lemmy_context(),
94       unparsed: Default::default(),
95     };
96     let inboxes = list_community_follower_inboxes(community, additional_inboxes, context).await?;
97     send_lemmy_activity(context, &announce, &announce.id, community, inboxes, false).await
98   }
99 }
100
101 #[async_trait::async_trait(?Send)]
102 impl ActivityHandler for AnnounceActivity {
103   type DataType = LemmyContext;
104   async fn verify(
105     &self,
106     context: &Data<LemmyContext>,
107     request_counter: &mut i32,
108   ) -> Result<(), LemmyError> {
109     verify_activity(self, &context.settings())?;
110     verify_community(&self.actor, context, request_counter).await?;
111     self.object.verify(context, request_counter).await?;
112     Ok(())
113   }
114
115   async fn receive(
116     self,
117     context: &Data<LemmyContext>,
118     request_counter: &mut i32,
119   ) -> Result<(), LemmyError> {
120     if is_activity_already_known(context.pool(), self.object.id_unchecked()).await? {
121       return Ok(());
122     }
123     insert_activity(
124       self.object.id_unchecked(),
125       self.object.clone(),
126       false,
127       true,
128       context.pool(),
129     )
130     .await?;
131     self.object.receive(context, request_counter).await
132   }
133 }