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,
277 post_report::{PostReport, PostReportForm},
279 traits::{Crud, Joinable, Reportable},
280 utils::establish_unpooled_connection,
282 use serial_test::serial;
287 let conn = &mut establish_unpooled_connection();
289 let new_person = PersonForm {
290 name: "timmy_prv".into(),
291 public_key: Some("pubkey".to_string()),
292 ..PersonForm::default()
295 let inserted_timmy = Person::create(conn, &new_person).unwrap();
297 let new_person_2 = PersonForm {
298 name: "sara_prv".into(),
299 public_key: Some("pubkey".to_string()),
300 ..PersonForm::default()
303 let inserted_sara = Person::create(conn, &new_person_2).unwrap();
305 // Add a third person, since new ppl can only report something once.
306 let new_person_3 = PersonForm {
307 name: "jessica_prv".into(),
308 public_key: Some("pubkey".to_string()),
309 ..PersonForm::default()
312 let inserted_jessica = Person::create(conn, &new_person_3).unwrap();
314 let new_community = CommunityForm {
315 name: "test community prv".to_string(),
316 title: "nada".to_owned(),
317 public_key: Some("pubkey".to_string()),
318 ..CommunityForm::default()
321 let inserted_community = Community::create(conn, &new_community).unwrap();
324 let timmy_moderator_form = CommunityModeratorForm {
325 community_id: inserted_community.id,
326 person_id: inserted_timmy.id,
329 let _inserted_moderator = CommunityModerator::join(conn, &timmy_moderator_form).unwrap();
331 let new_post = PostForm {
332 name: "A test post crv".into(),
333 creator_id: inserted_timmy.id,
334 community_id: inserted_community.id,
335 ..PostForm::default()
338 let inserted_post = Post::create(conn, &new_post).unwrap();
341 let sara_report_form = PostReportForm {
342 creator_id: inserted_sara.id,
343 post_id: inserted_post.id,
344 original_post_name: "Orig post".into(),
345 original_post_url: None,
346 original_post_body: None,
347 reason: "from sara".into(),
350 let inserted_sara_report = PostReport::report(conn, &sara_report_form).unwrap();
353 let jessica_report_form = PostReportForm {
354 creator_id: inserted_jessica.id,
355 post_id: inserted_post.id,
356 original_post_name: "Orig post".into(),
357 original_post_url: None,
358 original_post_body: None,
359 reason: "from jessica".into(),
362 let inserted_jessica_report = PostReport::report(conn, &jessica_report_form).unwrap();
364 let agg = PostAggregates::read(conn, inserted_post.id).unwrap();
366 let read_jessica_report_view =
367 PostReportView::read(conn, inserted_jessica_report.id, inserted_timmy.id).unwrap();
368 let expected_jessica_report_view = PostReportView {
369 post_report: inserted_jessica_report.to_owned(),
370 post: inserted_post.to_owned(),
371 community: CommunitySafe {
372 id: inserted_community.id,
373 name: inserted_community.name,
378 actor_id: inserted_community.actor_id.to_owned(),
380 title: inserted_community.title,
385 posting_restricted_to_mods: false,
386 published: inserted_community.published,
388 creator: PersonSafe {
389 id: inserted_jessica.id,
390 name: inserted_jessica.name,
392 published: inserted_jessica.published,
394 actor_id: inserted_jessica.actor_id.to_owned(),
403 inbox_url: inserted_jessica.inbox_url.to_owned(),
404 shared_inbox_url: None,
405 matrix_user_id: None,
408 post_creator: PersonSafe {
409 id: inserted_timmy.id,
410 name: inserted_timmy.name.to_owned(),
412 published: inserted_timmy.published,
414 actor_id: inserted_timmy.actor_id.to_owned(),
423 inbox_url: inserted_timmy.inbox_url.to_owned(),
424 shared_inbox_url: None,
425 matrix_user_id: None,
428 creator_banned_from_community: false,
430 counts: PostAggregates {
432 post_id: inserted_post.id,
438 published: agg.published,
439 newest_comment_time_necro: inserted_post.published,
440 newest_comment_time: inserted_post.published,
445 assert_eq!(read_jessica_report_view, expected_jessica_report_view);
447 let mut expected_sara_report_view = expected_jessica_report_view.clone();
448 expected_sara_report_view.post_report = inserted_sara_report;
449 expected_sara_report_view.my_vote = None;
450 expected_sara_report_view.creator = PersonSafe {
451 id: inserted_sara.id,
452 name: inserted_sara.name,
454 published: inserted_sara.published,
456 actor_id: inserted_sara.actor_id.to_owned(),
465 inbox_url: inserted_sara.inbox_url.to_owned(),
466 shared_inbox_url: None,
467 matrix_user_id: None,
471 // Do a batch read of timmys reports
472 let reports = PostReportQuery::builder()
474 .my_person_id(inserted_timmy.id)
483 expected_jessica_report_view.to_owned(),
484 expected_sara_report_view.to_owned()
488 // Make sure the counts are correct
490 PostReportView::get_report_count(conn, inserted_timmy.id, false, None).unwrap();
491 assert_eq!(2, report_count);
493 // Try to resolve the report
494 PostReport::resolve(conn, inserted_jessica_report.id, inserted_timmy.id).unwrap();
495 let read_jessica_report_view_after_resolve =
496 PostReportView::read(conn, inserted_jessica_report.id, inserted_timmy.id).unwrap();
498 let mut expected_jessica_report_view_after_resolve = expected_jessica_report_view;
499 expected_jessica_report_view_after_resolve
502 expected_jessica_report_view_after_resolve
504 .resolver_id = Some(inserted_timmy.id);
505 expected_jessica_report_view_after_resolve
507 .updated = read_jessica_report_view_after_resolve.post_report.updated;
508 expected_jessica_report_view_after_resolve.resolver = Some(PersonSafe {
509 id: inserted_timmy.id,
510 name: inserted_timmy.name.to_owned(),
512 published: inserted_timmy.published,
514 actor_id: inserted_timmy.actor_id.to_owned(),
523 inbox_url: inserted_timmy.inbox_url.to_owned(),
524 shared_inbox_url: None,
525 matrix_user_id: None,
530 read_jessica_report_view_after_resolve,
531 expected_jessica_report_view_after_resolve
534 // Do a batch read of timmys reports
535 // It should only show saras, which is unresolved
536 let reports_after_resolve = PostReportQuery::builder()
538 .my_person_id(inserted_timmy.id)
543 assert_eq!(reports_after_resolve[0], expected_sara_report_view);
545 // Make sure the counts are correct
546 let report_count_after_resolved =
547 PostReportView::get_report_count(conn, inserted_timmy.id, false, None).unwrap();
548 assert_eq!(1, report_count_after_resolved);
550 Person::delete(conn, inserted_timmy.id).unwrap();
551 Person::delete(conn, inserted_sara.id).unwrap();
552 Person::delete(conn, inserted_jessica.id).unwrap();
553 Community::delete(conn, inserted_community.id).unwrap();