2 fetcher::object_id::ObjectId,
4 objects::chat_message::{ChatMessage, ChatMessageType},
8 use chrono::NaiveDateTime;
9 use html2md::parse_html;
10 use lemmy_api_common::blocking;
13 values::{MediaTypeHtml, MediaTypeMarkdown},
15 use lemmy_db_schema::{
18 private_message::{PrivateMessage, PrivateMessageForm},
22 use lemmy_utils::{utils::convert_datetime, LemmyError};
23 use lemmy_websocket::LemmyContext;
27 #[derive(Clone, Debug)]
28 pub struct ApubPrivateMessage(PrivateMessage);
30 impl Deref for ApubPrivateMessage {
31 type Target = PrivateMessage;
32 fn deref(&self) -> &Self::Target {
37 impl From<PrivateMessage> for ApubPrivateMessage {
38 fn from(pm: PrivateMessage) -> Self {
39 ApubPrivateMessage { 0: pm }
43 #[async_trait::async_trait(?Send)]
44 impl ApubObject for ApubPrivateMessage {
45 type DataType = LemmyContext;
46 type ApubType = ChatMessage;
47 type TombstoneType = ();
49 fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
53 async fn read_from_apub_id(
55 context: &LemmyContext,
56 ) -> Result<Option<Self>, LemmyError> {
58 blocking(context.pool(), move |conn| {
59 PrivateMessage::read_from_apub_id(conn, object_id)
66 async fn delete(self, _context: &LemmyContext) -> Result<(), LemmyError> {
67 // do nothing, because pm can't be fetched over http
71 async fn to_apub(&self, context: &LemmyContext) -> Result<ChatMessage, LemmyError> {
72 let creator_id = self.creator_id;
73 let creator = blocking(context.pool(), move |conn| Person::read(conn, creator_id)).await??;
75 let recipient_id = self.recipient_id;
77 blocking(context.pool(), move |conn| Person::read(conn, recipient_id)).await??;
79 let note = ChatMessage {
80 r#type: ChatMessageType::ChatMessage,
81 id: self.ap_id.clone().into(),
82 attributed_to: ObjectId::new(creator.actor_id),
83 to: [ObjectId::new(recipient.actor_id)],
84 content: self.content.clone(),
85 media_type: Some(MediaTypeHtml::Html),
87 content: self.content.clone(),
88 media_type: MediaTypeMarkdown::Markdown,
90 published: Some(convert_datetime(self.published)),
91 updated: self.updated.map(convert_datetime),
92 unparsed: Default::default(),
97 fn to_tombstone(&self) -> Result<(), LemmyError> {
103 context: &LemmyContext,
104 expected_domain: &Url,
105 request_counter: &mut i32,
106 ) -> Result<ApubPrivateMessage, LemmyError> {
107 let ap_id = Some(note.id(expected_domain)?.clone().into());
110 .dereference(context, request_counter)
112 let recipient = note.to[0].dereference(context, request_counter).await?;
113 let content = if let Some(source) = ¬e.source {
114 source.content.clone()
116 parse_html(¬e.content)
119 let form = PrivateMessageForm {
120 creator_id: creator.id,
121 recipient_id: recipient.id,
123 published: note.published.map(|u| u.to_owned().naive_local()),
124 updated: note.updated.map(|u| u.to_owned().naive_local()),
130 let pm = blocking(context.pool(), move |conn| {
131 PrivateMessage::upsert(conn, &form)
141 use crate::objects::{
143 tests::{file_to_json_object, init_context},
145 use assert_json_diff::assert_json_include;
146 use serial_test::serial;
148 async fn prepare_comment_test(url: &Url, context: &LemmyContext) -> (ApubPerson, ApubPerson) {
149 let lemmy_person = file_to_json_object("assets/lemmy-person.json");
150 let person1 = ApubPerson::from_apub(&lemmy_person, context, url, &mut 0)
153 let pleroma_person = file_to_json_object("assets/pleroma-person.json");
154 let pleroma_url = Url::parse("https://queer.hacktivis.me/users/lanodan").unwrap();
155 let person2 = ApubPerson::from_apub(&pleroma_person, context, &pleroma_url, &mut 0)
161 fn cleanup(data: (ApubPerson, ApubPerson), context: &LemmyContext) {
162 Person::delete(&*context.pool().get().unwrap(), data.0.id).unwrap();
163 Person::delete(&*context.pool().get().unwrap(), data.1.id).unwrap();
168 async fn test_parse_lemmy_pm() {
169 let context = init_context();
170 let url = Url::parse("https://enterprise.lemmy.ml/private_message/1621").unwrap();
171 let data = prepare_comment_test(&url, &context).await;
172 let json = file_to_json_object("assets/lemmy-private-message.json");
173 let mut request_counter = 0;
174 let pm = ApubPrivateMessage::from_apub(&json, &context, &url, &mut request_counter)
178 assert_eq!(pm.ap_id.clone().into_inner(), url);
179 assert_eq!(pm.content.len(), 20);
180 assert_eq!(request_counter, 0);
182 let to_apub = pm.to_apub(&context).await.unwrap();
183 assert_json_include!(actual: json, expected: to_apub);
185 PrivateMessage::delete(&*context.pool().get().unwrap(), pm.id).unwrap();
186 cleanup(data, &context);
191 async fn test_parse_pleroma_pm() {
192 let context = init_context();
193 let url = Url::parse("https://enterprise.lemmy.ml/private_message/1621").unwrap();
194 let data = prepare_comment_test(&url, &context).await;
195 let pleroma_url = Url::parse("https://queer.hacktivis.me/objects/2").unwrap();
196 let json = file_to_json_object("assets/pleroma-private-message.json");
197 let mut request_counter = 0;
198 let pm = ApubPrivateMessage::from_apub(&json, &context, &pleroma_url, &mut request_counter)
202 assert_eq!(pm.ap_id.clone().into_inner(), pleroma_url);
203 assert_eq!(pm.content.len(), 3);
204 assert_eq!(request_counter, 0);
206 PrivateMessage::delete(&*context.pool().get().unwrap(), pm.id).unwrap();
207 cleanup(data, &context);