@@ -160,6 +160,8 @@ fn get_releases_by_owner(
160
160
struct SearchResult {
161
161
pub results : Vec < Release > ,
162
162
pub executed_query : Option < String > ,
163
+ pub prev_page : Option < String > ,
164
+ pub next_page : Option < String > ,
163
165
}
164
166
165
167
/// Get the search results for a crate search query
@@ -172,11 +174,17 @@ fn get_search_results(
172
174
#[ derive( Deserialize ) ]
173
175
struct CratesIoSearchResult {
174
176
crates : Vec < CratesIoCrate > ,
177
+ meta : CratesIoMeta ,
175
178
}
176
179
#[ derive( Deserialize , Debug ) ]
177
180
struct CratesIoCrate {
178
181
name : String ,
179
182
}
183
+ #[ derive( Deserialize , Debug ) ]
184
+ struct CratesIoMeta {
185
+ next_page : Option < String > ,
186
+ prev_page : Option < String > ,
187
+ }
180
188
181
189
use crate :: utils:: APP_USER_AGENT ;
182
190
use once_cell:: sync:: Lazy ;
@@ -287,6 +295,8 @@ fn get_search_results(
287
295
. cloned ( )
288
296
. collect ( ) ,
289
297
executed_query,
298
+ prev_page : releases. meta . prev_page ,
299
+ next_page : releases. meta . next_page ,
290
300
} )
291
301
}
292
302
@@ -457,9 +467,8 @@ pub(super) struct Search {
457
467
#[ serde( rename = "releases" ) ]
458
468
pub ( super ) results : Vec < Release > ,
459
469
pub ( super ) search_query : Option < String > ,
460
- pub ( super ) previous_page_button : bool ,
461
- pub ( super ) next_page_button : bool ,
462
- pub ( super ) current_page : i64 ,
470
+ pub ( super ) previous_page_link : Option < String > ,
471
+ pub ( super ) next_page_link : Option < String > ,
463
472
/// This should always be `ReleaseType::Search`
464
473
pub ( super ) release_type : ReleaseType ,
465
474
#[ serde( skip) ]
@@ -472,9 +481,8 @@ impl Default for Search {
472
481
title : String :: default ( ) ,
473
482
results : Vec :: default ( ) ,
474
483
search_query : None ,
475
- previous_page_button : false ,
476
- next_page_button : false ,
477
- current_page : 0 ,
484
+ previous_page_link : None ,
485
+ next_page_link : None ,
478
486
release_type : ReleaseType :: Search ,
479
487
status : iron:: status:: Ok ,
480
488
}
@@ -543,7 +551,7 @@ fn redirect_to_random_crate(req: &Request, conn: &mut PoolClient) -> IronResult<
543
551
}
544
552
545
553
impl_webpage ! {
546
- Search = "releases/releases .html" ,
554
+ Search = "releases/search_results .html" ,
547
555
status = |search| search. status,
548
556
}
549
557
@@ -632,11 +640,16 @@ pub fn search_handler(req: &mut Request) -> IronResult<Response> {
632
640
format ! ( "Search results for '{}'" , executed_query)
633
641
} ;
634
642
635
- // FIXME: There is no pagination
636
643
Search {
637
644
title,
638
645
results : search_result. results ,
639
646
search_query : Some ( executed_query) ,
647
+ next_page_link : search_result
648
+ . next_page
649
+ . map ( |params| format ! ( "/releases/search?paginate={}" , base64:: encode( params) ) ) ,
650
+ previous_page_link : search_result
651
+ . prev_page
652
+ . map ( |params| format ! ( "/releases/search?paginate={}" , base64:: encode( params) ) ) ,
640
653
..Default :: default ( )
641
654
}
642
655
. into_response ( req)
@@ -848,6 +861,109 @@ mod tests {
848
861
} )
849
862
}
850
863
864
+ #[ test]
865
+ fn search_result_passes_cratesio_pagination_links ( ) {
866
+ wrapper ( |env| {
867
+ let web = env. frontend ( ) ;
868
+ env. fake_release ( ) . name ( "some_random_crate" ) . create ( ) ?;
869
+
870
+ let _m = mock ( "GET" , "/api/v1/crates" )
871
+ . match_query ( Matcher :: AllOf ( vec ! [
872
+ Matcher :: UrlEncoded ( "q" . into( ) , "some_random_crate" . into( ) ) ,
873
+ Matcher :: UrlEncoded ( "per_page" . into( ) , "30" . into( ) ) ,
874
+ ] ) )
875
+ . with_status ( 200 )
876
+ . with_header ( "content-type" , "application/json" )
877
+ . with_body (
878
+ json ! ( {
879
+ "crates" : [
880
+ { "name" : "some_random_crate" } ,
881
+ ] ,
882
+ "meta" : {
883
+ "next_page" : "?some=parameters&that=cratesio&might=return" ,
884
+ "prev_page" : "?and=the¶meters=for&the=previouspage" ,
885
+ }
886
+ } )
887
+ . to_string ( ) ,
888
+ )
889
+ . create ( ) ;
890
+
891
+ let response = web. get ( "/releases/search?query=some_random_crate" ) . send ( ) ?;
892
+ assert ! ( response. status( ) . is_success( ) ) ;
893
+
894
+ let page = kuchiki:: parse_html ( ) . one ( response. text ( ) ?) ;
895
+
896
+ let other_search_links: Vec < _ > = page
897
+ . select ( "a" )
898
+ . expect ( "missing link" )
899
+ . map ( |el| {
900
+ let attributes = el. attributes . borrow ( ) ;
901
+ attributes. get ( "href" ) . unwrap ( ) . to_string ( )
902
+ } )
903
+ . filter ( |url| url. starts_with ( "/releases/search?" ) )
904
+ . collect ( ) ;
905
+
906
+ assert_eq ! ( other_search_links. len( ) , 2 ) ;
907
+ assert_eq ! (
908
+ other_search_links[ 0 ] ,
909
+ format!(
910
+ "/releases/search?paginate={}" ,
911
+ base64:: encode( "?and=the¶meters=for&the=previouspage" ) ,
912
+ )
913
+ ) ;
914
+ assert_eq ! (
915
+ other_search_links[ 1 ] ,
916
+ format!(
917
+ "/releases/search?paginate={}" ,
918
+ base64:: encode( "?some=parameters&that=cratesio&might=return" )
919
+ )
920
+ ) ;
921
+
922
+ Ok ( ( ) )
923
+ } )
924
+ }
925
+
926
+ #[ test]
927
+ fn search_encoded_pagination_passed_to_cratesio ( ) {
928
+ wrapper ( |env| {
929
+ let web = env. frontend ( ) ;
930
+ env. fake_release ( ) . name ( "some_random_crate" ) . create ( ) ?;
931
+
932
+ let _m = mock ( "GET" , "/api/v1/crates" )
933
+ . match_query ( Matcher :: AllOf ( vec ! [
934
+ Matcher :: UrlEncoded ( "some" . into( ) , "dummy" . into( ) ) ,
935
+ Matcher :: UrlEncoded ( "pagination" . into( ) , "parameters" . into( ) ) ,
936
+ ] ) )
937
+ . with_status ( 200 )
938
+ . with_header ( "content-type" , "application/json" )
939
+ . with_body (
940
+ json ! ( {
941
+ "crates" : [
942
+ { "name" : "some_random_crate" } ,
943
+ ] ,
944
+ "meta" : {
945
+ "next_page" : null,
946
+ "prev_page" : null,
947
+ }
948
+ } )
949
+ . to_string ( ) ,
950
+ )
951
+ . create ( ) ;
952
+
953
+ let links = get_release_links (
954
+ & format ! (
955
+ "/releases/search?paginate={}" ,
956
+ base64:: encode( "?some=dummy&pagination=parameters" )
957
+ ) ,
958
+ web,
959
+ ) ?;
960
+
961
+ assert_eq ! ( links. len( ) , 1 ) ;
962
+ assert_eq ! ( links[ 0 ] , "/some_random_crate/1.0.0/some_random_crate/" , ) ;
963
+ Ok ( ( ) )
964
+ } )
965
+ }
966
+
851
967
#[ test]
852
968
fn search_lucky_with_unknown_crate ( ) {
853
969
wrapper ( |env| {
0 commit comments