use crate::dtos::*; use crate::image_service; use crate::models::Product; use crate::repo; use crate::types::DbPool; use actix_web::{get, patch, post, web, Error, HttpResponse, Responder}; fn to_internal_error(e: impl std::error::Error) -> HttpResponse { eprintln!("{}", e); HttpResponse::InternalServerError().body(e.to_string()) } #[get("/")] async fn hello() -> impl Responder { HttpResponse::Ok().body("Hey, this is an API!") } #[get("/products")] async fn get_products(pool: web::Data) -> Result { let conn = pool.get().map_err(to_internal_error)?; let products: Vec = web::block(move || repo::find_all(&conn)) .await .map_err(to_internal_error)? .into_iter() .map(|p| p.into()) .collect(); Ok(HttpResponse::Ok().json(products)) } #[patch("/products")] async fn patch_product( pool: web::Data, patch: web::Json, ) -> Result { let patch = patch.into_inner(); let id = patch.id; let conn = pool.get().map_err(to_internal_error)?; let mut product = web::block(move || repo::find(&conn, id)) .await .map_err(to_internal_error)? .ok_or_else(|| HttpResponse::NotFound().finish())?; if let Some(data_uri) = patch.photo_data { // create new photo_set let photo_set = image_service::generate_photo_set(&data_uri).map_err(|e| { eprintln!("{}", e.to_string()); HttpResponse::InternalServerError().body(e.to_string()) })?; let conn = pool.get().map_err(to_internal_error)?; let photo_set = web::block(move || repo::store_photo_set(&conn, photo_set)) .await .map_err(to_internal_error)?; product.photo_set = photo_set; } // patch the rest of the product product.name = patch.name.unwrap_or(product.name); product.quantity = patch.quantity.unwrap_or(product.quantity); product.cents = patch.cents.unwrap_or(product.cents); product.description = patch.description.unwrap_or(product.description); product.featured = patch.featured.unwrap_or(product.featured); product.category = patch.category_path.unwrap_or(product.category); // store the updated product let conn = pool.get().map_err(to_internal_error)?; let product = web::block(move || repo::store_product(&conn, product)) .await .map_err(to_internal_error)?; Ok(HttpResponse::Ok().json(ProductGet::from(product))) } #[post("/products")] async fn post_product( pool: web::Data, post: web::Json, ) -> Result { let post = post.into_inner(); // create new photo_set let photo_set = image_service::generate_photo_set(&post.photo_data).map_err(|e| { eprintln!("{}", e.to_string()); HttpResponse::InternalServerError().body(e.to_string()) })?; let conn = pool.get().map_err(to_internal_error)?; let photo_set = web::block(move || repo::store_photo_set(&conn, photo_set)) .await .map_err(to_internal_error)?; let product = Product { id: None, name: post.name, quantity: post.quantity, cents: post.cents, description: post.description, featured: post.featured, category: post.category_path, photo_set, }; let conn = pool.get().map_err(to_internal_error)?; let product = web::block(move || repo::store_product(&conn, product)) .await .map_err(to_internal_error)?; Ok(HttpResponse::Ok().json::(product.into())) }