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