Can generate calendars
This commit is contained in:
		
							
								
								
									
										13
									
								
								geneit_backend/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										13
									
								
								geneit_backend/Cargo.lock
									
									
									
										generated
									
									
									
								
							@@ -727,8 +727,10 @@ checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "android-tzdata",
 | 
			
		||||
 "iana-time-zone",
 | 
			
		||||
 "js-sys",
 | 
			
		||||
 "num-traits",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "wasm-bindgen",
 | 
			
		||||
 "windows-targets 0.52.5",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@@ -1417,12 +1419,14 @@ dependencies = [
 | 
			
		||||
 "anyhow",
 | 
			
		||||
 "base64 0.22.1",
 | 
			
		||||
 "bcrypt",
 | 
			
		||||
 "chrono",
 | 
			
		||||
 "clap",
 | 
			
		||||
 "diesel",
 | 
			
		||||
 "diesel_migrations",
 | 
			
		||||
 "env_logger",
 | 
			
		||||
 "futures-util",
 | 
			
		||||
 "httpdate",
 | 
			
		||||
 "ical",
 | 
			
		||||
 "image",
 | 
			
		||||
 "lazy_static",
 | 
			
		||||
 "lettre",
 | 
			
		||||
@@ -1776,6 +1780,15 @@ dependencies = [
 | 
			
		||||
 "cc",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "ical"
 | 
			
		||||
version = "0.11.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "9b7cab7543a8b7729a19e2c04309f902861293dcdae6558dfbeb634454d279f6"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "thiserror",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "ident_case"
 | 
			
		||||
version = "1.0.1"
 | 
			
		||||
 
 | 
			
		||||
@@ -38,3 +38,5 @@ zip = "2.0.0"
 | 
			
		||||
mime_guess = "2.0.4"
 | 
			
		||||
tempfile = "3.10.1"
 | 
			
		||||
base64 = "0.22.0"
 | 
			
		||||
ical = { version = "0.11.0", features = ["generator", "ical", "vcard"] }
 | 
			
		||||
chrono = "0.4.38"
 | 
			
		||||
@@ -1,10 +1,17 @@
 | 
			
		||||
use ical::{generator::*, *};
 | 
			
		||||
 | 
			
		||||
use actix_web::{web, HttpResponse};
 | 
			
		||||
use chrono::DateTime;
 | 
			
		||||
 | 
			
		||||
use crate::constants::StaticConstraints;
 | 
			
		||||
use crate::controllers::HttpResult;
 | 
			
		||||
use crate::extractors::accommodation_reservation_calendar_extractor::FamilyAndAccommodationReservationCalendarInPath;
 | 
			
		||||
use crate::extractors::family_extractor::FamilyInPath;
 | 
			
		||||
use crate::models::AccommodationID;
 | 
			
		||||
use crate::services::{accommodations_list_service, accommodations_reservations_calendars_service};
 | 
			
		||||
use actix_web::{web, HttpResponse};
 | 
			
		||||
use crate::models::{AccommodationID, ReservationStatus};
 | 
			
		||||
use crate::services::{
 | 
			
		||||
    accommodations_list_service, accommodations_reservations_calendars_service,
 | 
			
		||||
    accommodations_reservations_service, families_service,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Deserialize)]
 | 
			
		||||
pub struct CreateCalendarQuery {
 | 
			
		||||
@@ -65,3 +72,86 @@ pub async fn delete(resa: FamilyAndAccommodationReservationCalendarInPath) -> Ht
 | 
			
		||||
    accommodations_reservations_calendars_service::delete(resa.to_reservation()).await?;
 | 
			
		||||
    Ok(HttpResponse::Ok().json("Calendar successfully deleted"))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn fmt_date(time: i64) -> String {
 | 
			
		||||
    let res = DateTime::from_timestamp(time, 0).expect("Failed to parse date");
 | 
			
		||||
 | 
			
		||||
    /*format!(
 | 
			
		||||
        "{:0>4}{:0>2}{:0>2}T{:0>2}{:0>2}",
 | 
			
		||||
        res.year(),
 | 
			
		||||
        res.month(),
 | 
			
		||||
        res.day(),
 | 
			
		||||
        res.minute(),
 | 
			
		||||
        res.second()
 | 
			
		||||
    )*/
 | 
			
		||||
 | 
			
		||||
    res.format("%Y%m%dT%H%M%S").to_string()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Deserialize)]
 | 
			
		||||
pub struct AnonymousAccessURL {
 | 
			
		||||
    token: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Get the content of the calendar
 | 
			
		||||
pub async fn anonymous_access(req: web::Path<AnonymousAccessURL>) -> HttpResult {
 | 
			
		||||
    let calendar =
 | 
			
		||||
        match accommodations_reservations_calendars_service::get_by_token(&req.token).await {
 | 
			
		||||
            Ok(c) => c,
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                log::error!("Calendar information could not be retrieved: {e}");
 | 
			
		||||
                return Ok(HttpResponse::NotFound().body("Calendar not found!"));
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
    let accommodations =
 | 
			
		||||
        accommodations_list_service::get_all_of_family(calendar.family_id()).await?;
 | 
			
		||||
    let members = families_service::get_memberships_of_family(calendar.family_id()).await?;
 | 
			
		||||
 | 
			
		||||
    // Get calendar associated events
 | 
			
		||||
    let events = match calendar.accommodation_id() {
 | 
			
		||||
        None => {
 | 
			
		||||
            accommodations_reservations_service::get_all_of_family(calendar.family_id()).await?
 | 
			
		||||
        }
 | 
			
		||||
        Some(a) => accommodations_reservations_service::get_all_of_accommodation(a).await?,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let mut cal = IcalCalendarBuilder::version("2.0")
 | 
			
		||||
        .gregorian()
 | 
			
		||||
        .prodid("-//geneit//")
 | 
			
		||||
        .build();
 | 
			
		||||
 | 
			
		||||
    for ev in events {
 | 
			
		||||
        let accommodation = accommodations
 | 
			
		||||
            .iter()
 | 
			
		||||
            .find(|a| a.id() == ev.accommodation_id())
 | 
			
		||||
            .unwrap();
 | 
			
		||||
        let member_name = members
 | 
			
		||||
            .iter()
 | 
			
		||||
            .find(|a| a.membership.user_id() == ev.user_id())
 | 
			
		||||
            .map(|m| m.user_name.as_str())
 | 
			
		||||
            .unwrap_or("other user");
 | 
			
		||||
 | 
			
		||||
        let event = IcalEventBuilder::tzid("Europe/Paris")
 | 
			
		||||
            .uid(format!("resa-{}", ev.id().0))
 | 
			
		||||
            .changed(fmt_date(ev.time_update))
 | 
			
		||||
            .start(fmt_date(ev.reservation_start))
 | 
			
		||||
            .end(fmt_date(ev.reservation_end))
 | 
			
		||||
            .set(ical_property!("SUMMARY", member_name))
 | 
			
		||||
            .set(ical_property!("LOCATION", &accommodation.name))
 | 
			
		||||
            .set(ical_property!(
 | 
			
		||||
                "STATUS",
 | 
			
		||||
                match ev.status() {
 | 
			
		||||
                    ReservationStatus::Pending => "TENTATIVE",
 | 
			
		||||
                    ReservationStatus::Accepted => "CONFIRMED",
 | 
			
		||||
                    ReservationStatus::Rejected => "CANCELLED",
 | 
			
		||||
                }
 | 
			
		||||
            ))
 | 
			
		||||
            .build();
 | 
			
		||||
        cal.events.push(event);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(HttpResponse::Ok()
 | 
			
		||||
        .content_type("text/calendar")
 | 
			
		||||
        .body(cal.generate()))
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -270,7 +270,10 @@ async fn main() -> std::io::Result<()> {
 | 
			
		||||
                "/family/{id}/accommodations/reservations_calendars/{cal_id}",
 | 
			
		||||
                web::delete().to(accommodations_reservations_calendars_controller::delete),
 | 
			
		||||
            )
 | 
			
		||||
            // TODO : anonymous URL access
 | 
			
		||||
            .route(
 | 
			
		||||
                "/acccommodations_calendar/{token}",
 | 
			
		||||
                web::get().to(accommodations_reservations_calendars_controller::anonymous_access),
 | 
			
		||||
            )
 | 
			
		||||
            // Photos controller
 | 
			
		||||
            .route(
 | 
			
		||||
                "/photo/{id}",
 | 
			
		||||
 
 | 
			
		||||
@@ -485,6 +485,12 @@ pub struct NewAccommodation {
 | 
			
		||||
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
 | 
			
		||||
pub struct AccommodationReservationID(pub i32);
 | 
			
		||||
 | 
			
		||||
pub enum ReservationStatus {
 | 
			
		||||
    Pending,
 | 
			
		||||
    Accepted,
 | 
			
		||||
    Rejected,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Queryable, Debug, serde::Serialize)]
 | 
			
		||||
pub struct AccommodationReservation {
 | 
			
		||||
    id: i32,
 | 
			
		||||
@@ -514,6 +520,14 @@ impl AccommodationReservation {
 | 
			
		||||
    pub fn user_id(&self) -> UserID {
 | 
			
		||||
        UserID(self.user_id)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn status(&self) -> ReservationStatus {
 | 
			
		||||
        match self.validated {
 | 
			
		||||
            None => ReservationStatus::Pending,
 | 
			
		||||
            Some(true) => ReservationStatus::Accepted,
 | 
			
		||||
            Some(false) => ReservationStatus::Rejected,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Insertable)]
 | 
			
		||||
 
 | 
			
		||||
@@ -61,6 +61,15 @@ pub async fn get_by_id(
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Get a single calendar by its token
 | 
			
		||||
pub async fn get_by_token(token: &str) -> anyhow::Result<AccommodationReservationCalendar> {
 | 
			
		||||
    db_connection::execute(|conn| {
 | 
			
		||||
        accommodations_reservations_cals_urls::table
 | 
			
		||||
            .filter(accommodations_reservations_cals_urls::dsl::token.eq(token))
 | 
			
		||||
            .get_result(conn)
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Delete a calendar
 | 
			
		||||
pub async fn delete(r: AccommodationReservationCalendar) -> anyhow::Result<()> {
 | 
			
		||||
    db_connection::execute(|conn| {
 | 
			
		||||
 
 | 
			
		||||
@@ -129,9 +129,9 @@ pub async fn update_membership(membership: &Membership) -> anyhow::Result<()> {
 | 
			
		||||
#[derive(serde::Serialize)]
 | 
			
		||||
pub struct FamilyMember {
 | 
			
		||||
    #[serde(flatten)]
 | 
			
		||||
    membership: Membership,
 | 
			
		||||
    user_name: String,
 | 
			
		||||
    user_mail: String,
 | 
			
		||||
    pub membership: Membership,
 | 
			
		||||
    pub user_name: String,
 | 
			
		||||
    pub user_mail: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Get information about the users of a family
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user