]> Untitled Git - lemmy.git/blob - crates/apub/src/http/person.rs
Merge pull request #1850 from LemmyNet/refactor-apub
[lemmy.git] / crates / apub / src / http / person.rs
1 use crate::{
2   activities::{
3     community::announce::{AnnouncableActivities, AnnounceActivity},
4     following::accept::AcceptFollowCommunity,
5     private_message::{
6       create_or_update::CreateOrUpdatePrivateMessage,
7       delete::DeletePrivateMessage,
8       undo_delete::UndoDeletePrivateMessage,
9     },
10   },
11   context::lemmy_context,
12   generate_outbox_url,
13   http::{
14     create_apub_response,
15     create_apub_tombstone_response,
16     payload_to_string,
17     receive_activity,
18   },
19   objects::person::ApubPerson,
20 };
21 use activitystreams::{
22   base::BaseExt,
23   collection::{CollectionExt, OrderedCollection},
24 };
25 use actix_web::{body::Body, web, web::Payload, HttpRequest, HttpResponse};
26 use lemmy_api_common::blocking;
27 use lemmy_apub_lib::traits::{ActivityFields, ActivityHandler, ToApub};
28 use lemmy_db_schema::source::person::Person;
29 use lemmy_utils::LemmyError;
30 use lemmy_websocket::LemmyContext;
31 use log::trace;
32 use serde::{Deserialize, Serialize};
33 use url::Url;
34
35 #[derive(Deserialize)]
36 pub struct PersonQuery {
37   user_name: String,
38 }
39
40 /// Return the ActivityPub json representation of a local person over HTTP.
41 pub(crate) async fn get_apub_person_http(
42   info: web::Path<PersonQuery>,
43   context: web::Data<LemmyContext>,
44 ) -> Result<HttpResponse<Body>, LemmyError> {
45   let user_name = info.into_inner().user_name;
46   // TODO: this needs to be able to read deleted persons, so that it can send tombstones
47   let person: ApubPerson = blocking(context.pool(), move |conn| {
48     Person::find_by_name(conn, &user_name)
49   })
50   .await??
51   .into();
52
53   if !person.deleted {
54     let apub = person.to_apub(context.pool()).await?;
55
56     Ok(create_apub_response(&apub))
57   } else {
58     Ok(create_apub_tombstone_response(&person.to_tombstone()?))
59   }
60 }
61
62 #[derive(Clone, Debug, Deserialize, Serialize, ActivityHandler, ActivityFields)]
63 #[serde(untagged)]
64 #[activity_handler(LemmyContext)]
65 pub enum PersonInboxActivities {
66   AcceptFollowCommunity(AcceptFollowCommunity),
67   /// Some activities can also be sent from user to user, eg a comment with mentions
68   AnnouncableActivities(AnnouncableActivities),
69   CreateOrUpdatePrivateMessage(CreateOrUpdatePrivateMessage),
70   DeletePrivateMessage(DeletePrivateMessage),
71   UndoDeletePrivateMessage(UndoDeletePrivateMessage),
72   AnnounceActivity(Box<AnnounceActivity>),
73 }
74
75 pub async fn person_inbox(
76   request: HttpRequest,
77   payload: Payload,
78   _path: web::Path<String>,
79   context: web::Data<LemmyContext>,
80 ) -> Result<HttpResponse, LemmyError> {
81   let unparsed = payload_to_string(payload).await?;
82   trace!("Received person inbox activity {}", unparsed);
83   let activity = serde_json::from_str::<PersonInboxActivities>(&unparsed)?;
84   receive_person_inbox(activity, request, &context).await
85 }
86
87 pub(in crate::http) async fn receive_person_inbox(
88   activity: PersonInboxActivities,
89   request: HttpRequest,
90   context: &LemmyContext,
91 ) -> Result<HttpResponse, LemmyError> {
92   receive_activity(request, activity, context).await
93 }
94
95 pub(crate) async fn get_apub_person_outbox(
96   info: web::Path<PersonQuery>,
97   context: web::Data<LemmyContext>,
98 ) -> Result<HttpResponse<Body>, LemmyError> {
99   let person = blocking(context.pool(), move |conn| {
100     Person::find_by_name(conn, &info.user_name)
101   })
102   .await??;
103   // TODO: populate the person outbox
104   let mut collection = OrderedCollection::new();
105   collection
106     .set_many_items(Vec::<Url>::new())
107     .set_many_contexts(lemmy_context())
108     .set_id(generate_outbox_url(&person.actor_id)?.into())
109     .set_total_items(0_u64);
110   Ok(create_apub_response(&collection))
111 }
112
113 pub(crate) async fn get_apub_person_inbox(
114   info: web::Path<PersonQuery>,
115   context: web::Data<LemmyContext>,
116 ) -> Result<HttpResponse<Body>, LemmyError> {
117   let person = blocking(context.pool(), move |conn| {
118     Person::find_by_name(conn, &info.user_name)
119   })
120   .await??;
121
122   let mut collection = OrderedCollection::new();
123   collection
124     .set_id(person.inbox_url.into())
125     .set_many_contexts(lemmy_context());
126   Ok(create_apub_response(&collection))
127 }