119 lines
3.3 KiB
Rust
119 lines
3.3 KiB
Rust
use chrono::NaiveTime;
|
|
use garde::Validate;
|
|
|
|
use super::{
|
|
start_time_lies_before_end_time, Assignment, Availability, AvailabilityTime, Event, Function,
|
|
};
|
|
|
|
#[derive(Validate)]
|
|
#[garde(allow_unvalidated)]
|
|
#[garde(context(AssignmentContext as ctx))]
|
|
/// check before: event and availabillity and must exist and user of availabillity is in event location
|
|
pub struct AssignmentChangeset {
|
|
#[garde(
|
|
custom(user_of_availability_has_function),
|
|
custom(event_has_free_slot_for_function)
|
|
)]
|
|
pub function: Function,
|
|
#[garde(
|
|
custom(available_time_fits),
|
|
custom(start_time_lies_before_end_time),
|
|
custom(availabillity_not_already_assigned)
|
|
)]
|
|
pub time: (NaiveTime, NaiveTime),
|
|
}
|
|
|
|
pub struct AssignmentContext {
|
|
pub event: Event,
|
|
pub availabillity: Availability,
|
|
pub user_function: Function,
|
|
pub assignments_for_event: Vec<Assignment>,
|
|
pub assignments_for_availabillity: Vec<Assignment>,
|
|
}
|
|
|
|
fn available_time_fits(
|
|
value: &(NaiveTime, NaiveTime),
|
|
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",
|
|
));
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn user_of_availability_has_function(
|
|
value: &Function,
|
|
context: &AssignmentContext,
|
|
) -> garde::Result {
|
|
if *value > context.user_function {
|
|
return Err(garde::Error::new(
|
|
"user has not the required function for this assignment",
|
|
));
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn event_has_free_slot_for_function(
|
|
_value: &Function,
|
|
context: &AssignmentContext,
|
|
) -> garde::Result {
|
|
let list: Vec<&Assignment> = context
|
|
.assignments_for_event
|
|
.iter()
|
|
.filter(|a| {
|
|
a.availabillity_id != context.availabillity.id && a.event_id != context.event.id
|
|
})
|
|
.collect();
|
|
|
|
let a = list
|
|
.iter()
|
|
.filter(|a| a.function == Function::Posten)
|
|
.count();
|
|
if match context.user_function {
|
|
Function::Posten => a >= context.event.amount_of_posten as usize,
|
|
Function::Fuehrungsassistent => context.event.voluntary_fuehrungsassistent && a >= 1,
|
|
Function::Wachhabender => context.event.voluntary_wachhabender && a >= 1,
|
|
} {
|
|
return Err(garde::Error::new(
|
|
"event already has enough assignments for this function",
|
|
));
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn availabillity_not_already_assigned(
|
|
value: &(NaiveTime, NaiveTime),
|
|
context: &AssignmentContext,
|
|
) -> garde::Result {
|
|
let list: Vec<&Assignment> = context
|
|
.assignments_for_availabillity
|
|
.iter()
|
|
.filter(|a| {
|
|
a.availabillity_id != context.availabillity.id && a.event_id != context.event.id
|
|
})
|
|
.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;
|
|
|
|
if list
|
|
.iter()
|
|
.any(|a| has_start_time_during_assignment(a) || has_end_time_during_assignment(a))
|
|
{
|
|
return Err(garde::Error::new(
|
|
"availabillity is already assigned for that time",
|
|
));
|
|
}
|
|
|
|
Ok(())
|
|
}
|