]> Untitled Git - lemmy.git/blob - lemmy_apub/src/private_message.rs
Move websocket code into workspace (#107)
[lemmy.git] / lemmy_apub / src / private_message.rs
1 use crate::{
2   activities::generate_activity_id,
3   activity_queue::send_activity,
4   check_actor_domain,
5   check_is_apub_id_valid,
6   create_tombstone,
7   fetcher::get_or_fetch_and_upsert_user,
8   insert_activity,
9   ActorType,
10   ApubObjectType,
11   FromApub,
12   ToApub,
13 };
14 use activitystreams::{
15   activity::{
16     kind::{CreateType, DeleteType, UndoType, UpdateType},
17     Create,
18     Delete,
19     Undo,
20     Update,
21   },
22   object::{kind::NoteType, Note, Tombstone},
23   prelude::*,
24 };
25 use anyhow::Context;
26 use lemmy_db::{
27   private_message::{PrivateMessage, PrivateMessageForm},
28   user::User_,
29   Crud,
30   DbPool,
31 };
32 use lemmy_structs::blocking;
33 use lemmy_utils::{location_info, utils::convert_datetime, LemmyError};
34 use lemmy_websocket::LemmyContext;
35 use url::Url;
36
37 #[async_trait::async_trait(?Send)]
38 impl ToApub for PrivateMessage {
39   type Response = Note;
40
41   async fn to_apub(&self, pool: &DbPool) -> Result<Note, LemmyError> {
42     let mut private_message = Note::new();
43
44     let creator_id = self.creator_id;
45     let creator = blocking(pool, move |conn| User_::read(conn, creator_id)).await??;
46
47     let recipient_id = self.recipient_id;
48     let recipient = blocking(pool, move |conn| User_::read(conn, recipient_id)).await??;
49
50     private_message
51       .set_context(activitystreams::context())
52       .set_id(Url::parse(&self.ap_id.to_owned())?)
53       .set_published(convert_datetime(self.published))
54       .set_content(self.content.to_owned())
55       .set_to(recipient.actor_id)
56       .set_attributed_to(creator.actor_id);
57
58     if let Some(u) = self.updated {
59       private_message.set_updated(convert_datetime(u));
60     }
61
62     Ok(private_message)
63   }
64
65   fn to_tombstone(&self) -> Result<Tombstone, LemmyError> {
66     create_tombstone(self.deleted, &self.ap_id, self.updated, NoteType::Note)
67   }
68 }
69
70 #[async_trait::async_trait(?Send)]
71 impl FromApub for PrivateMessageForm {
72   type ApubType = Note;
73
74   /// Parse an ActivityPub note received from another instance into a Lemmy Private message
75   async fn from_apub(
76     note: &Note,
77     context: &LemmyContext,
78     expected_domain: Option<Url>,
79   ) -> Result<PrivateMessageForm, LemmyError> {
80     let creator_actor_id = note
81       .attributed_to()
82       .context(location_info!())?
83       .clone()
84       .single_xsd_any_uri()
85       .context(location_info!())?;
86
87     let creator = get_or_fetch_and_upsert_user(&creator_actor_id, context).await?;
88     let recipient_actor_id = note
89       .to()
90       .context(location_info!())?
91       .clone()
92       .single_xsd_any_uri()
93       .context(location_info!())?;
94     let recipient = get_or_fetch_and_upsert_user(&recipient_actor_id, context).await?;
95     let ap_id = note.id_unchecked().context(location_info!())?.to_string();
96     check_is_apub_id_valid(&Url::parse(&ap_id)?)?;
97
98     Ok(PrivateMessageForm {
99       creator_id: creator.id,
100       recipient_id: recipient.id,
101       content: note
102         .content()
103         .context(location_info!())?
104         .as_single_xsd_string()
105         .context(location_info!())?
106         .to_string(),
107       published: note.published().map(|u| u.to_owned().naive_local()),
108       updated: note.updated().map(|u| u.to_owned().naive_local()),
109       deleted: None,
110       read: None,
111       ap_id: Some(check_actor_domain(note, expected_domain)?),
112       local: false,
113     })
114   }
115 }
116
117 #[async_trait::async_trait(?Send)]
118 impl ApubObjectType for PrivateMessage {
119   /// Send out information about a newly created private message
120   async fn send_create(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> {
121     let note = self.to_apub(context.pool()).await?;
122
123     let recipient_id = self.recipient_id;
124     let recipient = blocking(context.pool(), move |conn| User_::read(conn, recipient_id)).await??;
125
126     let mut create = Create::new(creator.actor_id.to_owned(), note.into_any_base()?);
127     let to = recipient.get_inbox_url()?;
128     create
129       .set_context(activitystreams::context())
130       .set_id(generate_activity_id(CreateType::Create)?)
131       .set_to(to.clone());
132
133     insert_activity(creator.id, create.clone(), true, context.pool()).await?;
134
135     send_activity(context.activity_queue(), create, creator, vec![to])?;
136     Ok(())
137   }
138
139   /// Send out information about an edited post, to the followers of the community.
140   async fn send_update(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> {
141     let note = self.to_apub(context.pool()).await?;
142
143     let recipient_id = self.recipient_id;
144     let recipient = blocking(context.pool(), move |conn| User_::read(conn, recipient_id)).await??;
145
146     let mut update = Update::new(creator.actor_id.to_owned(), note.into_any_base()?);
147     let to = recipient.get_inbox_url()?;
148     update
149       .set_context(activitystreams::context())
150       .set_id(generate_activity_id(UpdateType::Update)?)
151       .set_to(to.clone());
152
153     insert_activity(creator.id, update.clone(), true, context.pool()).await?;
154
155     send_activity(context.activity_queue(), update, creator, vec![to])?;
156     Ok(())
157   }
158
159   async fn send_delete(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> {
160     let note = self.to_apub(context.pool()).await?;
161
162     let recipient_id = self.recipient_id;
163     let recipient = blocking(context.pool(), move |conn| User_::read(conn, recipient_id)).await??;
164
165     let mut delete = Delete::new(creator.actor_id.to_owned(), note.into_any_base()?);
166     let to = recipient.get_inbox_url()?;
167     delete
168       .set_context(activitystreams::context())
169       .set_id(generate_activity_id(DeleteType::Delete)?)
170       .set_to(to.clone());
171
172     insert_activity(creator.id, delete.clone(), true, context.pool()).await?;
173
174     send_activity(context.activity_queue(), delete, creator, vec![to])?;
175     Ok(())
176   }
177
178   async fn send_undo_delete(
179     &self,
180     creator: &User_,
181     context: &LemmyContext,
182   ) -> Result<(), LemmyError> {
183     let note = self.to_apub(context.pool()).await?;
184
185     let recipient_id = self.recipient_id;
186     let recipient = blocking(context.pool(), move |conn| User_::read(conn, recipient_id)).await??;
187
188     let mut delete = Delete::new(creator.actor_id.to_owned(), note.into_any_base()?);
189     let to = recipient.get_inbox_url()?;
190     delete
191       .set_context(activitystreams::context())
192       .set_id(generate_activity_id(DeleteType::Delete)?)
193       .set_to(to.clone());
194
195     // Undo that fake activity
196     let mut undo = Undo::new(creator.actor_id.to_owned(), delete.into_any_base()?);
197     undo
198       .set_context(activitystreams::context())
199       .set_id(generate_activity_id(UndoType::Undo)?)
200       .set_to(to.clone());
201
202     insert_activity(creator.id, undo.clone(), true, context.pool()).await?;
203
204     send_activity(context.activity_queue(), undo, creator, vec![to])?;
205     Ok(())
206   }
207
208   async fn send_remove(&self, _mod_: &User_, _context: &LemmyContext) -> Result<(), LemmyError> {
209     unimplemented!()
210   }
211
212   async fn send_undo_remove(
213     &self,
214     _mod_: &User_,
215     _context: &LemmyContext,
216   ) -> Result<(), LemmyError> {
217     unimplemented!()
218   }
219 }