]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/following/accept.rs
Add SendActivity trait so that api crates compile in parallel with lemmy_apub
[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::AcceptFollow, follow::Follow},
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::{
15   community::CommunityResponse,
16   context::LemmyContext,
17   websocket::{messages::SendUserRoomMessage, UserOperation},
18 };
19 use lemmy_db_schema::{source::community::CommunityFollower, traits::Followable};
20 use lemmy_db_views::structs::LocalUserView;
21 use lemmy_db_views_actor::structs::CommunityView;
22 use lemmy_utils::error::LemmyError;
23 use url::Url;
24
25 impl AcceptFollow {
26   #[tracing::instrument(skip_all)]
27   pub async fn send(
28     follow: Follow,
29     context: &LemmyContext,
30     request_counter: &mut i32,
31   ) -> Result<(), LemmyError> {
32     let user_or_community = follow.object.dereference_local(context).await?;
33     let person = follow
34       .actor
35       .clone()
36       .dereference(context, local_instance(context).await, request_counter)
37       .await?;
38     let accept = AcceptFollow {
39       actor: ObjectId::new(user_or_community.actor_id()),
40       object: follow,
41       kind: AcceptType::Accept,
42       id: generate_activity_id(
43         AcceptType::Accept,
44         &context.settings().get_protocol_and_hostname(),
45       )?,
46     };
47     let inbox = vec![person.shared_inbox_or_inbox()];
48     send_lemmy_activity(context, accept, &user_or_community, inbox, true).await
49   }
50 }
51
52 /// Handle accepted follows
53 #[async_trait::async_trait(?Send)]
54 impl ActivityHandler for AcceptFollow {
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     verify_urls_match(self.actor.inner(), self.object.object.inner())?;
73     self.object.verify(context, request_counter).await?;
74     Ok(())
75   }
76
77   #[tracing::instrument(skip_all)]
78   async fn receive(
79     self,
80     context: &Data<LemmyContext>,
81     request_counter: &mut i32,
82   ) -> Result<(), LemmyError> {
83     let community = self
84       .actor
85       .dereference(context, local_instance(context).await, request_counter)
86       .await?;
87     let person = self
88       .object
89       .actor
90       .dereference(context, local_instance(context).await, request_counter)
91       .await?;
92     // This will throw an error if no follow was requested
93     let community_id = community.id;
94     let person_id = person.id;
95     CommunityFollower::follow_accepted(context.pool(), community_id, person_id).await?;
96
97     // Send the Subscribed message over websocket
98     // Re-read the community_view to get the new SubscribedType
99     let community_view = CommunityView::read(context.pool(), community_id, Some(person_id)).await?;
100
101     // Get the local_user_id
102     let local_recipient_id = LocalUserView::read_person(context.pool(), person_id)
103       .await?
104       .local_user
105       .id;
106
107     let response = CommunityResponse { community_view };
108
109     context.chat_server().do_send(SendUserRoomMessage {
110       op: UserOperation::FollowCommunity,
111       response,
112       local_recipient_id,
113       websocket_id: None,
114     });
115
116     Ok(())
117   }
118 }