summaryrefslogtreecommitdiff
path: root/dichroism/src/handlers.rs
blob: 0480abf374891b2aba287fa533ebc306220a0192 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
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 = web::block(move || image_service::generate_photo_set(&data_uri))
            .await
            .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 data_uri = post.photo_data;
    let photo_set = web::block(move || image_service::generate_photo_set(&data_uri))
        .await
        .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()))
}