use actix_web::{web, HttpResponse, Responder}; use garde::Validate; use serde::Deserialize; use sqlx::PgPool; use crate::{ endpoints::assignment::PlanEventPersonalTablePartialTemplate, models::{ Assignment, AssignmentChangeset, AssignmentContext, Availability, Event, Function, Role, User, }, utils::{ event_planning_template::{ generate_availability_assignment_list, generate_status_whether_staff_is_required, }, ApplicationError, TemplateResponse, }, }; #[derive(Deserialize)] pub struct AssignmentQuery { availability: 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) = Availability::read_by_id_including_user(pool.get_ref(), query.availability).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; if availability_user_not_in_event_location_area { return Ok(HttpResponse::BadRequest() .body("availability user is not in the same area as event location")); } let function = Function::try_from(query.function)?; let changeset = AssignmentChangeset { function, time: (event.start, event.end), }; let assignments_for_event = Assignment::read_all_by_event(pool.get_ref(), event.id).await?; let assignments_for_availability = Assignment::read_all_by_availability(pool.get_ref(), availability.id).await?; let context = AssignmentContext { event: event.clone(), availability: availability.clone(), user_function: availability.user.as_ref().unwrap().function.clone(), assignments_for_event, assignments_for_availability, }; if let Err(e) = changeset.validate_with(&context) { return Ok(HttpResponse::BadRequest().body(e.to_string())); }; Assignment::create(pool.get_ref(), event.id, availability.id, changeset).await?; let availabilities = generate_availability_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, availabilities, further_posten_required, further_fuehrungsassistent_required, further_wachhabender_required, }; Ok(template.to_response()?) }