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