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