diff --git a/web/src/endpoints/availability/get_new.rs b/web/src/endpoints/availability/get_new.rs index b5a73dad..43dd1a48 100644 --- a/web/src/endpoints/availability/get_new.rs +++ b/web/src/endpoints/availability/get_new.rs @@ -6,9 +6,10 @@ use sqlx::PgPool; use crate::endpoints::availability::NewOrEditAvailabilityTemplate; use crate::models::{ - find_free_time_slots, only_one_availability_exists_and_is_whole_day, Availability, User, + find_free_time_slots, only_one_availability_exists_and_is_whole_day, Availability, AvailabilityTime, User }; use crate::utils::ApplicationError; +use crate::{END_OF_DAY, START_OF_DAY}; #[derive(Deserialize)] struct AvailabilityNewQuery { @@ -27,20 +28,25 @@ pub async fn get( Availability::read_by_user_and_date(pool.get_ref(), user.id, &query.date).await?; let free_slots = find_free_time_slots(&availabilities_from_user); - let user_can_create_availabillity = - !(only_one_availability_exists_and_is_whole_day(&availabilities_from_user) - || free_slots.len() == 0); + let user_can_create_availabillity = availabilities_from_user.len() == 0 + || !only_one_availability_exists_and_is_whole_day(&availabilities_from_user) + || free_slots.len() > 0; if !user_can_create_availabillity { return Ok(HttpResponse::BadRequest().finish()); } + let time_selection = if query.whole_day.unwrap_or(true) { + AvailabilityTime::WholeDay + } else { + AvailabilityTime::Temporarily(START_OF_DAY, END_OF_DAY) + }; + let template = NewOrEditAvailabilityTemplate { user: user.into_inner(), date: query.date, - whole_day_selected: query.whole_day.unwrap_or(true), + time_selection, id: None, - time: None, comment: None, slot_suggestions: free_slots, }; diff --git a/web/src/endpoints/availability/get_overview.rs b/web/src/endpoints/availability/get_overview.rs index d83d383b..51c07254 100644 --- a/web/src/endpoints/availability/get_overview.rs +++ b/web/src/endpoints/availability/get_overview.rs @@ -71,10 +71,15 @@ async fn get( let availabilities_from_user = Availability::read_by_user_and_date(pool.get_ref(), user.id, &date).await?; + println!("{availabilities_from_user:#?}"); - let user_can_create_availabillity = - !(only_one_availability_exists_and_is_whole_day(&availabilities_from_user) - || find_free_time_slots(&availabilities_from_user).len() == 0); + let user_can_create_availabillity = availabilities_from_user.len() == 0 + || !only_one_availability_exists_and_is_whole_day(&availabilities_from_user) + || find_free_time_slots(&availabilities_from_user).len() > 0; + + println!("{} || {} || {} = {user_can_create_availabillity}", availabilities_from_user.len() == 0, + !only_one_availability_exists_and_is_whole_day(&availabilities_from_user), + find_free_time_slots(&availabilities_from_user).len() > 0); let mut events_and_assignments = Vec::new(); for e in Event::read_all_by_date_and_area_including_location( diff --git a/web/src/endpoints/availability/get_update.rs b/web/src/endpoints/availability/get_update.rs index 54d69aab..18016a3a 100644 --- a/web/src/endpoints/availability/get_update.rs +++ b/web/src/endpoints/availability/get_update.rs @@ -33,8 +33,6 @@ pub async fn get( return Err(ApplicationError::Unauthorized); } - let whole_day_selected = query.whole_day.unwrap_or(availability.time == AvailabilityTime::WholeDay); - let suggestions = if let AvailabilityTime::Temporarily(start, end) = availability.time { let availabilities = Availability::read_by_user_and_date( pool.get_ref(), @@ -51,14 +49,20 @@ pub async fn get( Vec::new() }; + let time_selection = if query.whole_day.unwrap_or(availability.time == AvailabilityTime::WholeDay) { + AvailabilityTime::WholeDay + } else { + availability.time.clone() + }; + + println!("{:?}", availability.time); let template = NewOrEditAvailabilityTemplate { user: user.into_inner(), date: availability.date, id: Some(path.id), - time: Some(availability.time), + time_selection, comment: availability.comment.as_deref(), slot_suggestions: suggestions, - whole_day_selected }; Ok(HttpResponse::Ok().body(template.render()?)) diff --git a/web/src/endpoints/availability/mod.rs b/web/src/endpoints/availability/mod.rs index f2d47a06..c6e5dfbf 100644 --- a/web/src/endpoints/availability/mod.rs +++ b/web/src/endpoints/availability/mod.rs @@ -2,7 +2,7 @@ use chrono::{NaiveDate, NaiveTime}; use rinja::Template; use crate::filters; -use crate::models::{AvailabilityTime, Role, User}; +use crate::models::{Availability, AvailabilityChangeset, AvailabilityTime, Role, User}; pub mod delete; pub mod get_new; @@ -17,8 +17,30 @@ struct NewOrEditAvailabilityTemplate<'a> { user: User, date: NaiveDate, id: Option, - time: Option, - whole_day_selected: bool, + time_selection: AvailabilityTime, comment: Option<&'a str>, slot_suggestions: Vec<(NaiveTime, NaiveTime)>, } + +fn find_adjacend_availability<'a>( + changeset: &AvailabilityChangeset, + availability_id_to_be_updated: Option, + existing_availabilities: &'a [Availability], +) -> Option<&'a Availability> { + let AvailabilityTime::Temporarily(changeset_start, changeset_end) = changeset.time else { + return None; + }; + + for a in existing_availabilities + .iter() + .filter(|a| availability_id_to_be_updated.is_none_or(|id| a.id != id)) + { + if let AvailabilityTime::Temporarily(start, end) = a.time { + if start == changeset_end || end == changeset_start { + return Some(a); + } + } + } + + None +} diff --git a/web/src/endpoints/availability/post_new.rs b/web/src/endpoints/availability/post_new.rs index 2f99bf95..f5a8660f 100644 --- a/web/src/endpoints/availability/post_new.rs +++ b/web/src/endpoints/availability/post_new.rs @@ -1,10 +1,12 @@ use actix_web::{http::header::LOCATION, web, HttpResponse, Responder}; use chrono::{NaiveDate, NaiveTime}; +use garde::Validate; use serde::Deserialize; use sqlx::PgPool; use crate::{ - models::{Availability, User}, + endpoints::availability::find_adjacend_availability, + models::{Availability, AvailabilityChangeset, AvailabilityContext, AvailabilityTime, User}, utils::{self, ApplicationError}, }; @@ -22,16 +24,43 @@ pub async fn post( pool: web::Data, form: web::Form, ) -> Result { - // TODO: create and validate changeset - //Availability::create( - // pool.get_ref(), - // user.id, - // form.date, - // form.from, - // form.till, - // form.comment.clone(), - //) - //.await?; + let existing_availabilities = + Availability::read_by_user_and_date(pool.get_ref(), user.id, &form.date).await?; + let context = AvailabilityContext { + existing_availabilities: existing_availabilities.clone(), + }; + + let time = if form.from.is_some() && form.till.is_some() { + AvailabilityTime::Temporarily(form.from.unwrap(), form.till.unwrap()) + } else { + AvailabilityTime::WholeDay + }; + + let mut changeset = AvailabilityChangeset { + time, + comment: form.comment.clone(), + }; + + if let Err(e) = changeset.validate_with(&context) { + return Ok(HttpResponse::BadRequest().body(e.to_string())); + }; + + if let Some(a) = find_adjacend_availability(&changeset, None, &existing_availabilities) { + let (changeset_start, changeset_end) = changeset.time.time_tuple_opt().unwrap(); + let (adjacent_start, adjacent_end) = changeset.time.time_tuple_opt().unwrap(); + + if adjacent_end == changeset_start { + changeset.time = AvailabilityTime::Temporarily(adjacent_start, changeset_end); + } + + if adjacent_start == changeset_end { + changeset.time = AvailabilityTime::Temporarily(changeset_start, adjacent_end); + } + + Availability::update(pool.get_ref(), a.id, changeset).await?; + } else { + Availability::create(pool.get_ref(), user.id, form.date, changeset).await?; + } let url = utils::get_return_url_for_date(&form.date); Ok(HttpResponse::Found() diff --git a/web/src/endpoints/availability/post_update.rs b/web/src/endpoints/availability/post_update.rs index 28b647a4..ea1ab9d2 100644 --- a/web/src/endpoints/availability/post_update.rs +++ b/web/src/endpoints/availability/post_update.rs @@ -3,7 +3,7 @@ use garde::Validate; use sqlx::PgPool; use crate::{ - endpoints::{availability::post_new::AvailabillityForm, IdPath}, + endpoints::{availability::{find_adjacend_availability, post_new::AvailabillityForm}, IdPath}, models::{Availability, AvailabilityChangeset, AvailabilityContext, AvailabilityTime, User}, utils::{self, ApplicationError}, }; @@ -44,22 +44,7 @@ pub async fn post( return Ok(HttpResponse::BadRequest().body(e.to_string())); }; - let mut adjacent = None; - if let AvailabilityTime::Temporarily(changeset_start, changeset_end) = changeset.time { - for a in existing_availabilities - .iter() - .filter(|a| a.id != availability.id) - { - if let AvailabilityTime::Temporarily(start, end) = a.time { - if start == changeset_end || end == changeset_start { - adjacent = Some(a); - break; - } - } - } - } - - if let Some(a) = adjacent { + if let Some(a) = find_adjacend_availability(&changeset, Some(availability.id), &existing_availabilities) { let (changeset_start, changeset_end) = changeset.time.time_tuple_opt().unwrap(); let (adjacent_start, adjacent_end) = changeset.time.time_tuple_opt().unwrap(); diff --git a/web/src/models/availability_changeset.rs b/web/src/models/availability_changeset.rs index 93d33700..627a6a2b 100644 --- a/web/src/models/availability_changeset.rs +++ b/web/src/models/availability_changeset.rs @@ -34,7 +34,7 @@ fn time_is_not_already_made_available( return Err(garde::Error::new("cant create a availability while an other availability for the whole day is already present")); } - if find_free_time_slots(&context.existing_availabilities).len() == 0 { + if context.existing_availabilities.len() > 0 && find_free_time_slots(&context.existing_availabilities).len() == 0 { return Err(garde::Error::new( "cant create a availability as every time slot is already filled", )); @@ -71,7 +71,7 @@ pub fn find_free_time_slots(availabilities: &[Availability]) -> Vec<(NaiveTime, if times.len() == 0 { return Vec::new(); } - //println!("zeiten {times:?}"); + println!("zeiten {times:?}"); times.sort(); diff --git a/web/templates/availability/new_or_edit.html b/web/templates/availability/new_or_edit.html index 198f9601..4c3d7f32 100644 --- a/web/templates/availability/new_or_edit.html +++ b/web/templates/availability/new_or_edit.html @@ -12,6 +12,7 @@ {% endif %} + {% let whole_day_selected = time_selection == AvailabilityTime::WholeDay %}
@@ -46,25 +47,21 @@
- {% let times = ("00:00".to_string(), "23:59".to_string()) -%} - {% if let Some(times) = time -%} - {% if let AvailabilityTime::Temporarily(start, end) = times -%} - {% let times = (start.to_string(), end.to_string()) -%} - {% endif -%} - {% endif -%} + {% let times = time_selection.time_tuple() -%}
- - + {% if slot_suggestions.len() > 0 %}

noch mögliche Zeiträume:

{% for (s, e) in slot_suggestions %} {{ s }} - {{ e }} {% endfor %}
+ {% endif %}
-