2 context::lemmy_context,
3 fetcher::object_id::ObjectId,
4 objects::{create_tombstone, FromApub, Source, ToApub},
8 object::{kind::NoteType, Tombstone},
13 use chrono::{DateTime, FixedOffset};
14 use lemmy_api_common::blocking;
16 values::{MediaTypeHtml, MediaTypeMarkdown},
17 verify::verify_domains_match,
19 use lemmy_db_schema::{
22 private_message::{PrivateMessage, PrivateMessageForm},
27 use lemmy_utils::{utils::convert_datetime, LemmyError};
28 use lemmy_websocket::LemmyContext;
29 use serde::{Deserialize, Serialize};
30 use serde_with::skip_serializing_none;
33 #[skip_serializing_none]
34 #[derive(Clone, Debug, Deserialize, Serialize)]
35 #[serde(rename_all = "camelCase")]
37 #[serde(rename = "@context")]
38 context: OneOrMany<AnyBase>,
41 pub(crate) attributed_to: ObjectId<Person>,
44 media_type: MediaTypeHtml,
46 published: DateTime<FixedOffset>,
47 updated: Option<DateTime<FixedOffset>>,
53 pub(crate) fn id_unchecked(&self) -> &Url {
56 pub(crate) fn id(&self, expected_domain: &Url) -> Result<&Url, LemmyError> {
57 verify_domains_match(&self.id, expected_domain)?;
61 pub(crate) async fn verify(
63 context: &LemmyContext,
64 request_counter: &mut i32,
65 ) -> Result<(), LemmyError> {
66 verify_domains_match(self.attributed_to.inner(), &self.id)?;
69 .dereference(context, request_counter)
72 return Err(anyhow!("Person is banned from site").into());
78 #[async_trait::async_trait(?Send)]
79 impl ToApub for PrivateMessage {
82 async fn to_apub(&self, pool: &DbPool) -> Result<Note, LemmyError> {
83 let creator_id = self.creator_id;
84 let creator = blocking(pool, move |conn| Person::read(conn, creator_id)).await??;
86 let recipient_id = self.recipient_id;
87 let recipient = blocking(pool, move |conn| Person::read(conn, recipient_id)).await??;
90 context: lemmy_context(),
91 r#type: NoteType::Note,
92 id: self.ap_id.clone().into(),
93 attributed_to: ObjectId::new(creator.actor_id),
94 to: ObjectId::new(recipient.actor_id),
95 content: self.content.clone(),
96 media_type: MediaTypeHtml::Html,
98 content: self.content.clone(),
99 media_type: MediaTypeMarkdown::Markdown,
101 published: convert_datetime(self.published),
102 updated: self.updated.map(convert_datetime),
103 unparsed: Default::default(),
108 fn to_tombstone(&self) -> Result<Tombstone, LemmyError> {
111 self.ap_id.to_owned().into(),
118 #[async_trait::async_trait(?Send)]
119 impl FromApub for PrivateMessage {
120 type ApubType = Note;
124 context: &LemmyContext,
125 expected_domain: &Url,
126 request_counter: &mut i32,
127 ) -> Result<PrivateMessage, LemmyError> {
128 let ap_id = Some(note.id(expected_domain)?.clone().into());
131 .dereference(context, request_counter)
133 let recipient = note.to.dereference(context, request_counter).await?;
135 let form = PrivateMessageForm {
136 creator_id: creator.id,
137 recipient_id: recipient.id,
138 content: note.source.content.clone(),
139 published: Some(note.published.naive_local()),
140 updated: note.updated.map(|u| u.to_owned().naive_local()),
147 blocking(context.pool(), move |conn| {
148 PrivateMessage::upsert(conn, &form)