@ -1,15 +1,35 @@
use diesel ::{ result ::Error , * } ;
use lemmy_db_queries ::{ limit_and_offset , MaybeOptional , ToSafe , ViewToVec } ;
use lemmy_db_queries ::{
aggregates ::comment_aggregates ::CommentAggregates ,
limit_and_offset ,
MaybeOptional ,
ToSafe ,
ViewToVec ,
} ;
use lemmy_db_schema ::{
schema ::{ comment , comment_report , community , person , person_alias_1 , person_alias_2 , post } ,
schema ::{
comment ,
comment_aggregates ,
comment_like ,
comment_report ,
community ,
community_moderator ,
community_person_ban ,
person ,
person_alias_1 ,
person_alias_2 ,
post ,
} ,
source ::{
comment ::Comment ,
comment_report ::CommentReport ,
community ::{ Community , CommunitySafe } ,
community ::{ Community , Community PersonBan, Community Safe} ,
person ::{ Person , PersonAlias1 , PersonAlias2 , PersonSafe , PersonSafeAlias1 , PersonSafeAlias2 } ,
post ::Post ,
} ,
CommentReportId ,
CommunityId ,
PersonId ,
} ;
use serde ::Serialize ;
@ -21,6 +41,9 @@ pub struct CommentReportView {
pub community : CommunitySafe ,
pub creator : PersonSafe ,
pub comment_creator : PersonSafeAlias1 ,
pub counts : CommentAggregates ,
pub creator_banned_from_community : bool , // Left Join to CommunityPersonBan
pub my_vote : Option < i16 > , // Left join to CommentLike
pub resolver : Option < PersonSafeAlias2 > ,
}
@ -31,6 +54,9 @@ type CommentReportViewTuple = (
CommunitySafe ,
PersonSafe ,
PersonSafeAlias1 ,
CommentAggregates ,
Option < CommunityPersonBan > ,
Option < i16 > ,
Option < PersonSafeAlias2 > ,
) ;
@ -38,28 +64,68 @@ impl CommentReportView {
/// returns the CommentReportView for the provided report_id
///
/// * `report_id` - the report id to obtain
pub fn read ( conn : & PgConnection , report_id : i32 ) -> Result < Self , Error > {
let ( comment_report , comment , post , community , creator , comment_creator , resolver ) =
comment_report ::table
. find ( report_id )
. inner_join ( comment ::table )
. inner_join ( post ::table . on ( comment ::post_id . eq ( post ::id ) ) )
. inner_join ( community ::table . on ( post ::community_id . eq ( community ::id ) ) )
. inner_join ( person ::table . on ( comment_report ::creator_id . eq ( person ::id ) ) )
. inner_join ( person_alias_1 ::table . on ( post ::creator_id . eq ( person_alias_1 ::id ) ) )
. left_join (
person_alias_2 ::table . on ( comment_report ::resolver_id . eq ( person_alias_2 ::id . nullable ( ) ) ) ,
)
. select ( (
comment_report ::all_columns ,
comment ::all_columns ,
post ::all_columns ,
Community ::safe_columns_tuple ( ) ,
Person ::safe_columns_tuple ( ) ,
PersonAlias1 ::safe_columns_tuple ( ) ,
PersonAlias2 ::safe_columns_tuple ( ) . nullable ( ) ,
) )
. first ::< CommentReportViewTuple > ( conn ) ? ;
pub fn read (
conn : & PgConnection ,
report_id : CommentReportId ,
my_person_id : PersonId ,
) -> Result < Self , Error > {
let (
comment_report ,
comment ,
post ,
community ,
creator ,
comment_creator ,
counts ,
creator_banned_from_community ,
comment_like ,
resolver ,
) = comment_report ::table
. find ( report_id )
. inner_join ( comment ::table )
. inner_join ( post ::table . on ( comment ::post_id . eq ( post ::id ) ) )
. inner_join ( community ::table . on ( post ::community_id . eq ( community ::id ) ) )
. inner_join ( person ::table . on ( comment_report ::creator_id . eq ( person ::id ) ) )
. inner_join ( person_alias_1 ::table . on ( post ::creator_id . eq ( person_alias_1 ::id ) ) )
. inner_join (
comment_aggregates ::table . on ( comment_report ::comment_id . eq ( comment_aggregates ::comment_id ) ) ,
)
. left_join (
community_person_ban ::table . on (
community ::id
. eq ( community_person_ban ::community_id )
. and ( community_person_ban ::person_id . eq ( comment ::creator_id ) ) ,
) ,
)
. left_join (
comment_like ::table . on (
comment ::id
. eq ( comment_like ::comment_id )
. and ( comment_like ::person_id . eq ( my_person_id ) ) ,
) ,
)
. left_join (
person_alias_2 ::table . on ( comment_report ::resolver_id . eq ( person_alias_2 ::id . nullable ( ) ) ) ,
)
. select ( (
comment_report ::all_columns ,
comment ::all_columns ,
post ::all_columns ,
Community ::safe_columns_tuple ( ) ,
Person ::safe_columns_tuple ( ) ,
PersonAlias1 ::safe_columns_tuple ( ) ,
comment_aggregates ::all_columns ,
community_person_ban ::all_columns . nullable ( ) ,
comment_like ::score . nullable ( ) ,
PersonAlias2 ::safe_columns_tuple ( ) . nullable ( ) ,
) )
. first ::< CommentReportViewTuple > ( conn ) ? ;
let my_vote = if comment_like . is_none ( ) {
None
} else {
comment_like
} ;
Ok ( Self {
comment_report ,
@ -68,6 +134,9 @@ impl CommentReportView {
community ,
creator ,
comment_creator ,
counts ,
creator_banned_from_community : creator_banned_from_community . is_some ( ) ,
my_vote ,
resolver ,
} )
}
@ -76,46 +145,60 @@ impl CommentReportView {
///
/// * `community_ids` - a Vec<i32> of community_ids to get a count for
/// TODO this eq_any is a bad way to do this, would be better to join to communitymoderator
/// TODO FIX THIS NOW
/// for a person id
pub fn get_report_count (
conn : & PgConnection ,
community_ids : & [ CommunityId ] ,
my_person_id : PersonId ,
community_id : Option < CommunityId > ,
) -> Result < i64 , Error > {
use diesel ::dsl ::* ;
comment_report ::table
let mut query = comment_report ::table
. inner_join ( comment ::table )
. inner_join ( post ::table . on ( comment ::post_id . eq ( post ::id ) ) )
. filter (
comment_report ::resolved
. eq ( false )
. and ( post ::community_id . eq_any ( community_ids ) ) ,
// Test this join
. inner_join (
community_moderator ::table . on (
community_moderator ::community_id
. eq ( post ::community_id )
. and ( community_moderator ::person_id . eq ( my_person_id ) ) ,
) ,
)
. select ( count ( comment_report ::id ) )
. first ::< i64 > ( conn )
. filter ( comment_report ::resolved . eq ( false ) )
. into_boxed ( ) ;
if let Some ( community_id ) = community_id {
query = query . filter ( post ::community_id . eq ( community_id ) )
}
query . select ( count ( comment_report ::id ) ) . first ::< i64 > ( conn )
}
}
pub struct CommentReportQueryBuilder < ' a > {
conn : & ' a PgConnection ,
community_ids : Option < Vec < CommunityId > > , // TODO bad way to do this
my_person_id : PersonId ,
community_id : Option < CommunityId > ,
page : Option < i64 > ,
limit : Option < i64 > ,
resolved: Option < bool > ,
un resolved_only : Option < bool > ,
}
impl < ' a > CommentReportQueryBuilder < ' a > {
pub fn create ( conn : & ' a PgConnection ) -> Self {
pub fn create ( conn : & ' a PgConnection , my_person_id : PersonId ) -> Self {
CommentReportQueryBuilder {
conn ,
community_ids : None ,
my_person_id ,
community_id : None ,
page : None ,
limit : None ,
resolved: Some ( fals e) ,
unresolved_only: Some ( tru e) ,
}
}
pub fn community_id s < T : MaybeOptional < Vec < CommunityId > > > ( mut self , community_id s : T ) -> Self {
self . community_id s = community_id s . get_optional ( ) ;
pub fn community_id < T : MaybeOptional < CommunityId > > ( mut self , community_id : T ) -> Self {
self . community_id = community_id . get_optional ( ) ;
self
}
@ -129,8 +212,8 @@ impl<'a> CommentReportQueryBuilder<'a> {
self
}
pub fn resolved< T : MaybeOptional < bool > > ( mut self , resolved: T ) -> Self {
self . resolved = resolved. get_optional ( ) ;
pub fn un resolved_only < T : MaybeOptional < bool > > ( mut self , un resolved_only : T ) -> Self {
self . un resolved_only = un resolved_only . get_optional ( ) ;
self
}
@ -141,6 +224,31 @@ impl<'a> CommentReportQueryBuilder<'a> {
. inner_join ( community ::table . on ( post ::community_id . eq ( community ::id ) ) )
. inner_join ( person ::table . on ( comment_report ::creator_id . eq ( person ::id ) ) )
. inner_join ( person_alias_1 ::table . on ( post ::creator_id . eq ( person_alias_1 ::id ) ) )
// Test this join
. inner_join (
community_moderator ::table . on (
community_moderator ::community_id
. eq ( post ::community_id )
. and ( community_moderator ::person_id . eq ( self . my_person_id ) ) ,
) ,
)
. inner_join (
comment_aggregates ::table . on ( comment_report ::comment_id . eq ( comment_aggregates ::comment_id ) ) ,
)
. left_join (
community_person_ban ::table . on (
community ::id
. eq ( community_person_ban ::community_id )
. and ( community_person_ban ::person_id . eq ( comment ::creator_id ) ) ,
) ,
)
. left_join (
comment_like ::table . on (
comment ::id
. eq ( comment_like ::comment_id )
. and ( comment_like ::person_id . eq ( self . my_person_id ) ) ,
) ,
)
. left_join (
person_alias_2 ::table . on ( comment_report ::resolver_id . eq ( person_alias_2 ::id . nullable ( ) ) ) ,
)
@ -151,16 +259,19 @@ impl<'a> CommentReportQueryBuilder<'a> {
Community ::safe_columns_tuple ( ) ,
Person ::safe_columns_tuple ( ) ,
PersonAlias1 ::safe_columns_tuple ( ) ,
comment_aggregates ::all_columns ,
community_person_ban ::all_columns . nullable ( ) ,
comment_like ::score . nullable ( ) ,
PersonAlias2 ::safe_columns_tuple ( ) . nullable ( ) ,
) )
. into_boxed ( ) ;
if let Some ( comm _ids ) = self . community_id s {
query = query . filter ( post ::community_id . eq _any ( comm _ids ) ) ;
if let Some ( comm unity _id) = self . community_id {
query = query . filter ( post ::community_id . eq ( comm unity _id) ) ;
}
if let Some ( resolved_flag ) = self . resolved {
query = query . filter ( comment_report ::resolved . eq ( resolved_flag ) ) ;
if self . unresolved_only . unwrap_or ( false ) {
query = query . filter ( comment_report ::resolved . eq ( false ) ) ;
}
let ( limit , offset ) = limit_and_offset ( self . page , self . limit ) ;
@ -187,8 +298,281 @@ impl ViewToVec for CommentReportView {
community : a . 3. to_owned ( ) ,
creator : a . 4. to_owned ( ) ,
comment_creator : a . 5. to_owned ( ) ,
resolver : a . 6. to_owned ( ) ,
counts : a . 6. to_owned ( ) ,
creator_banned_from_community : a . 7. is_some ( ) ,
my_vote : a . 8 ,
resolver : a . 9. to_owned ( ) ,
} )
. collect ::< Vec < Self > > ( )
}
}
#[ cfg(test) ]
mod tests {
use crate ::comment_report_view ::{ CommentReportQueryBuilder , CommentReportView } ;
use lemmy_db_queries ::{
aggregates ::comment_aggregates ::CommentAggregates ,
establish_unpooled_connection ,
Crud ,
Joinable ,
Reportable ,
} ;
use lemmy_db_schema ::source ::{ comment ::* , comment_report ::* , community ::* , person ::* , post ::* } ;
use serial_test ::serial ;
#[ test ]
#[ serial ]
fn test_crud ( ) {
let conn = establish_unpooled_connection ( ) ;
let new_person = PersonForm {
name : "timmy_crv" . into ( ) ,
.. PersonForm ::default ( )
} ;
let inserted_timmy = Person ::create ( & conn , & new_person ) . unwrap ( ) ;
let new_person_2 = PersonForm {
name : "sara_crv" . into ( ) ,
.. PersonForm ::default ( )
} ;
let inserted_sara = Person ::create ( & conn , & new_person_2 ) . unwrap ( ) ;
// Add a third person, since new ppl can only report something once.
let new_person_3 = PersonForm {
name : "jessica_crv" . into ( ) ,
.. PersonForm ::default ( )
} ;
let inserted_jessica = Person ::create ( & conn , & new_person_3 ) . unwrap ( ) ;
let new_community = CommunityForm {
name : "test community crv" . to_string ( ) ,
title : "nada" . to_owned ( ) ,
.. CommunityForm ::default ( )
} ;
let inserted_community = Community ::create ( & conn , & new_community ) . unwrap ( ) ;
// Make timmy a mod
let timmy_moderator_form = CommunityModeratorForm {
community_id : inserted_community . id ,
person_id : inserted_timmy . id ,
} ;
let _inserted_moderator = CommunityModerator ::join ( & conn , & timmy_moderator_form ) . unwrap ( ) ;
let new_post = PostForm {
name : "A test post crv" . into ( ) ,
creator_id : inserted_timmy . id ,
community_id : inserted_community . id ,
.. PostForm ::default ( )
} ;
let inserted_post = Post ::create ( & conn , & new_post ) . unwrap ( ) ;
let comment_form = CommentForm {
content : "A test comment 32" . into ( ) ,
creator_id : inserted_timmy . id ,
post_id : inserted_post . id ,
.. CommentForm ::default ( )
} ;
let inserted_comment = Comment ::create ( & conn , & comment_form ) . unwrap ( ) ;
// sara reports
let sara_report_form = CommentReportForm {
creator_id : inserted_sara . id ,
comment_id : inserted_comment . id ,
original_comment_text : "this was it at time of creation" . into ( ) ,
reason : "from sara" . into ( ) ,
} ;
let inserted_sara_report = CommentReport ::report ( & conn , & sara_report_form ) . unwrap ( ) ;
// jessica reports
let jessica_report_form = CommentReportForm {
creator_id : inserted_jessica . id ,
comment_id : inserted_comment . id ,
original_comment_text : "this was it at time of creation" . into ( ) ,
reason : "from jessica" . into ( ) ,
} ;
let inserted_jessica_report = CommentReport ::report ( & conn , & jessica_report_form ) . unwrap ( ) ;
let agg = CommentAggregates ::read ( & conn , inserted_comment . id ) . unwrap ( ) ;
let read_jessica_report_view =
CommentReportView ::read ( & conn , inserted_jessica_report . id , inserted_timmy . id ) . unwrap ( ) ;
let expected_jessica_report_view = CommentReportView {
comment_report : inserted_jessica_report . to_owned ( ) ,
comment : inserted_comment . to_owned ( ) ,
post : inserted_post ,
community : CommunitySafe {
id : inserted_community . id ,
name : inserted_community . name ,
icon : None ,
removed : false ,
deleted : false ,
nsfw : false ,
actor_id : inserted_community . actor_id . to_owned ( ) ,
local : true ,
title : inserted_community . title ,
description : None ,
updated : None ,
banner : None ,
published : inserted_community . published ,
} ,
creator : PersonSafe {
id : inserted_jessica . id ,
name : inserted_jessica . name ,
display_name : None ,
published : inserted_jessica . published ,
avatar : None ,
actor_id : inserted_jessica . actor_id . to_owned ( ) ,
local : true ,
banned : false ,
deleted : false ,
admin : false ,
bot_account : false ,
bio : None ,
banner : None ,
updated : None ,
inbox_url : inserted_jessica . inbox_url . to_owned ( ) ,
shared_inbox_url : None ,
matrix_user_id : None ,
} ,
comment_creator : PersonSafeAlias1 {
id : inserted_timmy . id ,
name : inserted_timmy . name . to_owned ( ) ,
display_name : None ,
published : inserted_timmy . published ,
avatar : None ,
actor_id : inserted_timmy . actor_id . to_owned ( ) ,
local : true ,
banned : false ,
deleted : false ,
admin : false ,
bot_account : false ,
bio : None ,
banner : None ,
updated : None ,
inbox_url : inserted_timmy . inbox_url . to_owned ( ) ,
shared_inbox_url : None ,
matrix_user_id : None ,
} ,
creator_banned_from_community : false ,
counts : CommentAggregates {
id : agg . id ,
comment_id : inserted_comment . id ,
score : 0 ,
upvotes : 0 ,
downvotes : 0 ,
published : agg . published ,
} ,
my_vote : None ,
resolver : None ,
} ;
assert_eq! ( read_jessica_report_view , expected_jessica_report_view ) ;
let mut expected_sara_report_view = expected_jessica_report_view . clone ( ) ;
expected_sara_report_view . comment_report = inserted_sara_report ;
expected_sara_report_view . creator = PersonSafe {
id : inserted_sara . id ,
name : inserted_sara . name ,
display_name : None ,
published : inserted_sara . published ,
avatar : None ,
actor_id : inserted_sara . actor_id . to_owned ( ) ,
local : true ,
banned : false ,
deleted : false ,
admin : false ,
bot_account : false ,
bio : None ,
banner : None ,
updated : None ,
inbox_url : inserted_sara . inbox_url . to_owned ( ) ,
shared_inbox_url : None ,
matrix_user_id : None ,
} ;
// Do a batch read of timmys reports
let reports = CommentReportQueryBuilder ::create ( & conn , inserted_timmy . id )
. list ( )
. unwrap ( ) ;
assert_eq! (
reports ,
[
expected_sara_report_view . to_owned ( ) ,
expected_jessica_report_view . to_owned ( )
]
) ;
// Make sure the counts are correct
let report_count = CommentReportView ::get_report_count ( & conn , inserted_timmy . id , None ) . unwrap ( ) ;
assert_eq! ( 2 , report_count ) ;
// Try to resolve the report
CommentReport ::resolve ( & conn , inserted_jessica_report . id , inserted_timmy . id ) . unwrap ( ) ;
let read_jessica_report_view_after_resolve =
CommentReportView ::read ( & conn , inserted_jessica_report . id , inserted_timmy . id ) . unwrap ( ) ;
let mut expected_jessica_report_view_after_resolve = expected_jessica_report_view ;
expected_jessica_report_view_after_resolve
. comment_report
. resolved = true ;
expected_jessica_report_view_after_resolve
. comment_report
. resolver_id = Some ( inserted_timmy . id ) ;
expected_jessica_report_view_after_resolve
. comment_report
. updated = read_jessica_report_view_after_resolve
. comment_report
. updated ;
expected_jessica_report_view_after_resolve . resolver = Some ( PersonSafeAlias2 {
id : inserted_timmy . id ,
name : inserted_timmy . name . to_owned ( ) ,
display_name : None ,
published : inserted_timmy . published ,
avatar : None ,
actor_id : inserted_timmy . actor_id . to_owned ( ) ,
local : true ,
banned : false ,
deleted : false ,
admin : false ,
bot_account : false ,
bio : None ,
banner : None ,
updated : None ,
inbox_url : inserted_timmy . inbox_url . to_owned ( ) ,
shared_inbox_url : None ,
matrix_user_id : None ,
} ) ;
assert_eq! (
read_jessica_report_view_after_resolve ,
expected_jessica_report_view_after_resolve
) ;
// Do a batch read of timmys reports
// It should only show saras, which is unresolved
let reports_after_resolve = CommentReportQueryBuilder ::create ( & conn , inserted_timmy . id )
. list ( )
. unwrap ( ) ;
assert_eq! ( reports_after_resolve [ 0 ] , expected_sara_report_view ) ;
// Make sure the counts are correct
let report_count_after_resolved =
CommentReportView ::get_report_count ( & conn , inserted_timmy . id , None ) . unwrap ( ) ;
assert_eq! ( 1 , report_count_after_resolved ) ;
Person ::delete ( & conn , inserted_timmy . id ) . unwrap ( ) ;
Person ::delete ( & conn , inserted_sara . id ) . unwrap ( ) ;
Person ::delete ( & conn , inserted_jessica . id ) . unwrap ( ) ;
Community ::delete ( & conn , inserted_community . id ) . unwrap ( ) ;
}
}