]> Untitled Git - lemmy.git/blob - crates/api/src/post_report.rs
e718b775a48cced4f3eb4851928ba4e546655e1c
[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 = blocking(context.pool(), move |conn| {
72       PostReport::report(conn, &report_form)
73     })
74     .await?
75     .map_err(|_| ApiError::err("couldnt_create_report"))?;
76
77     let res = CreatePostReportResponse { success: true };
78
79     context.chat_server().do_send(SendUserRoomMessage {
80       op: UserOperation::CreatePostReport,
81       response: res.clone(),
82       local_recipient_id: local_user_view.local_user.id,
83       websocket_id,
84     });
85
86     context.chat_server().do_send(SendModRoomMessage {
87       op: UserOperation::CreatePostReport,
88       response: report,
89       community_id: post_view.community.id,
90       websocket_id,
91     });
92
93     Ok(res)
94   }
95 }
96
97 /// Resolves or unresolves a post report and notifies the moderators of the community
98 #[async_trait::async_trait(?Send)]
99 impl Perform for ResolvePostReport {
100   type Response = ResolvePostReportResponse;
101
102   async fn perform(
103     &self,
104     context: &Data<LemmyContext>,
105     websocket_id: Option<ConnectionId>,
106   ) -> Result<ResolvePostReportResponse, LemmyError> {
107     let data: &ResolvePostReport = self;
108     let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
109
110     let report_id = data.report_id;
111     let report = blocking(context.pool(), move |conn| {
112       PostReportView::read(conn, report_id)
113     })
114     .await??;
115
116     let person_id = local_user_view.person.id;
117     is_mod_or_admin(context.pool(), person_id, report.community.id).await?;
118
119     let resolved = data.resolved;
120     let resolve_fun = move |conn: &'_ _| {
121       if resolved {
122         PostReport::resolve(conn, report_id, person_id)
123       } else {
124         PostReport::unresolve(conn, report_id, person_id)
125       }
126     };
127
128     let res = ResolvePostReportResponse {
129       report_id,
130       resolved: true,
131     };
132
133     if blocking(context.pool(), resolve_fun).await?.is_err() {
134       return Err(ApiError::err("couldnt_resolve_report").into());
135     };
136
137     context.chat_server().do_send(SendModRoomMessage {
138       op: UserOperation::ResolvePostReport,
139       response: res.clone(),
140       community_id: report.community.id,
141       websocket_id,
142     });
143
144     Ok(res)
145   }
146 }
147
148 /// Lists post reports for a community if an id is supplied
149 /// or returns all post reports for communities a user moderates
150 #[async_trait::async_trait(?Send)]
151 impl Perform for ListPostReports {
152   type Response = ListPostReportsResponse;
153
154   async fn perform(
155     &self,
156     context: &Data<LemmyContext>,
157     websocket_id: Option<ConnectionId>,
158   ) -> Result<ListPostReportsResponse, LemmyError> {
159     let data: &ListPostReports = self;
160     let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
161
162     let person_id = local_user_view.person.id;
163     let community_id = data.community;
164     let community_ids =
165       collect_moderated_communities(person_id, community_id, context.pool()).await?;
166
167     let page = data.page;
168     let limit = data.limit;
169     let posts = blocking(context.pool(), move |conn| {
170       PostReportQueryBuilder::create(conn)
171         .community_ids(community_ids)
172         .page(page)
173         .limit(limit)
174         .list()
175     })
176     .await??;
177
178     let res = ListPostReportsResponse { posts };
179
180     context.chat_server().do_send(SendUserRoomMessage {
181       op: UserOperation::ListPostReports,
182       response: res.clone(),
183       local_recipient_id: local_user_view.local_user.id,
184       websocket_id,
185     });
186
187     Ok(res)
188   }
189 }