use actix_web::{http::header::LOCATION, web, HttpResponse, Responder}; use chrono::{NaiveDate, NaiveTime}; use garde::Validate; use serde::Deserialize; use sqlx::PgPool; use crate::{ endpoints::IdPath, models::{ Assignment, AssignmentChangeset, Availabillity, Event, EventChangeset, EventContext, Function, Location, Role, User, }, utils::{self, ApplicationError}, }; #[derive(Deserialize)] pub struct EditEventForm { name: String, date: NaiveDate, from: NaiveTime, till: NaiveTime, location: i32, voluntarywachhabender: Option, voluntaryfuehrungsassistent: Option, amount: i16, clothing: String, note: Option, } #[actix_web::post("/events/{id}/edit")] pub async fn post( user: web::ReqData, pool: web::Data, form: web::Form, path: web::Path, ) -> Result { if user.role != Role::Admin && user.role != Role::AreaManager { return Err(ApplicationError::Unauthorized); } let Some(event) = Event::read_by_id_including_location(pool.get_ref(), path.id).await? else { return Ok(HttpResponse::NotFound().finish()); }; if event.location_id != form.location { let Some(location) = Location::read_by_id(pool.get_ref(), form.location).await? else { return Ok(HttpResponse::BadRequest().body("Location does not exist")); }; if user.role != Role::Admin && user.area_id != location.area_id { return Ok(HttpResponse::BadRequest().body("Can't use location outside of your area")); } if event.location.as_ref().unwrap().area_id != location.area_id { return Ok(HttpResponse::BadRequest() .body("Can't change to a location outside of previous location area")); } } let changeset = EventChangeset { date: form.date, amount_of_posten: form.amount, clothing: form.clothing.clone(), location_id: form.location, time: (form.from, form.till), name: form.name.clone(), note: form .note .clone() .and_then(|n| if n.len() != 0 { Some(n) } else { None }), voluntary_wachhabender: form.voluntarywachhabender.unwrap_or(false), voluntary_fuehrungsassistent: form.voluntaryfuehrungsassistent.unwrap_or(false), }; let assignments_for_event = Assignment::read_all_by_event(pool.get_ref(), event.id).await?; let mut common_time = ( NaiveTime::parse_from_str("00:00", "%R").unwrap(), NaiveTime::parse_from_str("23:59", "%R").unwrap(), ); for assignment in &assignments_for_event { let availability = Availabillity::read_by_id(pool.get_ref(), assignment.availabillity_id) .await? .unwrap(); let all_assignments = Assignment::read_all_by_availabillity(pool.get_ref(), assignment.availabillity_id) .await?; if all_assignments.len() == 1 { if availability.start_time.is_some() && availability.end_time.is_some() { let start = availability.start_time.unwrap(); let end = availability.end_time.unwrap(); if start > common_time.0 { common_time.0 = start; } if end < common_time.1 { common_time.1 = end; } } } else { let mut slots = if availability.start_time.is_some() && availability.end_time.is_some() { vec![( availability.start_time.as_ref().unwrap().clone(), availability.end_time.as_ref().unwrap().clone(), )] } else { vec![( NaiveTime::parse_from_str("00:00", "%R").unwrap(), NaiveTime::parse_from_str("23:59", "%R").unwrap(), )] }; for a in all_assignments .iter() .filter(|x| x.event_id != assignment.event_id) { let (fit, rest) = slots .into_iter() .partition(|s| s.0 >= a.start_time && s.1 <= a.end_time); slots = rest; let fit = fit.first().unwrap(); if fit.0 != a.start_time { slots.push((fit.0, a.start_time)); } if fit.1 != a.end_time { slots.push((a.end_time, fit.1)); } } let slot = slots .into_iter() .find(|s| s.0 >= assignment.start_time && s.1 <= assignment.end_time) .unwrap(); if slot.0 > common_time.0 { common_time.0 = slot.0; } if slot.1 < common_time.1 { common_time.1 = slot.1; } } } let context = Some(EventContext { date_in_db: event.date, common_min_max_available_time: common_time, // safe as max amount of posten can be only 100 amount_of_assigned_posten: assignments_for_event .iter() .filter(|a| a.function == Function::Posten) .count() as i16, wachhabender_assigned: assignments_for_event .iter() .any(|a| a.function == Function::Wachhabender), fuehrungsassistent_assigned: assignments_for_event .iter() .any(|a| a.function == Function::Fuehrungsassistent), }); if let Err(e) = changeset.validate_with(&context) { return Ok(HttpResponse::BadRequest().body(e.to_string())); }; if event.start_time != changeset.time.0 || event.end_time != changeset.time.1 { for a in assignments_for_event { let c = AssignmentChangeset { function: a.function, time: changeset.time.clone(), }; Assignment::update(pool.get_ref(), a.event_id, a.availabillity_id, c).await?; } } Event::update(pool.get_ref(), event.id, changeset).await?; let url = utils::get_return_url_for_date(&form.date); println!("redirecto to {url}"); Ok(HttpResponse::Found() .insert_header((LOCATION, url.clone())) .insert_header(("HX-LOCATION", url)) .finish()) }