@@ -3,7 +3,7 @@ use std::path::PathBuf;
33use std:: time:: Duration ;
44
55use chacha20poly1305:: XNonce ;
6- use rusqlite:: { Connection , Transaction , params} ;
6+ use rusqlite:: { Connection , Transaction , params, params_from_iter } ;
77use rusqlite_migration:: { HookError , M , Migrations } ;
88use tokio:: sync:: oneshot;
99
@@ -80,7 +80,7 @@ enum Command {
8080 } ,
8181 DeleteFor {
8282 id : Id ,
83- uid : i64 ,
83+ uids : Vec < i64 > ,
8484 result : oneshot:: Sender < Result < ( ) , Error > > ,
8585 } ,
8686 NextUid {
@@ -420,9 +420,9 @@ impl Handler {
420420 . send ( self . delete_many ( ids) )
421421 . map_err ( |_| Error :: ResultSendError ) ?;
422422 }
423- Command :: DeleteFor { id, uid , result } => {
423+ Command :: DeleteFor { id, uids , result } => {
424424 result
425- . send ( self . delete_for ( id, uid ) )
425+ . send ( self . delete_for ( id, & uids ) )
426426 . map_err ( |_| Error :: ResultSendError ) ?;
427427 }
428428 Command :: NextUid { result } => {
@@ -571,12 +571,28 @@ impl Handler {
571571 Ok ( affected)
572572 }
573573
574- fn delete_for ( & mut self , id : Id , uid : i64 ) -> Result < ( ) , Error > {
574+ fn delete_for ( & mut self , id : Id , uids : & [ i64 ] ) -> Result < ( ) , Error > {
575+ if uids. is_empty ( ) {
576+ return Err ( Error :: Delete ) ;
577+ }
578+
579+ let placeholders = vec ! [ "?" ; uids. len( ) ] . join ( "," ) ;
580+ let select_sql = format ! (
581+ "SELECT 1 FROM entries WHERE id=? AND uid IN ({placeholders})" ,
582+ ) ;
583+ let delete_sql = format ! (
584+ "DELETE FROM entries WHERE id=? AND uid IN ({placeholders})" ,
585+ ) ;
586+
587+ let mut params = Vec :: with_capacity ( uids. len ( ) + 1 ) ;
588+ params. push ( id. to_i64 ( ) ) ;
589+ params. extend_from_slice ( uids) ;
590+
575591 let tx = self . conn . transaction ( ) ?;
576592
577593 let exists = match tx. query_row (
578- "SELECT 1 FROM entries WHERE (id=?1 AND uid=?2)" ,
579- params ! [ id . to_i64 ( ) , uid ] ,
594+ & select_sql ,
595+ params_from_iter ( & params ) ,
580596 |row| row. get :: < _ , i64 > ( 0 ) ,
581597 ) {
582598 Ok ( _) => true ,
@@ -588,10 +604,7 @@ impl Handler {
588604 return Err ( Error :: Delete ) ;
589605 }
590606
591- tx. execute (
592- "DELETE FROM entries WHERE (id=?1 AND uid=?2)" ,
593- params ! [ id. to_i64( ) , uid] ,
594- ) ?;
607+ tx. execute ( & delete_sql, params_from_iter ( & params) ) ?;
595608
596609 tx. commit ( ) ?;
597610 Ok ( ( ) )
@@ -722,11 +735,15 @@ impl Database {
722735 command_result. await ?
723736 }
724737
725- /// Delete paste with `id` for user `uid` .
726- pub async fn delete_for ( & self , id : Id , uid : i64 ) -> Result < ( ) , Error > {
738+ /// Delete paste with `id` if any of `uids` owns it .
739+ pub async fn delete_for ( & self , id : Id , uids : & [ i64 ] ) -> Result < ( ) , Error > {
727740 let ( result, command_result) = oneshot:: channel ( ) ;
728741 self . sender
729- . send ( Command :: DeleteFor { id, uid, result } )
742+ . send ( Command :: DeleteFor {
743+ id,
744+ uids : uids. to_vec ( ) ,
745+ result,
746+ } )
730747 . await
731748 . map_err ( |_| Error :: SendError ) ?;
732749 command_result. await ?
@@ -867,7 +884,7 @@ mod tests {
867884 let ( id, _entry) = db. insert ( entry) . await ?;
868885
869886 assert ! ( db. get( id, None ) . await . is_ok( ) ) ;
870- assert ! ( db. delete_for( id, uid) . await . is_ok( ) ) ;
887+ assert ! ( db. delete_for( id, & [ uid] ) . await . is_ok( ) ) ;
871888 assert ! ( db. get( id, None ) . await . is_err( ) ) ;
872889
873890 let entry = write:: Entry {
@@ -878,7 +895,29 @@ mod tests {
878895
879896 let incorrect_uid = 99 ;
880897 assert ! ( matches!(
881- db. delete_for( id, incorrect_uid) . await ,
898+ db. delete_for( id, & [ incorrect_uid] ) . await ,
899+ Err ( Error :: Delete )
900+ ) ) ;
901+
902+ // Multi-uid: passes if any uid in the list matches.
903+ let entry = write:: Entry {
904+ uid : Some ( uid) ,
905+ ..Default :: default ( )
906+ } ;
907+ let ( id, _entry) = db. insert ( entry) . await ?;
908+
909+ assert ! ( db. delete_for( id, & [ 99 , uid, 7 ] ) . await . is_ok( ) ) ;
910+ assert ! ( db. get( id, None ) . await . is_err( ) ) ;
911+
912+ // Empty slice: nothing to authorize against.
913+ let entry = write:: Entry {
914+ uid : Some ( uid) ,
915+ ..Default :: default ( )
916+ } ;
917+ let ( id, _entry) = db. insert ( entry) . await ?;
918+
919+ assert ! ( matches!(
920+ db. delete_for( id, & [ ] ) . await ,
882921 Err ( Error :: Delete )
883922 ) ) ;
884923
0 commit comments