]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/following/follow.rs
Add diesel_async, get rid of blocking function (#2510)
[lemmy.git] / crates / apub / src / activities / following / follow.rs
1 use crate::{
2   activities::{
3     generate_activity_id,
4     send_lemmy_activity,
5     verify_person,
6     verify_person_in_community,
7   },
8   local_instance,
9   objects::{community::ApubCommunity, person::ApubPerson},
10   protocol::activities::following::{accept::AcceptFollowCommunity, follow::FollowCommunity},
11   ActorType,
12 };
13 use activitypub_federation::{
14   core::object_id::ObjectId,
15   data::Data,
16   traits::{ActivityHandler, Actor},
17 };
18 use activitystreams_kinds::activity::FollowType;
19 use lemmy_db_schema::{
20   source::community::{CommunityFollower, CommunityFollowerForm},
21   traits::Followable,
22 };
23 use lemmy_utils::error::LemmyError;
24 use lemmy_websocket::LemmyContext;
25 use url::Url;
26
27 impl FollowCommunity {
28   pub(in crate::activities::following) fn new(
29     actor: &ApubPerson,
30     community: &ApubCommunity,
31     context: &LemmyContext,
32   ) -> Result<FollowCommunity, LemmyError> {
33     Ok(FollowCommunity {
34       actor: ObjectId::new(actor.actor_id()),
35       object: ObjectId::new(community.actor_id()),
36       kind: FollowType::Follow,
37       id: generate_activity_id(
38         FollowType::Follow,
39         &context.settings().get_protocol_and_hostname(),
40       )?,
41       unparsed: Default::default(),
42     })
43   }
44
45   #[tracing::instrument(skip_all)]
46   pub async fn send(
47     actor: &ApubPerson,
48     community: &ApubCommunity,
49     context: &LemmyContext,
50   ) -> Result<(), LemmyError> {
51     let community_follower_form = CommunityFollowerForm {
52       community_id: community.id,
53       person_id: actor.id,
54       pending: true,
55     };
56     CommunityFollower::follow(context.pool(), &community_follower_form)
57       .await
58       .ok();
59
60     let follow = FollowCommunity::new(actor, community, context)?;
61     let inbox = vec![community.shared_inbox_or_inbox()];
62     send_lemmy_activity(context, follow, actor, inbox, true).await
63   }
64 }
65
66 #[async_trait::async_trait(?Send)]
67 impl ActivityHandler for FollowCommunity {
68   type DataType = LemmyContext;
69   type Error = LemmyError;
70
71   fn id(&self) -> &Url {
72     &self.id
73   }
74
75   fn actor(&self) -> &Url {
76     self.actor.inner()
77   }
78
79   #[tracing::instrument(skip_all)]
80   async fn verify(
81     &self,
82     context: &Data<LemmyContext>,
83     request_counter: &mut i32,
84   ) -> Result<(), LemmyError> {
85     verify_person(&self.actor, context, request_counter).await?;
86     let community = self
87       .object
88       .dereference(context, local_instance(context).await, request_counter)
89       .await?;
90     verify_person_in_community(&self.actor, &community, context, request_counter).await?;
91     Ok(())
92   }
93
94   #[tracing::instrument(skip_all)]
95   async fn receive(
96     self,
97     context: &Data<LemmyContext>,
98     request_counter: &mut i32,
99   ) -> Result<(), LemmyError> {
100     let person = self
101       .actor
102       .dereference(context, local_instance(context).await, request_counter)
103       .await?;
104     let community = self
105       .object
106       .dereference(context, local_instance(context).await, request_counter)
107       .await?;
108     let community_follower_form = CommunityFollowerForm {
109       community_id: community.id,
110       person_id: person.id,
111       pending: false,
112     };
113
114     // This will fail if they're already a follower, but ignore the error.
115     CommunityFollower::follow(context.pool(), &community_follower_form)
116       .await
117       .ok();
118
119     AcceptFollowCommunity::send(self, context, request_counter).await
120   }
121 }