@@ -23,7 +23,6 @@ use base64::{engine::general_purpose::STANDARD as b64, Engine};
2323use chrono:: { DateTime , Utc } ;
2424use futures_util:: stream:: TryStreamExt ;
2525use once_cell:: sync:: Lazy ;
26- use regex:: Regex ;
2726use serde:: { Deserialize , Serialize } ;
2827use sqlx:: Row ;
2928use std:: collections:: { BTreeMap , HashMap , HashSet } ;
@@ -510,7 +509,7 @@ pub(crate) async fn search_handler(
510509 . get ( "query" )
511510 . map ( |q| q. to_string ( ) )
512511 . unwrap_or_else ( || "" . to_string ( ) ) ;
513- let mut sort_by = params
512+ let sort_by = params
514513 . get ( "sort" )
515514 . map ( |q| q. to_string ( ) )
516515 . unwrap_or_else ( || "relevance" . to_string ( ) ) ;
@@ -580,13 +579,6 @@ pub(crate) async fn search_handler(
580579 return Err ( AxumNope :: NoResults ) ;
581580 }
582581
583- static RE : Lazy < Regex > = Lazy :: new ( || Regex :: new ( r"[?&]sort=([^&]+)" ) . unwrap ( ) ) ;
584- if let Some ( cap) = RE . captures ( & query_params) {
585- sort_by = cap
586- . get ( 1 )
587- . map_or ( "relevance" . to_string ( ) , |v| v. as_str ( ) . to_string ( ) ) ;
588- }
589-
590582 get_search_results ( & mut conn, & config, & query_params) . await ?
591583 } else if !query. is_empty ( ) {
592584 let query_params: String = form_urlencoded:: Serializer :: new ( String :: new ( ) )
@@ -888,6 +880,64 @@ mod tests {
888880 } )
889881 }
890882
883+ #[ test]
884+ fn search_result_can_retrive_sort_by_from_pagination ( ) {
885+ wrapper ( |env| {
886+ let mut crates_io = mockito:: Server :: new ( ) ;
887+ env. override_config ( |config| {
888+ config. registry_api_host = crates_io. url ( ) . parse ( ) . unwrap ( ) ;
889+ } ) ;
890+
891+ let web = env. frontend ( ) ;
892+ env. fake_release ( ) . name ( "some_random_crate" ) . create ( ) ?;
893+
894+ let _m = crates_io
895+ . mock ( "GET" , "/api/v1/crates" )
896+ . match_query ( Matcher :: AllOf ( vec ! [
897+ Matcher :: UrlEncoded ( "q" . into( ) , "some_random_crate" . into( ) ) ,
898+ Matcher :: UrlEncoded ( "per_page" . into( ) , "30" . into( ) ) ,
899+ Matcher :: UrlEncoded ( "page" . into( ) , "2" . into( ) ) ,
900+ Matcher :: UrlEncoded ( "sort" . into( ) , "recent-updates" . into( ) ) ,
901+ ] ) )
902+ . with_status ( 200 )
903+ . with_header ( "content-type" , "application/json" )
904+ . with_body (
905+ json ! ( {
906+ "crates" : [
907+ { "name" : "some_random_crate" } ,
908+ ] ,
909+ "meta" : {
910+ "next_page" : "?q=some_random_crate&sort=recent-updates&per_page=30&page=2" ,
911+ "prev_page" : "?q=some_random_crate&sort=recent-updates&per_page=30&page=1" ,
912+ }
913+ } )
914+ . to_string ( ) ,
915+ )
916+ . create ( ) ;
917+
918+ // click the "Next Page" Button, the "Sort by" SelectBox should keep the same option.
919+ let next_page_url = format ! (
920+ "/releases/search?paginate={}" ,
921+ b64. encode( "?q=some_random_crate&sort=recent-updates&per_page=30&page=2" ) ,
922+ ) ;
923+ let response = web. get ( & next_page_url) . send ( ) ?;
924+ assert ! ( response. status( ) . is_success( ) ) ;
925+
926+ let page = kuchikiki:: parse_html ( ) . one ( response. text ( ) ?) ;
927+ let is_target_option_selected = page
928+ . select ( "#nav-sort > option" )
929+ . expect ( "missing option" )
930+ . any ( |el| {
931+ let attributes = el. attributes . borrow ( ) ;
932+ attributes. get ( "selected" ) . is_some ( )
933+ && attributes. get ( "value" ) . unwrap ( ) . to_string ( ) == "recent-updates"
934+ } ) ;
935+ assert ! ( is_target_option_selected) ;
936+
937+ Ok ( ( ) )
938+ } )
939+ }
940+
891941 #[ test]
892942 fn search_result_passes_cratesio_pagination_links ( ) {
893943 wrapper ( |env| {
0 commit comments