1 use diesel::{result::Error, *};
2 use lemmy_db_queries::{
3 aggregates::post_aggregates::PostAggregates,
23 community::{Community, CommunityPersonBan, CommunitySafe},
24 person::{Person, PersonAlias1, PersonAlias2, PersonSafe, PersonSafeAlias1, PersonSafeAlias2},
26 post_report::PostReport,
34 #[derive(Debug, PartialEq, Serialize, Clone)]
35 pub struct PostReportView {
36 pub post_report: PostReport,
38 pub community: CommunitySafe,
39 pub creator: PersonSafe,
40 pub post_creator: PersonSafeAlias1,
41 pub creator_banned_from_community: bool,
42 pub my_vote: Option<i16>,
43 pub counts: PostAggregates,
44 pub resolver: Option<PersonSafeAlias2>,
47 type PostReportViewTuple = (
53 Option<CommunityPersonBan>,
56 Option<PersonSafeAlias2>,
60 /// returns the PostReportView for the provided report_id
62 /// * `report_id` - the report id to obtain
65 report_id: PostReportId,
66 my_person_id: PersonId,
67 ) -> Result<Self, Error> {
74 creator_banned_from_community,
78 ) = post_report::table
80 .inner_join(post::table)
81 .inner_join(community::table.on(post::community_id.eq(community::id)))
82 .inner_join(person::table.on(post_report::creator_id.eq(person::id)))
83 .inner_join(person_alias_1::table.on(post::creator_id.eq(person_alias_1::id)))
85 community_person_ban::table.on(
87 .eq(community_person_ban::community_id)
88 .and(community_person_ban::person_id.eq(post::creator_id)),
94 .eq(post_like::post_id)
95 .and(post_like::person_id.eq(my_person_id)),
98 .inner_join(post_aggregates::table.on(post_report::post_id.eq(post_aggregates::post_id)))
100 person_alias_2::table.on(post_report::resolver_id.eq(person_alias_2::id.nullable())),
103 post_report::all_columns,
105 Community::safe_columns_tuple(),
106 Person::safe_columns_tuple(),
107 PersonAlias1::safe_columns_tuple(),
108 community_person_ban::all_columns.nullable(),
109 post_like::score.nullable(),
110 post_aggregates::all_columns,
111 PersonAlias2::safe_columns_tuple().nullable(),
113 .first::<PostReportViewTuple>(conn)?;
115 let my_vote = if post_like.is_none() { None } else { post_like };
123 creator_banned_from_community: creator_banned_from_community.is_some(),
130 /// returns the current unresolved post report count for the communities you mod
131 pub fn get_report_count(
133 my_person_id: PersonId,
135 community_id: Option<CommunityId>,
136 ) -> Result<i64, Error> {
138 let mut query = post_report::table
139 .inner_join(post::table)
142 community_moderator::table.on(community_moderator::community_id.eq(post::community_id)),
144 .filter(post_report::resolved.eq(false))
147 // If its not an admin, get only the ones you mod
149 query = query.filter(community_moderator::person_id.eq(my_person_id));
152 if let Some(community_id) = community_id {
153 query = query.filter(post::community_id.eq(community_id))
156 query.select(count(post_report::id)).first::<i64>(conn)
160 pub struct PostReportQueryBuilder<'a> {
161 conn: &'a PgConnection,
162 my_person_id: PersonId,
164 community_id: Option<CommunityId>,
167 unresolved_only: Option<bool>,
170 impl<'a> PostReportQueryBuilder<'a> {
171 pub fn create(conn: &'a PgConnection, my_person_id: PersonId, admin: bool) -> Self {
172 PostReportQueryBuilder {
179 unresolved_only: Some(true),
183 pub fn community_id<T: MaybeOptional<CommunityId>>(mut self, community_id: T) -> Self {
184 self.community_id = community_id.get_optional();
188 pub fn page<T: MaybeOptional<i64>>(mut self, page: T) -> Self {
189 self.page = page.get_optional();
193 pub fn limit<T: MaybeOptional<i64>>(mut self, limit: T) -> Self {
194 self.limit = limit.get_optional();
198 pub fn unresolved_only<T: MaybeOptional<bool>>(mut self, unresolved_only: T) -> Self {
199 self.unresolved_only = unresolved_only.get_optional();
203 pub fn list(self) -> Result<Vec<PostReportView>, Error> {
204 let mut query = post_report::table
205 .inner_join(post::table)
206 .inner_join(community::table.on(post::community_id.eq(community::id)))
207 .inner_join(person::table.on(post_report::creator_id.eq(person::id)))
208 .inner_join(person_alias_1::table.on(post::creator_id.eq(person_alias_1::id)))
210 community_moderator::table.on(community_moderator::community_id.eq(post::community_id)),
213 community_person_ban::table.on(
215 .eq(community_person_ban::community_id)
216 .and(community_person_ban::person_id.eq(post::creator_id)),
222 .eq(post_like::post_id)
223 .and(post_like::person_id.eq(self.my_person_id)),
226 .inner_join(post_aggregates::table.on(post_report::post_id.eq(post_aggregates::post_id)))
228 person_alias_2::table.on(post_report::resolver_id.eq(person_alias_2::id.nullable())),
231 post_report::all_columns,
233 Community::safe_columns_tuple(),
234 Person::safe_columns_tuple(),
235 PersonAlias1::safe_columns_tuple(),
236 community_person_ban::all_columns.nullable(),
237 post_like::score.nullable(),
238 post_aggregates::all_columns,
239 PersonAlias2::safe_columns_tuple().nullable(),
243 // If its not an admin, get only the ones you mod
245 query = query.filter(community_moderator::person_id.eq(self.my_person_id));
248 if let Some(community_id) = self.community_id {
249 query = query.filter(post::community_id.eq(community_id));
252 if self.unresolved_only.unwrap_or(false) {
253 query = query.filter(post_report::resolved.eq(false));
256 let (limit, offset) = limit_and_offset(self.page, self.limit);
259 .order_by(post_report::published.asc())
262 .load::<PostReportViewTuple>(self.conn)?;
264 Ok(PostReportView::from_tuple_to_vec(res))
268 impl ViewToVec for PostReportView {
269 type DbTuple = PostReportViewTuple;
270 fn from_tuple_to_vec(items: Vec<Self::DbTuple>) -> Vec<Self> {
274 post_report: a.0.to_owned(),
275 post: a.1.to_owned(),
276 community: a.2.to_owned(),
277 creator: a.3.to_owned(),
278 post_creator: a.4.to_owned(),
279 creator_banned_from_community: a.5.is_some(),
281 counts: a.7.to_owned(),
282 resolver: a.8.to_owned(),
284 .collect::<Vec<Self>>()
290 use crate::post_report_view::{PostReportQueryBuilder, PostReportView};
291 use lemmy_db_queries::{
292 aggregates::post_aggregates::PostAggregates,
293 establish_unpooled_connection,
298 use lemmy_db_schema::source::{
302 post_report::{PostReport, PostReportForm},
304 use serial_test::serial;
309 let conn = establish_unpooled_connection();
311 let new_person = PersonForm {
312 name: "timmy_prv".into(),
313 ..PersonForm::default()
316 let inserted_timmy = Person::create(&conn, &new_person).unwrap();
318 let new_person_2 = PersonForm {
319 name: "sara_prv".into(),
320 ..PersonForm::default()
323 let inserted_sara = Person::create(&conn, &new_person_2).unwrap();
325 // Add a third person, since new ppl can only report something once.
326 let new_person_3 = PersonForm {
327 name: "jessica_prv".into(),
328 ..PersonForm::default()
331 let inserted_jessica = Person::create(&conn, &new_person_3).unwrap();
333 let new_community = CommunityForm {
334 name: "test community prv".to_string(),
335 title: "nada".to_owned(),
336 ..CommunityForm::default()
339 let inserted_community = Community::create(&conn, &new_community).unwrap();
342 let timmy_moderator_form = CommunityModeratorForm {
343 community_id: inserted_community.id,
344 person_id: inserted_timmy.id,
347 let _inserted_moderator = CommunityModerator::join(&conn, &timmy_moderator_form).unwrap();
349 let new_post = PostForm {
350 name: "A test post crv".into(),
351 creator_id: inserted_timmy.id,
352 community_id: inserted_community.id,
353 ..PostForm::default()
356 let inserted_post = Post::create(&conn, &new_post).unwrap();
359 let sara_report_form = PostReportForm {
360 creator_id: inserted_sara.id,
361 post_id: inserted_post.id,
362 original_post_name: "Orig post".into(),
363 original_post_url: None,
364 original_post_body: None,
365 reason: "from sara".into(),
368 let inserted_sara_report = PostReport::report(&conn, &sara_report_form).unwrap();
371 let jessica_report_form = PostReportForm {
372 creator_id: inserted_jessica.id,
373 post_id: inserted_post.id,
374 original_post_name: "Orig post".into(),
375 original_post_url: None,
376 original_post_body: None,
377 reason: "from jessica".into(),
380 let inserted_jessica_report = PostReport::report(&conn, &jessica_report_form).unwrap();
382 let agg = PostAggregates::read(&conn, inserted_post.id).unwrap();
384 let read_jessica_report_view =
385 PostReportView::read(&conn, inserted_jessica_report.id, inserted_timmy.id).unwrap();
386 let expected_jessica_report_view = PostReportView {
387 post_report: inserted_jessica_report.to_owned(),
388 post: inserted_post.to_owned(),
389 community: CommunitySafe {
390 id: inserted_community.id,
391 name: inserted_community.name,
396 actor_id: inserted_community.actor_id.to_owned(),
398 title: inserted_community.title,
402 published: inserted_community.published,
404 creator: PersonSafe {
405 id: inserted_jessica.id,
406 name: inserted_jessica.name,
408 published: inserted_jessica.published,
410 actor_id: inserted_jessica.actor_id.to_owned(),
419 inbox_url: inserted_jessica.inbox_url.to_owned(),
420 shared_inbox_url: None,
421 matrix_user_id: None,
423 post_creator: PersonSafeAlias1 {
424 id: inserted_timmy.id,
425 name: inserted_timmy.name.to_owned(),
427 published: inserted_timmy.published,
429 actor_id: inserted_timmy.actor_id.to_owned(),
438 inbox_url: inserted_timmy.inbox_url.to_owned(),
439 shared_inbox_url: None,
440 matrix_user_id: None,
442 creator_banned_from_community: false,
444 counts: PostAggregates {
446 post_id: inserted_post.id,
452 published: agg.published,
453 newest_comment_time_necro: inserted_post.published,
454 newest_comment_time: inserted_post.published,
459 assert_eq!(read_jessica_report_view, expected_jessica_report_view);
461 let mut expected_sara_report_view = expected_jessica_report_view.clone();
462 expected_sara_report_view.post_report = inserted_sara_report;
463 expected_sara_report_view.my_vote = None;
464 expected_sara_report_view.creator = PersonSafe {
465 id: inserted_sara.id,
466 name: inserted_sara.name,
468 published: inserted_sara.published,
470 actor_id: inserted_sara.actor_id.to_owned(),
479 inbox_url: inserted_sara.inbox_url.to_owned(),
480 shared_inbox_url: None,
481 matrix_user_id: None,
484 // Do a batch read of timmys reports
485 let reports = PostReportQueryBuilder::create(&conn, inserted_timmy.id, false)
492 expected_sara_report_view.to_owned(),
493 expected_jessica_report_view.to_owned()
497 // Make sure the counts are correct
499 PostReportView::get_report_count(&conn, inserted_timmy.id, false, None).unwrap();
500 assert_eq!(2, report_count);
502 // Try to resolve the report
503 PostReport::resolve(&conn, inserted_jessica_report.id, inserted_timmy.id).unwrap();
504 let read_jessica_report_view_after_resolve =
505 PostReportView::read(&conn, inserted_jessica_report.id, inserted_timmy.id).unwrap();
507 let mut expected_jessica_report_view_after_resolve = expected_jessica_report_view;
508 expected_jessica_report_view_after_resolve
511 expected_jessica_report_view_after_resolve
513 .resolver_id = Some(inserted_timmy.id);
514 expected_jessica_report_view_after_resolve
516 .updated = read_jessica_report_view_after_resolve.post_report.updated;
517 expected_jessica_report_view_after_resolve.resolver = Some(PersonSafeAlias2 {
518 id: inserted_timmy.id,
519 name: inserted_timmy.name.to_owned(),
521 published: inserted_timmy.published,
523 actor_id: inserted_timmy.actor_id.to_owned(),
532 inbox_url: inserted_timmy.inbox_url.to_owned(),
533 shared_inbox_url: None,
534 matrix_user_id: None,
538 read_jessica_report_view_after_resolve,
539 expected_jessica_report_view_after_resolve
542 // Do a batch read of timmys reports
543 // It should only show saras, which is unresolved
544 let reports_after_resolve = PostReportQueryBuilder::create(&conn, inserted_timmy.id, false)
547 assert_eq!(reports_after_resolve[0], expected_sara_report_view);
549 // Make sure the counts are correct
550 let report_count_after_resolved =
551 PostReportView::get_report_count(&conn, inserted_timmy.id, false, None).unwrap();
552 assert_eq!(1, report_count_after_resolved);
554 Person::delete(&conn, inserted_timmy.id).unwrap();
555 Person::delete(&conn, inserted_sara.id).unwrap();
556 Person::delete(&conn, inserted_jessica.id).unwrap();
557 Community::delete(&conn, inserted_community.id).unwrap();