174 lines
5.8 KiB
Rust
174 lines
5.8 KiB
Rust
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, Availability, 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<bool>,
|
|
voluntaryfuehrungsassistent: Option<bool>,
|
|
amount: i16,
|
|
clothing: String,
|
|
note: Option<String>,
|
|
}
|
|
|
|
#[actix_web::post("/events/{id}/edit")]
|
|
pub async fn post(
|
|
user: web::ReqData<User>,
|
|
pool: web::Data<PgPool>,
|
|
form: web::Form<EditEventForm>,
|
|
path: web::Path<IdPath>,
|
|
) -> Result<impl Responder, ApplicationError> {
|
|
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.is_empty() { 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 = Availability::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 {
|
|
// TODO: refactor
|
|
if availability.start.time() > common_time.0 {
|
|
common_time.0 = availability.start.time();
|
|
}
|
|
|
|
if availability.end.time() < common_time.1 {
|
|
common_time.1 = availability.end.time();
|
|
}
|
|
} else {
|
|
// TODO: refactor
|
|
let mut slots = vec![(availability.start.time(), availability.end.time())];
|
|
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,
|
|
};
|
|
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())
|
|
}
|