@ -191,20 +191,7 @@ impl QuoteRepository for NativeRepository {
let partial_quotes : Vec < Quote > = stmt
. query_map (
rusqlite ::params_from_iter ( param_refs2 . iter ( ) . copied ( ) ) ,
| row | {
let hidden_int : i64 = row . get ( 5 ) ? ;
Ok ( Quote {
id : row . get ( 0 ) ? ,
text : row . get ( 1 ) ? ,
author : row . get ( 2 ) ? ,
source : row . get ( 3 ) ? ,
date : row . get ( 4 ) ? ,
hidden : hidden_int ! = 0 ,
created_at : row . get ( 6 ) ? ,
updated_at : row . get ( 7 ) ? ,
tags : vec ! [ ] ,
} )
} ,
| row | row_to_quote ( row , vec! [ ] ) ,
) ?
. collect ::< Result < Vec < _ > , _ > > ( ) ? ;
@ -984,4 +971,135 @@ mod tests {
let stored = repo . get_admin_auth_code ( ) . await . unwrap ( ) ;
assert_eq! ( stored . as_deref ( ) , Some ( "correct-code" ) ) ;
}
// ── hidden flag filter tests ───────────────────────────────────────────────
/// `list_quotes` must exclude hidden quotes and include only visible ones.
#[ tokio::test ]
async fn test_list_quotes_excludes_hidden ( ) {
let repo = in_memory_repo ( ) . await ;
// Create a visible quote and a hidden quote.
let ( visible , _ ) = repo
. create_quote ( CreateQuoteInput {
text : "Visible quote" . to_owned ( ) ,
author : "Author A" . to_owned ( ) ,
source : None ,
date : None ,
tags : vec ! [ ] ,
auth_code : Some ( "auth-visible-xxxxx" . to_owned ( ) ) ,
cf_turnstile_token : None ,
} )
. await
. unwrap ( ) ;
let ( hidden , hidden_auth ) = repo
. create_quote ( CreateQuoteInput {
text : "Hidden quote" . to_owned ( ) ,
author : "Author B" . to_owned ( ) ,
source : None ,
date : None ,
tags : vec ! [ ] ,
auth_code : Some ( "auth-hidden-xxxxxx" . to_owned ( ) ) ,
cf_turnstile_token : None ,
} )
. await
. unwrap ( ) ;
// Mark the second quote as hidden.
repo . update_quote (
& hidden . id ,
UpdateQuoteInput {
hidden : Some ( true ) ,
.. UpdateQuoteInput ::default ( )
} ,
& hidden_auth ,
)
. await
. unwrap ( ) ;
let result = repo . list_quotes ( 1 , None , None , None , None ) . await . unwrap ( ) ;
assert_eq! ( result . total_count , 1 , "only the visible quote should count" ) ;
assert_eq! ( result . quotes . len ( ) , 1 ) ;
assert_eq! (
result . quotes [ 0 ] . id , visible . id ,
"the returned quote must be the visible one"
) ;
}
/// `get_random_quote` must return `None` when the only quote is hidden.
#[ tokio::test ]
async fn test_get_random_quote_excludes_hidden ( ) {
let repo = in_memory_repo ( ) . await ;
// Create a single quote and immediately hide it.
let ( quote , auth ) = repo
. create_quote ( CreateQuoteInput {
text : "Only quote, hidden" . to_owned ( ) ,
author : "Ghost" . to_owned ( ) ,
source : None ,
date : None ,
tags : vec ! [ ] ,
auth_code : Some ( "auth-ghost-xxxxxxx" . to_owned ( ) ) ,
cf_turnstile_token : None ,
} )
. await
. unwrap ( ) ;
repo . update_quote (
& quote . id ,
UpdateQuoteInput {
hidden : Some ( true ) ,
.. UpdateQuoteInput ::default ( )
} ,
& auth ,
)
. await
. unwrap ( ) ;
let result = repo . get_random_quote ( ) . await . unwrap ( ) ;
assert! (
result . is_none ( ) ,
"get_random_quote should return None when only hidden quotes exist"
) ;
}
/// `get_quote` (direct ID lookup) must return the quote even when it is hidden.
#[ tokio::test ]
async fn test_get_quote_returns_hidden_quote ( ) {
let repo = in_memory_repo ( ) . await ;
let ( quote , auth ) = repo
. create_quote ( CreateQuoteInput {
text : "Accessible but hidden" . to_owned ( ) ,
author : "Secret Author" . to_owned ( ) ,
source : None ,
date : None ,
tags : vec ! [ ] ,
auth_code : Some ( "auth-secret-xxxxxx" . to_owned ( ) ) ,
cf_turnstile_token : None ,
} )
. await
. unwrap ( ) ;
repo . update_quote (
& quote . id ,
UpdateQuoteInput {
hidden : Some ( true ) ,
.. UpdateQuoteInput ::default ( )
} ,
& auth ,
)
. await
. unwrap ( ) ;
let fetched = repo . get_quote ( & quote . id ) . await . unwrap ( ) ;
assert! (
fetched . is_some ( ) ,
"get_quote must return the quote even when it is hidden"
) ;
let fetched = fetched . unwrap ( ) ;
assert_eq! ( fetched . id , quote . id ) ;
assert! ( fetched . hidden , "the returned quote must have hidden=true" ) ;
}
}