image.rs 1.66 KB
use std::fmt::Display;

use crate::{models::image, AppData, error::Error};

use actix_web::{Error as ActixError, web, http::StatusCode};
use anyhow::Result;
use serde::{Deserialize, Serialize};

#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
#[serde (rename_all = "lowercase")]
pub enum Size {
    Original,
    Large,
    Medium,
    Small,
    Thumbnail
}

#[derive(Debug, Deserialize, Serialize)]
pub struct SizeQuery {
    size :Option<Size>,
}

impl Display for Size {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let size_str = match self {
            Size::Original => "original",
            Size::Large => "large",
            Size::Medium => "medium",
            Size::Small => "small",
            Size::Thumbnail => "thumbnail"
        };

        write!(f, "{}", size_str)
    }
}

pub async fn get_image( app_data: web::Data<AppData>
                      , ident: web::Path<i32>
                      , size: web::Query<SizeQuery>
                      ) -> Result<actix_files::NamedFile, ActixError>
{
    let pool = app_data.database_pool.clone();
    let ident = ident.into_inner();
    let size = size.into_inner().size.unwrap_or(Size::Large);

    let image = web::block(move || image::get_image(pool, ident)).await?;
    let path = image.clone().context()
             . path(size).await
             . ok_or(Error::new( "Image not ready"
                               , StatusCode::SERVICE_UNAVAILABLE ))?;

    Ok( actix_files::NamedFile::open(path)?
      . set_content_type( image.mime_type
                        . parse()
                        . map_err(|e| Error::from(e))? )
      . disable_content_disposition() )
}