]> Untitled Git - lemmy.git/blob - crates/api/src/post_report.rs
Merge branch 'remove_settings_and_secret_singletons_squashed'
[lemmy.git] / crates / api / src / post_report.rs
1 use crate::Perform;
2 use actix_web::web::Data;
3 use lemmy_api_common::{
4   blocking,
5   check_community_ban,
6   collect_moderated_communities,
7   get_local_user_view_from_jwt,
8   is_mod_or_admin,
9   post::{
10     CreatePostReport,
11     CreatePostReportResponse,
12     ListPostReports,
13     ListPostReportsResponse,
14     ResolvePostReport,
15     ResolvePostReportResponse,
16   },
17 };
18 use lemmy_db_queries::Reportable;
19 use lemmy_db_schema::source::post_report::{PostReport, PostReportForm};
20 use lemmy_db_views::{
21   post_report_view::{PostReportQueryBuilder, PostReportView},
22   post_view::PostView,
23 };
24 use lemmy_utils::{ApiError, ConnectionId, LemmyError};
25 use lemmy_websocket::{
26   messages::{SendModRoomMessage, SendUserRoomMessage},
27   LemmyContext,
28   UserOperation,
29 };
30
31 /// Creates a post report and notifies the moderators of the community
32 #[async_trait::async_trait(?Send)]
33 impl Perform for CreatePostReport {
34   type Response = CreatePostReportResponse;
35
36   async fn perform(
37     &self,
38     context: &Data<LemmyContext>,
39     websocket_id: Option<ConnectionId>,
40   ) -> Result<CreatePostReportResponse, LemmyError> {
41     let data: &CreatePostReport = self;
42     let local_user_view =
43       get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
44
45     // check size of report and check for whitespace
46     let reason = data.reason.trim();
47     if reason.is_empty() {
48       return Err(ApiError::err("report_reason_required").into());
49     }
50     if reason.chars().count() > 1000 {
51       return Err(ApiError::err("report_too_long").into());
52     }
53
54     let person_id = local_user_view.person.id;
55     let post_id = data.post_id;
56     let post_view = blocking(context.pool(), move |conn| {
57       PostView::read(conn, post_id, None)
58     })
59     .await??;
60
61     check_community_ban(person_id, post_view.community.id, context.pool()).await?;
62
63     let report_form = PostReportForm {
64       creator_id: person_id,
65       post_id,
66       original_post_name: post_view.post.name,
67       original_post_url: post_view.post.url,
68       original_post_body: post_view.post.body,
69       reason: data.reason.to_owned(),
70     };
71
72     let report = blocking(context.pool(), move |conn| {
73       PostReport::report(conn, &report_form)
74     })
75     .await?
76     .map_err(|_| ApiError::err("couldnt_create_report"))?;
77
78     let res = CreatePostReportResponse { success: true };
79
80     context.chat_server().do_send(SendUserRoomMessage {
81       op: UserOperation::CreatePostReport,
82       response: res.clone(),
83       local_recipient_id: local_user_view.local_user.id,
84       websocket_id,
85     });
86
87     context.chat_server().do_send(SendModRoomMessage {
88       op: UserOperation::CreatePostReport,
89       response: report,
90       community_id: post_view.community.id,
91       websocket_id,
92     });
93
94     Ok(res)
95   }
96 }
97
98 /// Resolves or unresolves a post report and notifies the moderators of the community
99 #[async_trait::async_trait(?Send)]
100 impl Perform for ResolvePostReport {
101   type Response = ResolvePostReportResponse;
102
103   async fn perform(
104     &self,
105     context: &Data<LemmyContext>,
106     websocket_id: Option<ConnectionId>,
107   ) -> Result<ResolvePostReportResponse, LemmyError> {
108     let data: &ResolvePostReport = self;
109     let local_user_view =
110       get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
111
112     let report_id = data.report_id;
113     let report = blocking(context.pool(), move |conn| {
114       PostReportView::read(conn, report_id)
115     })
116     .await??;
117
118     let person_id = local_user_view.person.id;
119     is_mod_or_admin(context.pool(), person_id, report.community.id).await?;
120
121     let resolved = data.resolved;
122     let resolve_fun = move |conn: &'_ _| {
123       if resolved {
124         PostReport::resolve(conn, report_id, person_id)
125       } else {
126         PostReport::unresolve(conn, report_id, person_id)
127       }
128     };
129
130     let res = ResolvePostReportResponse {
131       report_id,
132       resolved: true,
133     };
134
135     if blocking(context.pool(), resolve_fun).await?.is_err() {
136       return Err(ApiError::err("couldnt_resolve_report").into());
137     };
138
139     context.chat_server().do_send(SendModRoomMessage {
140       op: UserOperation::ResolvePostReport,
141       response: res.clone(),
142       community_id: report.community.id,
143       websocket_id,
144     });
145
146     Ok(res)
147   }
148 }
149
150 /// Lists post reports for a community if an id is supplied
151 /// or returns all post reports for communities a user moderates
152 #[async_trait::async_trait(?Send)]
153 impl Perform for ListPostReports {
154   type Response = ListPostReportsResponse;
155
156   async fn perform(
157     &self,
158     context: &Data<LemmyContext>,
159     websocket_id: Option<ConnectionId>,
160   ) -> Result<ListPostReportsResponse, LemmyError> {
161     let data: &ListPostReports = self;
162     let local_user_view =
163       get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
164
165     let person_id = local_user_view.person.id;
166     let community_id = data.community;
167     let community_ids =
168       collect_moderated_communities(person_id, community_id, context.pool()).await?;
169
170     let page = data.page;
171     let limit = data.limit;
172     let posts = blocking(context.pool(), move |conn| {
173       PostReportQueryBuilder::create(conn)
174         .community_ids(community_ids)
175         .page(page)
176         .limit(limit)
177         .list()
178     })
179     .await??;
180
181     let res = ListPostReportsResponse { posts };
182
183     context.chat_server().do_send(SendUserRoomMessage {
184       op: UserOperation::ListPostReports,
185       response: res.clone(),
186       local_recipient_id: local_user_view.local_user.id,
187       websocket_id,
188     });
189
190     Ok(res)
191   }
192 }