]> Untitled Git - lemmy.git/blob - crates/api/src/community/ban.rs
Split apart api files (#2216)
[lemmy.git] / crates / api / src / community / ban.rs
1 use crate::Perform;
2 use actix_web::web::Data;
3 use lemmy_api_common::{
4   blocking,
5   community::{BanFromCommunity, BanFromCommunityResponse},
6   get_local_user_view_from_jwt,
7   is_mod_or_admin,
8   remove_user_data_in_community,
9 };
10 use lemmy_apub::{
11   activities::block::SiteOrCommunity,
12   objects::{community::ApubCommunity, person::ApubPerson},
13   protocol::activities::block::{block_user::BlockUser, undo_block_user::UndoBlockUser},
14 };
15 use lemmy_db_schema::{
16   source::{
17     community::{
18       Community,
19       CommunityFollower,
20       CommunityFollowerForm,
21       CommunityPersonBan,
22       CommunityPersonBanForm,
23     },
24     moderator::{ModBanFromCommunity, ModBanFromCommunityForm},
25     person::Person,
26   },
27   traits::{Bannable, Crud, Followable},
28 };
29 use lemmy_db_views_actor::person_view::PersonViewSafe;
30 use lemmy_utils::{utils::naive_from_unix, ConnectionId, LemmyError};
31 use lemmy_websocket::{messages::SendCommunityRoomMessage, LemmyContext, UserOperation};
32
33 #[async_trait::async_trait(?Send)]
34 impl Perform for BanFromCommunity {
35   type Response = BanFromCommunityResponse;
36
37   #[tracing::instrument(skip(context, websocket_id))]
38   async fn perform(
39     &self,
40     context: &Data<LemmyContext>,
41     websocket_id: Option<ConnectionId>,
42   ) -> Result<BanFromCommunityResponse, LemmyError> {
43     let data: &BanFromCommunity = self;
44     let local_user_view =
45       get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
46
47     let community_id = data.community_id;
48     let banned_person_id = data.person_id;
49     let remove_data = data.remove_data.unwrap_or(false);
50     let expires = data.expires.map(naive_from_unix);
51
52     // Verify that only mods or admins can ban
53     is_mod_or_admin(context.pool(), local_user_view.person.id, community_id).await?;
54
55     let community_user_ban_form = CommunityPersonBanForm {
56       community_id: data.community_id,
57       person_id: data.person_id,
58       expires: Some(expires),
59     };
60
61     let community: ApubCommunity = blocking(context.pool(), move |conn: &'_ _| {
62       Community::read(conn, community_id)
63     })
64     .await??
65     .into();
66     let banned_person: ApubPerson = blocking(context.pool(), move |conn: &'_ _| {
67       Person::read(conn, banned_person_id)
68     })
69     .await??
70     .into();
71
72     if data.ban {
73       let ban = move |conn: &'_ _| CommunityPersonBan::ban(conn, &community_user_ban_form);
74       blocking(context.pool(), ban)
75         .await?
76         .map_err(|e| LemmyError::from_error_message(e, "community_user_already_banned"))?;
77
78       // Also unsubscribe them from the community, if they are subscribed
79       let community_follower_form = CommunityFollowerForm {
80         community_id: data.community_id,
81         person_id: banned_person_id,
82         pending: false,
83       };
84       blocking(context.pool(), move |conn: &'_ _| {
85         CommunityFollower::unfollow(conn, &community_follower_form)
86       })
87       .await?
88       .ok();
89
90       BlockUser::send(
91         &SiteOrCommunity::Community(community),
92         &banned_person,
93         &local_user_view.person.clone().into(),
94         remove_data,
95         data.reason.clone(),
96         expires,
97         context,
98       )
99       .await?;
100     } else {
101       let unban = move |conn: &'_ _| CommunityPersonBan::unban(conn, &community_user_ban_form);
102       blocking(context.pool(), unban)
103         .await?
104         .map_err(|e| LemmyError::from_error_message(e, "community_user_already_banned"))?;
105       UndoBlockUser::send(
106         &SiteOrCommunity::Community(community),
107         &banned_person,
108         &local_user_view.person.clone().into(),
109         data.reason.clone(),
110         context,
111       )
112       .await?;
113     }
114
115     // Remove/Restore their data if that's desired
116     if remove_data {
117       remove_user_data_in_community(community_id, banned_person_id, context.pool()).await?;
118     }
119
120     // Mod tables
121     let form = ModBanFromCommunityForm {
122       mod_person_id: local_user_view.person.id,
123       other_person_id: data.person_id,
124       community_id: data.community_id,
125       reason: data.reason.to_owned(),
126       banned: Some(data.ban),
127       expires,
128     };
129     blocking(context.pool(), move |conn| {
130       ModBanFromCommunity::create(conn, &form)
131     })
132     .await??;
133
134     let person_id = data.person_id;
135     let person_view = blocking(context.pool(), move |conn| {
136       PersonViewSafe::read(conn, person_id)
137     })
138     .await??;
139
140     let res = BanFromCommunityResponse {
141       person_view,
142       banned: data.ban,
143     };
144
145     context.chat_server().do_send(SendCommunityRoomMessage {
146       op: UserOperation::BanFromCommunity,
147       response: res.clone(),
148       community_id,
149       websocket_id,
150     });
151
152     Ok(res)
153   }
154 }