185 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			185 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
use crate::controllers::members_controller::RequestDate;
 | 
						|
use crate::controllers::HttpResult;
 | 
						|
use crate::extractors::couple_extractor::FamilyAndCoupleInPath;
 | 
						|
use crate::extractors::family_extractor::FamilyInPath;
 | 
						|
use crate::models::{Couple, CoupleState, MemberID, PhotoID};
 | 
						|
use crate::services::{couples_service, members_service, photos_service};
 | 
						|
use actix_multipart::form::tempfile::TempFile;
 | 
						|
use actix_multipart::form::MultipartForm;
 | 
						|
use actix_web::{web, HttpResponse};
 | 
						|
 | 
						|
serde_with::with_prefix!(prefix_wedding "wedding_");
 | 
						|
serde_with::with_prefix!(prefix_divorce "divorce_");
 | 
						|
 | 
						|
#[derive(thiserror::Error, Debug)]
 | 
						|
enum CoupleControllerErr {
 | 
						|
    #[error("Wife and husband are identical!")]
 | 
						|
    IdenticalWifeHusband,
 | 
						|
    #[error("Wife does not exist!")]
 | 
						|
    WifeNotExisting,
 | 
						|
    #[error("Husband does not exist!")]
 | 
						|
    HusbandNotExisting,
 | 
						|
    #[error("Invalid date of wedding")]
 | 
						|
    MalformedDateOfWedding,
 | 
						|
    #[error("Invalid date of divorce")]
 | 
						|
    MalformedDateOfDivorce,
 | 
						|
}
 | 
						|
 | 
						|
#[derive(serde::Deserialize, Clone)]
 | 
						|
pub struct CoupleRequest {
 | 
						|
    pub wife: Option<MemberID>,
 | 
						|
    pub husband: Option<MemberID>,
 | 
						|
    state: Option<CoupleState>,
 | 
						|
    #[serde(flatten, with = "prefix_wedding")]
 | 
						|
    wedding: Option<RequestDate>,
 | 
						|
    #[serde(flatten, with = "prefix_divorce")]
 | 
						|
    divorce: Option<RequestDate>,
 | 
						|
}
 | 
						|
 | 
						|
