2 activities::{generate_activity_id, send_lemmy_activity, verify_is_public},
3 activity_lists::AnnouncableActivities,
7 objects::community::ApubCommunity,
9 activities::{community::announce::AnnounceActivity, CreateOrUpdateType},
14 use activitypub_federation::{core::object_id::ObjectId, data::Data, traits::ActivityHandler};
15 use activitystreams_kinds::{activity::AnnounceType, public};
16 use lemmy_api_common::utils::blocking;
17 use lemmy_utils::error::LemmyError;
18 use lemmy_websocket::LemmyContext;
22 #[async_trait::async_trait(?Send)]
23 pub(crate) trait GetCommunity {
24 async fn get_community(
26 context: &LemmyContext,
27 request_counter: &mut i32,
28 ) -> Result<ApubCommunity, LemmyError>;
31 impl AnnounceActivity {
33 object: AnnouncableActivities,
34 community: &ApubCommunity,
35 context: &LemmyContext,
36 ) -> Result<AnnounceActivity, LemmyError> {
38 actor: ObjectId::new(community.actor_id()),
40 object: IdOrNestedObject::NestedObject(object),
41 cc: vec![community.followers_url.clone().into()],
42 kind: AnnounceType::Announce,
43 id: generate_activity_id(
44 &AnnounceType::Announce,
45 &context.settings().get_protocol_and_hostname(),
47 unparsed: Default::default(),
51 #[tracing::instrument(skip_all)]
53 object: AnnouncableActivities,
54 community: &ApubCommunity,
55 context: &LemmyContext,
56 ) -> Result<(), LemmyError> {
57 let announce = AnnounceActivity::new(object.clone(), community, context)?;
58 let inboxes = community.get_follower_inboxes(context).await?;
59 send_lemmy_activity(context, announce, community, inboxes.clone(), false).await?;
61 // Pleroma and Mastodon can't handle activities like Announce/Create/Page. So for
62 // compatibility, we also send Announce/Page so that they can follow Lemmy communities.
63 use AnnouncableActivities::*;
64 let object = match object {
65 CreateOrUpdatePost(c) if c.kind == CreateOrUpdateType::Create => Page(c.object),
68 let announce_compat = AnnounceActivity::new(object, community, context)?;
69 send_lemmy_activity(context, announce_compat, community, inboxes, false).await?;
74 #[async_trait::async_trait(?Send)]
75 impl ActivityHandler for AnnounceActivity {
76 type DataType = LemmyContext;
77 type Error = LemmyError;
79 fn id(&self) -> &Url {
83 fn actor(&self) -> &Url {
87 #[tracing::instrument(skip_all)]
90 context: &Data<LemmyContext>,
91 _request_counter: &mut i32,
92 ) -> Result<(), LemmyError> {
93 let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
94 check_apub_id_valid(self.id(), &local_site_data, context.settings())
95 .map_err(LemmyError::from_message)?;
97 verify_is_public(&self.to, &self.cc)?;
101 #[tracing::instrument(skip_all)]
104 context: &Data<LemmyContext>,
105 request_counter: &mut i32,
106 ) -> Result<(), LemmyError> {
107 let object = self.object.object(context, request_counter).await?;
108 // we have to verify this here in order to avoid fetching the object twice over http
109 object.verify(context, request_counter).await?;
111 // TODO: this can probably be implemented in a cleaner way
113 // Dont insert these into activities table, as they are not activities.
114 AnnouncableActivities::Page(_) => {}
116 let object_value = serde_json::to_value(&object)?;
118 insert_activity(object.id(), object_value, false, true, context.pool()).await?;
121 "Received duplicate activity in announce {}",
122 object.id().to_string()
128 object.receive(context, request_counter).await