aboutsummaryrefslogtreecommitdiffstats
path: root/crates/rocie-server/src
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-10-23 23:38:25 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-10-23 23:38:25 +0200
commitf0a797ebd2ac930ec6a326f4fba2221983e979bf (patch)
treeb02084e94819e6a5318f10f3d9b73b33ae086486 /crates/rocie-server/src
parentfeat(crates/rocie-server/api/get-product-{by-name,by-part-name}): Init (diff)
downloadserver-f0a797ebd2ac930ec6a326f4fba2221983e979bf.zip
fix(crates/rocie-server/api/get-product-{by-name,by-part-name}): Test
Diffstat (limited to '')
-rw-r--r--crates/rocie-server/src/api/get/product.rs43
1 files changed, 38 insertions, 5 deletions
diff --git a/crates/rocie-server/src/api/get/product.rs b/crates/rocie-server/src/api/get/product.rs
index 9356a68..55e5d91 100644
--- a/crates/rocie-server/src/api/get/product.rs
+++ b/crates/rocie-server/src/api/get/product.rs
@@ -1,10 +1,29 @@
-use actix_web::{HttpResponse, Responder, Result, get, web};
+use actix_web::{HttpRequest, HttpResponse, Responder, Result, get, web};
+use log::info;
+use percent_encoding::percent_decode_str;
use crate::{
app::App,
storage::sql::product::{Product, ProductId, ProductIdStub},
};
+/// A String, that is not url-decoded on parse.
+struct UrlEncodedString(String);
+
+impl UrlEncodedString {
+ /// Percent de-encode a given string
+ fn percent_decode(&self) -> Result<String, std::str::Utf8Error> {
+ percent_decode_str(self.0.replace('+', "%20").as_str())
+ .decode_utf8()
+ .map(|s| s.to_string())
+ .inspect(|s| info!("Decoded `{}` as `{s}`", self.0))
+ }
+
+ fn from_str(inner: &str) -> Self {
+ Self(inner.to_owned())
+ }
+}
+
/// Get Product by id
#[utoipa::path(
responses(
@@ -40,14 +59,20 @@ pub(crate) async fn product_by_id(
("name" = String, description = "Name of the product" ),
)
)]
-// TODO: Html decode the name, before use. Otherwise `Milk 2` will not work, as it is send as
-// `Milk+2` <2025-10-21>
#[get("/product/by-name/{name}")]
pub(crate) async fn product_by_name(
app: web::Data<App>,
+ req: HttpRequest,
name: web::Path<String>,
) -> Result<impl Responder> {
- let name = name.into_inner();
+ let _name = name;
+
+ let name = UrlEncodedString::from_str(
+ req.path()
+ .strip_prefix("/product/by-name/")
+ .expect("Will always exists"),
+ );
+ let name = name.percent_decode()?;
match Product::from_name(&app, name).await? {
Some(product) => Ok(HttpResponse::Ok().json(product)),
@@ -68,9 +93,17 @@ pub(crate) async fn product_by_name(
#[get("/product/by-part-name/{name}")]
pub(crate) async fn product_suggestion_by_name(
app: web::Data<App>,
+ req: HttpRequest,
name: web::Path<String>,
) -> Result<impl Responder> {
- let name = name.into_inner();
+ let _name = name;
+
+ let name = UrlEncodedString::from_str(
+ req.path()
+ .strip_prefix("/product/by-part-name/")
+ .expect("Will always exists"),
+ );
+ let name = &name.percent_decode()?;
let all = Product::get_all(&app).await?;