]> Untitled Git - lemmy.git/blobdiff - crates/apub/src/activities/create_or_update/post.rs
Add support for Featured Posts (#2585)
[lemmy.git] / crates / apub / src / activities / create_or_update / post.rs
index 09e9ae0d32af4a7e3b0992c021d7efff15a13045..69eae583c80f833d7d2d985bbeb546247d00a01c 100644 (file)
@@ -1,7 +1,7 @@
 use crate::{
   activities::{
     check_community_deleted_or_removed,
-    community::{announce::GetCommunity, send_activity_in_community},
+    community::send_activity_in_community,
     generate_activity_id,
     verify_is_public,
     verify_mod_action,
@@ -9,8 +9,12 @@ use crate::{
   },
   activity_lists::AnnouncableActivities,
   objects::{community::ApubCommunity, person::ApubPerson, post::ApubPost},
-  protocol::activities::{create_or_update::post::CreateOrUpdatePost, CreateOrUpdateType},
+  protocol::{
+    activities::{create_or_update::page::CreateOrUpdatePage, CreateOrUpdateType},
+    InCommunity,
+  },
   ActorType,
+  SendActivity,
 };
 use activitypub_federation::{
   core::object_id::ObjectId,
@@ -19,58 +23,158 @@ use activitypub_federation::{
   utils::{verify_domains_match, verify_urls_match},
 };
 use activitystreams_kinds::public;
+use lemmy_api_common::{
+  context::LemmyContext,
+  post::{CreatePost, EditPost, FeaturePost, LockPost, PostResponse},
+  utils::get_local_user_view_from_jwt,
+  websocket::{send::send_post_ws_message, UserOperationCrud},
+};
 use lemmy_db_schema::{
+  newtypes::PersonId,
   source::{
     community::Community,
-    post::{PostLike, PostLikeForm},
+    person::Person,
+    post::{Post, PostLike, PostLikeForm},
   },
   traits::{Crud, Likeable},
 };
 use lemmy_utils::error::LemmyError;
-use lemmy_websocket::{send::send_post_ws_message, LemmyContext, UserOperationCrud};
 use url::Url;
 
-impl CreateOrUpdatePost {
+#[async_trait::async_trait(?Send)]
+impl SendActivity for CreatePost {
+  type Response = PostResponse;
+
+  async fn send_activity(
+    _request: &Self,
+    response: &Self::Response,
+    context: &LemmyContext,
+  ) -> Result<(), LemmyError> {
+    CreateOrUpdatePage::send(
+      &response.post_view.post,
+      response.post_view.creator.id,
+      CreateOrUpdateType::Create,
+      context,
+    )
+    .await
+  }
+}
+
+#[async_trait::async_trait(?Send)]
+impl SendActivity for EditPost {
+  type Response = PostResponse;
+
+  async fn send_activity(
+    _request: &Self,
+    response: &Self::Response,
+    context: &LemmyContext,
+  ) -> Result<(), LemmyError> {
+    CreateOrUpdatePage::send(
+      &response.post_view.post,
+      response.post_view.creator.id,
+      CreateOrUpdateType::Update,
+      context,
+    )
+    .await
+  }
+}
+
+#[async_trait::async_trait(?Send)]
+impl SendActivity for LockPost {
+  type Response = PostResponse;
+
+  async fn send_activity(
+    request: &Self,
+    response: &Self::Response,
+    context: &LemmyContext,
+  ) -> Result<(), LemmyError> {
+    let local_user_view =
+      get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
+    CreateOrUpdatePage::send(
+      &response.post_view.post,
+      local_user_view.person.id,
+      CreateOrUpdateType::Update,
+      context,
+    )
+    .await
+  }
+}
+
+#[async_trait::async_trait(?Send)]
+impl SendActivity for FeaturePost {
+  type Response = PostResponse;
+
+  async fn send_activity(
+    request: &Self,
+    response: &Self::Response,
+    context: &LemmyContext,
+  ) -> Result<(), LemmyError> {
+    let local_user_view =
+      get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
+    CreateOrUpdatePage::send(
+      &response.post_view.post,
+      local_user_view.person.id,
+      CreateOrUpdateType::Update,
+      context,
+    )
+    .await
+  }
+}
+
+impl CreateOrUpdatePage {
   pub(crate) async fn new(
     post: ApubPost,
     actor: &ApubPerson,
     community: &ApubCommunity,
     kind: CreateOrUpdateType,
     context: &LemmyContext,
-  ) -> Result<CreateOrUpdatePost, LemmyError> {
+  ) -> Result<CreateOrUpdatePage, LemmyError> {
     let id = generate_activity_id(
       kind.clone(),
       &context.settings().get_protocol_and_hostname(),
     )?;
-    Ok(CreateOrUpdatePost {
+    Ok(CreateOrUpdatePage {
       actor: ObjectId::new(actor.actor_id()),
       to: vec![public()],
       object: post.into_apub(context).await?,
       cc: vec![community.actor_id()],
       kind,
       id: id.clone(),
-      unparsed: Default::default(),
+      audience: Some(ObjectId::new(community.actor_id())),
     })
   }
 
   #[tracing::instrument(skip_all)]
-  pub async fn send(
-    post: ApubPost,
-    actor: &ApubPerson,
+  async fn send(
+    post: &Post,
+    person_id: PersonId,
     kind: CreateOrUpdateType,
     context: &LemmyContext,
   ) -> Result<(), LemmyError> {
+    let post = ApubPost(post.clone());
     let community_id = post.community_id;
+    let person: ApubPerson = Person::read(context.pool(), person_id).await?.into();
     let community: ApubCommunity = Community::read(context.pool(), community_id).await?.into();
 
-    let create_or_update = CreateOrUpdatePost::new(post, actor, &community, kind, context).await?;
-    let activity = AnnouncableActivities::CreateOrUpdatePost(Box::new(create_or_update));
-    send_activity_in_community(activity, actor, &community, vec![], context).await
+    let create_or_update =
+      CreateOrUpdatePage::new(post, &person, &community, kind, context).await?;
+    let is_mod_action = create_or_update.object.is_mod_action(context).await?;
+    let activity = AnnouncableActivities::CreateOrUpdatePost(create_or_update);
+    send_activity_in_community(
+      activity,
+      &person,
+      &community,
+      vec![],
+      is_mod_action,
+      context,
+    )
+    .await?;
+    Ok(())
   }
 }
 
 #[async_trait::async_trait(?Send)]
-impl ActivityHandler for CreateOrUpdatePost {
+impl ActivityHandler for CreateOrUpdatePage {
   type DataType = LemmyContext;
   type Error = LemmyError;
 
@@ -89,7 +193,7 @@ impl ActivityHandler for CreateOrUpdatePost {
     request_counter: &mut i32,
   ) -> Result<(), LemmyError> {
     verify_is_public(&self.to, &self.cc)?;
-    let community = self.get_community(context, request_counter).await?;
+    let community = self.community(context, request_counter).await?;
     verify_person_in_community(&self.actor, &community, context, request_counter).await?;
     check_community_deleted_or_removed(&community)?;
 
@@ -101,9 +205,9 @@ impl ActivityHandler for CreateOrUpdatePost {
         // However, when fetching a remote post we generate a new create activity with the current
         // locked/stickied value, so this check may fail. So only check if its a local community,
         // because then we will definitely receive all create and update activities separately.
-        let is_stickied_or_locked =
+        let is_featured_or_locked =
           self.object.stickied == Some(true) || self.object.comments_enabled == Some(false);
-        if community.local && is_stickied_or_locked {
+        if community.local && is_featured_or_locked {
           return Err(LemmyError::from_message(
             "New post cannot be stickied or locked",
           ));
@@ -154,18 +258,3 @@ impl ActivityHandler for CreateOrUpdatePost {
     Ok(())
   }
 }
-
-#[async_trait::async_trait(?Send)]
-impl GetCommunity for CreateOrUpdatePost {
-  #[tracing::instrument(skip_all)]
-  async fn get_community(
-    &self,
-    context: &LemmyContext,
-    request_counter: &mut i32,
-  ) -> Result<ApubCommunity, LemmyError> {
-    self
-      .object
-      .extract_community(context, request_counter)
-      .await
-  }
-}