From 8688215f17ade05d52f78e916cafca04cc74af92 Mon Sep 17 00:00:00 2001 From: Max Hohlfeld Date: Thu, 2 Jan 2025 22:54:16 +0100 Subject: [PATCH] feat: edit event --- ...db032124ad921ebf473ca95da85d7537ade4.json} | 7 +- ...7be5dc4e4ceacfc14b37472c39e65d9501be9.json | 32 ---- web/src/endpoints/events/get_edit.rs | 51 ++++++ web/src/endpoints/events/get_new.rs | 15 +- web/src/endpoints/events/mod.rs | 20 ++- web/src/endpoints/events/post_new.rs | 13 +- .../endpoints/vehicle_assignment/post_new.rs | 2 +- web/src/models/vehicle_assignement.rs | 20 ++- web/templates/assignment/new.html | 146 ------------------ .../events/{new.html => new_or_edit.html} | 0 web/templates/events/plan.html | 9 ++ web/templates/index.html | 69 +++++++-- 12 files changed, 170 insertions(+), 214 deletions(-) rename .sqlx/{query-8897efc635987bca2c2d1a85e001c909404ad2356fc63872fdae5a0cf76e7099.json => query-b1e9b2e1aa8dec495988ff040e87db032124ad921ebf473ca95da85d7537ade4.json} (52%) delete mode 100644 .sqlx/query-c79fb8f25bf2e9f4299f690bebf7be5dc4e4ceacfc14b37472c39e65d9501be9.json create mode 100644 web/src/endpoints/events/get_edit.rs delete mode 100644 web/templates/assignment/new.html rename web/templates/events/{new.html => new_or_edit.html} (100%) diff --git a/.sqlx/query-8897efc635987bca2c2d1a85e001c909404ad2356fc63872fdae5a0cf76e7099.json b/.sqlx/query-b1e9b2e1aa8dec495988ff040e87db032124ad921ebf473ca95da85d7537ade4.json similarity index 52% rename from .sqlx/query-8897efc635987bca2c2d1a85e001c909404ad2356fc63872fdae5a0cf76e7099.json rename to .sqlx/query-b1e9b2e1aa8dec495988ff040e87db032124ad921ebf473ca95da85d7537ade4.json index 04a4d1ce..8f0769a0 100644 --- a/.sqlx/query-8897efc635987bca2c2d1a85e001c909404ad2356fc63872fdae5a0cf76e7099.json +++ b/.sqlx/query-b1e9b2e1aa8dec495988ff040e87db032124ad921ebf473ca95da85d7537ade4.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT * FROM vehicleAssignement WHERE vehicleAssignement.vehicleId = $1;", + "query": "\n SELECT\n vehicleAssignement.eventId,\n vehicleAssignement.vehicleId,\n vehicleAssignement.starttime,\n vehicleAssignement.endtime\n FROM vehicleAssignement\n JOIN event ON vehicleAssignement.eventId = event.id\n WHERE vehicleAssignement.vehicleid = $1\n AND event.date = $2;\n ", "describe": { "columns": [ { @@ -26,7 +26,8 @@ ], "parameters": { "Left": [ - "Int4" + "Int4", + "Date" ] }, "nullable": [ @@ -36,5 +37,5 @@ false ] }, - "hash": "8897efc635987bca2c2d1a85e001c909404ad2356fc63872fdae5a0cf76e7099" + "hash": "b1e9b2e1aa8dec495988ff040e87db032124ad921ebf473ca95da85d7537ade4" } diff --git a/.sqlx/query-c79fb8f25bf2e9f4299f690bebf7be5dc4e4ceacfc14b37472c39e65d9501be9.json b/.sqlx/query-c79fb8f25bf2e9f4299f690bebf7be5dc4e4ceacfc14b37472c39e65d9501be9.json deleted file mode 100644 index d4b751e4..00000000 --- a/.sqlx/query-c79fb8f25bf2e9f4299f690bebf7be5dc4e4ceacfc14b37472c39e65d9501be9.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT *\n FROM vehicle\n\n ;", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "id", - "type_info": "Int4" - }, - { - "ordinal": 1, - "name": "radiocallname", - "type_info": "Text" - }, - { - "ordinal": 2, - "name": "station", - "type_info": "Text" - } - ], - "parameters": { - "Left": [] - }, - "nullable": [ - false, - false, - false - ] - }, - "hash": "c79fb8f25bf2e9f4299f690bebf7be5dc4e4ceacfc14b37472c39e65d9501be9" -} diff --git a/web/src/endpoints/events/get_edit.rs b/web/src/endpoints/events/get_edit.rs new file mode 100644 index 00000000..0ef73107 --- /dev/null +++ b/web/src/endpoints/events/get_edit.rs @@ -0,0 +1,51 @@ +use actix_web::{web, HttpResponse, Responder}; +use rinja::Template; +use sqlx::PgPool; + +use crate::{ + endpoints::{events::NewEventTemplate, IdPath}, + models::{Assignment, Event, Function, Location, Role, User}, + utils::ApplicationError, +}; + +#[actix_web::get("/events/{id}/edit")] +pub async fn get( + user: web::ReqData, + pool: web::Data, + 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()); + }; + + let locations = if user.role == Role::Admin { + Location::read_all_including_area(pool.get_ref()).await? + } else { + Location::read_by_area(pool.get_ref(), user.area_id).await? + }; + + let assignments = Assignment::read_all_by_event(pool.get_ref(), event.id).await?; + + let template = NewEventTemplate { + user: user.into_inner(), + date: event.date, + locations, + event: Some(event), + amount_of_planned_posten: assignments + .iter() + .filter(|x| x.function == Function::Posten) + .count(), + is_fuehrungsassistent_planned: assignments + .iter() + .any(|x| x.function == Function::Fuehrungsassistent), + is_wachhabender_planned: assignments + .iter() + .any(|x| x.function == Function::Wachhabender), + }; + + Ok(HttpResponse::Ok().body(template.render()?)) +} diff --git a/web/src/endpoints/events/get_new.rs b/web/src/endpoints/events/get_new.rs index 79739705..2595576e 100644 --- a/web/src/endpoints/events/get_new.rs +++ b/web/src/endpoints/events/get_new.rs @@ -1,22 +1,13 @@ use actix_web::{web, HttpResponse, Responder}; -use chrono::NaiveDate; use rinja::Template; use sqlx::PgPool; use crate::{ - endpoints::NaiveDateQuery, + endpoints::{events::NewEventTemplate, NaiveDateQuery}, models::{Location, Role, User}, utils::ApplicationError, }; -#[derive(Template)] -#[template(path = "events/new.html")] -pub struct NewEventTemplate { - user: User, - date: NaiveDate, - locations: Vec, -} - #[actix_web::get("/events/new")] pub async fn get( user: web::ReqData, @@ -37,6 +28,10 @@ pub async fn get( user: user.into_inner(), date: query.date, locations, + event: None, + amount_of_planned_posten: 0, + is_fuehrungsassistent_planned: false, + is_wachhabender_planned: false }; Ok(HttpResponse::Ok().body(template.render()?)) diff --git a/web/src/endpoints/events/mod.rs b/web/src/endpoints/events/mod.rs index f1d8586e..f7ed6ec5 100644 --- a/web/src/endpoints/events/mod.rs +++ b/web/src/endpoints/events/mod.rs @@ -1,3 +1,21 @@ +use chrono::NaiveDate; +use rinja::Template; + +use crate::models::{Event, Location, Role, User}; + +pub mod get_edit; pub mod get_new; -pub mod post_new; pub mod get_plan; +pub mod post_new; + +#[derive(Template)] +#[template(path = "events/new_or_edit.html")] +pub struct NewEventTemplate { + user: User, + date: NaiveDate, + locations: Vec, + event: Option, + amount_of_planned_posten: usize, + is_fuehrungsassistent_planned: bool, + is_wachhabender_planned: bool, +} diff --git a/web/src/endpoints/events/post_new.rs b/web/src/endpoints/events/post_new.rs index c12a8947..ec37b5d1 100644 --- a/web/src/endpoints/events/post_new.rs +++ b/web/src/endpoints/events/post_new.rs @@ -3,7 +3,10 @@ use chrono::{NaiveDate, NaiveTime}; use serde::Deserialize; use sqlx::PgPool; -use crate::{models::{Event, Role, User}, utils::{self, ApplicationError}}; +use crate::{ + models::{Event, Role, User}, + utils::{self, ApplicationError}, +}; #[derive(Deserialize)] pub struct NewEventForm { @@ -16,7 +19,7 @@ pub struct NewEventForm { voluntaryfuehrungsassistent: Option, amount: i16, clothing: String, - note: Option + note: Option, } #[actix_web::post("/events/new")] @@ -29,6 +32,8 @@ pub async fn post( return Err(ApplicationError::Unauthorized); } + println!("{:?}", form.note); + Event::create( pool.get_ref(), &form.date, @@ -40,7 +45,9 @@ pub async fn post( form.voluntaryfuehrungsassistent.unwrap_or(false), form.amount, &form.clothing, - form.note.as_ref() + form.note + .as_ref() + .and_then(|n| if n.len() != 0 { Some(n) } else { None }), ) .await?; diff --git a/web/src/endpoints/vehicle_assignment/post_new.rs b/web/src/endpoints/vehicle_assignment/post_new.rs index 1d9f9fa5..c9a045bb 100644 --- a/web/src/endpoints/vehicle_assignment/post_new.rs +++ b/web/src/endpoints/vehicle_assignment/post_new.rs @@ -44,7 +44,7 @@ pub async fn post( }; let existing_assignments_for_vehicle = - VehicleAssignement::read_all_by_vehicle(pool.get_ref(), vehicle.id).await?; + VehicleAssignement::read_all_by_vehicle_and_date(pool.get_ref(), vehicle.id, event.date).await?; let has_start_time_during_event = |a: &VehicleAssignement| a.start_time >= event.start_time && a.start_time <= event.end_time; let has_end_time_during_event = diff --git a/web/src/models/vehicle_assignement.rs b/web/src/models/vehicle_assignement.rs index bf550a12..82c7afb2 100644 --- a/web/src/models/vehicle_assignement.rs +++ b/web/src/models/vehicle_assignement.rs @@ -1,4 +1,4 @@ -use chrono::NaiveTime; +use chrono::{NaiveDate, NaiveTime}; use sqlx::{query, PgPool}; use super::Result; @@ -73,13 +73,25 @@ impl VehicleAssignement { Ok(vehicle_assignments) } - pub async fn read_all_by_vehicle( + pub async fn read_all_by_vehicle_and_date( pool: &PgPool, vehicle_id: i32, + date: NaiveDate ) -> Result> { let records = query!( - "SELECT * FROM vehicleAssignement WHERE vehicleAssignement.vehicleId = $1;", - vehicle_id + r#" + SELECT + vehicleAssignement.eventId, + vehicleAssignement.vehicleId, + vehicleAssignement.starttime, + vehicleAssignement.endtime + FROM vehicleAssignement + JOIN event ON vehicleAssignement.eventId = event.id + WHERE vehicleAssignement.vehicleid = $1 + AND event.date = $2; + "#, + vehicle_id, + date, ) .fetch_all(pool) .await?; diff --git a/web/templates/assignment/new.html b/web/templates/assignment/new.html deleted file mode 100644 index 6d5e39dc..00000000 --- a/web/templates/assignment/new.html +++ /dev/null @@ -1,146 +0,0 @@ -{% extends "nav.html" %} - -{% block content %} -
-
-
- - -