impl CoupleRequest {
 | 
						|
    pub async fn to_couple(self, couple: &mut Couple) -> anyhow::Result<()> {
 | 
						|
        if let Some(wife) = self.wife {
 | 
						|
            if !members_service::exists(couple.family_id(), wife).await? {
 | 
						|
                return Err(CoupleControllerErr::WifeNotExisting.into());
 | 
						|
            }
 | 
						|
 | 
						|
            if self.wife == self.husband {
 | 
						|
                return Err(CoupleControllerErr::IdenticalWifeHusband.into());
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if let Some(husband) = self.husband {
 | 
						|
            if !members_service::exists(couple.family_id(), husband).await? {
 | 
						|
                return Err(CoupleControllerErr::HusbandNotExisting.into());
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if let Some(d) = &self.wedding {
 | 
						|
            if !d.check() {
 | 
						|
                return Err(CoupleControllerErr::MalformedDateOfWedding.into());
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if let Some(d) = &self.divorce {
 | 
						|
            if !d.check() {
 | 
						|
                return Err(CoupleControllerErr::MalformedDateOfDivorce.into());
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        couple.set_wife(self.wife);
 | 
						|
        couple.set_husband(self.husband);
 | 
						|
        couple.set_state(self.state);
 | 
						|
 | 
						|
        couple.wedding_year = self.wedding.as_ref().map(|m| m.year).unwrap_or_default();
 | 
						|
        couple.wedding_month = self.wedding.as_ref().map(|m| m.month).unwrap_or_default();
 | 
						|
        couple.wedding_day = self.wedding.as_ref().map(|m| m.day).unwrap_or_default();
 | 
						|
 | 
						|
        couple.divorce_year = self.divorce.as_ref().map(|m| m.year).unwrap_or_default();
 | 
						|
        couple.divorce_month = self.divorce.as_ref().map(|m| m.month).unwrap_or_default();
 | 
						|
        couple.divorce_day = self.divorce.as_ref().map(|m| m.day).unwrap_or_default();
 | 
						|
 | 
						|
        Ok(())
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#[derive(serde::Serialize)]
 | 
						|
struct CoupleAPI {
 | 
						|
    #[serde(flatten)]
 | 
						|
    member: Couple,
 | 
						|
    signed_photo_id: Option<String>,
 | 
						|
}
 | 
						|
 | 
						|
impl CoupleAPI {
 | 
						|
    pub fn new(member: Couple) -> Self {
 | 
						|
        Self {
 | 
						|
            signed_photo_id: member.photo_id().as_ref().map(PhotoID::to_signed_hash),
 | 
						|
            member,
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/// Create a new couple
 | 
						|
pub async fn create(m: FamilyInPath, req: web::Json<CoupleRequest>) -> HttpResult {
 | 
						|
    let mut couple = couples_service::create(m.family_id()).await?;
 | 
						|
 | 
						|
    if let Err(e) = req.0.to_couple(&mut couple).await {
 | 
						|
        log::error!("Failed to apply couple information! {e}");
 | 
						|
        couples_service::delete(&mut couple).await?;
 | 
						|
        return Ok(HttpResponse::BadRequest().body(e.to_string()));
 | 
						|
    }
 | 
						|
 | 
						|
    if let Err(e) = couples_service::update(&mut couple).await {
 | 
						|
        log::error!("Failed to update couple information! {e}");
 | 
						|
        couples_service::delete(&mut couple).await?;
 | 
						|
        return Ok(HttpResponse::InternalServerError().finish());
 | 
						|
    }
 | 
						|
 | 
						|
    Ok(HttpResponse::Ok().json(couple))
 | 
						|
}
 | 
						|
 | 
						|
/// Get the entire list of couples
 | 
						|
pub async fn get_all(m: FamilyInPath) -> HttpResult {
 | 
						|
    let couples = couples_service::get_all_of_family(m.family_id())
 | 
						|
        .await?
 | 
						|
        .into_iter()
 | 
						|
        .map(CoupleAPI::new)
 | 
						|
        .collect::<Vec<_>>();
 | 
						|
 | 
						|
    Ok(HttpResponse::Ok().json(couples))
 | 
						|
}
 | 
						|
 | 
						|
/// Get a single couple entry
 | 
						|
pub async fn get_single(m: FamilyAndCoupleInPath) -> HttpResult {
 | 
						|
    Ok(HttpResponse::Ok().json(CoupleAPI::new(m.to_couple())))
 | 
						|
}
 | 
						|
 | 
						|
/// Update a couple information
 | 
						|
pub async fn update(m: FamilyAndCoupleInPath, req: web::Json<CoupleRequest>) -> HttpResult {
 | 
						|
    let mut couple = m.to_couple();
 | 
						|
 | 
						|
    if let Err(e) = req.0.to_couple(&mut couple).await {
 | 
						|
        log::error!("Failed to parse couple information {e}!");
 | 
						|
        return Ok(HttpResponse::BadRequest().body(e.to_string()));
 | 
						|
    }
 | 
						|
 | 
						|
    couples_service::update(&mut couple).await?;
 | 
						|
 | 
						|
    Ok(HttpResponse::Accepted().finish())
 | 
						|
}
 | 
						|
 | 
						|
/// Delete a couple
 | 
						|
pub async fn delete(m: FamilyAndCoupleInPath) -> HttpResult {
 | 
						|
    couples_service::delete(&mut m.to_couple()).await?;
 | 
						|
    Ok(HttpResponse::Ok().finish())
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Debug, MultipartForm)]
 | 
						|
pub struct UploadPhotoForm {
 | 
						|
    #[multipart(rename = "photo")]
 | 
						|
    photo: TempFile,
 | 
						|
}
 | 
						|
 | 
						|
/// Upload a new photo for a user
 | 
						|
pub async fn set_photo(
 | 
						|
    m: FamilyAndCoupleInPath,
 | 
						|
    MultipartForm(form): MultipartForm<UploadPhotoForm>,
 | 
						|
) -> HttpResult {
 | 
						|
    let photo = photos_service::finalize_upload(form.photo.into()).await?;
 | 
						|
    let mut couple = m.to_couple();
 | 
						|
 | 
						|
    couples_service::remove_photo(&mut couple).await?;
 | 
						|
 | 
						|
    couple.set_photo_id(Some(photo.id()));
 | 
						|
    couples_service::update(&mut couple).await?;
 | 
						|
 | 
						|
    Ok(HttpResponse::Ok().finish())
 | 
						|
}
 | 
						|
 | 
						|
/// Remove a photo
 | 
						|
pub async fn remove_photo(m: FamilyAndCoupleInPath) -> HttpResult {
 | 
						|
    let mut couple = m.to_couple();
 | 
						|
    couples_service::remove_photo(&mut couple).await?;
 | 
						|
 | 
						|
    Ok(HttpResponse::Ok().finish())
 | 
						|
}
 |