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, pool: web::Data, query: web::Query, ) -> Result { 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()?)) }