]> Untitled Git - lemmy.git/blob - crates/apub/src/objects/private_message.rs
Rewrite private message apub and merge create/update
[lemmy.git] / crates / apub / src / objects / private_message.rs
1 use crate::{
2   extensions::context::lemmy_context,
3   fetcher::person::get_or_fetch_and_upsert_person,
4   objects::{create_tombstone, FromApub, Source, ToApub},
5 };
6 use activitystreams::{
7   base::AnyBase,
8   object::{kind::NoteType, Tombstone},
9   primitives::OneOrMany,
10   unparsed::Unparsed,
11 };
12 use anyhow::anyhow;
13 use chrono::{DateTime, FixedOffset};
14 use lemmy_api_common::blocking;
15 use lemmy_apub_lib::{
16   values::{MediaTypeHtml, MediaTypeMarkdown},
17   verify_domains_match,
18 };
19 use lemmy_db_queries::{ApubObject, Crud, DbPool};
20 use lemmy_db_schema::source::{
21   person::Person,
22   private_message::{PrivateMessage, PrivateMessageForm},
23 };
24 use lemmy_utils::{utils::convert_datetime, LemmyError};
25 use lemmy_websocket::LemmyContext;
26 use serde::{Deserialize, Serialize};
27 use url::Url;
28
29 #[derive(Clone, Debug, Deserialize, Serialize)]
30 #[serde(rename_all = "camelCase")]
31 pub struct Note {
32   #[serde(rename = "@context")]
33   context: OneOrMany<AnyBase>,
34   r#type: NoteType,
35   pub(crate) id: Url,
36   pub(crate) attributed_to: Url,
37   to: Url,
38   content: String,
39   media_type: MediaTypeHtml,
40   source: Source,
41   published: DateTime<FixedOffset>,
42   updated: Option<DateTime<FixedOffset>>,
43   #[serde(flatten)]
44   unparsed: Unparsed,
45 }
46
47 impl Note {
48   pub(crate) async fn verify(
49     &self,
50     context: &LemmyContext,
51     request_counter: &mut i32,
52   ) -> Result<(), LemmyError> {
53     verify_domains_match(&self.attributed_to, &self.id)?;
54     let person =
55       get_or_fetch_and_upsert_person(&self.attributed_to, context, request_counter).await?;
56     if person.banned {
57       return Err(anyhow!("Person is banned from site").into());
58     }
59     Ok(())
60   }
61 }
62
63 #[async_trait::async_trait(?Send)]
64 impl ToApub for PrivateMessage {
65   type ApubType = Note;
66
67   async fn to_apub(&self, pool: &DbPool) -> Result<Note, LemmyError> {
68     let creator_id = self.creator_id;
69     let creator = blocking(pool, move |conn| Person::read(conn, creator_id)).await??;
70
71     let recipient_id = self.recipient_id;
72     let recipient = blocking(pool, move |conn| Person::read(conn, recipient_id)).await??;
73
74     let note = Note {
75       context: lemmy_context(),
76       r#type: NoteType::Note,
77       id: self.ap_id.clone().into(),
78       attributed_to: creator.actor_id.into_inner(),
79       to: recipient.actor_id.into(),
80       content: self.content.clone(),
81       media_type: MediaTypeHtml::Html,
82       source: Source {
83         content: self.content.clone(),
84         media_type: MediaTypeMarkdown::Markdown,
85       },
86       published: convert_datetime(self.published),
87       updated: self.updated.map(convert_datetime),
88       unparsed: Default::default(),
89     };
90     Ok(note)
91   }
92
93   fn to_tombstone(&self) -> Result<Tombstone, LemmyError> {
94     create_tombstone(
95       self.deleted,
96       self.ap_id.to_owned().into(),
97       self.updated,
98       NoteType::Note,
99     )
100   }
101 }
102
103 #[async_trait::async_trait(?Send)]
104 impl FromApub for PrivateMessage {
105   type ApubType = Note;
106
107   async fn from_apub(
108     note: &Note,
109     context: &LemmyContext,
110     _expected_domain: Url,
111     request_counter: &mut i32,
112     _mod_action_allowed: bool,
113   ) -> Result<PrivateMessage, LemmyError> {
114     let creator =
115       get_or_fetch_and_upsert_person(&note.attributed_to, context, request_counter).await?;
116     let recipient = get_or_fetch_and_upsert_person(&note.to, context, request_counter).await?;
117
118     let form = PrivateMessageForm {
119       creator_id: creator.id,
120       recipient_id: recipient.id,
121       content: note.source.content.clone(),
122       published: Some(note.published.naive_local()),
123       updated: note.updated.map(|u| u.to_owned().naive_local()),
124       deleted: None,
125       read: None,
126       ap_id: Some(note.id.clone().into()),
127       local: Some(false),
128     };
129     Ok(
130       blocking(context.pool(), move |conn| {
131         PrivateMessage::upsert(conn, &form)
132       })
133       .await??,
134     )
135   }
136 }