@@ -23,7 +23,6 @@ use base64::{engine::general_purpose::STANDARD as b64, Engine};
23
23
use chrono:: { DateTime , Utc } ;
24
24
use futures_util:: stream:: TryStreamExt ;
25
25
use once_cell:: sync:: Lazy ;
26
- use regex:: Regex ;
27
26
use serde:: { Deserialize , Serialize } ;
28
27
use sqlx:: Row ;
29
28
use std:: collections:: { BTreeMap , HashMap , HashSet } ;
@@ -510,7 +509,7 @@ pub(crate) async fn search_handler(
510
509
. get ( "query" )
511
510
. map ( |q| q. to_string ( ) )
512
511
. unwrap_or_else ( || "" . to_string ( ) ) ;
513
- let mut sort_by = params
512
+ let sort_by = params
514
513
. get ( "sort" )
515
514
. map ( |q| q. to_string ( ) )
516
515
. unwrap_or_else ( || "relevance" . to_string ( ) ) ;
@@ -580,13 +579,6 @@ pub(crate) async fn search_handler(
580
579
return Err ( AxumNope :: NoResults ) ;
581
580
}
582
581
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
-
590
582
get_search_results ( & mut conn, & config, & query_params) . await ?
591
583
} else if !query. is_empty ( ) {
592
584
let query_params: String = form_urlencoded:: Serializer :: new ( String :: new ( ) )
@@ -888,6 +880,64 @@ mod tests {
888
880
} )
889
881
}
890
882
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
+
891
941
#[ test]
892
942
fn search_result_passes_cratesio_pagination_links ( ) {
893
943
wrapper ( |env| {
0 commit comments