]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/following/undo_follow.rs
221d8184f8c865853f206c0b4635d68e6af91718
[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       unparsed: Default::default(),
40     };
41     let inbox = vec![community.shared_inbox_or_inbox()];
42     send_lemmy_activity(context, undo, actor, inbox, true).await
43   }
44 }
45
46 #[async_trait::async_trait(?Send)]
47 impl ActivityHandler for UndoFollowCommunity {
48   type DataType = LemmyContext;
49   type Error = LemmyError;
50
51   fn id(&self) -> &Url {
52     &self.id
53   }
54
55   fn actor(&self) -> &Url {
56     self.actor.inner()
57   }
58
59   #[tracing::instrument(skip_all)]
60   async fn verify(
61     &self,
62     context: &Data<LemmyContext>,
63     request_counter: &mut i32,
64   ) -> Result<(), LemmyError> {
65     verify_urls_match(self.actor.inner(), self.object.actor.inner())?;
66     verify_person(&self.actor, context, request_counter).await?;
67     self.object.verify(context, request_counter).await?;
68     Ok(())
69   }
70
71   #[tracing::instrument(skip_all)]
72   async fn receive(
73     self,
74     context: &Data<LemmyContext>,
75     request_counter: &mut i32,
76   ) -> Result<(), LemmyError> {
77     let person = self
78       .actor
79       .dereference(context, local_instance(context).await, request_counter)
80       .await?;
81     let community = self
82       .object
83       .object
84       .dereference(context, local_instance(context).await, request_counter)
85       .await?;
86
87     let community_follower_form = CommunityFollowerForm {
88       community_id: community.id,
89       person_id: person.id,
90       pending: false,
91     };
92
93     // This will fail if they aren't a follower, but ignore the error.
94     CommunityFollower::unfollow(context.pool(), &community_follower_form)
95       .await
96       .ok();
97     Ok(())
98   }
99 }