Planung für {{ event.name }}

-
- {% if event.canceled %}Veranstaltung abgesagt!{% endif %} -

Ort: {{ event.location.as_ref().unwrap().name }}

-

Zeitraum: {{ event.start_time }} bis {{ event.end_time }}

-

Anzahl der Posten: {{ event.amount_of_posten }}

-

Wachhabender durch FF gestellt: {{ event.voluntary_wachhabender }}

-

Kleidungsordnung: {{ event.clothing }}

-
- -
- - - - - - - - - - - - {% for a in all %} - {% let u = a.user.as_ref().unwrap() %} - - - - - - - {% endfor %} - -
NameFunktionZeitKommentar
{{ u.name }} - {% match user.function %} - {% when Function::Posten %} - Posten - {% when Function::Wachhabender %} - Wachhabender - {% else %} - {% endmatch %} - - {% if a.start_time.is_some() && a.end_time.is_some() %} - {{ a.start_time.as_ref().unwrap() }} - {{ a.end_time.as_ref().unwrap() }} - {% else %} - ganztägig - {% endif %} - - {{ a.comment.as_deref().unwrap_or("") }} -
-
- - {% if event.voluntary_wachhabender %} -
- -
- -
-
- {% endif %} - -
- -

Mehrfachauswahl mit Strg+Mausklick

