diff options
Diffstat (limited to 'crates/rocie-server/src/api')
| -rw-r--r-- | crates/rocie-server/src/api/get/product.rs | 43 |
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?; |
