2 activities::{generate_activity_id, send_lemmy_activity},
4 protocol::activities::following::{accept::AcceptFollow, follow::Follow},
6 use activitypub_federation::{
8 kinds::activity::AcceptType,
9 protocol::verification::verify_urls_match,
10 traits::{ActivityHandler, Actor},
12 use lemmy_api_common::{
13 community::CommunityResponse,
14 context::LemmyContext,
16 handlers::messages::SendUserRoomMessage,
17 serialize_websocket_message,
21 use lemmy_db_schema::{
22 source::{actor_language::CommunityLanguage, community::CommunityFollower},
25 use lemmy_db_views::structs::LocalUserView;
26 use lemmy_db_views_actor::structs::CommunityView;
27 use lemmy_utils::error::LemmyError;
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 to: Some([person.id().into()]),
39 kind: AcceptType::Accept,
40 id: generate_activity_id(
42 &context.settings().get_protocol_and_hostname(),
45 let inbox = vec![person.shared_inbox_or_inbox()];
46 send_lemmy_activity(context, accept, &user_or_community, inbox, true).await
50 /// Handle accepted follows
51 #[async_trait::async_trait]
52 impl ActivityHandler for AcceptFollow {
53 type DataType = LemmyContext;
54 type Error = LemmyError;
56 fn id(&self) -> &Url {
60 fn actor(&self) -> &Url {
64 #[tracing::instrument(skip_all)]
65 async fn verify(&self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
66 verify_urls_match(self.actor.inner(), self.object.object.inner())?;
67 self.object.verify(context).await?;
68 if let Some(to) = &self.to {
69 verify_urls_match(to[0].inner(), self.object.actor.inner())?;
74 #[tracing::instrument(skip_all)]
75 async fn receive(self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
76 insert_activity(&self.id, &self, false, true, context).await?;
77 let community = self.actor.dereference(context).await?;
78 let person = self.object.actor.dereference(context).await?;
79 // This will throw an error if no follow was requested
80 let community_id = community.id;
81 let person_id = person.id;
82 CommunityFollower::follow_accepted(context.pool(), community_id, person_id).await?;
84 // Send the Subscribed message over websocket
85 // Re-read the community_view to get the new SubscribedType
87 CommunityView::read(context.pool(), community_id, Some(person_id), None).await?;
89 // Get the local_user_id
90 let local_recipient_id = LocalUserView::read_person(context.pool(), person_id)
94 let discussion_languages = CommunityLanguage::read(context.pool(), community_id).await?;
96 let res = CommunityResponse {
101 let message = serialize_websocket_message(&UserOperation::FollowCommunity, &res)?;
103 context.chat_server().do_send(SendUserRoomMessage {
104 recipient_id: local_recipient_id,