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