]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/following/follow.rs
Move ObjectId to library
[lemmy.git] / crates / apub / src / activities / following / follow.rs
1 use crate::{
2   activities::{
3     generate_activity_id,
4     send_lemmy_activity,
5     verify_activity,
6     verify_person,
7     verify_person_in_community,
8   },
9   objects::{community::ApubCommunity, person::ApubPerson},
10   protocol::activities::following::{accept::AcceptFollowCommunity, follow::FollowCommunity},
11 };
12 use activitystreams::activity::kind::FollowType;
13 use lemmy_api_common::blocking;
14 use lemmy_apub_lib::{
15   data::Data,
16   object_id::ObjectId,
17   traits::{ActivityHandler, ActorType},
18   verify::verify_urls_match,
19 };
20 use lemmy_db_schema::{
21   source::community::{CommunityFollower, CommunityFollowerForm},
22   traits::Followable,
23 };
24 use lemmy_utils::LemmyError;
25 use lemmy_websocket::LemmyContext;
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       to: [ObjectId::new(community.actor_id())],
36       object: ObjectId::new(community.actor_id()),
37       kind: FollowType::Follow,
38       id: generate_activity_id(
39         FollowType::Follow,
40         &context.settings().get_protocol_and_hostname(),
41       )?,
42       unparsed: Default::default(),
43     })
44   }
45   pub async fn send(
46     actor: &ApubPerson,
47     community: &ApubCommunity,
48     context: &LemmyContext,
49   ) -> Result<(), LemmyError> {
50     let community_follower_form = CommunityFollowerForm {
51       community_id: community.id,
52       person_id: actor.id,
53       pending: true,
54     };
55     blocking(context.pool(), move |conn| {
56       CommunityFollower::follow(conn, &community_follower_form).ok()
57     })
58     .await?;
59
60     let follow = FollowCommunity::new(actor, community, context)?;
61     let inbox = vec![community.inbox_url.clone().into()];
62     send_lemmy_activity(context, &follow, &follow.id, actor, inbox, true).await
63   }
64 }
65
66 #[async_trait::async_trait(?Send)]
67 impl ActivityHandler for FollowCommunity {
68   type DataType = LemmyContext;
69   async fn verify(
70     &self,
71     context: &Data<LemmyContext>,
72     request_counter: &mut i32,
73   ) -> Result<(), LemmyError> {
74     verify_activity(&self.id, self.actor.inner(), &context.settings())?;
75     verify_urls_match(self.to[0].inner(), self.object.inner())?;
76     verify_person(&self.actor, context, request_counter).await?;
77     let community = self.to[0].dereference(context, request_counter).await?;
78     verify_person_in_community(&self.actor, &community, context, request_counter).await?;
79     Ok(())
80   }
81
82   async fn receive(
83     self,
84     context: &Data<LemmyContext>,
85     request_counter: &mut i32,
86   ) -> Result<(), LemmyError> {
87     let actor = self.actor.dereference(context, request_counter).await?;
88     let community = self.to[0].dereference(context, request_counter).await?;
89     let community_follower_form = CommunityFollowerForm {
90       community_id: community.id,
91       person_id: actor.id,
92       pending: false,
93     };
94
95     // This will fail if they're already a follower, but ignore the error.
96     blocking(context.pool(), move |conn| {
97       CommunityFollower::follow(conn, &community_follower_form).ok()
98     })
99     .await?;
100
101     AcceptFollowCommunity::send(self, context, request_counter).await
102   }
103 }