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