1 use crate::structs::PostReportView;
2 use diesel::{dsl::*, result::Error, *};
4 aggregates::structs::PostAggregates,
5 newtypes::{CommunityId, PersonId, PostReportId},
17 community::{Community, CommunityPersonBan, CommunitySafe},
18 person::{Person, PersonSafe},
20 post_report::PostReport,
22 traits::{ToSafe, ViewToVec},
23 utils::limit_and_offset,
25 use typed_builder::TypedBuilder;
27 type PostReportViewTuple = (
33 Option<CommunityPersonBan>,
40 /// returns the PostReportView for the provided report_id
42 /// * `report_id` - the report id to obtain
44 conn: &mut PgConnection,
45 report_id: PostReportId,
46 my_person_id: PersonId,
47 ) -> Result<Self, Error> {
48 let (person_alias_1, person_alias_2) = diesel::alias!(person as person1, person as person2);
56 creator_banned_from_community,
60 ) = post_report::table
62 .inner_join(post::table)
63 .inner_join(community::table.on(post::community_id.eq(community::id)))
64 .inner_join(person::table.on(post_report::creator_id.eq(person::id)))
65 .inner_join(person_alias_1.on(post::creator_id.eq(person_alias_1.field(person::id))))
67 community_person_ban::table.on(
69 .eq(community_person_ban::community_id)
70 .and(community_person_ban::person_id.eq(post::creator_id))
72 community_person_ban::expires
74 .or(community_person_ban::expires.gt(now)),
81 .eq(post_like::post_id)
82 .and(post_like::person_id.eq(my_person_id)),
85 .inner_join(post_aggregates::table.on(post_report::post_id.eq(post_aggregates::post_id)))
87 person_alias_2.on(post_report::resolver_id.eq(person_alias_2.field(person::id).nullable())),
90 post_report::all_columns,
92 Community::safe_columns_tuple(),
93 Person::safe_columns_tuple(),
94 person_alias_1.fields(Person::safe_columns_tuple()),
95 community_person_ban::all_columns.nullable(),
96 post_like::score.nullable(),
97 post_aggregates::all_columns,
98 person_alias_2.fields(Person::safe_columns_tuple().nullable()),
100 .first::<PostReportViewTuple>(conn)?;
102 let my_vote = post_like;
110 creator_banned_from_community: creator_banned_from_community.is_some(),
117 /// returns the current unresolved post report count for the communities you mod
118 pub fn get_report_count(
119 conn: &mut PgConnection,
120 my_person_id: PersonId,
122 community_id: Option<CommunityId>,
123 ) -> Result<i64, Error> {
125 let mut query = post_report::table
126 .inner_join(post::table)
127 .filter(post_report::resolved.eq(false))
130 if let Some(community_id) = community_id {
131 query = query.filter(post::community_id.eq(community_id))
134 // If its not an admin, get only the ones you mod
138 community_moderator::table.on(
139 community_moderator::community_id
140 .eq(post::community_id)
141 .and(community_moderator::person_id.eq(my_person_id)),
144 .select(count(post_report::id))
147 query.select(count(post_report::id)).first::<i64>(conn)
152 #[derive(TypedBuilder)]
153 #[builder(field_defaults(default))]
154 pub struct PostReportQuery<'a> {
156 conn: &'a mut PgConnection,
158 my_person_id: PersonId,
161 community_id: Option<CommunityId>,
164 unresolved_only: Option<bool>,
167 impl<'a> PostReportQuery<'a> {
168 pub fn list(self) -> Result<Vec<PostReportView>, Error> {
169 let (person_alias_1, person_alias_2) = diesel::alias!(person as person1, person as person2);
171 let mut query = post_report::table
172 .inner_join(post::table)
173 .inner_join(community::table.on(post::community_id.eq(community::id)))
174 .inner_join(person::table.on(post_report::creator_id.eq(person::id)))
175 .inner_join(person_alias_1.on(post::creator_id.eq(person_alias_1.field(person::id))))
177 community_person_ban::table.on(
179 .eq(community_person_ban::community_id)
180 .and(community_person_ban::person_id.eq(post::creator_id))
182 community_person_ban::expires
184 .or(community_person_ban::expires.gt(now)),
191 .eq(post_like::post_id)
192 .and(post_like::person_id.eq(self.my_person_id)),
195 .inner_join(post_aggregates::table.on(post_report::post_id.eq(post_aggregates::post_id)))
197 person_alias_2.on(post_report::resolver_id.eq(person_alias_2.field(person::id).nullable())),
200 post_report::all_columns,
202 Community::safe_columns_tuple(),
203 Person::safe_columns_tuple(),
204 person_alias_1.fields(Person::safe_columns_tuple()),
205 community_person_ban::all_columns.nullable(),
206 post_like::score.nullable(),
207 post_aggregates::all_columns,
209 .fields(Person::safe_columns_tuple())
214 if let Some(community_id) = self.community_id {
215 query = query.filter(post::community_id.eq(community_id));
218 if self.unresolved_only.unwrap_or(true) {
219 query = query.filter(post_report::resolved.eq(false));
222 let (limit, offset) = limit_and_offset(self.page, self.limit)?;
225 .order_by(post_report::published.desc())
229 // If its not an admin, get only the ones you mod
230 let res = if !self.admin {
233 community_moderator::table.on(
234 community_moderator::community_id
235 .eq(post::community_id)
236 .and(community_moderator::person_id.eq(self.my_person_id)),
239 .load::<PostReportViewTuple>(self.conn)?
241 query.load::<PostReportViewTuple>(self.conn)?
244 Ok(PostReportView::from_tuple_to_vec(res))
248 impl ViewToVec for PostReportView {
249 type DbTuple = PostReportViewTuple;
250 fn from_tuple_to_vec(items: Vec<Self::DbTuple>) -> Vec<Self> {
259 creator_banned_from_community: a.5.is_some(),
264 .collect::<Vec<Self>>()
270 use crate::post_report_view::{PostReportQuery, PostReportView};
271 use lemmy_db_schema::{
272 aggregates::structs::PostAggregates,
278 post_report::{PostReport, PostReportForm},
280 traits::{Crud, Joinable, Reportable},
281 utils::establish_unpooled_connection,
283 use serial_test::serial;
288 let conn = &mut establish_unpooled_connection();
290 let inserted_instance = Instance::create(conn, "my_domain.tld").unwrap();
292 let new_person = PersonInsertForm::builder()
293 .name("timmy_prv".into())
294 .public_key("pubkey".to_string())
295 .instance_id(inserted_instance.id)
298 let inserted_timmy = Person::create(conn, &new_person).unwrap();
300 let new_person_2 = PersonInsertForm::builder()
301 .name("sara_prv".into())
302 .public_key("pubkey".to_string())
303 .instance_id(inserted_instance.id)
306 let inserted_sara = Person::create(conn, &new_person_2).unwrap();
308 // Add a third person, since new ppl can only report something once.
309 let new_person_3 = PersonInsertForm::builder()
310 .name("jessica_prv".into())
311 .public_key("pubkey".to_string())
312 .instance_id(inserted_instance.id)
315 let inserted_jessica = Person::create(conn, &new_person_3).unwrap();
317 let new_community = CommunityInsertForm::builder()
318 .name("test community prv".to_string())
319 .title("nada".to_owned())
320 .public_key("pubkey".to_string())
321 .instance_id(inserted_instance.id)
324 let inserted_community = Community::create(conn, &new_community).unwrap();
327 let timmy_moderator_form = CommunityModeratorForm {
328 community_id: inserted_community.id,
329 person_id: inserted_timmy.id,
332 let _inserted_moderator = CommunityModerator::join(conn, &timmy_moderator_form).unwrap();
334 let new_post = PostInsertForm::builder()
335 .name("A test post crv".into())
336 .creator_id(inserted_timmy.id)
337 .community_id(inserted_community.id)
340 let inserted_post = Post::create(conn, &new_post).unwrap();
343 let sara_report_form = PostReportForm {
344 creator_id: inserted_sara.id,
345 post_id: inserted_post.id,
346 original_post_name: "Orig post".into(),
347 original_post_url: None,
348 original_post_body: None,
349 reason: "from sara".into(),
352 let inserted_sara_report = PostReport::report(conn, &sara_report_form).unwrap();
355 let jessica_report_form = PostReportForm {
356 creator_id: inserted_jessica.id,
357 post_id: inserted_post.id,
358 original_post_name: "Orig post".into(),
359 original_post_url: None,
360 original_post_body: None,
361 reason: "from jessica".into(),
364 let inserted_jessica_report = PostReport::report(conn, &jessica_report_form).unwrap();
366 let agg = PostAggregates::read(conn, inserted_post.id).unwrap();
368 let read_jessica_report_view =
369 PostReportView::read(conn, inserted_jessica_report.id, inserted_timmy.id).unwrap();
370 let expected_jessica_report_view = PostReportView {
371 post_report: inserted_jessica_report.to_owned(),
372 post: inserted_post.to_owned(),
373 community: CommunitySafe {
374 id: inserted_community.id,
375 name: inserted_community.name,
380 actor_id: inserted_community.actor_id.to_owned(),
382 title: inserted_community.title,
387 posting_restricted_to_mods: false,
388 published: inserted_community.published,
389 instance_id: inserted_instance.id,
391 creator: PersonSafe {
392 id: inserted_jessica.id,
393 name: inserted_jessica.name,
395 published: inserted_jessica.published,
397 actor_id: inserted_jessica.actor_id.to_owned(),
406 inbox_url: inserted_jessica.inbox_url.to_owned(),
407 shared_inbox_url: None,
408 matrix_user_id: None,
410 instance_id: inserted_instance.id,
412 post_creator: PersonSafe {
413 id: inserted_timmy.id,
414 name: inserted_timmy.name.to_owned(),
416 published: inserted_timmy.published,
418 actor_id: inserted_timmy.actor_id.to_owned(),
427 inbox_url: inserted_timmy.inbox_url.to_owned(),
428 shared_inbox_url: None,
429 matrix_user_id: None,
431 instance_id: inserted_instance.id,
433 creator_banned_from_community: false,
435 counts: PostAggregates {
437 post_id: inserted_post.id,
443 published: agg.published,
444 newest_comment_time_necro: inserted_post.published,
445 newest_comment_time: inserted_post.published,
450 assert_eq!(read_jessica_report_view, expected_jessica_report_view);
452 let mut expected_sara_report_view = expected_jessica_report_view.clone();
453 expected_sara_report_view.post_report = inserted_sara_report;
454 expected_sara_report_view.my_vote = None;
455 expected_sara_report_view.creator = PersonSafe {
456 id: inserted_sara.id,
457 name: inserted_sara.name,
459 published: inserted_sara.published,
461 actor_id: inserted_sara.actor_id.to_owned(),
470 inbox_url: inserted_sara.inbox_url.to_owned(),
471 shared_inbox_url: None,
472 matrix_user_id: None,
474 instance_id: inserted_instance.id,
477 // Do a batch read of timmys reports
478 let reports = PostReportQuery::builder()
480 .my_person_id(inserted_timmy.id)
489 expected_jessica_report_view.to_owned(),
490 expected_sara_report_view.to_owned()
494 // Make sure the counts are correct
496 PostReportView::get_report_count(conn, inserted_timmy.id, false, None).unwrap();
497 assert_eq!(2, report_count);
499 // Try to resolve the report
500 PostReport::resolve(conn, inserted_jessica_report.id, inserted_timmy.id).unwrap();
501 let read_jessica_report_view_after_resolve =
502 PostReportView::read(conn, inserted_jessica_report.id, inserted_timmy.id).unwrap();
504 let mut expected_jessica_report_view_after_resolve = expected_jessica_report_view;
505 expected_jessica_report_view_after_resolve
508 expected_jessica_report_view_after_resolve
510 .resolver_id = Some(inserted_timmy.id);
511 expected_jessica_report_view_after_resolve
513 .updated = read_jessica_report_view_after_resolve.post_report.updated;
514 expected_jessica_report_view_after_resolve.resolver = Some(PersonSafe {
515 id: inserted_timmy.id,
516 name: inserted_timmy.name.to_owned(),
518 published: inserted_timmy.published,
520 actor_id: inserted_timmy.actor_id.to_owned(),
529 inbox_url: inserted_timmy.inbox_url.to_owned(),
530 shared_inbox_url: None,
531 matrix_user_id: None,
533 instance_id: inserted_instance.id,
537 read_jessica_report_view_after_resolve,
538 expected_jessica_report_view_after_resolve
541 // Do a batch read of timmys reports
542 // It should only show saras, which is unresolved
543 let reports_after_resolve = PostReportQuery::builder()
545 .my_person_id(inserted_timmy.id)
550 assert_eq!(reports_after_resolve[0], expected_sara_report_view);
552 // Make sure the counts are correct
553 let report_count_after_resolved =
554 PostReportView::get_report_count(conn, inserted_timmy.id, false, None).unwrap();
555 assert_eq!(1, report_count_after_resolved);
557 Person::delete(conn, inserted_timmy.id).unwrap();
558 Person::delete(conn, inserted_sara.id).unwrap();
559 Person::delete(conn, inserted_jessica.id).unwrap();
560 Community::delete(conn, inserted_community.id).unwrap();
561 Instance::delete(conn, inserted_instance.id).unwrap();