]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/following/follow.rs
Merge crates db_schema and db_queries
[lemmy.git] / crates / apub / src / activities / following / follow.rs
1 use crate::{
2   activities::{
3     following::accept::AcceptFollowCommunity,
4     generate_activity_id,
5     verify_activity,
6     verify_person,
7   },
8   context::lemmy_context,
9   fetcher::object_id::ObjectId,
10   send_lemmy_activity,
11 };
12 use activitystreams::{
13   activity::kind::FollowType,
14   base::AnyBase,
15   primitives::OneOrMany,
16   unparsed::Unparsed,
17 };
18 use lemmy_api_common::blocking;
19 use lemmy_apub_lib::{
20   data::Data,
21   traits::{ActivityFields, ActivityHandler, ActorType},
22   verify::verify_urls_match,
23 };
24 use lemmy_db_schema::{
25   source::{
26     community::{Community, CommunityFollower, CommunityFollowerForm},
27     person::Person,
28   },
29   traits::Followable,
30 };
31 use lemmy_utils::LemmyError;
32 use lemmy_websocket::LemmyContext;
33 use serde::{Deserialize, Serialize};
34 use url::Url;
35
36 #[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
37 #[serde(rename_all = "camelCase")]
38 pub struct FollowCommunity {
39   pub(in crate::activities::following) actor: ObjectId<Person>,
40   // TODO: is there any reason to put the same community id twice, in to and object?
41   pub(in crate::activities::following) to: ObjectId<Community>,
42   pub(in crate::activities::following) object: ObjectId<Community>,
43   #[serde(rename = "type")]
44   kind: FollowType,
45   id: Url,
46   #[serde(rename = "@context")]
47   context: OneOrMany<AnyBase>,
48   #[serde(flatten)]
49   unparsed: Unparsed,
50 }
51
52 impl FollowCommunity {
53   pub(in crate::activities::following) fn new(
54     actor: &Person,
55     community: &Community,
56     context: &LemmyContext,
57   ) -> Result<FollowCommunity, LemmyError> {
58     Ok(FollowCommunity {
59       actor: ObjectId::new(actor.actor_id()),
60       to: ObjectId::new(community.actor_id()),
61       object: ObjectId::new(community.actor_id()),
62       kind: FollowType::Follow,
63       id: generate_activity_id(
64         FollowType::Follow,
65         &context.settings().get_protocol_and_hostname(),
66       )?,
67       context: lemmy_context(),
68       unparsed: Default::default(),
69     })
70   }
71   pub async fn send(
72     actor: &Person,
73     community: &Community,
74     context: &LemmyContext,
75   ) -> Result<(), LemmyError> {
76     let community_follower_form = CommunityFollowerForm {
77       community_id: community.id,
78       person_id: actor.id,
79       pending: true,
80     };
81     blocking(context.pool(), move |conn| {
82       CommunityFollower::follow(conn, &community_follower_form).ok()
83     })
84     .await?;
85
86     let follow = FollowCommunity::new(actor, community, context)?;
87     let inbox = vec![community.inbox_url.clone().into()];
88     send_lemmy_activity(context, &follow, &follow.id, actor, inbox, true).await
89   }
90 }
91
92 #[async_trait::async_trait(?Send)]
93 impl ActivityHandler for FollowCommunity {
94   type DataType = LemmyContext;
95   async fn verify(
96     &self,
97     context: &Data<LemmyContext>,
98     request_counter: &mut i32,
99   ) -> Result<(), LemmyError> {
100     verify_activity(self, &context.settings())?;
101     verify_urls_match(self.to.inner(), self.object.inner())?;
102     verify_person(&self.actor, context, request_counter).await?;
103     Ok(())
104   }
105
106   async fn receive(
107     self,
108     context: &Data<LemmyContext>,
109     request_counter: &mut i32,
110   ) -> Result<(), LemmyError> {
111     let actor = self.actor.dereference(context, request_counter).await?;
112     let community = self.object.dereference(context, request_counter).await?;
113     let community_follower_form = CommunityFollowerForm {
114       community_id: community.id,
115       person_id: actor.id,
116       pending: false,
117     };
118
119     // This will fail if they're already a follower, but ignore the error.
120     blocking(context.pool(), move |conn| {
121       CommunityFollower::follow(conn, &community_follower_form).ok()
122     })
123     .await?;
124
125     AcceptFollowCommunity::send(self, context, request_counter).await
126   }
127 }