2 check_is_apub_id_valid,
3 community::do_announce,
4 extensions::signatures::verify,
6 get_or_fetch_and_upsert_actor,
7 get_or_fetch_and_upsert_community,
8 get_or_fetch_and_upsert_user,
11 announce::receive_announce,
12 create::receive_create,
13 delete::receive_delete,
14 dislike::receive_dislike,
16 remove::receive_remove,
18 update::receive_update,
22 use activitystreams::{
23 activity::{ActorAndObject, ActorAndObjectRef},
24 base::{AsBase, Extends},
28 use actix_web::{web, HttpRequest, HttpResponse};
30 use lemmy_db::user::User_;
31 use lemmy_utils::{location_info, LemmyError};
32 use lemmy_websocket::LemmyContext;
34 use serde::{Deserialize, Serialize};
38 #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
39 #[serde(rename_all = "PascalCase")]
51 // TODO: this isnt entirely correct, cause some of these activities are not ActorAndObject,
52 // but it might still work due to the anybase conversion
53 pub type AcceptedActivities = ActorAndObject<ValidTypes>;
55 /// Handler for all incoming activities to user inboxes.
56 pub async fn shared_inbox(
58 input: web::Json<AcceptedActivities>,
59 context: web::Data<LemmyContext>,
60 ) -> Result<HttpResponse, LemmyError> {
61 let activity = input.into_inner();
63 let json = serde_json::to_string(&activity)?;
64 debug!("Shared inbox received activity: {}", json);
66 // TODO: if we already received an activity with identical ID, then ignore this (same in other inboxes)
68 let sender = &activity
72 .context(location_info!())?;
73 let community = get_community_id_from_activity(&activity)?;
75 check_is_apub_id_valid(sender)?;
76 check_is_apub_id_valid(&community)?;
78 let actor = get_or_fetch_and_upsert_actor(sender, &context).await?;
79 verify(&request, actor.as_ref())?;
81 let any_base = activity.clone().into_any_base()?;
82 let kind = activity.kind().context(location_info!())?;
83 let res = match kind {
84 ValidTypes::Announce => receive_announce(any_base, &context).await,
85 ValidTypes::Create => receive_create(any_base, &context).await,
86 ValidTypes::Update => receive_update(any_base, &context).await,
87 ValidTypes::Like => receive_like(any_base, &context).await,
88 ValidTypes::Dislike => receive_dislike(any_base, &context).await,
89 ValidTypes::Remove => receive_remove(any_base, &context).await,
90 ValidTypes::Delete => receive_delete(any_base, &context).await,
91 ValidTypes::Undo => receive_undo(any_base, &context).await,
94 insert_activity(actor.user_id(), activity.clone(), false, context.pool()).await?;
98 pub(in crate::inbox) fn receive_unhandled_activity<A>(
100 ) -> Result<HttpResponse, LemmyError>
104 debug!("received unhandled activity type: {:?}", activity);
105 Ok(HttpResponse::NotImplemented().finish())
108 pub(in crate::inbox) async fn get_user_from_activity<T, A>(
110 context: &LemmyContext,
111 ) -> Result<User_, LemmyError>
113 T: AsBase<A> + ActorAndObjectRef,
115 let actor = activity.actor()?;
116 let user_uri = actor.as_single_xsd_any_uri().context(location_info!())?;
117 get_or_fetch_and_upsert_user(&user_uri, context).await
120 pub(in crate::inbox) fn get_community_id_from_activity<T, A>(
122 ) -> Result<Url, LemmyError>
124 T: AsBase<A> + ActorAndObjectRef + AsObject<A>,
126 let cc = activity.cc().context(location_info!())?;
127 let cc = cc.as_many().context(location_info!())?;
130 .context(location_info!())?
132 .context(location_info!())?
137 pub(in crate::inbox) async fn announce_if_community_is_local<T, Kind>(
140 context: &LemmyContext,
141 ) -> Result<(), LemmyError>
146 <T as Extends<Kind>>::Error: From<serde_json::Error> + Send + Sync + 'static,
148 let cc = activity.cc().context(location_info!())?;
149 let cc = cc.as_many().context(location_info!())?;
150 let community_followers_uri = cc
152 .context(location_info!())?
154 .context(location_info!())?;
155 // TODO: this is hacky but seems to be the only way to get the community ID
156 let community_uri = community_followers_uri
158 .replace("/followers", "");
159 let community = get_or_fetch_and_upsert_community(&Url::parse(&community_uri)?, context).await?;
162 do_announce(activity.into_any_base()?, &community, &user, context).await?;