]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/following/undo_follow.rs
When announcing incoming activities, keep extra fields (#2550)
[lemmy.git] / crates / apub / src / activities / following / undo_follow.rs
1 use crate::{
2   activities::{generate_activity_id, send_lemmy_activity, verify_person},
3   local_instance,
4   objects::{community::ApubCommunity, person::ApubPerson},
5   protocol::activities::following::{follow::FollowCommunity, undo_follow::UndoFollowCommunity},
6   ActorType,
7 };
8 use activitypub_federation::{
9   core::object_id::ObjectId,
10   data::Data,
11   traits::{ActivityHandler, Actor},
12   utils::verify_urls_match,
13 };
14 use activitystreams_kinds::activity::UndoType;
15 use lemmy_db_schema::{
16   source::community::{CommunityFollower, CommunityFollowerForm},
17   traits::Followable,
18 };
19 use lemmy_utils::error::LemmyError;
20 use lemmy_websocket::LemmyContext;
21 use url::Url;
22
23 impl UndoFollowCommunity {
24   #[tracing::instrument(skip_all)]
25   pub async fn send(
26     actor: &ApubPerson,
27     community: &ApubCommunity,
28     context: &LemmyContext,
29   ) -> Result<(), LemmyError> {
30     let object = FollowCommunity::new(actor, community, context)?;
31     let undo = UndoFollowCommunity {
32       actor: ObjectId::new(actor.actor_id()),
33       object,
34       kind: UndoType::Undo,
35       id: generate_activity_id(
36         UndoType::Undo,
37         &context.settings().get_protocol_and_hostname(),
38       )?,
39     };
40     let inbox = vec![community.shared_inbox_or_inbox()];
41     send_lemmy_activity(context, undo, actor, inbox, true).await
42   }
43 }
44
45 #[async_trait::async_trait(?Send)]
46 impl ActivityHandler for UndoFollowCommunity {
47   type DataType = LemmyContext;
48   type Error = LemmyError;
49
50   fn id(&self) -> &Url {
51     &self.id
52   }
53
54   fn actor(&self) -> &Url {
55     self.actor.inner()
56   }
57
58   #[tracing::instrument(skip_all)]
59   async fn verify(
60     &self,
61     context: &Data<LemmyContext>,
62     request_counter: &mut i32,
63   ) -> Result<(), LemmyError> {
64     verify_urls_match(self.actor.inner(), self.object.actor.inner())?;
65     verify_person(&self.actor, context, request_counter).await?;
66     self.object.verify(context, request_counter).await?;
67     Ok(())
68   }
69
70   #[tracing::instrument(skip_all)]
71   async fn receive(
72     self,
73     context: &Data<LemmyContext>,
74     request_counter: &mut i32,
75   ) -> Result<(), LemmyError> {
76     let person = self
77       .actor
78       .dereference(context, local_instance(context).await, request_counter)
79       .await?;
80     let community = self
81       .object
82       .object
83       .dereference(context, local_instance(context).await, request_counter)
84       .await?;
85
86     let community_follower_form = CommunityFollowerForm {
87       community_id: community.id,
88       person_id: person.id,
89       pending: false,
90     };
91
92     // This will fail if they aren't a follower, but ignore the error.
93     CommunityFollower::unfollow(context.pool(), &community_follower_form)
94       .await
95       .ok();
96     Ok(())
97   }
98 }