@@ -193,7 +193,7 @@ pub async fn handle_create_raid_submission(
193193 "Couldn't parse tweet reply link" . to_string ( ) ,
194194 ) ) ) ;
195195 } ;
196- if user_x. username != reply_username {
196+ if user_x. username . to_lowercase ( ) != reply_username. to_lowercase ( ) {
197197 return Err ( AppError :: Handler ( HandlerError :: Auth ( AuthHandlerError :: Unauthorized (
198198 "Only tweet reply author is eligible to submit" . to_string ( ) ,
199199 ) ) ) ) ;
@@ -582,7 +582,71 @@ mod tests {
582582 . await
583583 . unwrap ( ) ;
584584
585- assert_eq ! ( response. status( ) , StatusCode :: CREATED ) ; // Note: Handler returns CREATED (201), your assert was checking 200
585+ assert_eq ! ( response. status( ) , StatusCode :: CREATED ) ;
586+
587+ // 6. Verify in DB
588+ let sub = state. db . raid_submissions . find_by_id ( "999999999" ) . await . unwrap ( ) ;
589+ assert ! ( sub. is_some( ) ) ;
590+ let sub = sub. unwrap ( ) ;
591+ assert_eq ! ( sub. raid_id, raid_id) ;
592+ assert_eq ! ( & sub. id, "999999999" ) ;
593+ assert ! ( sub. target_id. is_none( ) ) ;
594+ }
595+
596+ #[ tokio:: test]
597+ async fn test_create_raid_submission_case_insensitive_success ( ) {
598+ let state = create_test_app_state ( ) . await ;
599+ reset_database ( & state. db . pool ) . await ;
600+
601+ // 1. Setup Active Raid
602+ let raid_id = state
603+ . db
604+ . raid_quests
605+ . create ( & CreateRaidQuest { name : "Active" . into ( ) } )
606+ . await
607+ . unwrap ( ) ;
608+
609+ // 2. Setup User
610+ let user = create_persisted_address ( & state. db . addresses , "submitter" ) . await ;
611+
612+ // 3. Seed Target Tweet (Required for Foreign Key)
613+ let target_tweet_id = "1868000000000000000" ;
614+ seed_target_tweet ( & state, target_tweet_id) . await ;
615+
616+ // 4. Setup X Association
617+ // The handler requires the user to have an X account, and that account
618+ // must match the username in the 'tweet_reply_link' (which is "me" below).
619+ sqlx:: query ( "INSERT INTO x_associations (quan_address, username, created_at) VALUES ($1, $2, NOW())" )
620+ . bind ( & user. quan_address . 0 )
621+ . bind ( "wao" ) // Must match the username in the payload URL
622+ . execute ( & state. db . pool )
623+ . await
624+ . expect ( "Failed to create X association" ) ;
625+
626+ let router = Router :: new ( )
627+ . route ( "/submissions" , post ( handle_create_raid_submission) )
628+ . layer ( Extension ( user) )
629+ . with_state ( state. clone ( ) ) ;
630+
631+ // 5. Payload
632+ // Reply Link -> ID 999999999, Username "me"
633+ let payload = RaidSubmissionInput {
634+ tweet_reply_link : "https://x.com/WaO/status/999999999" . to_string ( ) ,
635+ } ;
636+
637+ let response = router
638+ . oneshot (
639+ Request :: builder ( )
640+ . method ( "POST" )
641+ . uri ( "/submissions" )
642+ . header ( http:: header:: CONTENT_TYPE , "application/json" )
643+ . body ( Body :: from ( serde_json:: to_string ( & payload) . unwrap ( ) ) )
644+ . unwrap ( ) ,
645+ )
646+ . await
647+ . unwrap ( ) ;
648+
649+ assert_eq ! ( response. status( ) , StatusCode :: CREATED ) ;
586650
587651 // 6. Verify in DB
588652 let sub = state. db . raid_submissions . find_by_id ( "999999999" ) . await . unwrap ( ) ;
0 commit comments