]> Untitled Git - lemmy.git/blob - crates/apub/src/http/community.rs
Implement separate mod activities for feature, lock post (#2716)
[lemmy.git] / crates / apub / src / http / community.rs
1 use crate::{
2   activity_lists::GroupInboxActivities,
3   collections::{
4     community_featured::ApubCommunityFeatured,
5     community_moderators::ApubCommunityModerators,
6     community_outbox::ApubCommunityOutbox,
7     CommunityContext,
8   },
9   http::{create_apub_response, create_apub_tombstone_response, receive_lemmy_activity},
10   local_instance,
11   objects::{community::ApubCommunity, person::ApubPerson},
12   protocol::collections::group_followers::GroupFollowers,
13 };
14 use activitypub_federation::{
15   core::object_id::ObjectId,
16   deser::context::WithContext,
17   traits::ApubObject,
18 };
19 use actix_web::{web, HttpRequest, HttpResponse};
20 use lemmy_api_common::{
21   context::LemmyContext,
22   utils::{generate_featured_url, generate_outbox_url},
23 };
24 use lemmy_db_schema::{source::community::Community, traits::ApubActor};
25 use lemmy_utils::error::LemmyError;
26 use serde::Deserialize;
27
28 #[derive(Deserialize)]
29 pub(crate) struct CommunityQuery {
30   community_name: String,
31 }
32
33 /// Return the ActivityPub json representation of a local community over HTTP.
34 #[tracing::instrument(skip_all)]
35 pub(crate) async fn get_apub_community_http(
36   info: web::Path<CommunityQuery>,
37   context: web::Data<LemmyContext>,
38 ) -> Result<HttpResponse, LemmyError> {
39   let community: ApubCommunity =
40     Community::read_from_name(context.pool(), &info.community_name, true)
41       .await?
42       .into();
43
44   if !community.deleted && !community.removed {
45     let apub = community.into_apub(&context).await?;
46
47     Ok(create_apub_response(&apub))
48   } else {
49     Ok(create_apub_tombstone_response(community.actor_id.clone()))
50   }
51 }
52
53 /// Handler for all incoming receive to community inboxes.
54 #[tracing::instrument(skip_all)]
55 pub async fn community_inbox(
56   request: HttpRequest,
57   payload: String,
58   context: web::Data<LemmyContext>,
59 ) -> Result<HttpResponse, LemmyError> {
60   receive_lemmy_activity::<WithContext<GroupInboxActivities>, ApubPerson>(request, payload, context)
61     .await
62 }
63
64 /// Returns an empty followers collection, only populating the size (for privacy).
65 pub(crate) async fn get_apub_community_followers(
66   info: web::Path<CommunityQuery>,
67   context: web::Data<LemmyContext>,
68 ) -> Result<HttpResponse, LemmyError> {
69   let community = Community::read_from_name(context.pool(), &info.community_name, false).await?;
70   let followers = GroupFollowers::new(community, &context).await?;
71   Ok(create_apub_response(&followers))
72 }
73
74 /// Returns the community outbox, which is populated by a maximum of 20 posts (but no other
75 /// activites like votes or comments).
76 pub(crate) async fn get_apub_community_outbox(
77   info: web::Path<CommunityQuery>,
78   context: web::Data<LemmyContext>,
79 ) -> Result<HttpResponse, LemmyError> {
80   let community = Community::read_from_name(context.pool(), &info.community_name, false).await?;
81   if community.deleted || community.removed {
82     return Err(LemmyError::from_message("deleted"));
83   }
84   let id = ObjectId::new(generate_outbox_url(&community.actor_id)?);
85   let outbox_data = CommunityContext(community.into(), context.get_ref().clone());
86   let outbox: ApubCommunityOutbox = id
87     .dereference(&outbox_data, local_instance(&context).await, &mut 0)
88     .await?;
89   Ok(create_apub_response(&outbox.into_apub(&outbox_data).await?))
90 }
91
92 #[tracing::instrument(skip_all)]
93 pub(crate) async fn get_apub_community_moderators(
94   info: web::Path<CommunityQuery>,
95   context: web::Data<LemmyContext>,
96 ) -> Result<HttpResponse, LemmyError> {
97   let community: ApubCommunity =
98     Community::read_from_name(context.pool(), &info.community_name, false)
99       .await?
100       .into();
101   if community.deleted || community.removed {
102     return Err(LemmyError::from_message("deleted"));
103   }
104   let id = ObjectId::new(generate_outbox_url(&community.actor_id)?);
105   let outbox_data = CommunityContext(community, context.get_ref().clone());
106   let moderators: ApubCommunityModerators = id
107     .dereference(&outbox_data, local_instance(&context).await, &mut 0)
108     .await?;
109   Ok(create_apub_response(
110     &moderators.into_apub(&outbox_data).await?,
111   ))
112 }
113
114 /// Returns collection of featured (stickied) posts.
115 pub(crate) async fn get_apub_community_featured(
116   info: web::Path<CommunityQuery>,
117   context: web::Data<LemmyContext>,
118 ) -> Result<HttpResponse, LemmyError> {
119   let community = Community::read_from_name(context.pool(), &info.community_name, false).await?;
120   if community.deleted || community.removed {
121     return Err(LemmyError::from_message("deleted"));
122   }
123   let id = ObjectId::new(generate_featured_url(&community.actor_id)?);
124   let data = CommunityContext(community.into(), context.get_ref().clone());
125   let featured: ApubCommunityFeatured = id
126     .dereference(&data, local_instance(&context).await, &mut 0)
127     .await?;
128   Ok(create_apub_response(&featured.into_apub(&data).await?))
129 }