]> Untitled Git - lemmy.git/blob - crates/api/src/post_report.rs
Split api crate into api_structs and api
[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 = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
43
44     // check size of report and check for whitespace
45     let reason = data.reason.trim();
46     if reason.is_empty() {
47       return Err(ApiError::err("report_reason_required").into());
48     }
49     if reason.chars().count() > 1000 {
50       return Err(ApiError::err("report_too_long").into());
51     }
52
53     let person_id = local_user_view.person.id;
54     let post_id = data.post_id;
55     let post_view = blocking(context.pool(), move |conn| {
56       PostView::read(&conn, post_id, None)
57     })
58     .await??;
59
60     check_community_ban(person_id, post_view.community.id, context.pool()).await?;
61
62     let report_form = PostReportForm {
63       creator_id: person_id,
64       post_id,
65       original_post_name: post_view.post.name,
66       original_post_url: post_view.post.url,
67       original_post_body: post_view.post.body,
68       reason: data.reason.to_owned(),
69     };
70
71     let report = match blocking(context.pool(), move |conn| {
72       PostReport::report(conn, &report_form)
73     })
74     .await?
75     {
76       Ok(report) => report,
77       Err(_e) => return Err(ApiError::err("couldnt_create_report").into()),
78     };
79
80     let res = CreatePostReportResponse { success: true };
81
82     context.chat_server().do_send(SendUserRoomMessage {
83       op: UserOperation::CreatePostReport,
84       response: res.clone(),
85       local_recipient_id: local_user_view.local_user.id,
86       websocket_id,
87     });
88
89     context.chat_server().do_send(SendModRoomMessage {
90       op: UserOperation::CreatePostReport,
91       response: report,
92       community_id: post_view.community.id,
93       websocket_id,
94     });
95
96     Ok(res)
97   }
98 }
99
100 /// Resolves or unresolves a post report and notifies the moderators of the community
101 #[async_trait::async_trait(?Send)]
102 impl Perform for ResolvePostReport {
103   type Response = ResolvePostReportResponse;
104
105   async fn perform(
106     &self,
107     context: &Data<LemmyContext>,
108     websocket_id: Option<ConnectionId>,
109   ) -> Result<ResolvePostReportResponse, LemmyError> {
110     let data: &ResolvePostReport = &self;
111     let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
112
113     let report_id = data.report_id;
114     let report = blocking(context.pool(), move |conn| {
115       PostReportView::read(&conn, report_id)
116     })
117     .await??;
118
119     let person_id = local_user_view.person.id;
120     is_mod_or_admin(context.pool(), person_id, report.community.id).await?;
121
122     let resolved = data.resolved;
123     let resolve_fun = move |conn: &'_ _| {
124       if resolved {
125         PostReport::resolve(conn, report_id, person_id)
126       } else {
127         PostReport::unresolve(conn, report_id, person_id)
128       }
129     };
130
131     let res = ResolvePostReportResponse {
132       report_id,
133       resolved: true,
134     };
135
136     if blocking(context.pool(), resolve_fun).await?.is_err() {
137       return Err(ApiError::err("couldnt_resolve_report").into());
138     };
139
140     context.chat_server().do_send(SendModRoomMessage {
141       op: UserOperation::ResolvePostReport,
142       response: res.clone(),
143       community_id: report.community.id,
144       websocket_id,
145     });
146
147     Ok(res)
148   }
149 }
150
151 /// Lists post reports for a community if an id is supplied
152 /// or returns all post reports for communities a user moderates
153 #[async_trait::async_trait(?Send)]
154 impl Perform for ListPostReports {
155   type Response = ListPostReportsResponse;
156
157   async fn perform(
158     &self,
159     context: &Data<LemmyContext>,
160     websocket_id: Option<ConnectionId>,
161   ) -> Result<ListPostReportsResponse, LemmyError> {
162     let data: &ListPostReports = &self;
163     let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).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 }