]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/community/announce.rs
3e1e20418480d4de81caab542b64956a3a438ce3
[lemmy.git] / crates / apub / src / activities / community / announce.rs
1 use crate::{
2   activities::{generate_activity_id, send_lemmy_activity, verify_activity, verify_is_public},
3   activity_lists::AnnouncableActivities,
4   http::ActivityCommonFields,
5   insert_activity,
6   objects::community::ApubCommunity,
7   protocol::activities::{community::announce::AnnounceActivity, CreateOrUpdateType},
8 };
9 use activitystreams_kinds::{activity::AnnounceType, public};
10 use lemmy_apub_lib::{
11   data::Data,
12   object_id::ObjectId,
13   traits::{ActivityHandler, ActorType},
14 };
15 use lemmy_utils::LemmyError;
16 use lemmy_websocket::LemmyContext;
17 use tracing::info;
18
19 #[async_trait::async_trait(?Send)]
20 pub(crate) trait GetCommunity {
21   async fn get_community(
22     &self,
23     context: &LemmyContext,
24     request_counter: &mut i32,
25   ) -> Result<ApubCommunity, LemmyError>;
26 }
27
28 impl AnnounceActivity {
29   pub(crate) fn new(
30     object: AnnouncableActivities,
31     community: &ApubCommunity,
32     context: &LemmyContext,
33   ) -> Result<AnnounceActivity, LemmyError> {
34     Ok(AnnounceActivity {
35       actor: ObjectId::new(community.actor_id()),
36       to: vec![public()],
37       object,
38       cc: vec![community.followers_url.clone().into()],
39       kind: AnnounceType::Announce,
40       id: generate_activity_id(
41         &AnnounceType::Announce,
42         &context.settings().get_protocol_and_hostname(),
43       )?,
44       unparsed: Default::default(),
45     })
46   }
47
48   #[tracing::instrument(skip_all)]
49   pub async fn send(
50     object: AnnouncableActivities,
51     community: &ApubCommunity,
52     context: &LemmyContext,
53   ) -> Result<(), LemmyError> {
54     let announce = AnnounceActivity::new(object.clone(), community, context)?;
55     // temporary hack to get activity id of object
56     let object_fields: ActivityCommonFields =
57       serde_json::from_value(serde_json::to_value(&object)?)?;
58     info!(
59       "Announcing activity {} as {}",
60       object_fields.id, announce.id
61     );
62
63     let inboxes = community.get_follower_inboxes(context).await?;
64     send_lemmy_activity(
65       context,
66       &announce,
67       &announce.id,
68       community,
69       inboxes.clone(),
70       false,
71     )
72     .await?;
73
74     // Pleroma and Mastodon can't handle activities like Announce/Create/Page. So for
75     // compatibility, we also send Announce/Page so that they can follow Lemmy communities.
76     use AnnouncableActivities::*;
77     let object = match object {
78       CreateOrUpdatePost(c) if c.kind == CreateOrUpdateType::Create => Page(c.object),
79       _ => return Ok(()),
80     };
81     let announce_compat = AnnounceActivity::new(object, community, context)?;
82     send_lemmy_activity(
83       context,
84       &announce_compat,
85       &announce_compat.id,
86       community,
87       inboxes,
88       false,
89     )
90     .await?;
91     Ok(())
92   }
93 }
94
95 #[async_trait::async_trait(?Send)]
96 impl ActivityHandler for AnnounceActivity {
97   type DataType = LemmyContext;
98
99   #[tracing::instrument(skip_all)]
100   async fn verify(
101     &self,
102     context: &Data<LemmyContext>,
103     request_counter: &mut i32,
104   ) -> Result<(), LemmyError> {
105     verify_is_public(&self.to, &self.cc)?;
106     verify_activity(&self.id, self.actor.inner(), &context.settings())?;
107     self.object.verify(context, request_counter).await?;
108     Ok(())
109   }
110
111   #[tracing::instrument(skip_all)]
112   async fn receive(
113     self,
114     context: &Data<LemmyContext>,
115     request_counter: &mut i32,
116   ) -> Result<(), LemmyError> {
117     // TODO: this can probably be implemented in a cleaner way
118     match self.object {
119       // Dont insert these into activities table, as they are not activities.
120       AnnouncableActivities::Page(_) => {}
121       _ => {
122         let object_value = serde_json::to_value(&self.object)?;
123         let object_data: ActivityCommonFields = serde_json::from_value(object_value.to_owned())?;
124
125         insert_activity(&object_data.id, object_value, false, true, context.pool()).await?;
126       }
127     }
128     self.object.receive(context, request_counter).await
129   }
130 }