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<DbPool>) -> Result<HttpResponse, Error> {
let conn = pool.get().map_err(to_internal_error)?;
let products: Vec<ProductGet> = 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<DbPool>,
patch: web::Json<ProductPatch>,
) -> Result<HttpResponse, Error> {
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<DbPool>,
post: web::Json<ProductPost>,
) -> Result<HttpResponse, Error> {
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::<ProductGet>(product.into()))
}