Skip to content

Commit 9b0f8ff

Browse files
committed
add pagination to search-result page
1 parent c3adb7b commit 9b0f8ff

File tree

3 files changed

+156
-26
lines changed

3 files changed

+156
-26
lines changed

src/web/releases.rs

Lines changed: 124 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ fn get_releases_by_owner(
160160
struct SearchResult {
161161
pub results: Vec<Release>,
162162
pub executed_query: Option<String>,
163+
pub prev_page: Option<String>,
164+
pub next_page: Option<String>,
163165
}
164166

165167
/// Get the search results for a crate search query
@@ -172,11 +174,17 @@ fn get_search_results(
172174
#[derive(Deserialize)]
173175
struct CratesIoSearchResult {
174176
crates: Vec<CratesIoCrate>,
177+
meta: CratesIoMeta,
175178
}
176179
#[derive(Deserialize, Debug)]
177180
struct CratesIoCrate {
178181
name: String,
179182
}
183+
#[derive(Deserialize, Debug)]
184+
struct CratesIoMeta {
185+
next_page: Option<String>,
186+
prev_page: Option<String>,
187+
}
180188

181189
use crate::utils::APP_USER_AGENT;
182190
use once_cell::sync::Lazy;
@@ -287,6 +295,8 @@ fn get_search_results(
287295
.cloned()
288296
.collect(),
289297
executed_query,
298+
prev_page: releases.meta.prev_page,
299+
next_page: releases.meta.next_page,
290300
})
291301
}
292302

@@ -457,9 +467,8 @@ pub(super) struct Search {
457467
#[serde(rename = "releases")]
458468
pub(super) results: Vec<Release>,
459469
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>,
463472
/// This should always be `ReleaseType::Search`
464473
pub(super) release_type: ReleaseType,
465474
#[serde(skip)]
@@ -472,9 +481,8 @@ impl Default for Search {
472481
title: String::default(),
473482
results: Vec::default(),
474483
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,
478486
release_type: ReleaseType::Search,
479487
status: iron::status::Ok,
480488
}
@@ -543,7 +551,7 @@ fn redirect_to_random_crate(req: &Request, conn: &mut PoolClient) -> IronResult<
543551
}
544552

545553
impl_webpage! {
546-
Search = "releases/releases.html",
554+
Search = "releases/search_results.html",
547555
status = |search| search.status,
548556
}
549557

@@ -632,11 +640,16 @@ pub fn search_handler(req: &mut Request) -> IronResult<Response> {
632640
format!("Search results for '{}'", executed_query)
633641
};
634642

635-
// FIXME: There is no pagination
636643
Search {
637644
title,
638645
results: search_result.results,
639646
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))),
640653
..Default::default()
641654
}
642655
.into_response(req)
@@ -848,6 +861,109 @@ mod tests {
848861
})
849862
}
850863

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&parameters=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&parameters=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+
851967
#[test]
852968
fn search_lucky_with_unknown_crate() {
853969
wrapper(|env| {

templates/releases/releases.html

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -57,26 +57,25 @@
5757
</ul>
5858

5959
<div class="pagination">
60-
{%- if release_type == 'owner' -%}
61-
{%- set page_link = "/releases/" ~ owner -%}
62-
{%- else -%}
63-
{%- set page_link = "/releases/" ~ release_type -%}
64-
{%- endif -%}
65-
{%- if release_type == 'search' -%}
66-
{%- set query = "?search=" ~ search_query -%}
67-
{%- endif -%}
60+
{% block pagination %}
61+
{%- if release_type == 'owner' -%}
62+
{%- set page_link = "/releases/" ~ owner -%}
63+
{%- else -%}
64+
{%- set page_link = "/releases/" ~ release_type -%}
65+
{%- endif -%}
6866

69-
{%- if show_previous_page -%}
70-
<a class="pure-button pure-button-normal" href="{{ page_link | safe }}/{{ page_number - 1 }}{{ query | default(value='') }}">
71-
{{ "arrow-left" | fas }} Previous Page
72-
</a>
73-
{%- endif -%}
67+
{%- if show_previous_page -%}
68+
<a class="pure-button pure-button-normal" href="{{ page_link | safe }}/{{ page_number - 1 }}{{ query | default(value='') }}">
69+
{{ "arrow-left" | fas }} Previous Page
70+
</a>
71+
{%- endif -%}
7472

75-
{%- if show_next_page -%}
76-
<a class="pure-button pure-button-normal" href="{{ page_link | safe }}/{{ page_number + 1 }}{{ query | default(value='') }}">
77-
Next Page {{ "arrow-right" | fas }}
78-
</a>
79-
{%- endif -%}
73+
{%- if show_next_page -%}
74+
<a class="pure-button pure-button-normal" href="{{ page_link | safe }}/{{ page_number + 1 }}{{ query | default(value='') }}">
75+
Next Page {{ "arrow-right" | fas }}
76+
</a>
77+
{%- endif -%}
78+
{% endblock pagination %}
8079
</div>
8180
</div>
8281
</div>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{%- extends "releases/releases.html" -%}
2+
3+
{% block pagination %}
4+
{%- if previous_page_link -%}
5+
<a class="pure-button pure-button-normal" href="{{ previous_page_link|safe }}">
6+
{{ "arrow-left" | fas }} Previous Page
7+
</a>
8+
{%- endif -%}
9+
10+
{%- if next_page_link -%}
11+
<a class="pure-button pure-button-normal" href="{{ next_page_link|safe }}">
12+
Next Page {{ "arrow-right" | fas }}
13+
</a>
14+
{%- endif -%}
15+
{% endblock pagination %}

0 commit comments

Comments
 (0)