1 use crate::structs::CommentReportView;
8 NullableExpressionMethods,
11 use diesel_async::RunQueryDsl;
12 use lemmy_db_schema::{
13 aggregates::structs::CommentAggregates,
14 newtypes::{CommentReportId, CommunityId, PersonId},
28 comment_report::CommentReport,
29 community::{Community, CommunityPersonBan, CommunitySafe},
30 person::{Person, PersonSafe},
33 traits::{ToSafe, ViewToVec},
34 utils::{get_conn, limit_and_offset, DbPool},
36 use typed_builder::TypedBuilder;
38 type CommentReportViewTuple = (
46 Option<CommunityPersonBan>,
51 impl CommentReportView {
52 /// returns the CommentReportView for the provided report_id
54 /// * `report_id` - the report id to obtain
57 report_id: CommentReportId,
58 my_person_id: PersonId,
59 ) -> Result<Self, Error> {
60 let conn = &mut get_conn(pool).await?;
62 let (person_alias_1, person_alias_2) = diesel::alias!(person as person1, person as person2);
72 creator_banned_from_community,
75 ) = comment_report::table
77 .inner_join(comment::table)
78 .inner_join(post::table.on(comment::post_id.eq(post::id)))
79 .inner_join(community::table.on(post::community_id.eq(community::id)))
80 .inner_join(person::table.on(comment_report::creator_id.eq(person::id)))
81 .inner_join(person_alias_1.on(comment::creator_id.eq(person_alias_1.field(person::id))))
83 comment_aggregates::table.on(comment_report::comment_id.eq(comment_aggregates::comment_id)),
86 community_person_ban::table.on(
88 .eq(community_person_ban::community_id)
89 .and(community_person_ban::person_id.eq(comment::creator_id))
91 community_person_ban::expires
93 .or(community_person_ban::expires.gt(now)),
98 comment_like::table.on(
100 .eq(comment_like::comment_id)
101 .and(comment_like::person_id.eq(my_person_id)),
106 .on(comment_report::resolver_id.eq(person_alias_2.field(person::id).nullable())),
109 comment_report::all_columns,
110 comment::all_columns,
112 Community::safe_columns_tuple(),
113 Person::safe_columns_tuple(),
114 person_alias_1.fields(Person::safe_columns_tuple()),
115 comment_aggregates::all_columns,
116 community_person_ban::all_columns.nullable(),
117 comment_like::score.nullable(),
119 .fields(Person::safe_columns_tuple())
122 .first::<CommentReportViewTuple>(conn)
125 let my_vote = comment_like;
135 creator_banned_from_community: creator_banned_from_community.is_some(),
141 /// Returns the current unresolved post report count for the communities you mod
142 pub async fn get_report_count(
144 my_person_id: PersonId,
146 community_id: Option<CommunityId>,
147 ) -> Result<i64, Error> {
148 use diesel::dsl::count;
150 let conn = &mut get_conn(pool).await?;
152 let mut query = comment_report::table
153 .inner_join(comment::table)
154 .inner_join(post::table.on(comment::post_id.eq(post::id)))
155 .filter(comment_report::resolved.eq(false))
158 if let Some(community_id) = community_id {
159 query = query.filter(post::community_id.eq(community_id))
162 // If its not an admin, get only the ones you mod
166 community_moderator::table.on(
167 community_moderator::community_id
168 .eq(post::community_id)
169 .and(community_moderator::person_id.eq(my_person_id)),
172 .select(count(comment_report::id))
177 .select(count(comment_report::id))
184 #[derive(TypedBuilder)]
185 #[builder(field_defaults(default))]
186 pub struct CommentReportQuery<'a> {
190 my_person_id: PersonId,
193 community_id: Option<CommunityId>,
196 unresolved_only: Option<bool>,
199 impl<'a> CommentReportQuery<'a> {
200 pub async fn list(self) -> Result<Vec<CommentReportView>, Error> {
201 let conn = &mut get_conn(self.pool).await?;
203 let (person_alias_1, person_alias_2) = diesel::alias!(person as person1, person as person2);
205 let mut query = comment_report::table
206 .inner_join(comment::table)
207 .inner_join(post::table.on(comment::post_id.eq(post::id)))
208 .inner_join(community::table.on(post::community_id.eq(community::id)))
209 .inner_join(person::table.on(comment_report::creator_id.eq(person::id)))
210 .inner_join(person_alias_1.on(comment::creator_id.eq(person_alias_1.field(person::id))))
212 comment_aggregates::table.on(comment_report::comment_id.eq(comment_aggregates::comment_id)),
215 community_person_ban::table.on(
217 .eq(community_person_ban::community_id)
218 .and(community_person_ban::person_id.eq(comment::creator_id))
220 community_person_ban::expires
222 .or(community_person_ban::expires.gt(now)),
227 comment_like::table.on(
229 .eq(comment_like::comment_id)
230 .and(comment_like::person_id.eq(self.my_person_id)),
235 .on(comment_report::resolver_id.eq(person_alias_2.field(person::id).nullable())),
238 comment_report::all_columns,
239 comment::all_columns,
241 Community::safe_columns_tuple(),
242 Person::safe_columns_tuple(),
243 person_alias_1.fields(Person::safe_columns_tuple()),
244 comment_aggregates::all_columns,
245 community_person_ban::all_columns.nullable(),
246 comment_like::score.nullable(),
248 .fields(Person::safe_columns_tuple())
253 if let Some(community_id) = self.community_id {
254 query = query.filter(post::community_id.eq(community_id));
257 if self.unresolved_only.unwrap_or(true) {
258 query = query.filter(comment_report::resolved.eq(false));
261 let (limit, offset) = limit_and_offset(self.page, self.limit)?;
264 .order_by(comment_report::published.desc())
268 // If its not an admin, get only the ones you mod
269 let res = if !self.admin {
272 community_moderator::table.on(
273 community_moderator::community_id
274 .eq(post::community_id)
275 .and(community_moderator::person_id.eq(self.my_person_id)),
278 .load::<CommentReportViewTuple>(conn)
281 query.load::<CommentReportViewTuple>(conn).await?
284 Ok(CommentReportView::from_tuple_to_vec(res))
288 impl ViewToVec for CommentReportView {
289 type DbTuple = CommentReportViewTuple;
290 fn from_tuple_to_vec(items: Vec<Self::DbTuple>) -> Vec<Self> {
299 comment_creator: a.5,
301 creator_banned_from_community: a.7.is_some(),
305 .collect::<Vec<Self>>()
311 use crate::comment_report_view::{CommentReportQuery, CommentReportView};
312 use lemmy_db_schema::{
313 aggregates::structs::CommentAggregates,
315 comment::{Comment, CommentInsertForm},
316 comment_report::{CommentReport, CommentReportForm},
321 CommunityModeratorForm,
325 person::{Person, PersonInsertForm, PersonSafe},
326 post::{Post, PostInsertForm},
328 traits::{Crud, Joinable, Reportable},
329 utils::build_db_pool_for_tests,
331 use serial_test::serial;
335 async fn test_crud() {
336 let pool = &build_db_pool_for_tests().await;
338 let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string())
342 let new_person = PersonInsertForm::builder()
343 .name("timmy_crv".into())
344 .public_key("pubkey".to_string())
345 .instance_id(inserted_instance.id)
348 let inserted_timmy = Person::create(pool, &new_person).await.unwrap();
350 let new_person_2 = PersonInsertForm::builder()
351 .name("sara_crv".into())
352 .public_key("pubkey".to_string())
353 .instance_id(inserted_instance.id)
356 let inserted_sara = Person::create(pool, &new_person_2).await.unwrap();
358 // Add a third person, since new ppl can only report something once.
359 let new_person_3 = PersonInsertForm::builder()
360 .name("jessica_crv".into())
361 .public_key("pubkey".to_string())
362 .instance_id(inserted_instance.id)
365 let inserted_jessica = Person::create(pool, &new_person_3).await.unwrap();
367 let new_community = CommunityInsertForm::builder()
368 .name("test community crv".to_string())
369 .title("nada".to_owned())
370 .public_key("pubkey".to_string())
371 .instance_id(inserted_instance.id)
374 let inserted_community = Community::create(pool, &new_community).await.unwrap();
377 let timmy_moderator_form = CommunityModeratorForm {
378 community_id: inserted_community.id,
379 person_id: inserted_timmy.id,
382 let _inserted_moderator = CommunityModerator::join(pool, &timmy_moderator_form)
386 let new_post = PostInsertForm::builder()
387 .name("A test post crv".into())
388 .creator_id(inserted_timmy.id)
389 .community_id(inserted_community.id)
392 let inserted_post = Post::create(pool, &new_post).await.unwrap();
394 let comment_form = CommentInsertForm::builder()
395 .content("A test comment 32".into())
396 .creator_id(inserted_timmy.id)
397 .post_id(inserted_post.id)
400 let inserted_comment = Comment::create(pool, &comment_form, None).await.unwrap();
403 let sara_report_form = CommentReportForm {
404 creator_id: inserted_sara.id,
405 comment_id: inserted_comment.id,
406 original_comment_text: "this was it at time of creation".into(),
407 reason: "from sara".into(),
410 let inserted_sara_report = CommentReport::report(pool, &sara_report_form)
415 let jessica_report_form = CommentReportForm {
416 creator_id: inserted_jessica.id,
417 comment_id: inserted_comment.id,
418 original_comment_text: "this was it at time of creation".into(),
419 reason: "from jessica".into(),
422 let inserted_jessica_report = CommentReport::report(pool, &jessica_report_form)
426 let agg = CommentAggregates::read(pool, inserted_comment.id)
430 let read_jessica_report_view =
431 CommentReportView::read(pool, inserted_jessica_report.id, inserted_timmy.id)
434 let expected_jessica_report_view = CommentReportView {
435 comment_report: inserted_jessica_report.clone(),
436 comment: inserted_comment.clone(),
438 community: CommunitySafe {
439 id: inserted_community.id,
440 name: inserted_community.name,
445 actor_id: inserted_community.actor_id.clone(),
447 title: inserted_community.title,
452 posting_restricted_to_mods: false,
453 published: inserted_community.published,
454 instance_id: inserted_instance.id,
456 creator: PersonSafe {
457 id: inserted_jessica.id,
458 name: inserted_jessica.name,
460 published: inserted_jessica.published,
462 actor_id: inserted_jessica.actor_id.clone(),
471 inbox_url: inserted_jessica.inbox_url.clone(),
472 shared_inbox_url: None,
473 matrix_user_id: None,
475 instance_id: inserted_instance.id,
477 comment_creator: PersonSafe {
478 id: inserted_timmy.id,
479 name: inserted_timmy.name.clone(),
481 published: inserted_timmy.published,
483 actor_id: inserted_timmy.actor_id.clone(),
492 inbox_url: inserted_timmy.inbox_url.clone(),
493 shared_inbox_url: None,
494 matrix_user_id: None,
496 instance_id: inserted_instance.id,
498 creator_banned_from_community: false,
499 counts: CommentAggregates {
501 comment_id: inserted_comment.id,
505 published: agg.published,
512 assert_eq!(read_jessica_report_view, expected_jessica_report_view);
514 let mut expected_sara_report_view = expected_jessica_report_view.clone();
515 expected_sara_report_view.comment_report = inserted_sara_report;
516 expected_sara_report_view.creator = PersonSafe {
517 id: inserted_sara.id,
518 name: inserted_sara.name,
520 published: inserted_sara.published,
522 actor_id: inserted_sara.actor_id.clone(),
531 inbox_url: inserted_sara.inbox_url.clone(),
532 shared_inbox_url: None,
533 matrix_user_id: None,
535 instance_id: inserted_instance.id,
538 // Do a batch read of timmys reports
539 let reports = CommentReportQuery::builder()
541 .my_person_id(inserted_timmy.id)
551 expected_jessica_report_view.clone(),
552 expected_sara_report_view.clone()
556 // Make sure the counts are correct
557 let report_count = CommentReportView::get_report_count(pool, inserted_timmy.id, false, None)
560 assert_eq!(2, report_count);
562 // Try to resolve the report
563 CommentReport::resolve(pool, inserted_jessica_report.id, inserted_timmy.id)
566 let read_jessica_report_view_after_resolve =
567 CommentReportView::read(pool, inserted_jessica_report.id, inserted_timmy.id)
571 let mut expected_jessica_report_view_after_resolve = expected_jessica_report_view;
572 expected_jessica_report_view_after_resolve
575 expected_jessica_report_view_after_resolve
577 .resolver_id = Some(inserted_timmy.id);
578 expected_jessica_report_view_after_resolve
580 .updated = read_jessica_report_view_after_resolve
583 expected_jessica_report_view_after_resolve.resolver = Some(PersonSafe {
584 id: inserted_timmy.id,
585 name: inserted_timmy.name.clone(),
587 published: inserted_timmy.published,
589 actor_id: inserted_timmy.actor_id.clone(),
598 inbox_url: inserted_timmy.inbox_url.clone(),
599 shared_inbox_url: None,
600 matrix_user_id: None,
602 instance_id: inserted_instance.id,
606 read_jessica_report_view_after_resolve,
607 expected_jessica_report_view_after_resolve
610 // Do a batch read of timmys reports
611 // It should only show saras, which is unresolved
612 let reports_after_resolve = CommentReportQuery::builder()
614 .my_person_id(inserted_timmy.id)
620 assert_eq!(reports_after_resolve[0], expected_sara_report_view);
621 assert_eq!(reports_after_resolve.len(), 1);
623 // Make sure the counts are correct
624 let report_count_after_resolved =
625 CommentReportView::get_report_count(pool, inserted_timmy.id, false, None)
628 assert_eq!(1, report_count_after_resolved);
630 Person::delete(pool, inserted_timmy.id).await.unwrap();
631 Person::delete(pool, inserted_sara.id).await.unwrap();
632 Person::delete(pool, inserted_jessica.id).await.unwrap();
633 Community::delete(pool, inserted_community.id)
636 Instance::delete(pool, inserted_instance.id).await.unwrap();