6 verify_person_in_community,
8 activity_lists::AnnouncableActivities,
10 objects::community::ApubCommunity,
12 activities::community::announce::{AnnounceActivity, RawAnnouncableActivities},
19 use activitypub_federation::{core::object_id::ObjectId, data::Data, traits::ActivityHandler};
20 use activitystreams_kinds::{activity::AnnounceType, public};
21 use lemmy_api_common::context::LemmyContext;
22 use lemmy_utils::error::LemmyError;
23 use serde_json::Value;
27 #[async_trait::async_trait(?Send)]
28 impl ActivityHandler for RawAnnouncableActivities {
29 type DataType = LemmyContext;
30 type Error = LemmyError;
32 fn id(&self) -> &Url {
36 fn actor(&self) -> &Url {
40 #[tracing::instrument(skip_all)]
43 _data: &Data<Self::DataType>,
44 _request_counter: &mut i32,
45 ) -> Result<(), Self::Error> {
49 #[tracing::instrument(skip_all)]
52 data: &Data<Self::DataType>,
53 request_counter: &mut i32,
54 ) -> Result<(), Self::Error> {
55 let activity: AnnouncableActivities = self.clone().try_into()?;
56 // This is only for sending, not receiving so we reject it.
57 if let AnnouncableActivities::Page(_) = activity {
58 return Err(LemmyError::from_message("Cant receive page"));
60 let community = activity.community(data, &mut 0).await?;
61 let actor_id = ObjectId::new(activity.actor().clone());
63 // verify and receive activity
64 activity.verify(data, request_counter).await?;
65 activity.receive(data, request_counter).await?;
67 // send to community followers
69 verify_person_in_community(&actor_id, &community, data, &mut 0).await?;
70 AnnounceActivity::send(self, &community, data).await?;
76 impl AnnounceActivity {
78 object: RawAnnouncableActivities,
79 community: &ApubCommunity,
80 context: &LemmyContext,
81 ) -> Result<AnnounceActivity, LemmyError> {
83 actor: ObjectId::new(community.actor_id()),
85 object: IdOrNestedObject::NestedObject(object),
86 cc: vec![community.followers_url.clone().into()],
87 kind: AnnounceType::Announce,
88 id: generate_activity_id(
89 &AnnounceType::Announce,
90 &context.settings().get_protocol_and_hostname(),
95 #[tracing::instrument(skip_all)]
97 object: RawAnnouncableActivities,
98 community: &ApubCommunity,
99 context: &LemmyContext,
100 ) -> Result<(), LemmyError> {
101 let announce = AnnounceActivity::new(object.clone(), community, context)?;
102 let inboxes = community.get_follower_inboxes(context).await?;
103 send_lemmy_activity(context, announce, community, inboxes.clone(), false).await?;
105 // Pleroma and Mastodon can't handle activities like Announce/Create/Page. So for
106 // compatibility, we also send Announce/Page so that they can follow Lemmy communities.
107 let object_parsed = object.try_into()?;
108 if let AnnouncableActivities::CreateOrUpdatePost(c) = object_parsed {
109 // Hack: need to convert Page into a format which can be sent as activity, which requires
110 // adding actor field.
111 let announcable_page = RawAnnouncableActivities {
112 id: c.object.id.clone().into_inner(),
113 actor: c.actor.clone().into_inner(),
114 other: serde_json::to_value(c.object)?
119 let announce_compat = AnnounceActivity::new(announcable_page, community, context)?;
120 send_lemmy_activity(context, announce_compat, community, inboxes, false).await?;
126 #[async_trait::async_trait(?Send)]
127 impl ActivityHandler for AnnounceActivity {
128 type DataType = LemmyContext;
129 type Error = LemmyError;
131 fn id(&self) -> &Url {
135 fn actor(&self) -> &Url {
139 #[tracing::instrument(skip_all)]
142 _context: &Data<LemmyContext>,
143 _request_counter: &mut i32,
144 ) -> Result<(), LemmyError> {
145 verify_is_public(&self.to, &self.cc)?;
149 #[tracing::instrument(skip_all)]
152 context: &Data<LemmyContext>,
153 request_counter: &mut i32,
154 ) -> Result<(), LemmyError> {
155 let object: AnnouncableActivities = self
157 .object(context, request_counter)
160 // This is only for sending, not receiving so we reject it.
161 if let AnnouncableActivities::Page(_) = object {
162 return Err(LemmyError::from_message("Cant receive page"));
165 // we have to verify this here in order to avoid fetching the object twice over http
166 object.verify(context, request_counter).await?;
168 let object_value = serde_json::to_value(&object)?;
169 let insert = insert_activity(object.id(), object_value, false, true, context.pool()).await?;
172 "Received duplicate activity in announce {}",
173 object.id().to_string()
177 object.receive(context, request_counter).await
181 impl Id for RawAnnouncableActivities {
182 fn object_id(&self) -> &Url {
183 ActivityHandler::id(self)
187 impl TryFrom<RawAnnouncableActivities> for AnnouncableActivities {
188 type Error = serde_json::error::Error;
190 fn try_from(value: RawAnnouncableActivities) -> Result<Self, Self::Error> {
191 let mut map = value.other.clone();
192 map.insert("id".to_string(), Value::String(value.id.to_string()));
193 map.insert("actor".to_string(), Value::String(value.actor.to_string()));
194 serde_json::from_value(Value::Object(map))
198 impl TryFrom<AnnouncableActivities> for RawAnnouncableActivities {
199 type Error = serde_json::error::Error;
201 fn try_from(value: AnnouncableActivities) -> Result<Self, Self::Error> {
202 serde_json::from_value(serde_json::to_value(value)?)