]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/comment/create_or_update.rs
bfc1b7fe6d4544ed63f85b4a032a5b91d200d689
[lemmy.git] / crates / apub / src / activities / comment / create_or_update.rs
1 use crate::{
2   activities::{
3     comment::{collect_non_local_mentions, get_notif_recipients, send_websocket_message},
4     community::announce::AnnouncableActivities,
5     extract_community,
6     generate_activity_id,
7     verify_activity,
8     verify_person_in_community,
9     CreateOrUpdateType,
10   },
11   activity_queue::send_to_community_new,
12   extensions::context::lemmy_context,
13   objects::{comment::Note, FromApub, ToApub},
14   ActorType,
15 };
16 use activitystreams::link::Mention;
17 use lemmy_api_common::blocking;
18 use lemmy_apub_lib::{
19   values::PublicUrl,
20   verify_domains_match,
21   ActivityCommonFields,
22   ActivityHandler,
23 };
24 use lemmy_db_queries::Crud;
25 use lemmy_db_schema::source::{comment::Comment, community::Community, person::Person, post::Post};
26 use lemmy_utils::LemmyError;
27 use lemmy_websocket::{LemmyContext, UserOperationCrud};
28 use serde::{Deserialize, Serialize};
29 use url::Url;
30
31 #[derive(Clone, Debug, Deserialize, Serialize)]
32 #[serde(rename_all = "camelCase")]
33 pub struct CreateOrUpdateComment {
34   to: PublicUrl,
35   object: Note,
36   cc: Vec<Url>,
37   tag: Vec<Mention>,
38   #[serde(rename = "type")]
39   kind: CreateOrUpdateType,
40   #[serde(flatten)]
41   common: ActivityCommonFields,
42 }
43
44 impl CreateOrUpdateComment {
45   pub async fn send(
46     comment: &Comment,
47     actor: &Person,
48     kind: CreateOrUpdateType,
49     context: &LemmyContext,
50   ) -> Result<(), LemmyError> {
51     // TODO: might be helpful to add a comment method to retrieve community directly
52     let post_id = comment.post_id;
53     let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
54     let community_id = post.community_id;
55     let community = blocking(context.pool(), move |conn| {
56       Community::read(conn, community_id)
57     })
58     .await??;
59
60     let id = generate_activity_id(kind.clone())?;
61     let maa = collect_non_local_mentions(comment, &community, context).await?;
62
63     let create_or_update = CreateOrUpdateComment {
64       to: PublicUrl::Public,
65       object: comment.to_apub(context.pool()).await?,
66       cc: maa.ccs,
67       tag: maa.tags,
68       kind,
69       common: ActivityCommonFields {
70         context: lemmy_context(),
71         id: id.clone(),
72         actor: actor.actor_id(),
73         unparsed: Default::default(),
74       },
75     };
76
77     let activity = AnnouncableActivities::CreateOrUpdateComment(create_or_update);
78     send_to_community_new(activity, &id, actor, &community, maa.inboxes, context).await
79   }
80 }
81
82 #[async_trait::async_trait(?Send)]
83 impl ActivityHandler for CreateOrUpdateComment {
84   async fn verify(
85     &self,
86     context: &LemmyContext,
87     request_counter: &mut i32,
88   ) -> Result<(), LemmyError> {
89     let community = extract_community(&self.cc, context, request_counter).await?;
90
91     verify_activity(self.common())?;
92     verify_person_in_community(
93       &self.common.actor,
94       &community.actor_id(),
95       context,
96       request_counter,
97     )
98     .await?;
99     verify_domains_match(&self.common.actor, self.object.id_unchecked())?;
100     // TODO: should add a check that the correct community is in cc (probably needs changes to
101     //       comment deserialization)
102     self.object.verify(context, request_counter).await?;
103     Ok(())
104   }
105
106   async fn receive(
107     self,
108     context: &LemmyContext,
109     request_counter: &mut i32,
110   ) -> Result<(), LemmyError> {
111     let comment =
112       Comment::from_apub(&self.object, context, &self.common.actor, request_counter).await?;
113     let recipients =
114       get_notif_recipients(&self.common.actor, &comment, context, request_counter).await?;
115     let notif_type = match self.kind {
116       CreateOrUpdateType::Create => UserOperationCrud::CreateComment,
117       CreateOrUpdateType::Update => UserOperationCrud::EditComment,
118     };
119     send_websocket_message(comment.id, recipients, notif_type, context).await
120   }
121
122   fn common(&self) -> &ActivityCommonFields {
123     &self.common
124   }
125 }