]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/community/announce.rs
Merge pull request #1903 from LemmyNet/fix_direct_string_apub_serialize_error
[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::{is_activity_already_known, ActivityCommonFields},
5   insert_activity,
6   objects::community::ApubCommunity,
7   protocol::activities::community::announce::AnnounceActivity,
8 };
9 use activitystreams::{activity::kind::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 url::Url;
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   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   pub async fn send(
49     object: AnnouncableActivities,
50     community: &ApubCommunity,
51     additional_inboxes: Vec<Url>,
52     context: &LemmyContext,
53   ) -> Result<(), LemmyError> {
54     let announce = AnnounceActivity::new(object.clone(), community, context)?;
55     let inboxes = community
56       .get_follower_inboxes(additional_inboxes.clone(), context)
57       .await?;
58     send_lemmy_activity(
59       context,
60       &announce,
61       &announce.id,
62       community,
63       inboxes.clone(),
64       false,
65     )
66     .await?;
67
68     // Pleroma (and likely Mastodon) can't handle activities like Announce/Create/Page, so for
69     // compatibility, we also send Announce/Page and Announce/Note (for new and updated
70     // posts/comments).
71     use AnnouncableActivities::*;
72     let object = match object {
73       CreateOrUpdatePost(c) => Page(c.object),
74       CreateOrUpdateComment(c) => Note(c.object),
75       _ => return Ok(()),
76     };
77     let announce_compat = AnnounceActivity::new(object, community, context)?;
78     send_lemmy_activity(
79       context,
80       &announce_compat,
81       &announce_compat.id,
82       community,
83       inboxes,
84       false,
85     )
86     .await?;
87     Ok(())
88   }
89 }
90
91 #[async_trait::async_trait(?Send)]
92 impl ActivityHandler for AnnounceActivity {
93   type DataType = LemmyContext;
94   async fn verify(
95     &self,
96     context: &Data<LemmyContext>,
97     request_counter: &mut i32,
98   ) -> Result<(), LemmyError> {
99     verify_is_public(&self.to, &self.cc)?;
100     verify_activity(&self.id, self.actor.inner(), &context.settings())?;
101     self.object.verify(context, request_counter).await?;
102     Ok(())
103   }
104
105   async fn receive(
106     self,
107     context: &Data<LemmyContext>,
108     request_counter: &mut i32,
109   ) -> Result<(), LemmyError> {
110     let object_value = serde_json::to_value(&self.object)?;
111     let object_data: ActivityCommonFields = serde_json::from_value(object_value.to_owned())?;
112
113     if is_activity_already_known(context.pool(), &object_data.id).await? {
114       return Ok(());
115     }
116     insert_activity(&object_data.id, object_value, false, true, context.pool()).await?;
117     self.object.receive(context, request_counter).await
118   }
119 }