]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/following/accept.rs
Moving settings to Database. (#2492)
[lemmy.git] / crates / apub / src / activities / following / accept.rs
1 use crate::{
2   activities::{generate_activity_id, send_lemmy_activity},
3   check_apub_id_valid,
4   fetch_local_site_data,
5   local_instance,
6   protocol::activities::following::{accept::AcceptFollowCommunity, follow::FollowCommunity},
7   ActorType,
8 };
9 use activitypub_federation::{
10   core::object_id::ObjectId,
11   data::Data,
12   traits::{ActivityHandler, Actor},
13   utils::verify_urls_match,
14 };
15 use activitystreams_kinds::activity::AcceptType;
16 use lemmy_api_common::{community::CommunityResponse, utils::blocking};
17 use lemmy_db_schema::{source::community::CommunityFollower, traits::Followable};
18 use lemmy_db_views::structs::LocalUserView;
19 use lemmy_db_views_actor::structs::CommunityView;
20 use lemmy_utils::error::LemmyError;
21 use lemmy_websocket::{messages::SendUserRoomMessage, LemmyContext, UserOperation};
22 use url::Url;
23
24 impl AcceptFollowCommunity {
25   #[tracing::instrument(skip_all)]
26   pub async fn send(
27     follow: FollowCommunity,
28     context: &LemmyContext,
29     request_counter: &mut i32,
30   ) -> Result<(), LemmyError> {
31     let community = follow.object.dereference_local(context).await?;
32     let person = follow
33       .actor
34       .clone()
35       .dereference(context, local_instance(context), request_counter)
36       .await?;
37     let accept = AcceptFollowCommunity {
38       actor: ObjectId::new(community.actor_id()),
39       object: follow,
40       kind: AcceptType::Accept,
41       id: generate_activity_id(
42         AcceptType::Accept,
43         &context.settings().get_protocol_and_hostname(),
44       )?,
45       unparsed: Default::default(),
46     };
47     let inbox = vec![person.shared_inbox_or_inbox()];
48     send_lemmy_activity(context, accept, &community, inbox, true).await
49   }
50 }
51
52 /// Handle accepted follows
53 #[async_trait::async_trait(?Send)]
54 impl ActivityHandler for AcceptFollowCommunity {
55   type DataType = LemmyContext;
56   type Error = LemmyError;
57
58   fn id(&self) -> &Url {
59     &self.id
60   }
61
62   fn actor(&self) -> &Url {
63     self.actor.inner()
64   }
65
66   #[tracing::instrument(skip_all)]
67   async fn verify(
68     &self,
69     context: &Data<LemmyContext>,
70     request_counter: &mut i32,
71   ) -> Result<(), LemmyError> {
72     let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
73     check_apub_id_valid(self.id(), &local_site_data, context.settings())
74       .map_err(LemmyError::from_message)?;
75
76     verify_urls_match(self.actor.inner(), self.object.object.inner())?;
77     self.object.verify(context, request_counter).await?;
78     Ok(())
79   }
80
81   #[tracing::instrument(skip_all)]
82   async fn receive(
83     self,
84     context: &Data<LemmyContext>,
85     request_counter: &mut i32,
86   ) -> Result<(), LemmyError> {
87     let community = self
88       .actor
89       .dereference(context, local_instance(context), request_counter)
90       .await?;
91     let person = self
92       .object
93       .actor
94       .dereference(context, local_instance(context), request_counter)
95       .await?;
96     // This will throw an error if no follow was requested
97     let community_id = community.id;
98     let person_id = person.id;
99     blocking(context.pool(), move |conn| {
100       CommunityFollower::follow_accepted(conn, community_id, person_id)
101     })
102     .await??;
103
104     // Send the Subscribed message over websocket
105     // Re-read the community_view to get the new SubscribedType
106     let community_view = blocking(context.pool(), move |conn| {
107       CommunityView::read(conn, community_id, Some(person_id))
108     })
109     .await??;
110
111     // Get the local_user_id
112     let local_recipient_id = blocking(context.pool(), move |conn| {
113       LocalUserView::read_person(conn, person_id)
114     })
115     .await??
116     .local_user
117     .id;
118
119     let response = CommunityResponse { community_view };
120
121     context.chat_server().do_send(SendUserRoomMessage {
122       op: UserOperation::FollowCommunity,
123       response,
124       local_recipient_id,
125       websocket_id: None,
126     });
127
128     Ok(())
129   }
130 }