refactor: WIP datetime event and assignments

This commit is contained in:
Max Hohlfeld 2025-05-04 21:35:26 +02:00
parent 93e6a79a38
commit 8b61bb37a8
23 changed files with 187 additions and 207 deletions

View File

@ -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(())
}

View File

@ -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?;

View File

@ -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}")]

View File

@ -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())

View File

@ -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,

View File

@ -1,3 +1,4 @@
use chrono::Days;
use crate::filters;
use chrono::NaiveDate;
use askama::Template;

View File

@ -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()))

View File

@ -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()))

View File

@ -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())

View File

@ -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?;

View File

@ -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())
}

View File

@ -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(())
}

View File

@ -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()

View File

@ -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>,

View File

@ -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};

View File

@ -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?;

View File

@ -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 {

View File

@ -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 {

View File

@ -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();

View File

@ -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()

View File

@ -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>

View File

@ -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>

View File

@ -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">