157 lines
5.3 KiB
Rust
157 lines
5.3 KiB
Rust
use actix_web::{http::header::LOCATION, web, HttpResponse, Responder};
|
|
use chrono::Days;
|
|
use garde::Validate;
|
|
use sqlx::PgPool;
|
|
|
|
use crate::{
|
|
endpoints::{events::NewOrEditEventForm, IdPath},
|
|
utils::{self, ApplicationError},
|
|
END_OF_DAY, START_OF_DAY,
|
|
};
|
|
use brass_db::models::{
|
|
Assignment, AssignmentChangeset, Availability, Event, EventChangeset, EventContext, Function,
|
|
Location, Role, User,
|
|
};
|
|
|
|
#[actix_web::post("/events/{id}/edit")]
|
|
pub async fn post(
|
|
user: web::ReqData<User>,
|
|
pool: web::Data<PgPool>,
|
|
form: web::Form<NewOrEditEventForm>,
|
|
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 {
|
|
amount_of_posten: form.amount,
|
|
clothing: form.clothing,
|
|
location_id: form.location,
|
|
time: (form.date.and_time(form.start), form.end),
|
|
name: form.name.clone(),
|
|
note: form
|
|
.note
|
|
.clone()
|
|
.and_then(|n| if !n.is_empty() { Some(n) } else { None }),
|
|
voluntary_wachhabender: form.voluntarywachhabender,
|
|
voluntary_fuehrungsassistent: form.voluntaryfuehrungsassistent,
|
|
};
|
|
|
|
let assignments_for_event = Assignment::read_all_by_event(pool.get_ref(), event.id).await?;
|
|
|
|
let start = event.start.date();
|
|
let end = event.start.date().checked_add_days(Days::new(1)).unwrap();
|
|
let mut common_time = (start.and_time(START_OF_DAY), end.and_time(END_OF_DAY));
|
|
|
|
for assignment in &assignments_for_event {
|
|
let availability = Availability::read_by_id(pool.get_ref(), assignment.availability_id)
|
|
.await?
|
|
.unwrap();
|
|
let all_assignments =
|
|
Assignment::read_all_by_availability(pool.get_ref(), assignment.availability_id)
|
|
.await?;
|
|
|
|
if all_assignments.len() == 1 {
|
|
if availability.start > common_time.0 {
|
|
common_time.0 = availability.start;
|
|
}
|
|
|
|
if availability.end < common_time.1 {
|
|
common_time.1 = availability.end;
|
|
}
|
|
} else {
|
|
let mut slots = vec![(availability.start, availability.end)];
|
|
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 && s.1 <= a.end);
|
|
slots = rest;
|
|
let fit = fit.first().unwrap();
|
|
|
|
if fit.0 != a.start {
|
|
slots.push((fit.0, a.start));
|
|
}
|
|
|
|
if fit.1 != a.end {
|
|
slots.push((a.end, fit.1));
|
|
}
|
|
}
|
|
|
|
let slot = slots
|
|
.into_iter()
|
|
.find(|s| s.0 >= assignment.start && s.1 <= assignment.end)
|
|
.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.start.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 != changeset.time.0 || event.end != 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.availability_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())
|
|
}
|