6 verify_person_in_community,
8 activity_lists::AnnouncableActivities,
9 insert_received_activity,
10 objects::community::ApubCommunity,
12 activities::community::announce::{AnnounceActivity, RawAnnouncableActivities},
18 use activitypub_federation::{
20 kinds::{activity::AnnounceType, public},
21 traits::{ActivityHandler, Actor},
23 use lemmy_api_common::context::LemmyContext;
24 use lemmy_utils::error::{LemmyError, LemmyErrorType};
25 use serde_json::Value;
28 #[async_trait::async_trait]
29 impl ActivityHandler for RawAnnouncableActivities {
30 type DataType = LemmyContext;
31 type Error = LemmyError;
33 fn id(&self) -> &Url {
37 fn actor(&self) -> &Url {
41 #[tracing::instrument(skip_all)]
42 async fn verify(&self, _data: &Data<Self::DataType>) -> Result<(), Self::Error> {
46 #[tracing::instrument(skip_all)]
47 async fn receive(self, data: &Data<Self::DataType>) -> Result<(), Self::Error> {
48 let activity: AnnouncableActivities = self.clone().try_into()?;
49 // This is only for sending, not receiving so we reject it.
50 if let AnnouncableActivities::Page(_) = activity {
51 return Err(LemmyErrorType::CannotReceivePage)?;
54 // verify and receive activity
55 activity.verify(data).await?;
56 activity.clone().receive(data).await?;
58 // if activity is in a community, send to followers
59 let community = activity.community(data).await;
60 if let Ok(community) = community {
62 let actor_id = activity.actor().clone().into();
63 verify_person_in_community(&actor_id, &community, data).await?;
64 AnnounceActivity::send(self, &community, data).await?;
71 impl AnnounceActivity {
73 object: RawAnnouncableActivities,
74 community: &ApubCommunity,
75 context: &Data<LemmyContext>,
76 ) -> Result<AnnounceActivity, LemmyError> {
78 actor: community.id().into(),
80 object: IdOrNestedObject::NestedObject(object),
81 cc: vec![community.followers_url.clone().into()],
82 kind: AnnounceType::Announce,
83 id: generate_activity_id(
84 &AnnounceType::Announce,
85 &context.settings().get_protocol_and_hostname(),
90 #[tracing::instrument(skip_all)]
92 object: RawAnnouncableActivities,
93 community: &ApubCommunity,
94 context: &Data<LemmyContext>,
95 ) -> Result<(), LemmyError> {
96 let announce = AnnounceActivity::new(object.clone(), community, context)?;
97 let inboxes = community.get_follower_inboxes(context).await?;
98 send_lemmy_activity(context, announce, community, inboxes.clone(), false).await?;
100 // Pleroma and Mastodon can't handle activities like Announce/Create/Page. So for
101 // compatibility, we also send Announce/Page so that they can follow Lemmy communities.
102 let object_parsed = object.try_into()?;
103 if let AnnouncableActivities::CreateOrUpdatePost(c) = object_parsed {
104 // Hack: need to convert Page into a format which can be sent as activity, which requires
105 // adding actor field.
106 let announcable_page = RawAnnouncableActivities {
107 id: generate_activity_id(
108 AnnounceType::Announce,
109 &context.settings().get_protocol_and_hostname(),
111 actor: c.actor.clone().into_inner(),
112 other: serde_json::to_value(c.object)?
117 let announce_compat = AnnounceActivity::new(announcable_page, community, context)?;
118 send_lemmy_activity(context, announce_compat, community, inboxes, false).await?;
124 #[async_trait::async_trait]
125 impl ActivityHandler for AnnounceActivity {
126 type DataType = LemmyContext;
127 type Error = LemmyError;
129 fn id(&self) -> &Url {
133 fn actor(&self) -> &Url {
137 #[tracing::instrument(skip_all)]
138 async fn verify(&self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
139 insert_received_activity(&self.id, context).await?;
140 verify_is_public(&self.to, &self.cc)?;
144 #[tracing::instrument(skip_all)]
145 async fn receive(self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
146 let object: AnnouncableActivities = self.object.object(context).await?.try_into()?;
147 // This is only for sending, not receiving so we reject it.
148 if let AnnouncableActivities::Page(_) = object {
149 return Err(LemmyErrorType::CannotReceivePage)?;
152 // verify here in order to avoid fetching the object twice over http
153 object.verify(context).await?;
154 object.receive(context).await
158 impl Id for RawAnnouncableActivities {
159 fn object_id(&self) -> &Url {
160 ActivityHandler::id(self)
164 impl TryFrom<RawAnnouncableActivities> for AnnouncableActivities {
165 type Error = serde_json::error::Error;
167 fn try_from(value: RawAnnouncableActivities) -> Result<Self, Self::Error> {
168 let mut map = value.other.clone();
169 map.insert("id".to_string(), Value::String(value.id.to_string()));
170 map.insert("actor".to_string(), Value::String(value.actor.to_string()));
171 serde_json::from_value(Value::Object(map))
175 impl TryFrom<AnnouncableActivities> for RawAnnouncableActivities {
176 type Error = serde_json::error::Error;
178 fn try_from(value: AnnouncableActivities) -> Result<Self, Self::Error> {
179 serde_json::from_value(serde_json::to_value(value)?)