Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

116 changes: 43 additions & 73 deletions crates/bin/docs_rs_web/src/handlers/releases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
metrics::WebMetrics,
page::templates::{RenderBrands, RenderRegular, RenderSolid, filters},
};
use anyhow::{Context as _, Result};
use anyhow::{Context as _, Result, anyhow};
use askama::Template;
use axum::{
extract::{Extension, Query},
Expand All @@ -24,6 +24,7 @@ use docs_rs_registry_api::{self as registry_api, RegistryApi};
use docs_rs_types::{KrateName, ReqVersion, Version};
use docs_rs_uri::encode_url_path;
use futures_util::stream::TryStreamExt;
use http::StatusCode;
use serde::Deserialize;
use sqlx::Row;
use std::{
Expand Down Expand Up @@ -155,7 +156,7 @@ async fn get_search_results(
registry: &RegistryApi,
query_params: &str,
query: &str,
) -> Result<SearchResult, anyhow::Error> {
) -> Result<SearchResult, registry_api::Error> {
let registry_api::Search { crates, meta } = registry.search(query_params).await?;

let names = Arc::new(
Expand Down Expand Up @@ -221,7 +222,8 @@ async fn get_search_results(
)
})
.try_collect()
.await?;
.await
.map_err(|err| anyhow!(err))?;

// start with the original names from crates.io to keep the original ranking,
// extend with the release/build information from docs.rs
Expand Down Expand Up @@ -430,6 +432,7 @@ pub(crate) async fn owner_handler(Path(owner): Path<String>) -> AxumResult<impl
#[derive(Debug, Clone, PartialEq)]
pub(crate) struct Search {
pub(crate) title: String,
pub(crate) message: Option<String>,
pub(crate) releases: Vec<ReleaseStatus>,
pub(crate) search_query: Option<String>,
pub(crate) search_sort_by: Option<String>,
Expand All @@ -444,6 +447,7 @@ impl Default for Search {
fn default() -> Self {
Self {
title: String::default(),
message: None,
releases: Vec::default(),
search_query: None,
previous_page_link: None,
Expand Down Expand Up @@ -604,39 +608,54 @@ pub(crate) async fn search_handler(
}
}

get_search_results(&mut conn, &registry, query_params, "").await?
get_search_results(&mut conn, &registry, query_params, "").await
} else if !query.is_empty() {
let query_params: String = form_urlencoded::Serializer::new(String::new())
.append_pair("q", &query)
.append_pair("sort", &sort_by)
.append_pair("per_page", &RELEASES_IN_RELEASES.to_string())
.finish();

get_search_results(&mut conn, &registry, &query_params, &query).await?
get_search_results(&mut conn, &registry, &query_params, &query).await
} else {
return Err(AxumNope::NoResults);
};

let title = if search_result.results.is_empty() {
format!("No results found for '{query}'")
} else {
format!("Search results for '{query}'")
};
match search_result {
Ok(search_result) => {
let title = if search_result.results.is_empty() {
format!("No results found for '{query}'")
} else {
format!("Search results for '{query}'")
};

Ok(Search {
title,
releases: search_result.results,
search_query: Some(query),
search_sort_by: Some(sort_by),
next_page_link: search_result
.next_page
.map(|params| format!("/releases/search?paginate={}", b64.encode(params))),
previous_page_link: search_result
.prev_page
.map(|params| format!("/releases/search?paginate={}", b64.encode(params))),
..Default::default()
Ok(Search {
title,
releases: search_result.results,
search_query: Some(query),
search_sort_by: Some(sort_by),
next_page_link: search_result
.next_page
.map(|params| format!("/releases/search?paginate={}", b64.encode(params))),
previous_page_link: search_result
.prev_page
.map(|params| format!("/releases/search?paginate={}", b64.encode(params))),
..Default::default()
}
.into_response())
}
Err(err) => {
warn!(%query, ?err, "error during crate search");

Ok(Search {
title: format!("Error searching for '{query}'"),
message: Some(err.to_string()),
status: err.status().unwrap_or(StatusCode::INTERNAL_SERVER_ERROR),
..Default::default()
}
.into_response())
}
}
.into_response())
}

#[derive(Template)]
Expand Down Expand Up @@ -1199,55 +1218,6 @@ mod tests {
})
}

#[tokio::test(flavor = "multi_thread")]
async fn crates_io_errors_as_status_code_200() -> Result<()> {
let mut crates_io = mockito::Server::new_async().await;

let env = TestEnvironment::builder()
.registry_api_config(
docs_rs_registry_api::Config::builder()
.registry_api_host(crates_io.url().parse().unwrap())
.build(),
)
.build()
.await?;

let _m = crates_io
.mock("GET", "/api/v1/crates")
.match_query(Matcher::AllOf(vec![
Matcher::UrlEncoded("q".into(), "doesnt_matter_here".into()),
Matcher::UrlEncoded("per_page".into(), "30".into()),
]))
.with_status(200)
.with_header("content-type", "application/json")
.with_body(
json!({
"errors": [
{ "detail": "error name 1" },
{ "detail": "error name 2" },
]
})
.to_string(),
)
.create_async()
.await;

let response = env
.web_app()
.await
.get("/releases/search?query=doesnt_matter_here")
.await?;
assert_eq!(response.status(), 500);

assert!(
response
.text()
.await?
.contains("error name 1\nerror name 2")
);
Ok(())
}

#[test_case(StatusCode::NOT_FOUND)]
#[test_case(StatusCode::INTERNAL_SERVER_ERROR)]
#[test_case(StatusCode::BAD_GATEWAY)]
Expand Down Expand Up @@ -1282,7 +1252,7 @@ mod tests {
.await
.get("/releases/search?query=doesnt_matter_here")
.await?;
assert_eq!(response.status(), 500);
assert_eq!(response.status(), status);

assert!(response.text().await?.contains(&format!("{status}")));
Ok(())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

{%- block header -%}
{% call release_macros::search_header(title=title) %}{% endcall %}
{% if let Some(message) = message %}
<p>{{ message|linebreaksbr }}</p>
{% endif %}
{%- endblock header -%}

{%- block topbar -%}
Expand Down
8 changes: 8 additions & 0 deletions crates/lib/docs_rs_registry_api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ docs_rs_types = { path = "../docs_rs_types" }
docs_rs_utils = { path = "../docs_rs_utils" }
reqwest = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
sqlx = { workspace = true }
thiserror = { workspace = true }
tracing = { workspace = true }
url = { workspace = true }

[dev-dependencies]
mime = { workspace = true }
mockito = { workspace = true }
test-case = { workspace = true }
tokio = { workspace = true }
Loading
Loading