]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/post/update.rs
Merge pull request #1678 from LemmyNet/rewrite-post
[lemmy.git] / crates / apub / src / activities / post / update.rs
1 use crate::{
2   activities::{
3     community::announce::AnnouncableActivities,
4     generate_activity_id,
5     post::send_websocket_message,
6     verify_activity,
7     verify_mod_action,
8     verify_person_in_community,
9   },
10   activity_queue::send_to_community_new,
11   extensions::context::lemmy_context,
12   fetcher::community::get_or_fetch_and_upsert_community,
13   objects::{post::Page, FromApub, ToApub},
14   ActorType,
15 };
16 use activitystreams::activity::kind::UpdateType;
17 use lemmy_api_common::blocking;
18 use lemmy_apub_lib::{values::PublicUrl, verify_urls_match, ActivityCommonFields, ActivityHandler};
19 use lemmy_db_queries::Crud;
20 use lemmy_db_schema::source::{community::Community, person::Person, post::Post};
21 use lemmy_utils::LemmyError;
22 use lemmy_websocket::{LemmyContext, UserOperationCrud};
23 use url::Url;
24
25 #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
26 #[serde(rename_all = "camelCase")]
27 pub struct UpdatePost {
28   to: PublicUrl,
29   object: Page,
30   cc: [Url; 1],
31   r#type: UpdateType,
32   #[serde(flatten)]
33   common: ActivityCommonFields,
34 }
35
36 impl UpdatePost {
37   pub async fn send(post: &Post, actor: &Person, context: &LemmyContext) -> Result<(), LemmyError> {
38     let community_id = post.community_id;
39     let community = blocking(context.pool(), move |conn| {
40       Community::read(conn, community_id)
41     })
42     .await??;
43
44     let id = generate_activity_id(UpdateType::Update)?;
45     let update = UpdatePost {
46       to: PublicUrl::Public,
47       object: post.to_apub(context.pool()).await?,
48       cc: [community.actor_id()],
49       r#type: Default::default(),
50       common: ActivityCommonFields {
51         context: lemmy_context(),
52         id: id.clone(),
53         actor: actor.actor_id(),
54         unparsed: Default::default(),
55       },
56     };
57     let activity = AnnouncableActivities::UpdatePost(update);
58     send_to_community_new(activity, &id, actor, &community, vec![], context).await
59   }
60 }
61
62 #[async_trait::async_trait(?Send)]
63 impl ActivityHandler for UpdatePost {
64   async fn verify(
65     &self,
66     context: &LemmyContext,
67     request_counter: &mut i32,
68   ) -> Result<(), LemmyError> {
69     let community_id = get_or_fetch_and_upsert_community(&self.cc[0], context, request_counter)
70       .await?
71       .actor_id();
72     let is_mod_action = self.object.is_mod_action(context.pool()).await?;
73
74     verify_activity(self.common())?;
75     verify_person_in_community(&self.common.actor, &community_id, context, request_counter).await?;
76     if is_mod_action {
77       verify_mod_action(&self.common.actor, community_id, context).await?;
78     } else {
79       verify_urls_match(&self.common.actor, &self.object.attributed_to)?;
80     }
81     self.object.verify(context, request_counter).await?;
82     Ok(())
83   }
84
85   async fn receive(
86     &self,
87     context: &LemmyContext,
88     request_counter: &mut i32,
89   ) -> Result<(), LemmyError> {
90     let post = Post::from_apub(
91       &self.object,
92       context,
93       self.common.actor.clone(),
94       request_counter,
95       // TODO: we already check here if the mod action is valid, can remove that check param
96       true,
97     )
98     .await?;
99
100     send_websocket_message(post.id, UserOperationCrud::EditPost, context).await
101   }
102
103   fn common(&self) -> &ActivityCommonFields {
104     &self.common
105   }
106 }