2 activity_lists::GroupInboxActivities,
4 community_moderators::ApubCommunityModerators,
5 community_outbox::ApubCommunityOutbox,
9 http::{create_apub_response, create_apub_tombstone_response, receive_lemmy_activity},
11 objects::{community::ApubCommunity, person::ApubPerson},
12 protocol::collections::group_followers::GroupFollowers,
14 use activitypub_federation::{
15 core::object_id::ObjectId,
16 deser::context::WithContext,
19 use actix_web::{web, HttpRequest, HttpResponse};
20 use lemmy_api_common::utils::blocking;
21 use lemmy_db_schema::{source::community::Community, traits::ApubActor};
22 use lemmy_utils::error::LemmyError;
23 use lemmy_websocket::LemmyContext;
24 use serde::Deserialize;
26 #[derive(Deserialize)]
27 pub(crate) struct CommunityQuery {
28 community_name: String,
31 /// Return the ActivityPub json representation of a local community over HTTP.
32 #[tracing::instrument(skip_all)]
33 pub(crate) async fn get_apub_community_http(
34 info: web::Path<CommunityQuery>,
35 context: web::Data<LemmyContext>,
36 ) -> Result<HttpResponse, LemmyError> {
37 let community: ApubCommunity = blocking(context.pool(), move |conn| {
38 Community::read_from_name(conn, &info.community_name, true)
43 if !community.deleted && !community.removed {
44 let apub = community.into_apub(&**context).await?;
46 Ok(create_apub_response(&apub))
48 Ok(create_apub_tombstone_response(community.actor_id.clone()))
52 /// Handler for all incoming receive to community inboxes.
53 #[tracing::instrument(skip_all)]
54 pub async fn community_inbox(
57 context: web::Data<LemmyContext>,
58 ) -> Result<HttpResponse, LemmyError> {
59 receive_lemmy_activity::<WithContext<GroupInboxActivities>, ApubPerson>(request, payload, context)
63 /// Returns an empty followers collection, only populating the size (for privacy).
64 pub(crate) async fn get_apub_community_followers(
65 info: web::Path<CommunityQuery>,
66 context: web::Data<LemmyContext>,
67 ) -> Result<HttpResponse, LemmyError> {
68 let community = blocking(context.pool(), move |conn| {
69 Community::read_from_name(conn, &info.community_name, false)
72 let followers = GroupFollowers::new(community, &context).await?;
73 Ok(create_apub_response(&followers))
76 /// Returns the community outbox, which is populated by a maximum of 20 posts (but no other
77 /// activites like votes or comments).
78 pub(crate) async fn get_apub_community_outbox(
79 info: web::Path<CommunityQuery>,
80 context: web::Data<LemmyContext>,
81 ) -> Result<HttpResponse, LemmyError> {
82 let community = blocking(context.pool(), move |conn| {
83 Community::read_from_name(conn, &info.community_name, false)
86 if community.deleted || community.removed {
87 return Err(LemmyError::from_message("deleted"));
90 let id = ObjectId::new(generate_outbox_url(&community.actor_id)?);
91 let outbox_data = CommunityContext(community.into(), context.get_ref().clone());
92 let outbox: ApubCommunityOutbox = id
93 .dereference(&outbox_data, local_instance(&context), &mut 0)
95 Ok(create_apub_response(&outbox.into_apub(&outbox_data).await?))
98 #[tracing::instrument(skip_all)]
99 pub(crate) async fn get_apub_community_moderators(
100 info: web::Path<CommunityQuery>,
101 context: web::Data<LemmyContext>,
102 ) -> Result<HttpResponse, LemmyError> {
103 let community: ApubCommunity = blocking(context.pool(), move |conn| {
104 Community::read_from_name(conn, &info.community_name, false)
108 if community.deleted || community.removed {
109 return Err(LemmyError::from_message("deleted"));
112 let id = ObjectId::new(generate_outbox_url(&community.actor_id)?);
113 let outbox_data = CommunityContext(community, context.get_ref().clone());
114 let moderators: ApubCommunityModerators = id
115 .dereference(&outbox_data, local_instance(&context), &mut 0)
117 Ok(create_apub_response(
118 &moderators.into_apub(&outbox_data).await?,