Can download uploaded images
This commit is contained in:
@ -2,7 +2,7 @@ use crate::constants::{SizeConstraint, StaticConstraints};
|
||||
use crate::controllers::HttpResult;
|
||||
use crate::extractors::family_extractor::FamilyInPath;
|
||||
use crate::extractors::member_extractor::FamilyAndMemberInPath;
|
||||
use crate::models::{Member, MemberID, Sex};
|
||||
use crate::models::{Member, MemberID, PhotoID, Sex};
|
||||
use crate::services::{members_service, photos_service};
|
||||
use crate::utils::countries_utils;
|
||||
use actix_multipart::form::tempfile::TempFile;
|
||||
@ -231,6 +231,22 @@ impl MemberRequest {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
struct MemberAPI {
|
||||
#[serde(flatten)]
|
||||
member: Member,
|
||||
signed_photo_id: Option<String>,
|
||||
}
|
||||
|
||||
impl MemberAPI {
|
||||
pub fn new(member: Member) -> Self {
|
||||
Self {
|
||||
signed_photo_id: member.photo_id().as_ref().map(PhotoID::to_signed_hash),
|
||||
member,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new family member
|
||||
pub async fn create(f: FamilyInPath, req: web::Json<MemberRequest>) -> HttpResult {
|
||||
let mut member = members_service::create(f.family_id()).await?;
|
||||
@ -253,12 +269,12 @@ pub async fn create(f: FamilyInPath, req: web::Json<MemberRequest>) -> HttpResul
|
||||
/// Get the entire list of members of the family
|
||||
pub async fn get_all(f: FamilyInPath) -> HttpResult {
|
||||
let members = members_service::get_all_of_family(f.family_id()).await?;
|
||||
Ok(HttpResponse::Ok().json(members))
|
||||
Ok(HttpResponse::Ok().json(members.into_iter().map(MemberAPI::new).collect::<Vec<_>>()))
|
||||
}
|
||||
|
||||
/// Get the information of a single family member
|
||||
pub async fn get_single(m: FamilyAndMemberInPath) -> HttpResult {
|
||||
Ok(HttpResponse::Ok().json(m.to_member()))
|
||||
Ok(HttpResponse::Ok().json(MemberAPI::new(m.to_member())))
|
||||
}
|
||||
|
||||
/// Update a member information
|
||||
|
@ -7,6 +7,7 @@ use std::fmt::{Debug, Display, Formatter};
|
||||
pub mod auth_controller;
|
||||
pub mod families_controller;
|
||||
pub mod members_controller;
|
||||
pub mod photos_controller;
|
||||
pub mod server_controller;
|
||||
pub mod users_controller;
|
||||
|
||||
|
74
geneit_backend/src/controllers/photos_controller.rs
Normal file
74
geneit_backend/src/controllers/photos_controller.rs
Normal file
@ -0,0 +1,74 @@
|
||||
use crate::connections::s3_connection;
|
||||
use crate::controllers::HttpResult;
|
||||
use crate::models::PhotoID;
|
||||
use crate::services::photos_service;
|
||||
use actix_web::http::header;
|
||||
use actix_web::{web, HttpRequest, HttpResponse};
|
||||
use std::ops::Add;
|
||||
use std::time::{Duration, UNIX_EPOCH};
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct PhotoIdPath {
|
||||
id: String,
|
||||
}
|
||||
|
||||
pub async fn get_full_size(id: web::Path<PhotoIdPath>, req: HttpRequest) -> HttpResult {
|
||||
get_photo(&id, true, req).await
|
||||
}
|
||||
|
||||
pub async fn get_thumbnail(id: web::Path<PhotoIdPath>, req: HttpRequest) -> HttpResult {
|
||||
get_photo(&id, false, req).await
|
||||
}
|
||||
|
||||
async fn get_photo(id: &PhotoIdPath, full_size: bool, req: HttpRequest) -> HttpResult {
|
||||
let id = match PhotoID::from_signed_hash(&id.id) {
|
||||
None => {
|
||||
return Ok(HttpResponse::Unauthorized().body("Invalid hash"));
|
||||
}
|
||||
Some(p) => p,
|
||||
};
|
||||
|
||||
let photo = photos_service::get_by_id(id).await?;
|
||||
|
||||
let (hash, content_type) = match full_size {
|
||||
true => (photo.sha512.as_str(), photo.mime_type.as_str()),
|
||||
false => (photo.thumb_sha512.as_str(), "application/png"),
|
||||
};
|
||||
|
||||
// Check if an upload is un-necessary
|
||||
if let Some(c) = req.headers().get(header::IF_NONE_MATCH) {
|
||||
if c.to_str().unwrap_or("") == hash {
|
||||
return Ok(HttpResponse::NotModified().finish());
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(c) = req.headers().get(header::IF_MODIFIED_SINCE) {
|
||||
let date_str = c.to_str().unwrap_or("");
|
||||
if let Ok(date) = httpdate::parse_http_date(date_str) {
|
||||
if date
|
||||
.add(Duration::from_secs(1))
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs()
|
||||
>= photo.time_create as u64
|
||||
{
|
||||
return Ok(HttpResponse::NotModified().finish());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let bytes = s3_connection::get_file(&match full_size {
|
||||
true => photo.photo_path(),
|
||||
false => photo.thumbnail_path(),
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type(content_type)
|
||||
.insert_header(("etag", hash))
|
||||
.insert_header((
|
||||
"last-modified",
|
||||
httpdate::fmt_http_date(UNIX_EPOCH + Duration::from_secs(photo.time_create as u64)),
|
||||
))
|
||||
.body(bytes))
|
||||
}
|
Reference in New Issue
Block a user