Can create a family member
This commit is contained in:
242
geneit_backend/src/controllers/members_controller.rs
Normal file
242
geneit_backend/src/controllers/members_controller.rs
Normal file
@ -0,0 +1,242 @@
|
||||
use crate::constants::{SizeConstraint, StaticConstraints};
|
||||
use crate::controllers::HttpResult;
|
||||
use crate::extractors::family_extractor::FamilyInPath;
|
||||
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))
|
||||
}
|
@ -6,6 +6,7 @@ use std::fmt::{Debug, Display, Formatter};
|
||||
|
||||
pub mod auth_controller;
|
||||
pub mod families_controller;
|
||||
pub mod members_controller;
|
||||
pub mod server_controller;
|
||||
pub mod users_controller;
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
use crate::app_config::{AppConfig, OIDCProvider};
|
||||
use crate::constants::StaticConstraints;
|
||||
use crate::utils::countries_utils;
|
||||
use crate::utils::countries_utils::CountryCode;
|
||||
use actix_web::{HttpResponse, Responder};
|
||||
|
||||
/// Default hello route
|
||||
@ -12,6 +14,7 @@ struct ServerConfig<'a> {
|
||||
constraints: StaticConstraints,
|
||||
mail: &'static str,
|
||||
oidc_providers: Vec<OIDCProvider<'a>>,
|
||||
countries: Vec<CountryCode>,
|
||||
}
|
||||
|
||||
impl Default for ServerConfig<'_> {
|
||||
@ -20,6 +23,7 @@ impl Default for ServerConfig<'_> {
|
||||
mail: AppConfig::get().mail_sender.as_str(),
|
||||
constraints: StaticConstraints::default(),
|
||||
oidc_providers: AppConfig::get().openid_providers(),
|
||||
countries: countries_utils::get_list(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user