3 community::announce::AnnouncableActivities,
8 verify_person_in_community,
11 activity_queue::send_to_community_new,
12 extensions::context::lemmy_context,
13 fetcher::person::get_or_fetch_and_upsert_person,
14 objects::{post::Page, FromApub, ToApub},
17 use activitystreams::{base::AnyBase, primitives::OneOrMany, unparsed::Unparsed};
19 use lemmy_api_common::blocking;
27 use lemmy_db_queries::Crud;
28 use lemmy_db_schema::source::{community::Community, person::Person, post::Post};
29 use lemmy_utils::LemmyError;
30 use lemmy_websocket::{send::send_post_ws_message, LemmyContext, UserOperationCrud};
31 use serde::{Deserialize, Serialize};
34 #[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
35 #[serde(rename_all = "camelCase")]
36 pub struct CreateOrUpdatePost {
41 #[serde(rename = "type")]
42 kind: CreateOrUpdateType,
44 #[serde(rename = "@context")]
45 context: OneOrMany<AnyBase>,
50 impl CreateOrUpdatePost {
54 kind: CreateOrUpdateType,
55 context: &LemmyContext,
56 ) -> Result<(), LemmyError> {
57 let community_id = post.community_id;
58 let community = blocking(context.pool(), move |conn| {
59 Community::read(conn, community_id)
63 let id = generate_activity_id(kind.clone())?;
64 let create_or_update = CreateOrUpdatePost {
65 actor: actor.actor_id(),
66 to: PublicUrl::Public,
67 object: post.to_apub(context.pool()).await?,
68 cc: [community.actor_id()],
71 context: lemmy_context(),
72 unparsed: Default::default(),
75 let activity = AnnouncableActivities::CreateOrUpdatePost(Box::new(create_or_update));
76 send_to_community_new(activity, &id, actor, &community, vec![], context).await
80 #[async_trait::async_trait(?Send)]
81 impl ActivityHandler for CreateOrUpdatePost {
84 context: &LemmyContext,
85 request_counter: &mut i32,
86 ) -> Result<(), LemmyError> {
87 verify_activity(self)?;
88 let community = extract_community(&self.cc, context, request_counter).await?;
89 let community_id = community.actor_id();
90 verify_person_in_community(&self.actor, &community_id, context, request_counter).await?;
92 CreateOrUpdateType::Create => {
93 verify_domains_match(&self.actor, self.object.id_unchecked())?;
94 verify_urls_match(&self.actor, &self.object.attributed_to)?;
95 // Check that the post isnt locked or stickied, as that isnt possible for newly created posts.
96 // However, when fetching a remote post we generate a new create activity with the current
97 // locked/stickied value, so this check may fail. So only check if its a local community,
98 // because then we will definitely receive all create and update activities separately.
99 let is_stickied_or_locked =
100 self.object.stickied == Some(true) || self.object.comments_enabled == Some(false);
101 if community.local && is_stickied_or_locked {
102 return Err(anyhow!("New post cannot be stickied or locked").into());
105 CreateOrUpdateType::Update => {
106 let is_mod_action = self.object.is_mod_action(context.pool()).await?;
108 verify_mod_action(&self.actor, community_id, context).await?;
110 verify_domains_match(&self.actor, self.object.id_unchecked())?;
111 verify_urls_match(&self.actor, &self.object.attributed_to)?;
115 self.object.verify(context, request_counter).await?;
121 context: &LemmyContext,
122 request_counter: &mut i32,
123 ) -> Result<(), LemmyError> {
124 let actor = get_or_fetch_and_upsert_person(&self.actor, context, request_counter).await?;
125 let post = Post::from_apub(&self.object, context, &actor.actor_id(), request_counter).await?;
127 let notif_type = match self.kind {
128 CreateOrUpdateType::Create => UserOperationCrud::CreatePost,
129 CreateOrUpdateType::Update => UserOperationCrud::EditPost,
131 send_post_ws_message(post.id, notif_type, None, None, context).await?;