]> Untitled Git - lemmy.git/blob - crates/api/src/community/follow.rs
Split apart api files (#2216)
[lemmy.git] / crates / api / src / community / follow.rs
1 use crate::Perform;
2 use actix_web::web::Data;
3 use lemmy_api_common::{
4   blocking,
5   check_community_ban,
6   check_community_deleted_or_removed,
7   community::{CommunityResponse, FollowCommunity},
8   get_local_user_view_from_jwt,
9 };
10 use lemmy_apub::{
11   objects::community::ApubCommunity,
12   protocol::activities::following::{
13     follow::FollowCommunity as FollowCommunityApub,
14     undo_follow::UndoFollowCommunity,
15   },
16 };
17 use lemmy_db_schema::{
18   source::community::{Community, CommunityFollower, CommunityFollowerForm},
19   traits::{Crud, Followable},
20 };
21 use lemmy_db_views_actor::community_view::CommunityView;
22 use lemmy_utils::{ConnectionId, LemmyError};
23 use lemmy_websocket::LemmyContext;
24
25 #[async_trait::async_trait(?Send)]
26 impl Perform for FollowCommunity {
27   type Response = CommunityResponse;
28
29   #[tracing::instrument(skip(context, _websocket_id))]
30   async fn perform(
31     &self,
32     context: &Data<LemmyContext>,
33     _websocket_id: Option<ConnectionId>,
34   ) -> Result<CommunityResponse, LemmyError> {
35     let data: &FollowCommunity = self;
36     let local_user_view =
37       get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
38
39     let community_id = data.community_id;
40     let community: ApubCommunity = blocking(context.pool(), move |conn| {
41       Community::read(conn, community_id)
42     })
43     .await??
44     .into();
45     let community_follower_form = CommunityFollowerForm {
46       community_id: data.community_id,
47       person_id: local_user_view.person.id,
48       pending: false,
49     };
50
51     if community.local {
52       if data.follow {
53         check_community_ban(local_user_view.person.id, community_id, context.pool()).await?;
54         check_community_deleted_or_removed(community_id, context.pool()).await?;
55
56         let follow = move |conn: &'_ _| CommunityFollower::follow(conn, &community_follower_form);
57         blocking(context.pool(), follow)
58           .await?
59           .map_err(|e| LemmyError::from_error_message(e, "community_follower_already_exists"))?;
60       } else {
61         let unfollow =
62           move |conn: &'_ _| CommunityFollower::unfollow(conn, &community_follower_form);
63         blocking(context.pool(), unfollow)
64           .await?
65           .map_err(|e| LemmyError::from_error_message(e, "community_follower_already_exists"))?;
66       }
67     } else if data.follow {
68       // Dont actually add to the community followers here, because you need
69       // to wait for the accept
70       FollowCommunityApub::send(&local_user_view.person.clone().into(), &community, context)
71         .await?;
72     } else {
73       UndoFollowCommunity::send(&local_user_view.person.clone().into(), &community, context)
74         .await?;
75       let unfollow = move |conn: &'_ _| CommunityFollower::unfollow(conn, &community_follower_form);
76       blocking(context.pool(), unfollow)
77         .await?
78         .map_err(|e| LemmyError::from_error_message(e, "community_follower_already_exists"))?;
79     }
80
81     let community_id = data.community_id;
82     let person_id = local_user_view.person.id;
83     let mut community_view = blocking(context.pool(), move |conn| {
84       CommunityView::read(conn, community_id, Some(person_id))
85     })
86     .await??;
87
88     // TODO: this needs to return a "pending" state, until Accept is received from the remote server
89     // For now, just assume that remote follows are accepted.
90     // Otherwise, the subscribed will be null
91     if !community.local {
92       community_view.subscribed = data.follow;
93     }
94
95     Ok(CommunityResponse { community_view })
96   }
97 }