2023-07-20 14:36:16 +00:00
use crate ::structs ::{ CommentView , LocalUserView } ;
2022-11-09 10:05:00 +00:00
use diesel ::{
2023-07-28 08:36:50 +00:00
pg ::Pg ,
2022-11-09 10:05:00 +00:00
result ::Error ,
BoolExpressionMethods ,
ExpressionMethods ,
JoinOnDsl ,
NullableExpressionMethods ,
PgTextExpressionMethods ,
QueryDsl ,
} ;
use diesel_async ::RunQueryDsl ;
2022-07-30 03:55:59 +00:00
use diesel_ltree ::{ nlevel , subpath , Ltree , LtreeExtensions } ;
2021-10-16 13:33:38 +00:00
use lemmy_db_schema ::{
2023-04-12 14:40:59 +00:00
newtypes ::{ CommentId , CommunityId , LocalUserId , PersonId , PostId } ,
2020-12-15 15:28:25 +00:00
schema ::{
2022-08-23 19:38:51 +00:00
comment ,
comment_aggregates ,
comment_like ,
comment_saved ,
community ,
community_block ,
community_follower ,
2023-08-31 11:07:45 +00:00
community_moderator ,
2022-08-23 19:38:51 +00:00
community_person_ban ,
local_user_language ,
person ,
person_block ,
2021-03-11 04:43:11 +00:00
post ,
2020-12-15 15:28:25 +00:00
} ,
2023-08-31 13:26:10 +00:00
source ::community ::CommunityFollower ,
2023-07-28 08:36:50 +00:00
utils ::{ fuzzy_search , limit_and_offset , DbConn , DbPool , ListFn , Queries , ReadFn } ,
2022-08-23 19:38:51 +00:00
CommentSortType ,
ListingType ,
2020-12-15 15:28:25 +00:00
} ;
2023-07-28 08:36:50 +00:00
fn queries < ' a > ( ) -> Queries <
impl ReadFn < ' a , CommentView , ( CommentId , Option < PersonId > ) > ,
impl ListFn < ' a , CommentView , CommentQuery < ' a > > ,
> {
let all_joins = | query : comment ::BoxedQuery < ' a , Pg > , my_person_id : Option < PersonId > | {
2020-12-15 15:28:25 +00:00
// The left join below will return None in this case
2021-03-18 20:25:21 +00:00
let person_id_join = my_person_id . unwrap_or ( PersonId ( - 1 ) ) ;
2023-07-28 08:36:50 +00:00
query
2021-03-10 22:33:55 +00:00
. inner_join ( person ::table )
2020-12-15 15:28:25 +00:00
. inner_join ( post ::table )
. inner_join ( community ::table . on ( post ::community_id . eq ( community ::id ) ) )
. inner_join ( comment_aggregates ::table )
. left_join (
2021-03-10 22:33:55 +00:00
community_person_ban ::table . on (
2020-12-15 15:28:25 +00:00
community ::id
2021-03-10 22:33:55 +00:00
. eq ( community_person_ban ::community_id )
2023-04-25 23:28:06 +00:00
. and ( community_person_ban ::person_id . eq ( comment ::creator_id ) ) ,
2020-12-15 15:28:25 +00:00
) ,
)
. left_join (
community_follower ::table . on (
post ::community_id
. eq ( community_follower ::community_id )
2021-03-10 22:33:55 +00:00
. and ( community_follower ::person_id . eq ( person_id_join ) ) ,
2020-12-15 15:28:25 +00:00
) ,
)
. left_join (
comment_saved ::table . on (
comment ::id
. eq ( comment_saved ::comment_id )
2021-03-10 22:33:55 +00:00
. and ( comment_saved ::person_id . eq ( person_id_join ) ) ,
2020-12-15 15:28:25 +00:00
) ,
)
2021-08-19 20:54:15 +00:00
. left_join (
person_block ::table . on (
comment ::creator_id
. eq ( person_block ::target_id )
. and ( person_block ::person_id . eq ( person_id_join ) ) ,
) ,
)
2020-12-15 15:28:25 +00:00
. left_join (
comment_like ::table . on (
comment ::id
. eq ( comment_like ::comment_id )
2021-03-10 22:33:55 +00:00
. and ( comment_like ::person_id . eq ( person_id_join ) ) ,
2020-12-15 15:28:25 +00:00
) ,
)
2023-08-31 11:07:45 +00:00
. left_join (
community_moderator ::table . on (
post ::id
. eq ( comment ::post_id )
. and ( post ::community_id . eq ( community_moderator ::community_id ) )
. and ( community_moderator ::person_id . eq ( person_id_join ) ) ,
) ,
)
2023-07-28 08:36:50 +00:00
} ;
let selection = (
comment ::all_columns ,
person ::all_columns ,
post ::all_columns ,
community ::all_columns ,
comment_aggregates ::all_columns ,
2023-08-08 09:41:10 +00:00
community_person_ban ::id . nullable ( ) . is_not_null ( ) ,
CommunityFollower ::select_subscribed_type ( ) ,
comment_saved ::id . nullable ( ) . is_not_null ( ) ,
person_block ::id . nullable ( ) . is_not_null ( ) ,
2023-07-28 08:36:50 +00:00
comment_like ::score . nullable ( ) ,
) ;
let read = move | mut conn : DbConn < ' a > ,
( comment_id , my_person_id ) : ( CommentId , Option < PersonId > ) | async move {
all_joins ( comment ::table . find ( comment_id ) . into_boxed ( ) , my_person_id )
. select ( selection )
2023-08-31 13:26:10 +00:00
. first ::< CommentView > ( & mut conn )
2023-07-28 08:36:50 +00:00
. await
} ;
let list = move | mut conn : DbConn < ' a > , options : CommentQuery < ' a > | async move {
let person_id = options . local_user . map ( | l | l . person . id ) ;
let local_user_id = options . local_user . map ( | l | l . local_user . id ) ;
2020-12-15 15:28:25 +00:00
2020-12-16 18:59:43 +00:00
// The left join below will return None in this case
2023-07-28 08:36:50 +00:00
let person_id_join = person_id . unwrap_or ( PersonId ( - 1 ) ) ;
let local_user_id_join = local_user_id . unwrap_or ( LocalUserId ( - 1 ) ) ;
2020-12-16 18:59:43 +00:00
2023-07-28 08:36:50 +00:00
let mut query = all_joins ( comment ::table . into_boxed ( ) , person_id )
2021-08-19 20:54:15 +00:00
. left_join (
community_block ::table . on (
community ::id
. eq ( community_block ::community_id )
. and ( community_block ::person_id . eq ( person_id_join ) ) ,
) ,
)
2022-08-22 20:55:10 +00:00
. left_join (
local_user_language ::table . on (
2022-08-23 21:20:00 +00:00
comment ::language_id
2022-08-22 20:55:10 +00:00
. eq ( local_user_language ::language_id )
. and ( local_user_language ::local_user_id . eq ( local_user_id_join ) ) ,
) ,
)
2023-07-28 08:36:50 +00:00
. select ( selection ) ;
if let Some ( creator_id ) = options . creator_id {
2020-12-16 18:59:43 +00:00
query = query . filter ( comment ::creator_id . eq ( creator_id ) ) ;
2020-12-15 15:28:25 +00:00
} ;
2023-07-28 08:36:50 +00:00
if let Some ( post_id ) = options . post_id {
2020-12-16 18:59:43 +00:00
query = query . filter ( comment ::post_id . eq ( post_id ) ) ;
2020-12-15 15:28:25 +00:00
} ;
2023-07-28 08:36:50 +00:00
if let Some ( parent_path ) = options . parent_path . as_ref ( ) {
2022-07-30 03:55:59 +00:00
query = query . filter ( comment ::path . contained_by ( parent_path ) ) ;
} ;
2023-07-28 08:36:50 +00:00
if let Some ( search_term ) = options . search_term {
2020-12-15 15:28:25 +00:00
query = query . filter ( comment ::content . ilike ( fuzzy_search ( & search_term ) ) ) ;
} ;
2023-07-28 08:36:50 +00:00
if let Some ( community_id ) = options . community_id {
2023-04-25 23:28:06 +00:00
query = query . filter ( post ::community_id . eq ( community_id ) ) ;
}
2023-07-28 08:36:50 +00:00
if let Some ( listing_type ) = options . listing_type {
2022-02-18 02:30:47 +00:00
match listing_type {
2023-08-08 09:41:10 +00:00
ListingType ::Subscribed = > query = query . filter ( community_follower ::pending . is_not_null ( ) ) , // TODO could be this: and(community_follower::person_id.eq(person_id_join)),
2022-02-18 02:30:47 +00:00
ListingType ::Local = > {
query = query . filter ( community ::local . eq ( true ) ) . filter (
community ::hidden
. eq ( false )
. or ( community_follower ::person_id . eq ( person_id_join ) ) ,
)
}
ListingType ::All = > {
query = query . filter (
community ::hidden
. eq ( false )
. or ( community_follower ::person_id . eq ( person_id_join ) ) ,
)
}
2023-08-31 11:07:45 +00:00
ListingType ::ModeratorView = > {
query = query . filter ( community_moderator ::person_id . is_not_null ( ) ) ;
}
2022-07-08 10:21:33 +00:00
}
2022-07-29 10:57:39 +00:00
}
2023-08-11 09:13:14 +00:00
if options . saved_only {
2023-02-18 14:35:35 +00:00
query = query . filter ( comment_saved ::comment_id . is_not_null ( ) ) ;
2020-12-15 15:28:25 +00:00
}
2023-08-11 09:13:14 +00:00
if options . liked_only {
2023-08-08 09:40:28 +00:00
query = query . filter ( comment_like ::score . eq ( 1 ) ) ;
2023-08-11 09:13:14 +00:00
} else if options . disliked_only {
2023-08-08 09:40:28 +00:00
query = query . filter ( comment_like ::score . eq ( - 1 ) ) ;
}
2023-07-28 08:36:50 +00:00
let is_creator = options . creator_id = = options . local_user . map ( | l | l . person . id ) ;
2023-07-20 14:36:16 +00:00
// only show deleted comments to creator
if ! is_creator {
2022-09-21 01:33:33 +00:00
query = query . filter ( comment ::deleted . eq ( false ) ) ;
2023-07-20 14:36:16 +00:00
}
2023-08-24 09:40:08 +00:00
let is_admin = options
. local_user
. map ( | l | l . local_user . admin )
. unwrap_or ( false ) ;
2023-07-20 14:36:16 +00:00
// only show removed comments to admin when viewing user profile
2023-08-04 15:36:36 +00:00
if ! ( options . is_profile_view & & is_admin ) {
2022-09-21 01:33:33 +00:00
query = query . filter ( comment ::removed . eq ( false ) ) ;
}
2023-07-28 08:36:50 +00:00
if ! options
2023-07-20 14:36:16 +00:00
. local_user
. map ( | l | l . local_user . show_bot_accounts )
. unwrap_or ( true )
{
2021-04-21 21:41:14 +00:00
query = query . filter ( person ::bot_account . eq ( false ) ) ;
} ;
2023-08-31 11:07:45 +00:00
if options . local_user . is_some ( )
& & options . listing_type . unwrap_or_default ( ) ! = ListingType ::ModeratorView
{
2022-08-22 20:55:10 +00:00
// Filter out the rows with missing languages
2023-02-18 14:35:35 +00:00
query = query . filter ( local_user_language ::language_id . is_not_null ( ) ) ;
2022-08-22 20:55:10 +00:00
// Don't show blocked communities or persons
2023-07-28 08:36:50 +00:00
if options . post_id . is_none ( ) {
2023-05-29 15:41:47 +00:00
query = query . filter ( community_block ::person_id . is_null ( ) ) ;
}
2021-08-19 20:54:15 +00:00
query = query . filter ( person_block ::person_id . is_null ( ) ) ;
}
2022-07-30 03:55:59 +00:00
// A Max depth given means its a tree fetch
2023-07-28 08:36:50 +00:00
let ( limit , offset ) = if let Some ( max_depth ) = options . max_depth {
let depth_limit = if let Some ( parent_path ) = options . parent_path . as_ref ( ) {
2022-07-30 03:55:59 +00:00
parent_path . 0. split ( '.' ) . count ( ) as i32 + max_depth
// Add one because of root "0"
} else {
max_depth + 1
} ;
query = query . filter ( nlevel ( comment ::path ) . le ( depth_limit ) ) ;
2023-08-07 09:11:07 +00:00
// only order if filtering by a post id, or parent_path. DOS potential otherwise and max_depth + !post_id isn't used anyways (afaik)
if options . post_id . is_some ( ) | | options . parent_path . is_some ( ) {
2023-07-25 16:46:00 +00:00
// Always order by the parent path first
query = query . order_by ( subpath ( comment ::path , 0 , - 1 ) ) ;
}
2022-07-30 03:55:59 +00:00
// TODO limit question. Limiting does not work for comment threads ATM, only max_depth
// For now, don't do any limiting for tree fetches
// https://stackoverflow.com/questions/72983614/postgres-ltree-how-to-limit-the-max-number-of-children-at-any-given-level
// Don't use the regular error-checking one, many more comments must ofter be fetched.
// This does not work for comment trees, and the limit should be manually set to a high number
//
// If a max depth is given, then you know its a tree fetch, and limits should be ignored
2023-07-03 22:02:57 +00:00
// TODO a kludge to prevent attacks. Limit comments to 300 for now.
// (i64::MAX, 0)
( 300 , 0 )
2022-07-30 03:55:59 +00:00
} else {
2023-07-28 08:36:50 +00:00
// limit_and_offset_unlimited(options.page, options.limit)
limit_and_offset ( options . page , options . limit ) ?
2022-07-30 03:55:59 +00:00
} ;
2023-07-28 08:36:50 +00:00
query = match options . sort . unwrap_or ( CommentSortType ::Hot ) {
2023-07-20 14:44:23 +00:00
CommentSortType ::Hot = > query
. then_order_by ( comment_aggregates ::hot_rank . desc ( ) )
2023-07-21 09:44:47 +00:00
. then_order_by ( comment_aggregates ::score . desc ( ) ) ,
2023-07-26 17:07:05 +00:00
CommentSortType ::Controversial = > {
query . then_order_by ( comment_aggregates ::controversy_rank . desc ( ) )
}
2022-07-30 03:55:59 +00:00
CommentSortType ::New = > query . then_order_by ( comment ::published . desc ( ) ) ,
CommentSortType ::Old = > query . then_order_by ( comment ::published . asc ( ) ) ,
2023-07-21 09:44:47 +00:00
CommentSortType ::Top = > query . order_by ( comment_aggregates ::score . desc ( ) ) ,
2022-07-30 03:55:59 +00:00
} ;
2020-12-15 15:28:25 +00:00
// Note: deleted and removed comments are done on the front side
2023-07-28 08:36:50 +00:00
query
2020-12-15 15:28:25 +00:00
. limit ( limit )
. offset ( offset )
2023-08-31 13:26:10 +00:00
. load ::< CommentView > ( & mut conn )
2023-07-28 08:36:50 +00:00
. await
} ;
Queries ::new ( read , list )
}
impl CommentView {
pub async fn read (
pool : & mut DbPool < '_ > ,
comment_id : CommentId ,
my_person_id : Option < PersonId > ,
) -> Result < Self , Error > {
// If a person is given, then my_vote (res.9), if None, should be 0, not null
// Necessary to differentiate between other person's votes
let mut res = queries ( ) . read ( pool , ( comment_id , my_person_id ) ) . await ? ;
if my_person_id . is_some ( ) & & res . my_vote . is_none ( ) {
res . my_vote = Some ( 0 ) ;
}
Ok ( res )
}
}
2020-12-15 15:28:25 +00:00
2023-07-28 08:36:50 +00:00
#[ derive(Default) ]
pub struct CommentQuery < ' a > {
pub listing_type : Option < ListingType > ,
pub sort : Option < CommentSortType > ,
pub community_id : Option < CommunityId > ,
pub post_id : Option < PostId > ,
pub parent_path : Option < Ltree > ,
pub creator_id : Option < PersonId > ,
pub local_user : Option < & ' a LocalUserView > ,
pub search_term : Option < String > ,
2023-08-11 09:13:14 +00:00
pub saved_only : bool ,
pub liked_only : bool ,
pub disliked_only : bool ,
2023-08-04 15:36:36 +00:00
pub is_profile_view : bool ,
2023-07-28 08:36:50 +00:00
pub page : Option < i64 > ,
pub limit : Option < i64 > ,
pub max_depth : Option < i32 > ,
}
impl < ' a > CommentQuery < ' a > {
pub async fn list ( self , pool : & mut DbPool < '_ > ) -> Result < Vec < CommentView > , Error > {
queries ( ) . list ( pool , self ) . await
2020-12-15 15:28:25 +00:00
}
}
2020-12-15 19:39:18 +00:00
#[ cfg(test) ]
mod tests {
2023-07-17 15:04:14 +00:00
#![ allow(clippy::unwrap_used) ]
#![ allow(clippy::indexing_slicing) ]
2023-07-20 14:36:16 +00:00
use crate ::{
2023-08-31 13:26:10 +00:00
comment_view ::{ CommentQuery , CommentSortType , CommentView , DbPool } ,
2023-07-20 14:36:16 +00:00
structs ::LocalUserView ,
2022-11-19 04:33:54 +00:00
} ;
2021-10-16 13:33:38 +00:00
use lemmy_db_schema ::{
2022-05-03 17:44:13 +00:00
aggregates ::structs ::CommentAggregates ,
2023-03-01 00:49:31 +00:00
impls ::actor_language ::UNDETERMINED_ID ,
2022-08-22 20:55:10 +00:00
newtypes ::LanguageId ,
2022-08-19 14:27:39 +00:00
source ::{
2022-10-06 18:27:58 +00:00
actor_language ::LocalUserLanguage ,
2023-08-31 13:26:10 +00:00
comment ::{ Comment , CommentInsertForm , CommentLike , CommentLikeForm } ,
community ::{ Community , CommunityInsertForm } ,
2022-10-27 09:24:07 +00:00
instance ::Instance ,
2022-08-23 21:20:00 +00:00
language ::Language ,
2023-07-20 14:36:16 +00:00
local_user ::{ LocalUser , LocalUserInsertForm } ,
2023-08-31 13:26:10 +00:00
person ::{ Person , PersonInsertForm } ,
2023-08-08 09:41:10 +00:00
person_block ::{ PersonBlock , PersonBlockForm } ,
2023-08-31 13:26:10 +00:00
post ::{ Post , PostInsertForm } ,
2022-08-19 14:27:39 +00:00
} ,
2021-10-16 13:33:38 +00:00
traits ::{ Blockable , Crud , Likeable } ,
2022-11-09 10:05:00 +00:00
utils ::build_db_pool_for_tests ,
2022-06-22 12:05:41 +00:00
SubscribedType ,
2021-08-19 20:54:15 +00:00
} ;
2021-02-25 19:43:39 +00:00
use serial_test ::serial ;
2020-12-15 19:39:18 +00:00
2022-08-22 20:55:10 +00:00
struct Data {
2022-10-27 09:24:07 +00:00
inserted_instance : Instance ,
2022-08-22 20:55:10 +00:00
inserted_comment_0 : Comment ,
inserted_comment_1 : Comment ,
inserted_comment_2 : Comment ,
inserted_post : Post ,
2023-07-20 14:36:16 +00:00
local_user_view : LocalUserView ,
2022-08-22 20:55:10 +00:00
inserted_person_2 : Person ,
inserted_community : Community ,
}
2020-12-15 19:39:18 +00:00
2023-07-11 13:09:59 +00:00
async fn init_data ( pool : & mut DbPool < '_ > ) -> Data {
2023-03-01 02:36:57 +00:00
let inserted_instance = Instance ::read_or_create ( pool , " my_domain.tld " . to_string ( ) )
. await
. unwrap ( ) ;
2022-10-27 09:24:07 +00:00
let new_person = PersonInsertForm ::builder ( )
. name ( " timmy " . into ( ) )
. public_key ( " pubkey " . to_string ( ) )
. instance_id ( inserted_instance . id )
. build ( ) ;
2022-11-09 10:05:00 +00:00
let inserted_person = Person ::create ( pool , & new_person ) . await . unwrap ( ) ;
2022-10-27 09:24:07 +00:00
let local_user_form = LocalUserInsertForm ::builder ( )
. person_id ( inserted_person . id )
2022-11-19 04:33:54 +00:00
. password_encrypted ( String ::new ( ) )
2022-10-27 09:24:07 +00:00
. build ( ) ;
2022-11-09 10:05:00 +00:00
let inserted_local_user = LocalUser ::create ( pool , & local_user_form ) . await . unwrap ( ) ;
2020-12-15 19:39:18 +00:00
2022-10-27 09:24:07 +00:00
let new_person_2 = PersonInsertForm ::builder ( )
. name ( " sara " . into ( ) )
. public_key ( " pubkey " . to_string ( ) )
. instance_id ( inserted_instance . id )
. build ( ) ;
2022-11-09 10:05:00 +00:00
let inserted_person_2 = Person ::create ( pool , & new_person_2 ) . await . unwrap ( ) ;
2021-08-19 20:54:15 +00:00
2022-10-27 09:24:07 +00:00
let new_community = CommunityInsertForm ::builder ( )
. name ( " test community 5 " . to_string ( ) )
. title ( " nada " . to_owned ( ) )
. public_key ( " pubkey " . to_string ( ) )
. instance_id ( inserted_instance . id )
. build ( ) ;
2020-12-15 19:39:18 +00:00
2022-11-09 10:05:00 +00:00
let inserted_community = Community ::create ( pool , & new_community ) . await . unwrap ( ) ;
2020-12-15 19:39:18 +00:00
2022-10-27 09:24:07 +00:00
let new_post = PostInsertForm ::builder ( )
. name ( " A test post 2 " . into ( ) )
. creator_id ( inserted_person . id )
. community_id ( inserted_community . id )
. build ( ) ;
2020-12-15 19:39:18 +00:00
2022-11-09 10:05:00 +00:00
let inserted_post = Post ::create ( pool , & new_post ) . await . unwrap ( ) ;
2023-05-18 14:34:21 +00:00
let english_id = Language ::read_id_from_code ( pool , Some ( " en " ) ) . await . unwrap ( ) ;
2020-12-15 19:39:18 +00:00
2022-07-30 03:55:59 +00:00
// Create a comment tree with this hierarchy
// 0
// \ \
// 1 2
// \
// 3 4
// \
// 5
2022-10-27 09:24:07 +00:00
let comment_form_0 = CommentInsertForm ::builder ( )
. content ( " Comment 0 " . into ( ) )
. creator_id ( inserted_person . id )
. post_id ( inserted_post . id )
2023-05-18 14:34:21 +00:00
. language_id ( english_id )
2022-10-27 09:24:07 +00:00
. build ( ) ;
2020-12-15 19:39:18 +00:00
2022-11-09 10:05:00 +00:00
let inserted_comment_0 = Comment ::create ( pool , & comment_form_0 , None ) . await . unwrap ( ) ;
2020-12-15 19:39:18 +00:00
2022-10-27 09:24:07 +00:00
let comment_form_1 = CommentInsertForm ::builder ( )
. content ( " Comment 1, A test blocked comment " . into ( ) )
. creator_id ( inserted_person_2 . id )
. post_id ( inserted_post . id )
2023-05-18 14:34:21 +00:00
. language_id ( english_id )
2022-10-27 09:24:07 +00:00
. build ( ) ;
2021-08-19 20:54:15 +00:00
2022-11-09 10:05:00 +00:00
let inserted_comment_1 = Comment ::create ( pool , & comment_form_1 , Some ( & inserted_comment_0 . path ) )
. await
. unwrap ( ) ;
2022-07-30 03:55:59 +00:00
2023-05-18 14:34:21 +00:00
let finnish_id = Language ::read_id_from_code ( pool , Some ( " fi " ) ) . await . unwrap ( ) ;
2022-10-27 09:24:07 +00:00
let comment_form_2 = CommentInsertForm ::builder ( )
. content ( " Comment 2 " . into ( ) )
. creator_id ( inserted_person . id )
. post_id ( inserted_post . id )
2023-05-18 14:34:21 +00:00
. language_id ( finnish_id )
2022-10-27 09:24:07 +00:00
. build ( ) ;
2022-07-30 03:55:59 +00:00
2022-11-09 10:05:00 +00:00
let inserted_comment_2 = Comment ::create ( pool , & comment_form_2 , Some ( & inserted_comment_0 . path ) )
. await
. unwrap ( ) ;
2022-07-30 03:55:59 +00:00
2022-10-27 09:24:07 +00:00
let comment_form_3 = CommentInsertForm ::builder ( )
. content ( " Comment 3 " . into ( ) )
. creator_id ( inserted_person . id )
. post_id ( inserted_post . id )
2023-05-18 14:34:21 +00:00
. language_id ( english_id )
2022-10-27 09:24:07 +00:00
. build ( ) ;
2022-07-30 03:55:59 +00:00
let _inserted_comment_3 =
2022-11-09 10:05:00 +00:00
Comment ::create ( pool , & comment_form_3 , Some ( & inserted_comment_1 . path ) )
. await
. unwrap ( ) ;
2022-07-30 03:55:59 +00:00
2023-02-05 05:38:08 +00:00
let polish_id = Language ::read_id_from_code ( pool , Some ( " pl " ) )
. await
. unwrap ( )
. unwrap ( ) ;
2022-10-27 09:24:07 +00:00
let comment_form_4 = CommentInsertForm ::builder ( )
. content ( " Comment 4 " . into ( ) )
. creator_id ( inserted_person . id )
. post_id ( inserted_post . id )
. language_id ( Some ( polish_id ) )
. build ( ) ;
2022-07-30 03:55:59 +00:00
2022-11-09 10:05:00 +00:00
let inserted_comment_4 = Comment ::create ( pool , & comment_form_4 , Some ( & inserted_comment_1 . path ) )
. await
. unwrap ( ) ;
2022-07-30 03:55:59 +00:00
2022-10-27 09:24:07 +00:00
let comment_form_5 = CommentInsertForm ::builder ( )
. content ( " Comment 5 " . into ( ) )
. creator_id ( inserted_person . id )
. post_id ( inserted_post . id )
. build ( ) ;
2022-07-30 03:55:59 +00:00
let _inserted_comment_5 =
2022-11-09 10:05:00 +00:00
Comment ::create ( pool , & comment_form_5 , Some ( & inserted_comment_4 . path ) )
. await
. unwrap ( ) ;
2021-08-19 20:54:15 +00:00
let timmy_blocks_sara_form = PersonBlockForm {
person_id : inserted_person . id ,
target_id : inserted_person_2 . id ,
} ;
2022-11-09 10:05:00 +00:00
let inserted_block = PersonBlock ::block ( pool , & timmy_blocks_sara_form )
. await
. unwrap ( ) ;
2021-08-19 20:54:15 +00:00
let expected_block = PersonBlock {
id : inserted_block . id ,
person_id : inserted_person . id ,
target_id : inserted_person_2 . id ,
published : inserted_block . published ,
} ;
assert_eq! ( expected_block , inserted_block ) ;
2022-08-23 19:38:51 +00:00
let comment_like_form = CommentLikeForm {
comment_id : inserted_comment_0 . id ,
post_id : inserted_post . id ,
person_id : inserted_person . id ,
score : 1 ,
} ;
2022-11-09 10:05:00 +00:00
let _inserted_comment_like = CommentLike ::like ( pool , & comment_like_form ) . await . unwrap ( ) ;
2022-08-23 19:38:51 +00:00
2023-07-20 14:36:16 +00:00
let local_user_view = LocalUserView {
local_user : inserted_local_user . clone ( ) ,
person : inserted_person . clone ( ) ,
counts : Default ::default ( ) ,
} ;
2022-08-22 20:55:10 +00:00
Data {
2022-10-27 09:24:07 +00:00
inserted_instance ,
2022-08-22 20:55:10 +00:00
inserted_comment_0 ,
inserted_comment_1 ,
inserted_comment_2 ,
inserted_post ,
2023-07-20 14:36:16 +00:00
local_user_view ,
2022-08-22 20:55:10 +00:00
inserted_person_2 ,
inserted_community ,
}
}
2022-11-09 10:05:00 +00:00
#[ tokio::test ]
2022-08-22 20:55:10 +00:00
#[ serial ]
2022-11-09 10:05:00 +00:00
async fn test_crud ( ) {
let pool = & build_db_pool_for_tests ( ) . await ;
2023-07-11 13:09:59 +00:00
let pool = & mut pool . into ( ) ;
2022-11-09 10:05:00 +00:00
let data = init_data ( pool ) . await ;
2022-08-22 20:55:10 +00:00
2022-11-09 10:05:00 +00:00
let expected_comment_view_no_person = expected_comment_view ( & data , pool ) . await ;
2020-12-15 19:39:18 +00:00
2022-11-19 04:33:54 +00:00
let mut expected_comment_view_with_person = expected_comment_view_no_person . clone ( ) ;
2021-03-10 22:33:55 +00:00
expected_comment_view_with_person . my_vote = Some ( 1 ) ;
2020-12-15 19:39:18 +00:00
2023-07-17 10:20:25 +00:00
let read_comment_views_no_person = CommentQuery {
sort : ( Some ( CommentSortType ::Old ) ) ,
post_id : ( Some ( data . inserted_post . id ) ) ,
.. Default ::default ( )
}
. list ( pool )
. await
. unwrap ( ) ;
2020-12-15 19:39:18 +00:00
2022-07-30 03:55:59 +00:00
assert_eq! (
expected_comment_view_no_person ,
read_comment_views_no_person [ 0 ]
) ;
2023-07-17 10:20:25 +00:00
let read_comment_views_with_person = CommentQuery {
sort : ( Some ( CommentSortType ::Old ) ) ,
post_id : ( Some ( data . inserted_post . id ) ) ,
2023-07-20 14:36:16 +00:00
local_user : ( Some ( & data . local_user_view ) ) ,
2023-07-17 10:20:25 +00:00
.. Default ::default ( )
}
. list ( pool )
. await
. unwrap ( ) ;
2020-12-15 19:39:18 +00:00
2022-07-30 03:55:59 +00:00
assert_eq! (
expected_comment_view_with_person ,
read_comment_views_with_person [ 0 ]
) ;
// Make sure its 1, not showing the blocked comment
assert_eq! ( 5 , read_comment_views_with_person . len ( ) ) ;
2022-08-22 20:55:10 +00:00
let read_comment_from_blocked_person = CommentView ::read (
2022-11-09 10:05:00 +00:00
pool ,
2022-08-22 20:55:10 +00:00
data . inserted_comment_1 . id ,
2023-07-20 14:36:16 +00:00
Some ( data . local_user_view . person . id ) ,
2022-08-22 20:55:10 +00:00
)
2022-11-09 10:05:00 +00:00
. await
2022-08-22 20:55:10 +00:00
. unwrap ( ) ;
2021-08-19 20:54:15 +00:00
2022-07-30 03:55:59 +00:00
// Make sure block set the creator blocked
assert! ( read_comment_from_blocked_person . creator_blocked ) ;
2021-08-19 20:54:15 +00:00
2023-08-08 09:40:28 +00:00
let read_liked_comment_views = CommentQuery {
local_user : ( Some ( & data . local_user_view ) ) ,
2023-08-11 09:13:14 +00:00
liked_only : ( true ) ,
2023-08-08 09:40:28 +00:00
.. Default ::default ( )
}
. list ( pool )
. await
. unwrap ( ) ;
assert_eq! (
expected_comment_view_with_person ,
read_liked_comment_views [ 0 ]
) ;
assert_eq! ( 1 , read_liked_comment_views . len ( ) ) ;
let read_disliked_comment_views : Vec < CommentView > = CommentQuery {
local_user : ( Some ( & data . local_user_view ) ) ,
2023-08-11 09:13:14 +00:00
disliked_only : ( true ) ,
2023-08-08 09:40:28 +00:00
.. Default ::default ( )
}
. list ( pool )
. await
. unwrap ( ) ;
assert! ( read_disliked_comment_views . is_empty ( ) ) ;
2022-11-09 10:05:00 +00:00
cleanup ( data , pool ) . await ;
2022-08-22 20:55:10 +00:00
}
2022-11-09 10:05:00 +00:00
#[ tokio::test ]
2022-08-22 20:55:10 +00:00
#[ serial ]
2022-11-09 10:05:00 +00:00
async fn test_comment_tree ( ) {
let pool = & build_db_pool_for_tests ( ) . await ;
2023-07-11 13:09:59 +00:00
let pool = & mut pool . into ( ) ;
2022-11-09 10:05:00 +00:00
let data = init_data ( pool ) . await ;
2022-08-22 20:55:10 +00:00
let top_path = data . inserted_comment_0 . path . clone ( ) ;
2023-07-17 10:20:25 +00:00
let read_comment_views_top_path = CommentQuery {
post_id : ( Some ( data . inserted_post . id ) ) ,
parent_path : ( Some ( top_path ) ) ,
.. Default ::default ( )
}
. list ( pool )
. await
. unwrap ( ) ;
2022-07-30 03:55:59 +00:00
2022-08-22 20:55:10 +00:00
let child_path = data . inserted_comment_1 . path . clone ( ) ;
2023-07-17 10:20:25 +00:00
let read_comment_views_child_path = CommentQuery {
post_id : ( Some ( data . inserted_post . id ) ) ,
parent_path : ( Some ( child_path ) ) ,
.. Default ::default ( )
}
. list ( pool )
. await
. unwrap ( ) ;
2022-07-30 03:55:59 +00:00
// Make sure the comment parent-limited fetch is correct
assert_eq! ( 6 , read_comment_views_top_path . len ( ) ) ;
assert_eq! ( 4 , read_comment_views_child_path . len ( ) ) ;
// Make sure it contains the parent, but not the comment from the other tree
let child_comments = read_comment_views_child_path
. into_iter ( )
. map ( | c | c . comment )
. collect ::< Vec < Comment > > ( ) ;
2022-08-22 20:55:10 +00:00
assert! ( child_comments . contains ( & data . inserted_comment_1 ) ) ;
assert! ( ! child_comments . contains ( & data . inserted_comment_2 ) ) ;
2022-07-30 03:55:59 +00:00
2023-07-17 10:20:25 +00:00
let read_comment_views_top_max_depth = CommentQuery {
post_id : ( Some ( data . inserted_post . id ) ) ,
max_depth : ( Some ( 1 ) ) ,
.. Default ::default ( )
}
. list ( pool )
. await
. unwrap ( ) ;
2020-12-15 19:39:18 +00:00
2022-07-30 03:55:59 +00:00
// Make sure a depth limited one only has the top comment
2021-03-11 04:43:11 +00:00
assert_eq! (
2022-11-09 10:05:00 +00:00
expected_comment_view ( & data , pool ) . await ,
2022-07-30 03:55:59 +00:00
read_comment_views_top_max_depth [ 0 ]
2020-12-15 19:39:18 +00:00
) ;
2022-07-30 03:55:59 +00:00
assert_eq! ( 1 , read_comment_views_top_max_depth . len ( ) ) ;
2021-08-19 20:54:15 +00:00
2022-08-22 20:55:10 +00:00
let child_path = data . inserted_comment_1 . path . clone ( ) ;
2023-07-17 10:20:25 +00:00
let read_comment_views_parent_max_depth = CommentQuery {
post_id : ( Some ( data . inserted_post . id ) ) ,
parent_path : ( Some ( child_path ) ) ,
max_depth : ( Some ( 1 ) ) ,
sort : ( Some ( CommentSortType ::New ) ) ,
.. Default ::default ( )
}
. list ( pool )
. await
. unwrap ( ) ;
2022-07-30 03:55:59 +00:00
// Make sure a depth limited one, and given child comment 1, has 3
assert! ( read_comment_views_parent_max_depth [ 2 ]
. comment
. content
. eq ( " Comment 3 " ) ) ;
assert_eq! ( 3 , read_comment_views_parent_max_depth . len ( ) ) ;
2022-11-09 10:05:00 +00:00
cleanup ( data , pool ) . await ;
2022-08-22 20:55:10 +00:00
}
2022-11-09 10:05:00 +00:00
#[ tokio::test ]
2022-08-23 21:20:00 +00:00
#[ serial ]
2022-11-09 10:05:00 +00:00
async fn test_languages ( ) {
let pool = & build_db_pool_for_tests ( ) . await ;
2023-07-11 13:09:59 +00:00
let pool = & mut pool . into ( ) ;
2022-11-09 10:05:00 +00:00
let data = init_data ( pool ) . await ;
2022-08-23 21:20:00 +00:00
// by default, user has all languages enabled and should see all comments
// (except from blocked user)
2023-07-17 10:20:25 +00:00
let all_languages = CommentQuery {
2023-07-20 14:36:16 +00:00
local_user : ( Some ( & data . local_user_view ) ) ,
2023-07-17 10:20:25 +00:00
.. Default ::default ( )
}
. list ( pool )
. await
. unwrap ( ) ;
2022-08-23 21:20:00 +00:00
assert_eq! ( 5 , all_languages . len ( ) ) ;
2023-05-18 14:34:21 +00:00
// change user lang to finnish, should only show one post in finnish and one undetermined
2023-02-05 05:38:08 +00:00
let finnish_id = Language ::read_id_from_code ( pool , Some ( " fi " ) )
. await
. unwrap ( )
. unwrap ( ) ;
2023-07-20 14:36:16 +00:00
LocalUserLanguage ::update ( pool , vec! [ finnish_id ] , data . local_user_view . local_user . id )
2022-11-09 10:05:00 +00:00
. await
. unwrap ( ) ;
2023-07-17 10:20:25 +00:00
let finnish_comments = CommentQuery {
2023-07-20 14:36:16 +00:00
local_user : ( Some ( & data . local_user_view ) ) ,
2023-07-17 10:20:25 +00:00
.. Default ::default ( )
}
. list ( pool )
. await
. unwrap ( ) ;
2023-05-18 14:34:21 +00:00
assert_eq! ( 2 , finnish_comments . len ( ) ) ;
let finnish_comment = finnish_comments
. iter ( )
. find ( | c | c . comment . language_id = = finnish_id ) ;
assert! ( finnish_comment . is_some ( ) ) ;
2022-08-23 21:20:00 +00:00
assert_eq! (
data . inserted_comment_2 . content ,
2023-05-18 14:34:21 +00:00
finnish_comment . unwrap ( ) . comment . content
2022-08-23 21:20:00 +00:00
) ;
// now show all comments with undetermined language (which is the default value)
2023-07-20 14:36:16 +00:00
LocalUserLanguage ::update (
pool ,
vec! [ UNDETERMINED_ID ] ,
data . local_user_view . local_user . id ,
)
. await
. unwrap ( ) ;
2023-07-17 10:20:25 +00:00
let undetermined_comment = CommentQuery {
2023-07-20 14:36:16 +00:00
local_user : ( Some ( & data . local_user_view ) ) ,
2023-07-17 10:20:25 +00:00
.. Default ::default ( )
}
. list ( pool )
. await
. unwrap ( ) ;
2023-05-18 14:34:21 +00:00
assert_eq! ( 1 , undetermined_comment . len ( ) ) ;
2022-08-23 21:20:00 +00:00
2022-11-09 10:05:00 +00:00
cleanup ( data , pool ) . await ;
2022-08-23 21:20:00 +00:00
}
2023-07-11 13:09:59 +00:00
async fn cleanup ( data : Data , pool : & mut DbPool < '_ > ) {
2023-07-20 14:36:16 +00:00
CommentLike ::remove (
pool ,
data . local_user_view . person . id ,
data . inserted_comment_0 . id ,
)
. await
. unwrap ( ) ;
2022-11-09 10:05:00 +00:00
Comment ::delete ( pool , data . inserted_comment_0 . id )
. await
. unwrap ( ) ;
Comment ::delete ( pool , data . inserted_comment_1 . id )
. await
. unwrap ( ) ;
Post ::delete ( pool , data . inserted_post . id ) . await . unwrap ( ) ;
Community ::delete ( pool , data . inserted_community . id )
. await
. unwrap ( ) ;
2023-07-20 14:36:16 +00:00
Person ::delete ( pool , data . local_user_view . person . id )
. await
. unwrap ( ) ;
2022-11-09 10:05:00 +00:00
Person ::delete ( pool , data . inserted_person_2 . id )
. await
. unwrap ( ) ;
Instance ::delete ( pool , data . inserted_instance . id )
. await
. unwrap ( ) ;
2022-08-22 20:55:10 +00:00
}
2023-07-11 13:09:59 +00:00
async fn expected_comment_view ( data : & Data , pool : & mut DbPool < '_ > ) -> CommentView {
2022-11-09 10:05:00 +00:00
let agg = CommentAggregates ::read ( pool , data . inserted_comment_0 . id )
. await
. unwrap ( ) ;
2022-08-22 20:55:10 +00:00
CommentView {
creator_banned_from_community : false ,
my_vote : None ,
subscribed : SubscribedType ::NotSubscribed ,
saved : false ,
creator_blocked : false ,
comment : Comment {
id : data . inserted_comment_0 . id ,
content : " Comment 0 " . into ( ) ,
2023-07-20 14:36:16 +00:00
creator_id : data . local_user_view . person . id ,
2022-08-22 20:55:10 +00:00
post_id : data . inserted_post . id ,
removed : false ,
deleted : false ,
published : data . inserted_comment_0 . published ,
ap_id : data . inserted_comment_0 . ap_id . clone ( ) ,
updated : None ,
local : true ,
distinguished : false ,
2022-11-19 04:33:54 +00:00
path : data . inserted_comment_0 . clone ( ) . path ,
2023-05-18 14:34:21 +00:00
language_id : LanguageId ( 37 ) ,
2022-08-22 20:55:10 +00:00
} ,
2023-03-01 17:19:46 +00:00
creator : Person {
2023-07-20 14:36:16 +00:00
id : data . local_user_view . person . id ,
2022-08-22 20:55:10 +00:00
name : " timmy " . into ( ) ,
display_name : None ,
2023-07-20 14:36:16 +00:00
published : data . local_user_view . person . published ,
2022-08-22 20:55:10 +00:00
avatar : None ,
2023-07-20 14:36:16 +00:00
actor_id : data . local_user_view . person . actor_id . clone ( ) ,
2022-08-22 20:55:10 +00:00
local : true ,
banned : false ,
deleted : false ,
bot_account : false ,
bio : None ,
banner : None ,
updated : None ,
2023-07-20 14:36:16 +00:00
inbox_url : data . local_user_view . person . inbox_url . clone ( ) ,
2022-08-22 20:55:10 +00:00
shared_inbox_url : None ,
matrix_user_id : None ,
ban_expires : None ,
2022-10-27 09:24:07 +00:00
instance_id : data . inserted_instance . id ,
2023-07-20 14:36:16 +00:00
private_key : data . local_user_view . person . private_key . clone ( ) ,
public_key : data . local_user_view . person . public_key . clone ( ) ,
last_refreshed_at : data . local_user_view . person . last_refreshed_at ,
2022-08-22 20:55:10 +00:00
} ,
post : Post {
id : data . inserted_post . id ,
2022-11-19 04:33:54 +00:00
name : data . inserted_post . name . clone ( ) ,
2023-07-20 14:36:16 +00:00
creator_id : data . local_user_view . person . id ,
2022-08-22 20:55:10 +00:00
url : None ,
body : None ,
published : data . inserted_post . published ,
updated : None ,
community_id : data . inserted_community . id ,
removed : false ,
deleted : false ,
locked : false ,
nsfw : false ,
embed_title : None ,
embed_description : None ,
embed_video_url : None ,
thumbnail_url : None ,
2022-11-19 04:33:54 +00:00
ap_id : data . inserted_post . ap_id . clone ( ) ,
2022-08-22 20:55:10 +00:00
local : true ,
language_id : Default ::default ( ) ,
2022-12-12 11:17:10 +00:00
featured_community : false ,
featured_local : false ,
2022-08-22 20:55:10 +00:00
} ,
2023-03-01 17:19:46 +00:00
community : Community {
2022-08-22 20:55:10 +00:00
id : data . inserted_community . id ,
name : " test community 5 " . to_string ( ) ,
icon : None ,
removed : false ,
deleted : false ,
nsfw : false ,
2022-11-19 04:33:54 +00:00
actor_id : data . inserted_community . actor_id . clone ( ) ,
2022-08-22 20:55:10 +00:00
local : true ,
title : " nada " . to_owned ( ) ,
description : None ,
updated : None ,
banner : None ,
hidden : false ,
posting_restricted_to_mods : false ,
published : data . inserted_community . published ,
2022-10-27 09:24:07 +00:00
instance_id : data . inserted_instance . id ,
2023-03-01 17:19:46 +00:00
private_key : data . inserted_community . private_key . clone ( ) ,
public_key : data . inserted_community . public_key . clone ( ) ,
last_refreshed_at : data . inserted_community . last_refreshed_at ,
followers_url : data . inserted_community . followers_url . clone ( ) ,
inbox_url : data . inserted_community . inbox_url . clone ( ) ,
shared_inbox_url : data . inserted_community . shared_inbox_url . clone ( ) ,
moderators_url : data . inserted_community . moderators_url . clone ( ) ,
featured_url : data . inserted_community . featured_url . clone ( ) ,
2022-08-22 20:55:10 +00:00
} ,
counts : CommentAggregates {
id : agg . id ,
comment_id : data . inserted_comment_0 . id ,
score : 1 ,
upvotes : 1 ,
downvotes : 0 ,
published : agg . published ,
child_count : 5 ,
2023-06-08 20:15:15 +00:00
hot_rank : 1728 ,
2023-07-26 17:07:05 +00:00
controversy_rank : 0.0 ,
2022-08-22 20:55:10 +00:00
} ,
}
2020-12-15 19:39:18 +00:00
}
}