summaryrefslogblamecommitdiff
path: root/dichroism/src/handlers.rs
blob: b9420af4e5b91437c991904f18669e4c005d7a2d (plain) (tree)
1
2
3
4
5
6
7
8
9
                   

                           
                                                
                         
                               
                                                                       
                                       
 
                                                                 


                                                           




                                                   
                   
                                                                               
                                                      
                                                                                     
              
                                    



                                         

 


                            
                                              
                                  

                      
                                      
                                                      
                                                                       



                                                           

                                        
                                                          
                                                                           
                  

                                                                                  


                                      

                              


                                                      
                                                                         



                                                          
 
 
                    

                            
                                            
                                  

                                   
                                                      
                                                                              
              

                                                                               
 
                         










                                      
                    
                                                      
                                                                         



                                                             
 







                                                     




                                                                     


                                                    
                                


                               
                                                                                   
                  
                                         








                                                                                   
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))
}