refactor: WIP datetime event and assignments
This commit is contained in:
parent
93e6a79a38
commit
8b61bb37a8
@ -88,21 +88,25 @@ mod tests {
|
||||
let start = NaiveTime::from_hms_opt(10, 0, 0).unwrap();
|
||||
let end = NaiveTime::from_hms_opt(15, 30, 0).unwrap();
|
||||
|
||||
let new_event = EventChangeset::create_for_test(date.clone(), start.clone(), end.clone());
|
||||
let new_event = EventChangeset::create_for_test(date.and_time(start), date.and_time(end));
|
||||
Event::create(pool, new_event).await?;
|
||||
|
||||
let new_availability = AvailabilityChangeset {
|
||||
time: (date.and_hms_opt(12, 0, 0).unwrap(), date.and_hms_opt(15, 0, 0).unwrap()),
|
||||
time: (
|
||||
date.and_hms_opt(12, 0, 0).unwrap(),
|
||||
date.and_hms_opt(15, 0, 0).unwrap(),
|
||||
),
|
||||
comment: None,
|
||||
};
|
||||
Availability::create(pool, 1, new_availability).await?;
|
||||
|
||||
let new_assignment = AssignmentChangeset {
|
||||
function: Function::Posten,
|
||||
time: (start, end),
|
||||
time: (date.and_time(start), date.and_time(end)),
|
||||
};
|
||||
Assignment::create(pool, 1, 1, new_assignment).await?;
|
||||
|
||||
// TODO: check this test after large refactoring
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ pub async fn post(
|
||||
|
||||
let changeset = AssignmentChangeset {
|
||||
function,
|
||||
time: (event.start_time, event.end_time),
|
||||
time: (event.start, event.end),
|
||||
};
|
||||
|
||||
let assignments_for_event = Assignment::read_all_by_event(pool.get_ref(), event.id).await?;
|
||||
|
@ -1,5 +1,4 @@
|
||||
use actix_web::{http::header::LOCATION, web, HttpResponse, Responder};
|
||||
use chrono::NaiveTime;
|
||||
use garde::Validate;
|
||||
use sqlx::PgPool;
|
||||
|
||||
@ -10,7 +9,6 @@ use crate::{
|
||||
},
|
||||
models::{Availability, AvailabilityChangeset, AvailabilityContext, User},
|
||||
utils::{self, ApplicationError},
|
||||
END_OF_DAY,
|
||||
};
|
||||
|
||||
#[actix_web::post("/availabillity/edit/{id}")]
|
||||
|
@ -33,7 +33,7 @@ pub async fn delete(
|
||||
|
||||
Event::delete(pool.get_ref(), event.id).await?;
|
||||
|
||||
let url = utils::get_return_url_for_date(&event.date);
|
||||
let url = utils::get_return_url_for_date(&event.start.date());
|
||||
Ok(HttpResponse::Ok()
|
||||
.insert_header(("HX-LOCATION", url))
|
||||
.finish())
|
||||
|
@ -39,7 +39,7 @@ pub async fn get(
|
||||
|
||||
let template = NewEventTemplate {
|
||||
user: user.into_inner(),
|
||||
date: event.date,
|
||||
date: event.start.date(),
|
||||
locations,
|
||||
event: Some(event),
|
||||
amount_of_planned_posten: assignments
|
||||
@ -85,11 +85,12 @@ async fn produces_template(context: &DbTestContext) {
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let date = NaiveDate::parse_from_str("2025-01-01", "%F").unwrap();
|
||||
|
||||
let changeset = crate::models::EventChangeset {
|
||||
date: NaiveDate::parse_from_str("2025-01-01", "%F").unwrap(),
|
||||
time: (
|
||||
NaiveTime::parse_from_str("08:00", "%R").unwrap(),
|
||||
NaiveTime::parse_from_str("10:00", "%R").unwrap(),
|
||||
date.and_time(NaiveTime::parse_from_str("08:00", "%R").unwrap()),
|
||||
date.and_time(NaiveTime::parse_from_str("10:00", "%R").unwrap()),
|
||||
),
|
||||
name: "Vorstellung".to_string(),
|
||||
location_id: 1,
|
||||
|
@ -1,3 +1,4 @@
|
||||
use chrono::Days;
|
||||
use crate::filters;
|
||||
use chrono::NaiveDate;
|
||||
use askama::Template;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use actix_web::{http::header::LOCATION, web, HttpResponse, Responder};
|
||||
use chrono::{NaiveDate, NaiveTime};
|
||||
use chrono::{Days, NaiveDateTime};
|
||||
use garde::Validate;
|
||||
use serde::Deserialize;
|
||||
use sqlx::PgPool;
|
||||
@ -7,18 +7,18 @@ use sqlx::PgPool;
|
||||
use crate::{
|
||||
endpoints::IdPath,
|
||||
models::{
|
||||
Assignment, AssignmentChangeset, Availability, Event, EventChangeset,
|
||||
EventContext, Function, Location, Role, User,
|
||||
Assignment, AssignmentChangeset, Availability, Event, EventChangeset, EventContext,
|
||||
Function, Location, Role, User,
|
||||
},
|
||||
utils::{self, ApplicationError},
|
||||
END_OF_DAY, START_OF_DAY,
|
||||
};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct EditEventForm {
|
||||
name: String,
|
||||
date: NaiveDate,
|
||||
from: NaiveTime,
|
||||
till: NaiveTime,
|
||||
from: NaiveDateTime,
|
||||
till: NaiveDateTime,
|
||||
location: i32,
|
||||
voluntarywachhabender: Option<bool>,
|
||||
voluntaryfuehrungsassistent: Option<bool>,
|
||||
@ -58,7 +58,6 @@ pub async fn post(
|
||||
}
|
||||
|
||||
let changeset = EventChangeset {
|
||||
date: form.date,
|
||||
amount_of_posten: form.amount,
|
||||
clothing: form.clothing.clone(),
|
||||
location_id: form.location,
|
||||
@ -74,10 +73,10 @@ pub async fn post(
|
||||
|
||||
let assignments_for_event = Assignment::read_all_by_event(pool.get_ref(), event.id).await?;
|
||||
|
||||
let mut common_time = (
|
||||
NaiveTime::parse_from_str("00:00", "%R").unwrap(),
|
||||
NaiveTime::parse_from_str("23:59", "%R").unwrap(),
|
||||
);
|
||||
let start = event.start.date();
|
||||
let end = event.start.date().checked_add_days(Days::new(1)).unwrap();
|
||||
let mut common_time = (start.and_time(START_OF_DAY), end.and_time(END_OF_DAY));
|
||||
|
||||
for assignment in &assignments_for_event {
|
||||
let availability = Availability::read_by_id(pool.get_ref(), assignment.availabillity_id)
|
||||
.await?
|
||||
@ -87,39 +86,37 @@ pub async fn post(
|
||||
.await?;
|
||||
|
||||
if all_assignments.len() == 1 {
|
||||
// TODO: refactor
|
||||
if availability.start.time() > common_time.0 {
|
||||
common_time.0 = availability.start.time();
|
||||
}
|
||||
if availability.start > common_time.0 {
|
||||
common_time.0 = availability.start;
|
||||
}
|
||||
|
||||
if availability.end.time() < common_time.1 {
|
||||
common_time.1 = availability.end.time();
|
||||
}
|
||||
if availability.end < common_time.1 {
|
||||
common_time.1 = availability.end;
|
||||
}
|
||||
} else {
|
||||
// TODO: refactor
|
||||
let mut slots = vec![(availability.start.time(), availability.end.time())];
|
||||
let mut slots = vec![(availability.start, availability.end)];
|
||||
for a in all_assignments
|
||||
.iter()
|
||||
.filter(|x| x.event_id != assignment.event_id)
|
||||
{
|
||||
let (fit, rest) = slots
|
||||
.into_iter()
|
||||
.partition(|s| s.0 >= a.start_time && s.1 <= a.end_time);
|
||||
.partition(|s| s.0 >= a.start && s.1 <= a.end);
|
||||
slots = rest;
|
||||
let fit = fit.first().unwrap();
|
||||
|
||||
if fit.0 != a.start_time {
|
||||
slots.push((fit.0, a.start_time));
|
||||
if fit.0 != a.start {
|
||||
slots.push((fit.0, a.start));
|
||||
}
|
||||
|
||||
if fit.1 != a.end_time {
|
||||
slots.push((a.end_time, fit.1));
|
||||
if fit.1 != a.end {
|
||||
slots.push((a.end, fit.1));
|
||||
}
|
||||
}
|
||||
|
||||
let slot = slots
|
||||
.into_iter()
|
||||
.find(|s| s.0 >= assignment.start_time && s.1 <= assignment.end_time)
|
||||
.find(|s| s.0 >= assignment.start && s.1 <= assignment.end)
|
||||
.unwrap();
|
||||
|
||||
if slot.0 > common_time.0 {
|
||||
@ -133,7 +130,7 @@ pub async fn post(
|
||||
}
|
||||
|
||||
let context = Some(EventContext {
|
||||
date_in_db: event.date,
|
||||
date_in_db: event.start.date(),
|
||||
common_min_max_available_time: common_time,
|
||||
// safe as max amount of posten can be only 100
|
||||
amount_of_assigned_posten: assignments_for_event
|
||||
@ -152,7 +149,7 @@ pub async fn post(
|
||||
return Ok(HttpResponse::BadRequest().body(e.to_string()));
|
||||
};
|
||||
|
||||
if event.start_time != changeset.time.0 || event.end_time != changeset.time.1 {
|
||||
if event.start != changeset.time.0 || event.end != changeset.time.1 {
|
||||
for a in assignments_for_event {
|
||||
let c = AssignmentChangeset {
|
||||
function: a.function,
|
||||
@ -164,7 +161,7 @@ pub async fn post(
|
||||
|
||||
Event::update(pool.get_ref(), event.id, changeset).await?;
|
||||
|
||||
let url = utils::get_return_url_for_date(&form.date);
|
||||
let url = utils::get_return_url_for_date(&form.from.date());
|
||||
//println!("redirecto to {url}");
|
||||
Ok(HttpResponse::Found()
|
||||
.insert_header((LOCATION, url.clone()))
|
||||
|
@ -1,5 +1,5 @@
|
||||
use actix_web::{http::header::LOCATION, web, HttpResponse, Responder};
|
||||
use chrono::{NaiveDate, NaiveTime};
|
||||
use chrono::NaiveDateTime;
|
||||
use garde::Validate;
|
||||
use serde::Deserialize;
|
||||
use sqlx::PgPool;
|
||||
@ -12,9 +12,8 @@ use crate::{
|
||||
#[derive(Deserialize)]
|
||||
pub struct NewEventForm {
|
||||
name: String,
|
||||
date: NaiveDate,
|
||||
from: NaiveTime,
|
||||
till: NaiveTime,
|
||||
from: NaiveDateTime,
|
||||
till: NaiveDateTime,
|
||||
location: i32,
|
||||
voluntarywachhabender: Option<bool>,
|
||||
voluntaryfuehrungsassistent: Option<bool>,
|
||||
@ -42,7 +41,6 @@ pub async fn post(
|
||||
}
|
||||
|
||||
let changeset = EventChangeset {
|
||||
date: form.date,
|
||||
amount_of_posten: form.amount,
|
||||
clothing: form.clothing.clone(),
|
||||
location_id: form.location,
|
||||
@ -62,7 +60,7 @@ pub async fn post(
|
||||
|
||||
Event::create(pool.get_ref(), changeset).await?;
|
||||
|
||||
let url = utils::get_return_url_for_date(&form.date);
|
||||
let url = utils::get_return_url_for_date(&form.from.date());
|
||||
//println!("redirecto to {url}");
|
||||
Ok(HttpResponse::Found()
|
||||
.insert_header((LOCATION, url.clone()))
|
||||
|
@ -47,7 +47,7 @@ async fn handle_set_event_cancelation_to(
|
||||
Event::update_cancelation(pool.get_ref(), event.id, cancelation_state).await?;
|
||||
}
|
||||
|
||||
let url = utils::get_return_url_for_date(&event.date);
|
||||
let url = utils::get_return_url_for_date(&event.start.date());
|
||||
Ok(HttpResponse::Ok()
|
||||
.insert_header(("HX-LOCATION", url))
|
||||
.finish())
|
||||
|
@ -45,13 +45,16 @@ pub async fn post(
|
||||
return Ok(HttpResponse::NotFound().finish());
|
||||
};
|
||||
|
||||
let existing_assignments_for_vehicle =
|
||||
VehicleAssignement::read_all_by_vehicle_and_date(pool.get_ref(), vehicle.id, event.date)
|
||||
.await?;
|
||||
let existing_assignments_for_vehicle = VehicleAssignement::read_all_by_vehicle_and_date(
|
||||
pool.get_ref(),
|
||||
vehicle.id,
|
||||
event.start.date(),
|
||||
)
|
||||
.await?;
|
||||
let has_start_time_during_event =
|
||||
|a: &VehicleAssignement| a.start_time >= event.start_time && a.start_time <= event.end_time;
|
||||
|a: &VehicleAssignement| a.start >= event.start && a.start <= event.end;
|
||||
let has_end_time_during_event =
|
||||
|a: &VehicleAssignement| a.end_time >= event.start_time && a.end_time <= event.end_time;
|
||||
|a: &VehicleAssignement| a.end >= event.start && a.end <= event.end;
|
||||
|
||||
let availability_already_assigned = existing_assignments_for_vehicle
|
||||
.iter()
|
||||
@ -62,14 +65,8 @@ pub async fn post(
|
||||
.body("Vehicle already assigned to a timely conflicting event."));
|
||||
}
|
||||
|
||||
VehicleAssignement::create(
|
||||
pool.get_ref(),
|
||||
event.id,
|
||||
vehicle.id,
|
||||
event.start_time,
|
||||
event.end_time,
|
||||
)
|
||||
.await?;
|
||||
VehicleAssignement::create(pool.get_ref(), event.id, vehicle.id, event.start, event.end)
|
||||
.await?;
|
||||
|
||||
let (vehicles_assigned, vehicles_available) =
|
||||
generate_vehicles_assigned_and_available(pool.get_ref(), &event).await?;
|
||||
|
@ -1,3 +1,4 @@
|
||||
use chrono::{NaiveDate, NaiveDateTime};
|
||||
use maud::html;
|
||||
|
||||
use crate::models::UserFunction;
|
||||
@ -57,3 +58,19 @@ pub fn show_tree(f: &UserFunction) -> askama::Result<String> {
|
||||
|
||||
Ok(html.into_string())
|
||||
}
|
||||
|
||||
pub fn dt_f(v: &NaiveDateTime) -> askama::Result<String> {
|
||||
Ok(v.format("%F").to_string())
|
||||
}
|
||||
|
||||
pub fn dt_d(v: &NaiveDateTime) -> askama::Result<String> {
|
||||
Ok(v.format("%d.%m.%Y").to_string())
|
||||
}
|
||||
|
||||
pub fn date_d(v: &NaiveDate) -> askama::Result<String> {
|
||||
Ok(v.format("%d.%m.%Y").to_string())
|
||||
}
|
||||
|
||||
pub fn dt_t(v: &NaiveDateTime) -> askama::Result<String> {
|
||||
Ok(v.format("%R").to_string())
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use chrono::{Local, NaiveDateTime, NaiveTime};
|
||||
use chrono::NaiveDateTime;
|
||||
use sqlx::{query, PgPool};
|
||||
|
||||
use super::{assignment_changeset::AssignmentChangeset, Function, Result};
|
||||
@ -7,8 +7,8 @@ pub struct Assignment {
|
||||
pub event_id: i32,
|
||||
pub availabillity_id: i32,
|
||||
pub function: Function,
|
||||
pub start_time: NaiveTime,
|
||||
pub end_time: NaiveTime,
|
||||
pub start: NaiveDateTime,
|
||||
pub end: NaiveDateTime,
|
||||
}
|
||||
|
||||
impl Assignment {
|
||||
@ -18,10 +18,6 @@ impl Assignment {
|
||||
availabillity_id: i32,
|
||||
changeset: AssignmentChangeset,
|
||||
) -> Result<()> {
|
||||
// TODO: refactor
|
||||
let date1 = Local::now();
|
||||
let date2 = Local::now();
|
||||
|
||||
query!(
|
||||
r##"
|
||||
INSERT INTO assignment (eventId, availabillityId, function, startTimestamp, endTimestamp)
|
||||
@ -30,8 +26,8 @@ impl Assignment {
|
||||
event_id,
|
||||
availabillity_id,
|
||||
changeset.function as Function,
|
||||
date1,
|
||||
date2
|
||||
changeset.time.0.and_utc(),
|
||||
changeset.time.1.and_utc()
|
||||
)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
@ -65,9 +61,8 @@ impl Assignment {
|
||||
event_id: r.eventid,
|
||||
availabillity_id: r.availabillityid,
|
||||
function: r.function,
|
||||
// TODO: refactor
|
||||
start_time: r.starttimestamp.time(),
|
||||
end_time: r.endtimestamp.time(),
|
||||
start: r.starttimestamp.naive_utc(),
|
||||
end: r.endtimestamp.naive_utc(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
@ -97,9 +92,8 @@ impl Assignment {
|
||||
event_id: r.eventid,
|
||||
availabillity_id: r.availabillityid,
|
||||
function: r.function,
|
||||
// TODO: refactor
|
||||
start_time: r.starttimestamp.time(),
|
||||
end_time: r.endtimestamp.time(),
|
||||
start: r.starttimestamp.naive_utc(),
|
||||
end: r.endtimestamp.naive_utc(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
@ -134,9 +128,8 @@ impl Assignment {
|
||||
event_id: r.eventid,
|
||||
availabillity_id: r.availabillityid,
|
||||
function: r.function,
|
||||
// TODO: refactor
|
||||
start_time: r.starttimestamp.time(),
|
||||
end_time: r.endtimestamp.time(),
|
||||
start: r.starttimestamp.naive_utc(),
|
||||
end: r.endtimestamp.naive_utc(),
|
||||
});
|
||||
|
||||
Ok(assignemnet)
|
||||
@ -148,11 +141,7 @@ impl Assignment {
|
||||
availabillity_id: i32,
|
||||
changeset: AssignmentChangeset,
|
||||
) -> Result<()> {
|
||||
// TODO: refactor
|
||||
let date1 = Local::now();
|
||||
let date2 = Local::now();
|
||||
|
||||
query!("UPDATE assignment SET function = $1, startTimestamp = $2, endTimestamp = $3 WHERE eventId = $4 AND availabillityId = $5;", changeset.function as Function, date1, date2, event_id, availabillity_id).execute(pool).await?;
|
||||
query!("UPDATE assignment SET function = $1, startTimestamp = $2, endTimestamp = $3 WHERE eventId = $4 AND availabillityId = $5;", changeset.function as Function, changeset.time.0.and_utc(), changeset.time.1.and_utc(), event_id, availabillity_id).execute(pool).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use chrono::NaiveTime;
|
||||
use chrono::NaiveDateTime;
|
||||
use garde::Validate;
|
||||
|
||||
use super::{
|
||||
start_time_lies_before_end_time, Assignment, Availability, Event, Function, UserFunction,
|
||||
start_date_time_lies_before_end_date_time, Assignment, Availability, Event, Function, UserFunction,
|
||||
};
|
||||
|
||||
#[derive(Validate)]
|
||||
@ -17,10 +17,10 @@ pub struct AssignmentChangeset {
|
||||
pub function: Function,
|
||||
#[garde(
|
||||
custom(available_time_fits),
|
||||
custom(start_time_lies_before_end_time),
|
||||
custom(start_date_time_lies_before_end_date_time),
|
||||
custom(availabillity_not_already_assigned)
|
||||
)]
|
||||
pub time: (NaiveTime, NaiveTime),
|
||||
pub time: (NaiveDateTime, NaiveDateTime),
|
||||
}
|
||||
|
||||
pub struct AssignmentContext {
|
||||
@ -32,16 +32,14 @@ pub struct AssignmentContext {
|
||||
}
|
||||
|
||||
fn available_time_fits(
|
||||
value: &(NaiveTime, NaiveTime),
|
||||
value: &(NaiveDateTime, NaiveDateTime),
|
||||
context: &AssignmentContext,
|
||||
) -> garde::Result {
|
||||
// if let AvailabilityTime::Temporarily(start, end) = context.availabillity.time {
|
||||
// if value.0 < start || value.1 > end {
|
||||
// return Err(garde::Error::new(
|
||||
// "time not made available can't be assigned",
|
||||
// ));
|
||||
// }
|
||||
// }
|
||||
if value.0 < context.availabillity.start || value.1 > context.availabillity.end {
|
||||
return Err(garde::Error::new(
|
||||
"time not made available can't be assigned",
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -89,7 +87,7 @@ fn event_has_free_slot_for_function(
|
||||
}
|
||||
|
||||
fn availabillity_not_already_assigned(
|
||||
value: &(NaiveTime, NaiveTime),
|
||||
value: &(NaiveDateTime, NaiveDateTime),
|
||||
context: &AssignmentContext,
|
||||
) -> garde::Result {
|
||||
let list: Vec<&Assignment> = context
|
||||
@ -101,9 +99,8 @@ fn availabillity_not_already_assigned(
|
||||
.collect();
|
||||
|
||||
let has_start_time_during_assignment =
|
||||
|a: &Assignment| a.start_time >= value.0 && a.start_time <= value.1;
|
||||
let has_end_time_during_assignment =
|
||||
|a: &Assignment| a.end_time >= value.0 && a.end_time <= value.1;
|
||||
|a: &Assignment| a.start >= value.0 && a.start <= value.1;
|
||||
let has_end_time_during_assignment = |a: &Assignment| a.end >= value.0 && a.end <= value.1;
|
||||
|
||||
if list
|
||||
.iter()
|
||||
|
@ -3,7 +3,7 @@ use garde::Validate;
|
||||
|
||||
use crate::{END_OF_DAY, START_OF_DAY};
|
||||
|
||||
use super::{start_date_time_lies_before_end_time, Availability};
|
||||
use super::{start_date_time_lies_before_end_date_time, Availability};
|
||||
|
||||
#[derive(Validate)]
|
||||
#[garde(allow_unvalidated)]
|
||||
@ -11,7 +11,7 @@ use super::{start_date_time_lies_before_end_time, Availability};
|
||||
pub struct AvailabilityChangeset {
|
||||
#[garde(
|
||||
custom(time_is_not_already_made_available),
|
||||
custom(start_date_time_lies_before_end_time)
|
||||
custom(start_date_time_lies_before_end_date_time)
|
||||
)]
|
||||
pub time: (NaiveDateTime, NaiveDateTime),
|
||||
pub comment: Option<String>,
|
||||
|
@ -1,4 +1,4 @@
|
||||
use chrono::{Local, NaiveDate, NaiveDateTime, NaiveTime};
|
||||
use chrono::{NaiveDate, NaiveDateTime};
|
||||
use sqlx::{query, PgPool};
|
||||
|
||||
use super::{Area, AvailabilityChangeset, Result, Role, User, UserFunction};
|
||||
|
@ -1,4 +1,4 @@
|
||||
use chrono::{Local, NaiveDate, NaiveTime};
|
||||
use chrono::{NaiveDate, NaiveDateTime};
|
||||
use sqlx::{query, PgPool};
|
||||
|
||||
use super::{event_changeset::EventChangeset, Location, Result};
|
||||
@ -6,9 +6,8 @@ use super::{event_changeset::EventChangeset, Location, Result};
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Event {
|
||||
pub id: i32,
|
||||
pub date: NaiveDate,
|
||||
pub start_time: NaiveTime,
|
||||
pub end_time: NaiveTime,
|
||||
pub start: NaiveDateTime,
|
||||
pub end: NaiveDateTime,
|
||||
pub name: String,
|
||||
pub location_id: i32,
|
||||
pub location: Option<Location>,
|
||||
@ -22,15 +21,11 @@ pub struct Event {
|
||||
|
||||
impl Event {
|
||||
pub async fn create(pool: &PgPool, changeset: EventChangeset) -> Result<()> {
|
||||
// TODO: refactor
|
||||
let date1 = Local::now();
|
||||
let date2 = Local::now();
|
||||
|
||||
query!(r#"
|
||||
INSERT INTO event (startTimestamp, endTimestamp, name, locationId, voluntaryWachhabender, voluntaryFuehrungsassistent, amountOfPosten, clothing, note)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9);
|
||||
"#,
|
||||
date1, date2, changeset.name, changeset.location_id, changeset.voluntary_wachhabender, changeset.voluntary_fuehrungsassistent, changeset.amount_of_posten, changeset.clothing, changeset.note).execute(pool).await?;
|
||||
changeset.time.0.and_utc(), changeset.time.1.and_utc(), changeset.name, changeset.location_id, changeset.voluntary_wachhabender, changeset.voluntary_fuehrungsassistent, changeset.amount_of_posten, changeset.clothing, changeset.note).execute(pool).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -73,9 +68,8 @@ impl Event {
|
||||
.into_iter()
|
||||
.map(|record| Event {
|
||||
id: record.eventid,
|
||||
date: record.starttimestamp.date_naive(),
|
||||
start_time: record.starttimestamp.time(),
|
||||
end_time: record.endtimestamp.time(),
|
||||
start: record.starttimestamp.naive_utc(),
|
||||
end: record.endtimestamp.naive_utc(),
|
||||
name: record.name.to_string(),
|
||||
location_id: record.locationid,
|
||||
location: Some(Location {
|
||||
@ -125,9 +119,8 @@ impl Event {
|
||||
|
||||
let event = record.map(|record| Event {
|
||||
id: record.eventid,
|
||||
date: record.starttimestamp.date_naive(),
|
||||
start_time: record.starttimestamp.time(),
|
||||
end_time: record.endtimestamp.time(),
|
||||
start: record.starttimestamp.naive_utc(),
|
||||
end: record.endtimestamp.naive_utc(),
|
||||
name: record.name.to_string(),
|
||||
location_id: record.locationid,
|
||||
location: Some(Location {
|
||||
@ -148,16 +141,18 @@ impl Event {
|
||||
}
|
||||
|
||||
pub async fn update(pool: &PgPool, id: i32, changeset: EventChangeset) -> Result<()> {
|
||||
// TODO: refactor
|
||||
let date1 = Local::now();
|
||||
let date2 = Local::now();
|
||||
|
||||
query!(r#"
|
||||
UPDATE event SET startTimestamp = $1, endTimestamp = $2, name = $3, locationId = $4, voluntaryWachhabender = $5, voluntaryFuehrungsassistent = $6, amountOfPosten = $7, clothing = $8, note = $9 WHERE id = $10;
|
||||
"#,
|
||||
date1,
|
||||
date2
|
||||
,changeset.name, changeset.location_id, changeset.voluntary_wachhabender, changeset.voluntary_fuehrungsassistent, changeset.amount_of_posten, changeset.clothing, changeset.note, id)
|
||||
changeset.time.0.and_utc(),
|
||||
changeset.time.1.and_utc(),
|
||||
changeset.name,
|
||||
changeset.location_id,
|
||||
changeset.voluntary_wachhabender,
|
||||
changeset.voluntary_fuehrungsassistent,
|
||||
changeset.amount_of_posten,
|
||||
changeset.clothing,
|
||||
changeset.note, id)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
|
@ -1,22 +1,21 @@
|
||||
use chrono::NaiveDate;
|
||||
use chrono::NaiveTime;
|
||||
use chrono::NaiveDateTime;
|
||||
#[cfg(test)]
|
||||
use fake::{Faker, Fake};
|
||||
use fake::{Fake, Faker};
|
||||
use garde::Validate;
|
||||
|
||||
use super::start_time_lies_before_end_time;
|
||||
use super::start_date_time_lies_before_end_date_time;
|
||||
|
||||
#[derive(Validate)]
|
||||
#[garde(allow_unvalidated)]
|
||||
#[garde(context(Option<EventContext> as ctx))]
|
||||
pub struct EventChangeset {
|
||||
#[garde(custom(date_unchanged_if_edit))]
|
||||
pub date: NaiveDate,
|
||||
#[garde(
|
||||
custom(start_time_lies_before_end_time),
|
||||
custom(time_can_be_extended_if_edit)
|
||||
custom(start_date_time_lies_before_end_date_time),
|
||||
custom(time_can_be_extended_if_edit),
|
||||
custom(date_unchanged_if_edit)
|
||||
)]
|
||||
pub time: (NaiveTime, NaiveTime),
|
||||
pub time: (NaiveDateTime, NaiveDateTime),
|
||||
pub name: String,
|
||||
/// check before: must exist and user can create event for this location
|
||||
pub location_id: i32,
|
||||
@ -32,9 +31,8 @@ pub struct EventChangeset {
|
||||
|
||||
#[cfg(test)]
|
||||
impl EventChangeset {
|
||||
pub fn create_for_test(date: NaiveDate, start: NaiveTime, end: NaiveTime) -> EventChangeset {
|
||||
pub fn create_for_test(start: NaiveDateTime, end: NaiveDateTime) -> EventChangeset {
|
||||
let changeset = EventChangeset {
|
||||
date,
|
||||
time: (start, end),
|
||||
name: Faker.fake(),
|
||||
location_id: 1,
|
||||
@ -51,14 +49,14 @@ impl EventChangeset {
|
||||
|
||||
pub struct EventContext {
|
||||
pub date_in_db: NaiveDate,
|
||||
pub common_min_max_available_time: (NaiveTime, NaiveTime),
|
||||
pub common_min_max_available_time: (NaiveDateTime, NaiveDateTime),
|
||||
pub wachhabender_assigned: bool,
|
||||
pub fuehrungsassistent_assigned: bool,
|
||||
pub amount_of_assigned_posten: i16,
|
||||
}
|
||||
|
||||
fn date_unchanged_if_edit(value: &NaiveDate, context: &Option<EventContext>) -> garde::Result {
|
||||
if context.as_ref().is_some_and(|c| c.date_in_db != *value) {
|
||||
fn date_unchanged_if_edit(value: &(NaiveDateTime, NaiveDateTime), context: &Option<EventContext>) -> garde::Result {
|
||||
if context.as_ref().is_some_and(|c| c.date_in_db != value.0.date() ) {
|
||||
return Err(garde::Error::new("event date can't be changed"));
|
||||
}
|
||||
|
||||
@ -66,7 +64,7 @@ fn date_unchanged_if_edit(value: &NaiveDate, context: &Option<EventContext>) ->
|
||||
}
|
||||
|
||||
fn time_can_be_extended_if_edit(
|
||||
value: &(NaiveTime, NaiveTime),
|
||||
value: &(NaiveDateTime, NaiveDateTime),
|
||||
context: &Option<EventContext>,
|
||||
) -> garde::Result {
|
||||
if let Some(context) = context {
|
||||
|
@ -25,7 +25,7 @@ pub use availability_changeset::{
|
||||
};
|
||||
pub use availabillity::Availability;
|
||||
pub use availabillity_assignment_state::AvailabillityAssignmentState;
|
||||
use chrono::{NaiveDateTime, NaiveTime};
|
||||
use chrono::NaiveDateTime;
|
||||
pub use event::Event;
|
||||
pub use event_changeset::{EventChangeset, EventContext};
|
||||
pub use function::Function;
|
||||
@ -41,18 +41,7 @@ pub use vehicle_assignement::VehicleAssignement;
|
||||
|
||||
type Result<T> = std::result::Result<T, sqlx::Error>;
|
||||
|
||||
fn start_time_lies_before_end_time<T>(
|
||||
value: &(NaiveTime, NaiveTime),
|
||||
_context: &T,
|
||||
) -> garde::Result {
|
||||
if value.0 >= value.1 {
|
||||
return Err(garde::Error::new("endtime can't lie before starttime"));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn start_date_time_lies_before_end_time<T>(
|
||||
fn start_date_time_lies_before_end_date_time<T>(
|
||||
value: &(NaiveDateTime, NaiveDateTime),
|
||||
_context: &T,
|
||||
) -> garde::Result {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use chrono::{Local, NaiveDate, NaiveTime};
|
||||
use chrono::{NaiveDate, NaiveDateTime};
|
||||
use sqlx::{query, PgPool};
|
||||
|
||||
use super::Result;
|
||||
@ -6,8 +6,8 @@ use super::Result;
|
||||
pub struct VehicleAssignement {
|
||||
pub event_id: i32,
|
||||
pub vehicle_id: i32,
|
||||
pub start_time: NaiveTime,
|
||||
pub end_time: NaiveTime,
|
||||
pub start: NaiveDateTime,
|
||||
pub end: NaiveDateTime,
|
||||
}
|
||||
|
||||
impl VehicleAssignement {
|
||||
@ -15,19 +15,15 @@ impl VehicleAssignement {
|
||||
pool: &PgPool,
|
||||
event_id: i32,
|
||||
vehicle_id: i32,
|
||||
start_time: NaiveTime,
|
||||
end_time: NaiveTime,
|
||||
start: NaiveDateTime,
|
||||
end: NaiveDateTime,
|
||||
) -> Result<()> {
|
||||
// TODO: refactor
|
||||
let date1 = Local::now();
|
||||
let date2 = Local::now();
|
||||
|
||||
query!(
|
||||
"INSERT INTO vehicleassignement (eventId, vehicleId, startTimestamp, endTimestamp) VALUES ($1, $2, $3, $4);",
|
||||
event_id,
|
||||
vehicle_id,
|
||||
date1,
|
||||
date2
|
||||
start.and_utc(),
|
||||
end.and_utc()
|
||||
)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
@ -43,12 +39,11 @@ impl VehicleAssignement {
|
||||
let record = query!("SELECT * FROM vehicleAssignement WHERE vehicleAssignement.eventId = $1 AND vehicleAssignement.vehicleId = $2;", event_id, vehicle_id).fetch_optional(pool)
|
||||
.await?;
|
||||
|
||||
// TODO: refactor
|
||||
let vehicle_assignment = record.map(|r| VehicleAssignement {
|
||||
event_id: r.eventid,
|
||||
vehicle_id: r.vehicleid,
|
||||
start_time: r.starttimestamp.time(),
|
||||
end_time: r.endtimestamp.time(),
|
||||
event_id: r.eventid,
|
||||
vehicle_id: r.vehicleid,
|
||||
start: r.starttimestamp.naive_utc(),
|
||||
end: r.endtimestamp.naive_utc(),
|
||||
});
|
||||
|
||||
Ok(vehicle_assignment)
|
||||
@ -65,14 +60,13 @@ impl VehicleAssignement {
|
||||
.fetch_all(pool)
|
||||
.await?;
|
||||
|
||||
// TODO: refactor
|
||||
let vehicle_assignments = records
|
||||
.iter()
|
||||
.map(|r| VehicleAssignement {
|
||||
event_id: r.eventid,
|
||||
vehicle_id: r.vehicleid,
|
||||
start_time: r.starttimestamp.time(),
|
||||
end_time: r.endtimestamp.time(),
|
||||
start: r.starttimestamp.naive_utc(),
|
||||
end: r.endtimestamp.naive_utc(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
@ -82,7 +76,7 @@ impl VehicleAssignement {
|
||||
pub async fn read_all_by_vehicle_and_date(
|
||||
pool: &PgPool,
|
||||
vehicle_id: i32,
|
||||
date: NaiveDate
|
||||
date: NaiveDate,
|
||||
) -> Result<Vec<VehicleAssignement>> {
|
||||
let records = query!(
|
||||
r#"
|
||||
@ -109,8 +103,8 @@ impl VehicleAssignement {
|
||||
.map(|r| VehicleAssignement {
|
||||
event_id: r.eventid,
|
||||
vehicle_id: r.vehicleid,
|
||||
start_time: r.starttimestamp.time(),
|
||||
end_time: r.endtimestamp.time(),
|
||||
start: r.starttimestamp.naive_utc(),
|
||||
end: r.endtimestamp.naive_utc(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -13,8 +13,8 @@ pub async fn generate_availabillity_assignment_list(
|
||||
) -> Result<Vec<(Availability, AvailabillityAssignmentState)>, ApplicationError> {
|
||||
let availabillities_in_db = Availability::read_by_date_time_area_including_user(
|
||||
pool,
|
||||
event.date,
|
||||
(event.start_time, event.end_time),
|
||||
event.start.date(),
|
||||
(event.start, event.end),
|
||||
event.location.as_ref().unwrap().area_id,
|
||||
)
|
||||
.await?;
|
||||
@ -46,9 +46,8 @@ pub async fn generate_availabillity_assignment_list(
|
||||
}
|
||||
|
||||
let has_start_time_during_event =
|
||||
|a: &Assignment| a.start_time >= event.start_time && a.start_time <= event.end_time;
|
||||
let has_end_time_during_event =
|
||||
|a: &Assignment| a.end_time >= event.start_time && a.end_time <= event.end_time;
|
||||
|a: &Assignment| a.start >= event.start && a.start <= event.end;
|
||||
let has_end_time_during_event = |a: &Assignment| a.end >= event.start && a.end <= event.end;
|
||||
|
||||
if assignments
|
||||
.iter()
|
||||
|
@ -8,11 +8,9 @@
|
||||
<h1 class="title">Event '{{ event.name }}' bearbeiten</h1>
|
||||
{% else %}
|
||||
<form method="post" action="/events/new">
|
||||
<h1 class="title">Neues Event anlegen für den {{ date.format("%d.%m.%Y") }}</h1>
|
||||
<h1 class="title">Neues Event anlegen für den {{ date|date_d }}</h1>
|
||||
{% endif %}
|
||||
|
||||
<input type="hidden" name="date" value="{{ date }}">
|
||||
|
||||
{% if let Some(event) = event %}
|
||||
<div class="field is-horizontal">
|
||||
<div class="field-label"></div>
|
||||
@ -20,7 +18,7 @@
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<button class="button is-warning" type="button"
|
||||
hx-put="/events/{{ event.id }}/{% if event.canceled %}uncancel{% else %}cancel{% endif %}">
|
||||
hx-put="/events/{{ event.id }}/{% if event.canceled %}uncancel{% else %}cancel{% endif %}">
|
||||
<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#alert-circle" />
|
||||
</svg>
|
||||
@ -32,8 +30,9 @@
|
||||
<div class="control">
|
||||
{% let delete_disabled = amount_of_planned_posten > 0 || is_wachhabender_planned ||
|
||||
is_fuehrungsassistent_planned %}
|
||||
<button class="button is-danger" type="button" hx-delete="/events/{{ event.id }}" {{
|
||||
delete_disabled|cond_show("disabled") }} hx-trigger="confirmed">
|
||||
<button class="button is-danger" type="button"
|
||||
hx-delete="/events/{{ event.id }}" {{ delete_disabled|cond_show("disabled") }}
|
||||
hx-trigger="confirmed">
|
||||
<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#x-circle" />
|
||||
</svg>
|
||||
@ -59,8 +58,9 @@
|
||||
<div class="field-body">
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input class="input" name="name" placeholder="Wave Gotik Treffen" required {% if let Some(event)=event
|
||||
%} value="{{ event.name }}" {% endif %} {{ disabled|cond_show("disabled") }} />
|
||||
<input class="input" name="name" placeholder="Wave Gotik Treffen" required
|
||||
{% if let Some(event)=event %} value="{{ event.name }}" {% endif %}
|
||||
{{ disabled|cond_show("disabled") }} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -71,14 +71,17 @@
|
||||
<label class="label">Startzeit - Endzeit</label>
|
||||
</div>
|
||||
<div class="field-body">
|
||||
{% let f = "%H:%M" %}
|
||||
<div class="field">
|
||||
<input class="input" type="time" id="from" name="from" required value="{% if let Some(event)=event
|
||||
%}{{ event.start_time.format(f) }}{% else %}00:00{% endif %}" {{ disabled|cond_show("disabled") }} />
|
||||
<input class="input" type="datetime-local" id="from" name="from" required
|
||||
value="{% if let Some(event)=event %}{{ event.start|dt_f }}{% else %}{{ date }}{% endif
|
||||
%}"
|
||||
{{ disabled|cond_show("disabled") }} min="{{ date }}T00:00" max="{{ date }}T23:59" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<input class="input" type="time" id="till" name="till" required value="{% if let Some(event)=event
|
||||
%}{{ event.end_time.format(f) }}{% else %}23:59{% endif %}" {{ disabled|cond_show("disabled") }} />
|
||||
<input class="input" type="datetime-local" id="till" name="till" required
|
||||
value="{% if let Some(event)=event %}{{ event.end|dt_f }}{% else %}{{ date }}{% endif %}"
|
||||
{{ disabled|cond_show("disabled") }} min="{{ date }}T00:00"
|
||||
max="{{ date.checked_add_days(Days::new(1)).unwrap() }}T23:59" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -94,7 +97,8 @@
|
||||
<select name="location" required {{ disabled|cond_show("disabled") }}>
|
||||
{% for location in locations %}
|
||||
<option value="{{ location.id }}" {% if let Some(event)=event %}{{
|
||||
(event.location_id==location.id)|cond_show("selected") }}{% endif %}>{{ location.name }}{% if
|
||||
(event.location_id==location.id)|cond_show("selected") }}{% endif %}>{{ location.name }}{%
|
||||
if
|
||||
user.role == Role::Admin %} - ({{
|
||||
location.area.as_ref().unwrap().name }}){% endif %}
|
||||
</option>
|
||||
@ -116,9 +120,10 @@
|
||||
<div class="control">
|
||||
<label class="checkbox">
|
||||
<input class="checkbox" type="checkbox" name="voluntarywachhabender" value="true" {{
|
||||
wh_disabled|cond_show("disabled")}} {% if let Some(event)=event %} {{
|
||||
event.voluntary_wachhabender|cond_show("checked") }} {% endif %} {{ disabled|cond_show("disabled")
|
||||
}}>
|
||||
wh_disabled|cond_show("disabled")}} {% if let Some(event)=event %} {{
|
||||
event.voluntary_wachhabender|cond_show("checked") }} {% endif %} {{
|
||||
disabled|cond_show("disabled")
|
||||
}}>
|
||||
</label>
|
||||
</div>
|
||||
{% if wh_disabled %}
|
||||
@ -140,9 +145,9 @@
|
||||
<div class="control">
|
||||
<label class="checkbox">
|
||||
<input class="checkbox" type="checkbox" name="voluntaryfuehrungsassistent" value="true" {{
|
||||
fa_disabled|cond_show("disabled") }} {% if let Some(event)=event %} {{
|
||||
event.voluntary_fuehrungsassistent|cond_show("checked") }} {% endif %} {{
|
||||
disabled|cond_show("disabled") }}>
|
||||
fa_disabled|cond_show("disabled") }} {% if let Some(event)=event %} {{
|
||||
event.voluntary_fuehrungsassistent|cond_show("checked") }} {% endif %} {{
|
||||
disabled|cond_show("disabled") }}>
|
||||
</label>
|
||||
</div>
|
||||
{% if fa_disabled %}
|
||||
@ -163,9 +168,10 @@
|
||||
{% let posten_planned = event.is_some() && amount_of_planned_posten > 0 %}
|
||||
<div class="control">
|
||||
<input class="input" type="number" name="amount"
|
||||
min="{% if posten_planned %}{{ amount_of_planned_posten }}{% else %}0{% endif %}" max="100" required
|
||||
{% if let Some(event)=event %} value="{{ event.amount_of_posten }}" {% endif %} {{
|
||||
disabled|cond_show("disabled") }} />
|
||||
min="{% if posten_planned %}{{ amount_of_planned_posten }}{% else %}0{% endif %}" max="100"
|
||||
required
|
||||
{% if let Some(event)=event %} value="{{ event.amount_of_posten }}" {% endif %} {{
|
||||
disabled|cond_show("disabled") }} />
|
||||
</div>
|
||||
{% if posten_planned %}
|
||||
<p class="help">
|
||||
@ -186,7 +192,7 @@
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input class="input" name="clothing" placeholder="Tuchuniform" required {% if let Some(event)=event %}
|
||||
value="{{ event.clothing }}" {% endif %} {{ disabled|cond_show("disabled") }} />
|
||||
value="{{ event.clothing }}" {% endif %} {{ disabled|cond_show("disabled") }} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -200,7 +206,7 @@
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input class="input" name="note" {% if let Some(event)=event %} {{ event.note|insert_value }} {% endif
|
||||
%} {{ disabled|cond_show("disabled") }} />
|
||||
%} {{ disabled|cond_show("disabled") }} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -15,11 +15,11 @@
|
||||
</div>
|
||||
|
||||
<div class="cell">
|
||||
<p><b>Datum:</b> {{ event.date.format("%d.%m.%Y") }}</p>
|
||||
<p><b>Datum:</b> {{ event.start.format("%d.%m.%Y") }}</p>
|
||||
</div>
|
||||
|
||||
<div class="cell">
|
||||
<p><b>Uhrzeit:</b> {{ event.start_time.format("%R") }} Uhr - {{ event.end_time.format("%R") }} Uhr</p>
|
||||
<p><b>Uhrzeit:</b> {{ event.start.format("%R") }} Uhr - {{ event.end.format("%d.%m.%Y %R") }} Uhr</p>
|
||||
</div>
|
||||
|
||||
<div class="cell is-col-span-2">
|
||||
@ -62,7 +62,7 @@
|
||||
</div>
|
||||
|
||||
<div class="control">
|
||||
<a class="button is-link is-light" hx-boost="true" href="/?date={{ event.date }}">
|
||||
<a class="button is-link is-light" hx-boost="true" href="/?date={{ event.start.date() }}">
|
||||
<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#arrow-left" />
|
||||
</svg>
|
||||
|
@ -106,7 +106,7 @@
|
||||
{% endif %}
|
||||
|
||||
<div class="cell">
|
||||
<p><b>Uhrzeit:</b> {{ event.start_time.format("%R") }} Uhr - {{ event.end_time.format("%R") }} Uhr</p>
|
||||
<p><b>Uhrzeit:</b> {{ event.start|dt_t }} Uhr - {{ event.end|dt_f }} Uhr</p>
|
||||
</div>
|
||||
|
||||
<div class="cell">
|
||||
|
Loading…
x
Reference in New Issue
Block a user