brass/web/src/models/assignment_changeset.rs

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