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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
use crate::dtos::*;
use crate::image_service;
use crate::models::Product;
use crate::repo::{photo_set_repo, product_repo};
use crate::types::DbPool;
use actix_multipart::Multipart;
use actix_web::{get, patch, post, web, Error, HttpResponse, Responder};
use futures::{StreamExt, TryStreamExt};
fn to_internal_error(e: impl std::error::Error) -> HttpResponse {
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 || product_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>,
web::Json(patch): web::Json<ProductPatch>,
) -> Result<HttpResponse, Error> {
let id = patch.id;
// get product referenced by patch
let conn = pool.get().map_err(to_internal_error)?;
let mut product = web::block(move || product_repo::find(&conn, id))
.await
.map_err(to_internal_error)?
.ok_or_else(|| HttpResponse::NotFound().finish())?;
// get photo set referenced by patch
if let Some(id) = patch.photo_set {
let conn = pool.get().map_err(to_internal_error)?;
let photo_set = web::block(move || photo_set_repo::find(&conn, id))
.await
.map_err(to_internal_error)?
.ok_or_else(|| HttpResponse::NotFound().body("Photo set not found"))?;
product.photo_set = photo_set;
}
// update product fields
patch.patch(&mut product);
// store the updated product
let conn = pool.get().map_err(to_internal_error)?;
let product = web::block(move || product_repo::store(&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>,
web::Json(post): web::Json<ProductPost>,
) -> Result<HttpResponse, Error> {
// find associated photo set
let photo_set = post.photo_set;
let conn = pool.get().map_err(to_internal_error)?;
let photo_set = web::block(move || photo_set_repo::find(&conn, photo_set))
.await
.map_err(to_internal_error)?
.ok_or_else(|| HttpResponse::NotFound().body("Photo set not found."))?;
// create new product
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,
};
// store product
let conn = pool.get().map_err(to_internal_error)?;
let product = web::block(move || product_repo::store(&conn, product))
.await
.map_err(to_internal_error)?;
Ok(HttpResponse::Ok().json::<ProductGet>(product.into()))
}
#[post("/photos")]
async fn post_photo(
pool: web::Data<DbPool>,
mut payload: Multipart,
) -> Result<HttpResponse, Error> {
let mut responses: Vec<PhotoSetGet> = Vec::new();
while let Some(mut field) = payload
.try_next()
.await
.map_err(|e| HttpResponse::BadRequest().body(e.to_string()))?
{
// grab all bytes
let mut data: Vec<u8> = Vec::new();
while let Some(chunk) = field.next().await {
data.extend(chunk?);
}
// create new photo_set
let photo_set = web::block(move || image_service::generate_photo_set(data))
.await
.map_err(to_internal_error)?;
let conn = pool.get().map_err(to_internal_error)?;
let photo_set = web::block(move || photo_set_repo::store(&conn, photo_set))
.await
.map_err(to_internal_error)?;
responses.push(photo_set.into());
}
Ok(HttpResponse::Ok().json(responses))
}
|