111 lines
3.9 KiB
Rust

use actix_web::{web, HttpResponse, Responder};
use rinja::Template;
use serde::Deserialize;
use sqlx::PgPool;
use crate::{
endpoints::assignment::PlanEventPersonalTablePartialTemplate,
models::{Assignment, Availabillity, Event, Function, Role, User},
utils::{
event_planning_template::{
generate_availabillity_assignment_list, generate_status_whether_staff_is_required,
},
ApplicationError,
},
};
#[derive(Deserialize)]
pub struct AssignmentQuery {
availabillity: i32,
function: u8,
event: i32,
}
#[actix_web::post("/assignments/new")]
pub async fn post(
user: web::ReqData<User>,
pool: web::Data<PgPool>,
query: web::Query<AssignmentQuery>,
) -> Result<impl Responder, ApplicationError> {
let Some(event) = Event::read_by_id_including_location(pool.get_ref(), query.event).await?
else {
return Ok(HttpResponse::NotFound().finish());
};
let user_is_admin_or_area_manager_of_event_area = user.role == Role::Admin
|| (user.role == Role::AreaManager
&& user.area_id == event.location.as_ref().unwrap().area_id);
if !user_is_admin_or_area_manager_of_event_area {
return Err(ApplicationError::Unauthorized);
}
let Some(availability) =
Availabillity::read_by_id_including_user(pool.get_ref(), query.availabillity).await?
else {
return Ok(HttpResponse::NotFound().finish());
};
let availability_user_not_in_event_location_area =
availability.user.as_ref().unwrap().area_id != event.location.as_ref().unwrap().area_id;
let existing_assignments_for_availabillity =
Assignment::read_all_by_availabillity(pool.get_ref(), availability.id).await?;
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;
let availability_already_assigned = existing_assignments_for_availabillity
.iter()
.any(|a| has_start_time_during_event(a) || has_end_time_during_event(a));
let function = Function::try_from(query.function)?;
let user_not_qualified_for_assigned_function =
availability.user.as_ref().unwrap().function < function;
let a = Assignment::count_by_event_and_function(pool.get_ref(), event.id, function).await?;
let event_already_has_enough_assignments_for_function = match function {
Function::Posten => a >= event.amount_of_posten as i64,
Function::Fuehrungsassistent => event.voluntary_fuehrungsassistent && a >= 1,
Function::Wachhabender => event.voluntary_wachhabender && a >= 1,
};
if availability_user_not_in_event_location_area
|| availability_already_assigned
|| user_not_qualified_for_assigned_function
|| event_already_has_enough_assignments_for_function
{
// TODO: Fehlermeldung verbessern
return Ok(HttpResponse::BadRequest().body(format!("{availability_user_not_in_event_location_area} {availability_already_assigned} {user_not_qualified_for_assigned_function} {event_already_has_enough_assignments_for_function}")));
}
Assignment::create(
pool.get_ref(),
event.id,
availability.id,
function,
event.start_time,
event.end_time,
)
.await?;
let availabillities = generate_availabillity_assignment_list(pool.get_ref(), &event).await?;
let (
further_posten_required,
further_fuehrungsassistent_required,
further_wachhabender_required,
) = generate_status_whether_staff_is_required(pool.get_ref(), &event).await?;
let template = PlanEventPersonalTablePartialTemplate {
event,
availabillities,
further_posten_required,
further_fuehrungsassistent_required,
further_wachhabender_required,
};
Ok(HttpResponse::Ok().body(template.render()?))
}