2023-08-04 17:03:46 +00:00
|
|
|
use crate::constants::{SizeConstraint, StaticConstraints};
|
|
|
|
use crate::controllers::HttpResult;
|
|
|
|
use crate::extractors::family_extractor::FamilyInPath;
|
2023-08-05 08:24:19 +00:00
|
|
|
use crate::extractors::member_extractor::FamilyAndMemberInPath;
|
2023-08-04 17:03:46 +00:00
|
|
|
use crate::models::{Member, MemberID, Sex};
|
|
|
|
use crate::services::members_service;
|
|
|
|
use crate::utils::countries_utils;
|
|
|
|
use actix_web::{web, HttpResponse};
|
|
|
|
|
|
|
|
serde_with::with_prefix!(prefix_birth "birth_");
|
|
|
|
serde_with::with_prefix!(prefix_death "death_");
|
|
|
|
|
|
|
|
#[derive(serde::Deserialize)]
|
|
|
|
pub struct RequestDate {
|
|
|
|
pub year: Option<i16>,
|
|
|
|
pub month: Option<i16>,
|
|
|
|
pub day: Option<i16>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RequestDate {
|
|
|
|
pub fn check(&self) -> bool {
|
|
|
|
let c = StaticConstraints::default();
|
|
|
|
|
|
|
|
self.year.map(|y| c.date_year.validate(y)).unwrap_or(true)
|
|
|
|
&& self.month.map(|y| c.date_month.validate(y)).unwrap_or(true)
|
|
|
|
&& self.day.map(|y| c.date_day.validate(y)).unwrap_or(true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(serde::Deserialize)]
|
|
|
|
pub struct MemberRequest {
|
|
|
|
first_name: Option<String>,
|
|
|
|
last_name: Option<String>,
|
|
|
|
birth_last_name: Option<String>,
|
|
|
|
email: Option<String>,
|
|
|
|
phone: Option<String>,
|
|
|
|
address: Option<String>,
|
|
|
|
city: Option<String>,
|
|
|
|
postal_code: Option<String>,
|
|
|
|
country: Option<String>,
|
|
|
|
sex: Option<Sex>,
|
|
|
|
mother: Option<MemberID>,
|
|
|
|
father: Option<MemberID>,
|
|
|
|
#[serde(flatten, with = "prefix_birth")]
|
|
|
|
birth: Option<RequestDate>,
|
|
|
|
#[serde(flatten, with = "prefix_death")]
|
|
|
|
death: Option<RequestDate>,
|
|
|
|
note: Option<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(thiserror::Error, Debug)]
|
|
|
|
enum MemberControllerErr {
|
|
|
|
#[error("Malformed first name!")]
|
|
|
|
MalformedFirstname,
|
|
|
|
#[error("Malformed last name!")]
|
|
|
|
MalformedLastname,
|
|
|
|
#[error("Malformed birth last name!")]
|
|
|
|
MalformedBirthLastname,
|
|
|
|
#[error("Malformed email address!")]
|
|
|
|
MalformedEmailAddress,
|
|
|
|
#[error("Invalid email address!")]
|
|
|
|
InvalidEmailAddress,
|
|
|
|
#[error("Malformed phone number!")]
|
|
|
|
MalformedPhoneNumber,
|
|
|
|
#[error("Malformed address!")]
|
|
|
|
MalformedAddress,
|
|
|
|
#[error("Malformed city!")]
|
|
|
|
MalformedCity,
|
|
|
|
#[error("Malformed postal code!")]
|
|
|
|
MalformedPostalCode,
|
|
|
|
#[error("Malformed country!")]
|
|
|
|
MalformedCountry,
|
|
|
|
#[error("Invalid country code!")]
|
|
|
|
InvalidCountryCode,
|
|
|
|
#[error("Malformed date of birth!")]
|
|
|
|
MalformedDateOfBirth,
|
|
|
|
#[error("Malformed date of death!")]
|
|
|
|
MalformedDateOfDeath,
|
|
|
|
#[error("Malformed note!")]
|
|
|
|
MalformedNote,
|
|
|
|
#[error("Mother does not exists!")]
|
|
|
|
MotherNotExisting,
|
|
|
|
#[error("Father does not exists!")]
|
|
|
|
FatherNotExisting,
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_opt_str_val(
|
|
|
|
val: &Option<String>,
|
|
|
|
c: SizeConstraint,
|
|
|
|
err: MemberControllerErr,
|
|
|
|
) -> anyhow::Result<()> {
|
|
|
|
if let Some(v) = val {
|
|
|
|
if !c.validate(v) {
|
|
|
|
return Err(err.into());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
impl MemberRequest {
|
|
|
|
pub async fn to_member(self, member: &mut Member) -> anyhow::Result<()> {
|
|
|
|
let c = StaticConstraints::default();
|
|
|
|
check_opt_str_val(
|
|
|
|
&self.first_name,
|
|
|
|
c.member_first_name,
|
|
|
|
MemberControllerErr::MalformedFirstname,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
check_opt_str_val(
|
|
|
|
&self.last_name,
|
|
|
|
c.member_last_name,
|
|
|
|
MemberControllerErr::MalformedLastname,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
check_opt_str_val(
|
|
|
|
&self.birth_last_name,
|
|
|
|
c.member_birth_last_name,
|
|
|
|
MemberControllerErr::MalformedBirthLastname,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
check_opt_str_val(
|
|
|
|
&self.email,
|
|
|
|
c.member_email,
|
|
|
|
MemberControllerErr::MalformedEmailAddress,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
if let Some(mail) = &self.email {
|
|
|
|
if !mailchecker::is_valid(mail) {
|
|
|
|
return Err(MemberControllerErr::InvalidEmailAddress.into());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
check_opt_str_val(
|
|
|
|
&self.phone,
|
|
|
|
c.member_phone,
|
|
|
|
MemberControllerErr::MalformedPhoneNumber,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
check_opt_str_val(
|
|
|
|
&self.address,
|
|
|
|
c.member_address,
|
|
|
|
MemberControllerErr::MalformedAddress,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
check_opt_str_val(
|
|
|
|
&self.city,
|
|
|
|
c.member_city,
|
|
|
|
MemberControllerErr::MalformedCity,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
check_opt_str_val(
|
|
|
|
&self.postal_code,
|
|
|
|
c.member_postal_code,
|
|
|
|
MemberControllerErr::MalformedPostalCode,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
check_opt_str_val(
|
|
|
|
&self.country,
|
|
|
|
c.member_country,
|
|
|
|
MemberControllerErr::MalformedCountry,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
if let Some(c) = &self.country {
|
|
|
|
if !countries_utils::is_code_valid(c) {
|
|
|
|
return Err(MemberControllerErr::InvalidCountryCode.into());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(d) = &self.birth {
|
|
|
|
if !d.check() {
|
|
|
|
return Err(MemberControllerErr::MalformedDateOfBirth.into());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(d) = &self.death {
|
|
|
|
if !d.check() {
|
|
|
|
return Err(MemberControllerErr::MalformedDateOfDeath.into());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
check_opt_str_val(
|
|
|
|
&self.note,
|
|
|
|
c.member_note,
|
|
|
|
MemberControllerErr::MalformedNote,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
if let Some(mother) = self.mother {
|
|
|
|
if !members_service::exists(member.family_id(), mother).await? {
|
|
|
|
return Err(MemberControllerErr::MotherNotExisting.into());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(father) = self.father {
|
|
|
|
if !members_service::exists(member.family_id(), father).await? {
|
|
|
|
return Err(MemberControllerErr::FatherNotExisting.into());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
member.first_name = self.first_name;
|
|
|
|
member.last_name = self.last_name;
|
|
|
|
member.birth_last_name = self.birth_last_name;
|
|
|
|
member.email = self.email;
|
|
|
|
member.phone = self.phone;
|
|
|
|
member.address = self.address;
|
|
|
|
member.city = self.city;
|
|
|
|
member.postal_code = self.postal_code;
|
|
|
|
member.country = self.country;
|
|
|
|
member.set_sex(self.sex);
|
|
|
|
member.set_mother(self.mother);
|
|
|
|
member.set_father(self.father);
|
|
|
|
|
|
|
|
member.birth_year = self.birth.as_ref().map(|m| m.year).unwrap_or_default();
|
|
|
|
member.birth_month = self.birth.as_ref().map(|m| m.month).unwrap_or_default();
|
|
|
|
member.birth_day = self.birth.as_ref().map(|m| m.day).unwrap_or_default();
|
|
|
|
|
|
|
|
member.death_year = self.death.as_ref().map(|m| m.year).unwrap_or_default();
|
|
|
|
member.death_month = self.death.as_ref().map(|m| m.month).unwrap_or_default();
|
|
|
|
member.death_day = self.death.as_ref().map(|m| m.day).unwrap_or_default();
|
|
|
|
|
|
|
|
member.note = self.note;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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?;
|
|
|
|
|
|
|
|
if let Err(e) = req.0.to_member(&mut member).await {
|
|
|
|
log::error!("Failed to apply member information! {e}");
|
|
|
|
members_service::delete(&member).await?;
|
|
|
|
return Ok(HttpResponse::BadRequest().body(e.to_string()));
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Err(e) = members_service::update(&mut member).await {
|
|
|
|
log::error!("Failed to update member information! {e}");
|
|
|
|
members_service::delete(&member).await?;
|
|
|
|
return Ok(HttpResponse::InternalServerError().finish());
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(HttpResponse::Ok().json(member))
|
|
|
|
}
|
2023-08-05 08:24:19 +00:00
|
|
|
|
|
|
|
/// Get the information of a single family member
|
|
|
|
pub async fn get_single(m: FamilyAndMemberInPath) -> HttpResult {
|
|
|
|
Ok(HttpResponse::Ok().json(m.to_member()))
|
|
|
|
}
|