Can create new accommodations using the API
This commit is contained in:
		@@ -32,6 +32,8 @@ interface Constraints {
 | 
			
		||||
  member_country: LenConstraint;
 | 
			
		||||
  member_sex: LenConstraint;
 | 
			
		||||
  member_note: LenConstraint;
 | 
			
		||||
  accomodation_name_len: LenConstraint;
 | 
			
		||||
  accomodation_description_len: LenConstraint;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface OIDCProvider {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
ALTER TABLE public.families
 | 
			
		||||
    DROP COLUMN enable_accommodations;
 | 
			
		||||
 | 
			
		||||
DROP TABLE IF EXISTS accomodations_reservations;
 | 
			
		||||
DROP TABLE IF EXISTS accomodations_list;
 | 
			
		||||
DROP TABLE IF EXISTS accommodations_reservations;
 | 
			
		||||
DROP TABLE IF EXISTS accommodations_list;
 | 
			
		||||
@@ -12,9 +12,10 @@ CREATE TABLE IF NOT EXISTS accommodations_list
 | 
			
		||||
    family_id            integer     NOT NULL REFERENCES families,
 | 
			
		||||
    time_create          BIGINT      NOT NULL,
 | 
			
		||||
    time_update          BIGINT      NOT NULL,
 | 
			
		||||
    need_validation     BOOLEAN,
 | 
			
		||||
    name                 VARCHAR(50) NOT NULL,
 | 
			
		||||
    need_validation      BOOLEAN     NOT NULL DEFAULT true,
 | 
			
		||||
    description          text        NULL,
 | 
			
		||||
    open_to_reservation BOOLEAN
 | 
			
		||||
    open_to_reservations BOOLEAN     NOT NULL DEFAULT false
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE IF NOT EXISTS accommodations_reservations
 | 
			
		||||
@@ -27,5 +28,5 @@ CREATE TABLE IF NOT EXISTS accommodations_reservations
 | 
			
		||||
    time_update       BIGINT  NOT NULL,
 | 
			
		||||
    reservation_start BIGINT  NOT NULL,
 | 
			
		||||
    reservation_end   BIGINT  NOT NULL,
 | 
			
		||||
    validated         BOOLEAN
 | 
			
		||||
    validated         BOOLEAN NULL
 | 
			
		||||
);
 | 
			
		||||
@@ -60,6 +60,9 @@ pub struct StaticConstraints {
 | 
			
		||||
    pub member_country: SizeConstraint,
 | 
			
		||||
    pub member_sex: SizeConstraint,
 | 
			
		||||
    pub member_note: SizeConstraint,
 | 
			
		||||
 | 
			
		||||
    pub accomodation_name_len: SizeConstraint,
 | 
			
		||||
    pub accomodation_description_len: SizeConstraint,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for StaticConstraints {
 | 
			
		||||
@@ -91,6 +94,9 @@ impl Default for StaticConstraints {
 | 
			
		||||
            member_country: SizeConstraint::new(0, 2),
 | 
			
		||||
            member_sex: SizeConstraint::new(0, 1),
 | 
			
		||||
            member_note: SizeConstraint::new(0, 35000),
 | 
			
		||||
 | 
			
		||||
            accomodation_name_len: SizeConstraint::new(1, 50),
 | 
			
		||||
            accomodation_description_len: SizeConstraint::new(0, 500),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,75 @@
 | 
			
		||||
use crate::constants::StaticConstraints;
 | 
			
		||||
use crate::controllers::HttpResult;
 | 
			
		||||
use crate::extractors::family_extractor::FamilyInPathWithAdminMembership;
 | 
			
		||||
use crate::models::{Accommodation, FamilyID};
 | 
			
		||||
use crate::services::accommodations_list_service;
 | 
			
		||||
use crate::services::couples_service::{delete, get_all_of_family};
 | 
			
		||||
use actix_web::{web, HttpResponse};
 | 
			
		||||
 | 
			
		||||
#[derive(thiserror::Error, Debug)]
 | 
			
		||||
enum AccommodationListControllerErr {
 | 
			
		||||
    #[error("Malformed name!")]
 | 
			
		||||
    MalformedName,
 | 
			
		||||
    #[error("Malformed description!")]
 | 
			
		||||
    MalformedDescription,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Deserialize, Clone)]
 | 
			
		||||
pub struct AccommodationRequest {
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    pub need_validation: bool,
 | 
			
		||||
    pub description: Option<String>,
 | 
			
		||||
    pub open_to_reservations: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl AccommodationRequest {
 | 
			
		||||
    pub async fn to_accommodation(self, accommodation: &mut Accommodation) -> anyhow::Result<()> {
 | 
			
		||||
        let c = StaticConstraints::default();
 | 
			
		||||
 | 
			
		||||
        if !c.accomodation_name_len.validate(&self.name) {
 | 
			
		||||
            return Err(AccommodationListControllerErr::MalformedName.into());
 | 
			
		||||
        }
 | 
			
		||||
        accommodation.name = self.name;
 | 
			
		||||
 | 
			
		||||
        if let Some(d) = &self.description {
 | 
			
		||||
            if !c.accomodation_description_len.validate(d) {
 | 
			
		||||
                return Err(AccommodationListControllerErr::MalformedDescription.into());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        accommodation.description.clone_from(&self.description);
 | 
			
		||||
 | 
			
		||||
        accommodation.need_validation = self.need_validation;
 | 
			
		||||
        accommodation.open_to_reservations = self.open_to_reservations;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Create a new accommodation
 | 
			
		||||
pub async fn create(
 | 
			
		||||
    m: FamilyInPathWithAdminMembership,
 | 
			
		||||
    req: web::Json<AccommodationRequest>,
 | 
			
		||||
) -> HttpResult {
 | 
			
		||||
    let mut accommodation = accommodations_list_service::create(m.family_id()).await?;
 | 
			
		||||
 | 
			
		||||
    if let Err(e) = req.0.to_accommodation(&mut accommodation).await {
 | 
			
		||||
        log::error!("Failed to apply accommodation information! {e}");
 | 
			
		||||
        accommodations_list_service::delete(&mut accommodation).await?;
 | 
			
		||||
        return Ok(HttpResponse::BadRequest().body(e.to_string()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if let Err(e) = accommodations_list_service::update(&mut accommodation).await {
 | 
			
		||||
        log::error!("Failed to update accommodation information! {e}");
 | 
			
		||||
        accommodations_list_service::delete(&mut accommodation).await?;
 | 
			
		||||
        return Ok(HttpResponse::InternalServerError().finish());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(HttpResponse::Ok().json(accommodation))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Delete all the accommodations of a family
 | 
			
		||||
pub async fn delete_all_family(family_id: FamilyID) -> anyhow::Result<()> {
 | 
			
		||||
    for mut m in get_all_of_family(family_id).await? {
 | 
			
		||||
        delete(&mut m).await?;
 | 
			
		||||
    }
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
@@ -5,6 +5,7 @@ use actix_web::HttpResponse;
 | 
			
		||||
use std::fmt::{Debug, Display, Formatter};
 | 
			
		||||
use zip::result::ZipError;
 | 
			
		||||
 | 
			
		||||
pub mod accommodations_list_controller;
 | 
			
		||||
pub mod auth_controller;
 | 
			
		||||
pub mod couples_controller;
 | 
			
		||||
pub mod data_controller;
 | 
			
		||||
 
 | 
			
		||||
@@ -6,8 +6,9 @@ use actix_web::{web, App, HttpServer};
 | 
			
		||||
use geneit_backend::app_config::AppConfig;
 | 
			
		||||
use geneit_backend::connections::{db_connection, s3_connection};
 | 
			
		||||
use geneit_backend::controllers::{
 | 
			
		||||
    auth_controller, couples_controller, data_controller, families_controller, members_controller,
 | 
			
		||||
    photos_controller, server_controller, users_controller,
 | 
			
		||||
    accommodations_list_controller, auth_controller, couples_controller, data_controller,
 | 
			
		||||
    families_controller, members_controller, photos_controller, server_controller,
 | 
			
		||||
    users_controller,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[actix_web::main]
 | 
			
		||||
@@ -205,7 +206,10 @@ async fn main() -> std::io::Result<()> {
 | 
			
		||||
                web::put().to(data_controller::import_family),
 | 
			
		||||
            )
 | 
			
		||||
            // [ACCOMODATIONS] List controller
 | 
			
		||||
            // TODO : create
 | 
			
		||||
            .route(
 | 
			
		||||
                "/family/{id}/accommodations/list/create",
 | 
			
		||||
                web::post().to(accommodations_list_controller::create),
 | 
			
		||||
            )
 | 
			
		||||
            // TODO : update
 | 
			
		||||
            // TODO : delete
 | 
			
		||||
            // TODO : list
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
use crate::app_config::AppConfig;
 | 
			
		||||
use crate::schema::{couples, families, members, memberships, photos, users};
 | 
			
		||||
use crate::schema::{accommodations_list, couples, families, members, memberships, photos, users};
 | 
			
		||||
use crate::utils::crypt_utils::sha256;
 | 
			
		||||
use diesel::prelude::*;
 | 
			
		||||
 | 
			
		||||
@@ -309,7 +309,7 @@ pub struct NewMember {
 | 
			
		||||
    pub time_update: i64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Member ID holder
 | 
			
		||||
/// Couple ID holder
 | 
			
		||||
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
 | 
			
		||||
pub struct CoupleID(pub i32);
 | 
			
		||||
 | 
			
		||||
@@ -442,3 +442,34 @@ pub struct NewCouple {
 | 
			
		||||
    pub time_create: i64,
 | 
			
		||||
    pub time_update: i64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Accommodation ID holder
 | 
			
		||||
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
 | 
			
		||||
pub struct AccommodationID(pub i32);
 | 
			
		||||
 | 
			
		||||
#[derive(Queryable, Debug, serde::Serialize)]
 | 
			
		||||
pub struct Accommodation {
 | 
			
		||||
    id: i32,
 | 
			
		||||
    family_id: i32,
 | 
			
		||||
    time_create: i64,
 | 
			
		||||
    pub time_update: i64,
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    pub need_validation: bool,
 | 
			
		||||
    pub description: Option<String>,
 | 
			
		||||
    pub open_to_reservations: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Accommodation {
 | 
			
		||||
    pub fn id(&self) -> AccommodationID {
 | 
			
		||||
        AccommodationID(self.id)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Insertable)]
 | 
			
		||||
#[diesel(table_name = accommodations_list)]
 | 
			
		||||
pub struct NewAccommodation {
 | 
			
		||||
    pub family_id: i32,
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    pub time_create: i64,
 | 
			
		||||
    pub time_update: i64,
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,9 +6,11 @@ diesel::table! {
 | 
			
		||||
        family_id -> Int4,
 | 
			
		||||
        time_create -> Int8,
 | 
			
		||||
        time_update -> Int8,
 | 
			
		||||
        need_validation -> Nullable<Bool>,
 | 
			
		||||
        #[max_length = 50]
 | 
			
		||||
        name -> Varchar,
 | 
			
		||||
        need_validation -> Bool,
 | 
			
		||||
        description -> Nullable<Text>,
 | 
			
		||||
        open_to_reservation -> Nullable<Bool>,
 | 
			
		||||
        open_to_reservations -> Bool,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										102
									
								
								geneit_backend/src/services/accommodations_list_service.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								geneit_backend/src/services/accommodations_list_service.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,102 @@
 | 
			
		||||
use crate::connections::db_connection;
 | 
			
		||||
use crate::models::{Accommodation, AccommodationID, FamilyID, NewAccommodation};
 | 
			
		||||
use crate::schema::accommodations_list;
 | 
			
		||||
use crate::utils::time_utils::time;
 | 
			
		||||
use diesel::prelude::*;
 | 
			
		||||
 | 
			
		||||
/// Create a new accommodation
 | 
			
		||||
pub async fn create(family_id: FamilyID) -> anyhow::Result<Accommodation> {
 | 
			
		||||
    db_connection::execute(|conn| {
 | 
			
		||||
        let res: Accommodation = diesel::insert_into(accommodations_list::table)
 | 
			
		||||
            .values(&NewAccommodation {
 | 
			
		||||
                family_id: family_id.0,
 | 
			
		||||
                name: "".to_string(),
 | 
			
		||||
                time_create: time() as i64,
 | 
			
		||||
                time_update: time() as i64,
 | 
			
		||||
            })
 | 
			
		||||
            .get_result(conn)?;
 | 
			
		||||
 | 
			
		||||
        Ok(res)
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Get the information of an accommodation
 | 
			
		||||
pub async fn get_by_id(id: AccommodationID) -> anyhow::Result<Accommodation> {
 | 
			
		||||
    db_connection::execute(|conn| {
 | 
			
		||||
        accommodations_list::table
 | 
			
		||||
            .filter(accommodations_list::dsl::id.eq(id.0))
 | 
			
		||||
            .first(conn)
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Get all the couples of an accommodation
 | 
			
		||||
pub async fn get_all_of_family(id: FamilyID) -> anyhow::Result<Vec<Accommodation>> {
 | 
			
		||||
    db_connection::execute(|conn| {
 | 
			
		||||
        accommodations_list::table
 | 
			
		||||
            .filter(accommodations_list::dsl::family_id.eq(id.0))
 | 
			
		||||
            .get_results(conn)
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Check whether accommodation with a given id exists or not
 | 
			
		||||
pub async fn exists(
 | 
			
		||||
    family_id: FamilyID,
 | 
			
		||||
    accommodation_id: AccommodationID,
 | 
			
		||||
) -> anyhow::Result<bool> {
 | 
			
		||||
    db_connection::execute(|conn| {
 | 
			
		||||
        let count: i64 = accommodations_list::table
 | 
			
		||||
            .filter(
 | 
			
		||||
                accommodations_list::id
 | 
			
		||||
                    .eq(accommodation_id.0)
 | 
			
		||||
                    .and(accommodations_list::family_id.eq(family_id.0)),
 | 
			
		||||
            )
 | 
			
		||||
            .count()
 | 
			
		||||
            .get_result(conn)?;
 | 
			
		||||
 | 
			
		||||
        Ok(count != 0)
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Update the information of a couple
 | 
			
		||||
pub async fn update(accommodation: &mut Accommodation) -> anyhow::Result<()> {
 | 
			
		||||
    accommodation.time_update = time() as i64;
 | 
			
		||||
 | 
			
		||||
    db_connection::execute(|conn| {
 | 
			
		||||
        diesel::update(
 | 
			
		||||
            accommodations_list::dsl::accommodations_list
 | 
			
		||||
                .filter(accommodations_list::dsl::id.eq(accommodation.id().0)),
 | 
			
		||||
        )
 | 
			
		||||
        .set((
 | 
			
		||||
            accommodations_list::dsl::time_update.eq(accommodation.time_update),
 | 
			
		||||
            accommodations_list::dsl::name.eq(accommodation.name.to_string()),
 | 
			
		||||
            accommodations_list::dsl::need_validation.eq(accommodation.need_validation),
 | 
			
		||||
            accommodations_list::dsl::description.eq(accommodation.description.clone()),
 | 
			
		||||
            accommodations_list::dsl::open_to_reservations.eq(accommodation.open_to_reservations),
 | 
			
		||||
        ))
 | 
			
		||||
        .execute(conn)
 | 
			
		||||
    })?;
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Delete an accommodation
 | 
			
		||||
pub async fn delete(accommodation: &mut Accommodation) -> anyhow::Result<()> {
 | 
			
		||||
    // Remove the accommodation
 | 
			
		||||
    db_connection::execute(|conn| {
 | 
			
		||||
        diesel::delete(
 | 
			
		||||
            accommodations_list::dsl::accommodations_list
 | 
			
		||||
                .filter(accommodations_list::dsl::id.eq(accommodation.id().0)),
 | 
			
		||||
        )
 | 
			
		||||
        .execute(conn)
 | 
			
		||||
    })?;
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Delete all the accommodations of a family
 | 
			
		||||
pub async fn delete_all_family(family_id: FamilyID) -> anyhow::Result<()> {
 | 
			
		||||
    for mut m in get_all_of_family(family_id).await? {
 | 
			
		||||
        delete(&mut m).await?;
 | 
			
		||||
    }
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
@@ -5,7 +5,9 @@ use crate::models::{
 | 
			
		||||
    Family, FamilyID, FamilyMembership, Membership, NewFamily, NewMembership, UserID,
 | 
			
		||||
};
 | 
			
		||||
use crate::schema::{families, memberships};
 | 
			
		||||
use crate::services::{couples_service, members_service, users_service};
 | 
			
		||||
use crate::services::{
 | 
			
		||||
    accommodations_list_service, couples_service, members_service, users_service,
 | 
			
		||||
};
 | 
			
		||||
use crate::utils::string_utils::rand_str;
 | 
			
		||||
use crate::utils::time_utils::time;
 | 
			
		||||
use diesel::prelude::*;
 | 
			
		||||
@@ -186,6 +188,9 @@ pub async fn update_family(family: &Family) -> anyhow::Result<()> {
 | 
			
		||||
 | 
			
		||||
/// Delete a family
 | 
			
		||||
pub async fn delete_family(family_id: FamilyID) -> anyhow::Result<()> {
 | 
			
		||||
    // Delete all family accommodations
 | 
			
		||||
    accommodations_list_service::delete_all_family(family_id).await?;
 | 
			
		||||
 | 
			
		||||
    // Delete all family couples
 | 
			
		||||
    couples_service::delete_all_family(family_id).await?;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
//! # Backend services
 | 
			
		||||
 | 
			
		||||
pub mod accommodations_list_service;
 | 
			
		||||
pub mod couples_service;
 | 
			
		||||
pub mod families_service;
 | 
			
		||||
pub mod login_token_service;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user