diff --git a/migrations/20230609121618_initial.sql b/migrations/20230609121618_initial.sql index d3b434cf..4c6c2baf 100644 --- a/migrations/20230609121618_initial.sql +++ b/migrations/20230609121618_initial.sql @@ -55,13 +55,13 @@ CREATE TABLE event canceled BOOLEAN NOT NULL DEFAULT false ); -CREATE TABLE assignement +CREATE TABLE assignment ( eventId INTEGER REFERENCES event (id), availabillityId INTEGER REFERENCES availabillity (id), function function NOT NULL, - startTime TIME, - endTime TIME, + startTime TIME NOT NULL, + endTime TIME NOT NULL, PRIMARY KEY (eventId, availabillityId) ); diff --git a/src/endpoints/assignment/post_new.rs b/src/endpoints/assignment/post_new.rs index 3102676d..8aebe1f9 100644 --- a/src/endpoints/assignment/post_new.rs +++ b/src/endpoints/assignment/post_new.rs @@ -2,8 +2,11 @@ use actix_web::{web, HttpResponse, Responder}; use serde::Deserialize; use sqlx::PgPool; +use crate::models::{Assignment, Event, Function}; + #[derive(Deserialize)] pub struct NewAssignmentsForm { + event: i32, wachhabender: Option, posten: Vec } @@ -11,5 +14,41 @@ pub struct NewAssignmentsForm { #[actix_web::post("/assignments/new")] pub async fn post(pool: web::Data, form: web::Form) -> impl Responder { + let event = Event::read_by_id_including_location(&pool, form.event).await.unwrap(); // TODO: Check if location is needed + + if event.voluntary_wachhabender && form.wachhabender.is_some() && form.posten.contains(&form.wachhabender.unwrap()) { + return HttpResponse::BadRequest().body("Wachhabender kann nicht zugleich Posten sein!"); + } + + let mut joined_ids = form.posten.clone(); + if let Some(id) = form.wachhabender { + joined_ids.push(id); + } + + for availabillity_id in joined_ids { + let assignments = Assignment::read_by_availabillity(pool.get_ref(), availabillity_id).await.unwrap(); + + let mut can_be_used = true; + + for assignment in assignments { + if event.start_time >= assignment.start_time && event.start_time <= assignment.end_time { + can_be_used = false; + break; + } + } + + if !can_be_used { + return HttpResponse::BadRequest().body("availabillity time slot bereits genutzt!"); + } + } + + if let Some(id) = form.wachhabender { + Assignment::create(pool.get_ref(), id, event.id, Function::Wachhabender, event.start_time, event.end_time).await.unwrap(); + } + + for id in &form.posten { + Assignment::create(pool.get_ref(), *id, event.id, Function::Posten, event.start_time, event.end_time).await.unwrap(); + } + HttpResponse::Ok().finish() } diff --git a/src/models/assignement.rs b/src/models/assignement.rs index 91c129d4..a4ce9961 100644 --- a/src/models/assignement.rs +++ b/src/models/assignement.rs @@ -1,5 +1,5 @@ use chrono::NaiveTime; -use sqlx::PgPool; +use sqlx::{query, PgPool}; use super::Function; @@ -8,12 +8,66 @@ pub struct Assignment { pub availabillity_id: i32, pub function: Function, pub start_time: NaiveTime, - pub end_time: NaiveTime + pub end_time: NaiveTime, } impl Assignment { - pub async fn create(pool: &PgPool) -> anyhow::Result { + pub async fn create( + pool: &PgPool, + availabillity_id: i32, + event_id: i32, + function: Function, + start_time: NaiveTime, + end_time: NaiveTime, + ) -> anyhow::Result<()> { + query!( + r##" + INSERT INTO assignment (eventId, availabillityId, function, startTime, endTime) + VALUES ($1, $2, $3, $4, $5); + "##, + availabillity_id, + event_id, + function as Function, + start_time, + end_time + ) + .execute(pool) + .await?; - Ok(0) + Ok(()) + } + + pub async fn read_by_availabillity( + pool: &PgPool, + availabillity_id: i32, + ) -> anyhow::Result> { + let records = query!( + r##" + SELECT + assignment.eventId, + assignment.availabillityId, + assignment.function AS "function: Function", + assignment.startTime, + assignment.endTime + FROM assignment + WHERE assignment.AvailabillityId = $1; + "##, + availabillity_id + ) + .fetch_all(pool) + .await?; + + let assignemnets = records + .iter() + .map(|r| Assignment { + event_id: r.eventid, + availabillity_id: r.availabillityid, + function: r.function, + start_time: r.starttime, + end_time: r.endtime, + }) + .collect(); + + Ok(assignemnets) } } diff --git a/src/models/availabillity.rs b/src/models/availabillity.rs index 2b4d9c9c..67e56c7a 100644 --- a/src/models/availabillity.rs +++ b/src/models/availabillity.rs @@ -139,7 +139,7 @@ impl Availabillity { user_.lastLogin, user_.receiveNotifications FROM availabillity - LEFT JOIN assignement ON availabillity.Id = assignement.availabillityId + LEFT JOIN assignment ON availabillity.Id = assignment.availabillityId JOIN user_ ON availabillity.userId = user_.id WHERE availabillity.date = $1; "##, diff --git a/src/models/user.rs b/src/models/user.rs index 642f0783..1f6b432d 100644 --- a/src/models/user.rs +++ b/src/models/user.rs @@ -1,5 +1,5 @@ use chrono::{DateTime, Utc}; -use sqlx::{Execute, PgPool}; +use sqlx::PgPool; use super::{Area, Function, Role}; diff --git a/templates/assignment/new.html b/templates/assignment/new.html index aef94601..8c644b24 100644 --- a/templates/assignment/new.html +++ b/templates/assignment/new.html @@ -3,7 +3,9 @@ {% block content %}
-
+ + +

Planung für {{ event.name }}

{% if event.canceled %}Veranstaltung abgesagt!{% endif %} @@ -45,6 +47,7 @@
+

Mehrfachauswahl mit Strg+Mausklick

+
+
+ Zurück +
+
+
+
+