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