]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/community/lock_page.rs
Implement separate mod activities for feature, lock post (#2716)
[lemmy.git] / crates / apub / src / activities / community / lock_page.rs
1 use crate::{
2   activities::{
3     check_community_deleted_or_removed,
4     community::send_activity_in_community,
5     generate_activity_id,
6     verify_is_public,
7     verify_mod_action,
8     verify_person_in_community,
9   },
10   activity_lists::AnnouncableActivities,
11   local_instance,
12   protocol::{
13     activities::{
14       community::lock_page::{LockPage, LockType, UndoLockPage},
15       create_or_update::page::CreateOrUpdatePage,
16       CreateOrUpdateType,
17     },
18     InCommunity,
19   },
20   SendActivity,
21 };
22 use activitypub_federation::{core::object_id::ObjectId, data::Data, traits::ActivityHandler};
23 use activitystreams_kinds::{activity::UndoType, public};
24 use lemmy_api_common::{
25   context::LemmyContext,
26   post::{LockPost, PostResponse},
27   utils::get_local_user_view_from_jwt,
28 };
29 use lemmy_db_schema::{
30   source::{
31     community::Community,
32     post::{Post, PostUpdateForm},
33   },
34   traits::Crud,
35 };
36 use lemmy_utils::error::LemmyError;
37 use url::Url;
38
39 #[async_trait::async_trait(?Send)]
40 impl ActivityHandler for LockPage {
41   type DataType = LemmyContext;
42   type Error = LemmyError;
43
44   fn id(&self) -> &Url {
45     &self.id
46   }
47
48   fn actor(&self) -> &Url {
49     self.actor.inner()
50   }
51
52   async fn verify(
53     &self,
54     context: &Data<Self::DataType>,
55     request_counter: &mut i32,
56   ) -> Result<(), Self::Error> {
57     verify_is_public(&self.to, &self.cc)?;
58     let community = self.community(context, request_counter).await?;
59     verify_person_in_community(&self.actor, &community, context, request_counter).await?;
60     check_community_deleted_or_removed(&community)?;
61     verify_mod_action(
62       &self.actor,
63       self.object.inner(),
64       community.id,
65       context,
66       request_counter,
67     )
68     .await?;
69     Ok(())
70   }
71
72   async fn receive(
73     self,
74     context: &Data<Self::DataType>,
75     request_counter: &mut i32,
76   ) -> Result<(), Self::Error> {
77     let form = PostUpdateForm::builder().locked(Some(true)).build();
78     let post = self
79       .object
80       .dereference(context, local_instance(context).await, request_counter)
81       .await?;
82     Post::update(context.pool(), post.id, &form).await?;
83     Ok(())
84   }
85 }
86
87 #[async_trait::async_trait(?Send)]
88 impl ActivityHandler for UndoLockPage {
89   type DataType = LemmyContext;
90   type Error = LemmyError;
91
92   fn id(&self) -> &Url {
93     &self.id
94   }
95
96   fn actor(&self) -> &Url {
97     self.actor.inner()
98   }
99
100   async fn verify(
101     &self,
102     context: &Data<Self::DataType>,
103     request_counter: &mut i32,
104   ) -> Result<(), Self::Error> {
105     verify_is_public(&self.to, &self.cc)?;
106     let community = self.community(context, request_counter).await?;
107     verify_person_in_community(&self.actor, &community, context, request_counter).await?;
108     check_community_deleted_or_removed(&community)?;
109     verify_mod_action(
110       &self.actor,
111       self.object.object.inner(),
112       community.id,
113       context,
114       request_counter,
115     )
116     .await?;
117     Ok(())
118   }
119
120   async fn receive(
121     self,
122     context: &Data<Self::DataType>,
123     request_counter: &mut i32,
124   ) -> Result<(), Self::Error> {
125     let form = PostUpdateForm::builder().locked(Some(false)).build();
126     let post = self
127       .object
128       .object
129       .dereference(context, local_instance(context).await, request_counter)
130       .await?;
131     Post::update(context.pool(), post.id, &form).await?;
132     Ok(())
133   }
134 }
135
136 #[async_trait::async_trait(?Send)]
137 impl SendActivity for LockPost {
138   type Response = PostResponse;
139
140   async fn send_activity(
141     request: &Self,
142     response: &Self::Response,
143     context: &LemmyContext,
144   ) -> Result<(), LemmyError> {
145     let local_user_view =
146       get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
147     // For backwards compat with 0.17
148     CreateOrUpdatePage::send(
149       &response.post_view.post,
150       local_user_view.person.id,
151       CreateOrUpdateType::Update,
152       context,
153     )
154     .await?;
155     let id = generate_activity_id(
156       LockType::Lock,
157       &context.settings().get_protocol_and_hostname(),
158     )?;
159     let community_id: Url = response.post_view.community.actor_id.clone().into();
160     let actor = ObjectId::new(local_user_view.person.actor_id.clone());
161     let lock = LockPage {
162       actor,
163       to: vec![public()],
164       object: ObjectId::new(response.post_view.post.ap_id.clone()),
165       cc: vec![community_id.clone()],
166       kind: LockType::Lock,
167       id,
168       audience: Some(ObjectId::new(community_id)),
169     };
170     let activity = if request.locked {
171       AnnouncableActivities::LockPost(lock)
172     } else {
173       let id = generate_activity_id(
174         UndoType::Undo,
175         &context.settings().get_protocol_and_hostname(),
176       )?;
177       let undo = UndoLockPage {
178         actor: lock.actor.clone(),
179         to: vec![public()],
180         cc: lock.cc.clone(),
181         kind: UndoType::Undo,
182         id,
183         audience: lock.audience.clone(),
184         object: lock,
185       };
186       AnnouncableActivities::UndoLockPost(undo)
187     };
188     let community = Community::read(context.pool(), response.post_view.community.id).await?;
189     send_activity_in_community(
190       activity,
191       &local_user_view.person.into(),
192       &community.into(),
193       vec![],
194       true,
195       context,
196     )
197     .await?;
198     Ok(())
199   }
200 }