-
- -
-
- -
- -
- -
-
- -
-
-
-
-
- -
-
- Zurück -
-
-
-
- -
-
-
- - -{% endblock %} diff --git a/web/templates/events/new.html b/web/templates/events/new_or_edit.html similarity index 100% rename from web/templates/events/new.html rename to web/templates/events/new_or_edit.html diff --git a/web/templates/events/plan.html b/web/templates/events/plan.html index ba5a1041..a26b9cfa 100644 --- a/web/templates/events/plan.html +++ b/web/templates/events/plan.html @@ -60,6 +60,15 @@ {% include "plan_vehicles.html" %} + + {% endblock %} diff --git a/web/templates/index.html b/web/templates/index.html index 2ee9ebab..2b93f4cd 100644 --- a/web/templates/index.html +++ b/web/templates/index.html @@ -76,23 +76,64 @@ {% else %} {% for event in events %}
- {% if event.canceled %}Veranstaltung abgesagt!{% endif %} -
-
{{ event.name }}
- +
+
+
+
{{ event.name }}
+
+ {% if user.role == Role::AreaManager || user.role == Role::Admin %} - Planen - bearbeiten - als abgesagt markieren + {% endif %} - + + {% if event.canceled %}Veranstaltung abgesagt!{% endif %} + +
+

Uhrzeit: {{ event.start_time.format("%R") }} Uhr - {{ event.end_time.format("%R") }} Uhr

+
+ +
+

Veranstaltungsort: {{ event.location.as_ref().unwrap().name }}

+
+ +
+

Wachhabender: {% if event.voluntary_wachhabender %}FF{% else %}BF{% endif %}

+
+ +
+

Führungsassistent: {% if event.voluntary_fuehrungsassistent %}FF{% else %}BF{% endif %}

+
+ +
+

Anzahl der Posten: {{ event.amount_of_posten }}

+
+ +
+

Anzugsordnung: {{ event.clothing }}

+
+ + {% if let Some(note) = event.note %} +
+

Anmerkungen: {{ note }}

+
+ {% endif %} + +
-

Ort: {{ event.location.as_ref().unwrap().name }}

-

Zeitraum: {{ event.start_time }} bis {{ event.end_time }}

-

Anzahl der Posten: {{ event.amount_of_posten }}

-

Wachhabender durch FF gestellt: {{ event.voluntary_wachhabender }}

-

Kleidungsordnung: {{ event.clothing }}

{% endfor %} {% endif %}