From d1e1ccd90681442ddf314885fae332f8df6fb591 Mon Sep 17 00:00:00 2001 From: Max Hohlfeld Date: Wed, 4 Jun 2025 15:24:27 +0200 Subject: [PATCH] refactor: correct output of event export --- ...604130602_export_event_assignment_type.sql | 4 + web/src/endpoints/export/get_events_data.rs | 162 +++++++----------- web/src/models/export_event_row.rs | 24 ++- web/src/models/function.rs | 8 +- web/src/models/mod.rs | 2 +- 5 files changed, 95 insertions(+), 105 deletions(-) create mode 100644 migrations/20250604130602_export_event_assignment_type.sql diff --git a/migrations/20250604130602_export_event_assignment_type.sql b/migrations/20250604130602_export_event_assignment_type.sql new file mode 100644 index 00000000..0781734f --- /dev/null +++ b/migrations/20250604130602_export_event_assignment_type.sql @@ -0,0 +1,4 @@ +CREATE TYPE simpleAssignment AS ( + name text, + function function +); diff --git a/web/src/endpoints/export/get_events_data.rs b/web/src/endpoints/export/get_events_data.rs index 12d9d978..015d4afc 100644 --- a/web/src/endpoints/export/get_events_data.rs +++ b/web/src/endpoints/export/get_events_data.rs @@ -1,4 +1,4 @@ -use crate::models::{ExportEventRow, Function}; +use crate::models::{ExportEventRow, Function, SimpleAssignment}; use actix_http::header::CONTENT_DISPOSITION; use actix_web::{http::header::ContentDisposition, web, HttpResponse, Responder}; use chrono::{Datelike, NaiveDate}; @@ -35,117 +35,87 @@ fn read(rows: Vec) -> Vec { let mut entries = Vec::new(); for r in rows { - let date = r - .start_timestamp - .format(DateTimeFormat::DayMonthYear.into()); - let weekday = r.start_timestamp.weekday(); - let start_time = r - .start_timestamp - .time() - .format(DateTimeFormat::HourMinute.into()); - let end_time = r - .end_timestamp - .time() - .format(DateTimeFormat::HourMinute.into()); - let hours = (r.end_timestamp - r.start_timestamp).as_seconds_f32() / 3600.0 + 1.0; + let create_new_entry = |n: Option<&str>, f: Option<&str>| EventExportEntry { + date: r + .start_timestamp + .format(DateTimeFormat::DayMonthYear.into()) + .to_string(), + weekday: r.start_timestamp.weekday().to_string(), + start_time: r + .start_timestamp + .time() + .format(DateTimeFormat::HourMinute.into()) + .to_string(), + end_time: r + .end_timestamp + .time() + .format(DateTimeFormat::HourMinute.into()) + .to_string(), + hours: (r.end_timestamp - r.start_timestamp).as_seconds_f32() / 3600.0 + 1.0, + location: r.location_name.to_string(), + name: r.event_name.to_string(), + assigned_name: n.and_then(|s| Some(s.to_string())), + assigned_function: f.and_then(|s| Some(s.to_string())), + }; - let mut event_new: Vec = Vec::new(); - - let mut assigned_posten: i16 = 0; - let mut assigned_wachhabender = false; - let mut assigned_fuehrungassistent = false; - - for (assigned_name, assigned_function) in r.assignments { - match assigned_function { - Function::Posten => { - assigned_posten += 1; - } - Function::Wachhabender => { - assigned_wachhabender = true; - } - Function::Fuehrungsassistent => { - assigned_fuehrungassistent = true; - } - }; - - event_new.push(EventExportEntry { - date: date.to_string(), - weekday: weekday.to_string(), - start_time: start_time.to_string(), - end_time: end_time.to_string(), - hours, - location: r.location_name.to_string(), - name: r.event_name.to_string(), - assigned_name: Some(assigned_name.trim().to_string()), - assigned_function: Some(assigned_function.to_string()), - }); - } - - if !assigned_wachhabender { + if let Some(assigned_wh) = r + .assignments + .iter() + .find(|a| a.function == Function::Wachhabender) + { + entries.push(create_new_entry( + Some(&assigned_wh.name), + Some(&assigned_wh.function.short_display()), + )); + } else { let function = if r.voluntary_wachhabender { "WH" } else { "BF-WH" }; - event_new.push(EventExportEntry { - date: date.to_string(), - weekday: weekday.to_string(), - start_time: start_time.to_string(), - end_time: end_time.to_string(), - hours, - location: r.location_name.to_string(), - name: r.event_name.to_string(), - assigned_name: None, - assigned_function: Some(function.to_string()), - }); + entries.push(create_new_entry(None, Some(function))); } - if !assigned_fuehrungassistent && r.voluntary_fuehrungsassistent { - event_new.push(EventExportEntry { - date: date.to_string(), - weekday: weekday.to_string(), - start_time: start_time.to_string(), - end_time: end_time.to_string(), - hours, - location: r.location_name.to_string(), - name: r.event_name.to_string(), - assigned_name: None, - assigned_function: Some("FüAss".to_string()), - }); + if let Some(assigned_fuass) = r + .assignments + .iter() + .find(|a| a.function == Function::Fuehrungsassistent) + { + entries.push(create_new_entry( + Some(&assigned_fuass.name), + Some(&assigned_fuass.function.short_display()), + )); + } else if r.voluntary_fuehrungsassistent { + entries.push(create_new_entry( + None, + Some(&Function::Fuehrungsassistent.short_display()), + )); } - if assigned_posten < r.amount_of_posten { - for _ in 0..(r.amount_of_posten - assigned_posten) { - event_new.push(EventExportEntry { - date: date.to_string(), - weekday: weekday.to_string(), - start_time: start_time.to_string(), - end_time: end_time.to_string(), - hours, - location: r.location_name.to_string(), - name: r.event_name.to_string(), - assigned_name: None, - assigned_function: Some("PO".to_string()), - }); + let assigned_po: Vec<&SimpleAssignment> = r + .assignments + .iter() + .filter(|a| a.function == Function::Posten) + .collect(); + + for i in 0..r.amount_of_posten { + if let Some(po) = assigned_po.get(i as usize) { + entries.push(create_new_entry( + Some(&po.name), + Some(&po.function.short_display()), + )); + } else { + entries.push(create_new_entry( + None, + Some(&Function::Posten.short_display()), + )); } } for v in r.vehicles { - event_new.push(EventExportEntry { - date: date.to_string(), - weekday: weekday.to_string(), - start_time: start_time.to_string(), - end_time: end_time.to_string(), - hours, - location: r.location_name.to_string(), - name: r.event_name.to_string(), - assigned_name: Some(v.to_string()), - assigned_function: Some(String::from("Fzg")), - }); + entries.push(create_new_entry(Some(&v), Some("Fzg"))); } - - entries.append(&mut event_new); } entries diff --git a/web/src/models/export_event_row.rs b/web/src/models/export_event_row.rs index f5c88c09..b5e46959 100644 --- a/web/src/models/export_event_row.rs +++ b/web/src/models/export_event_row.rs @@ -1,5 +1,8 @@ use chrono::NaiveDateTime; -use sqlx::{query, PgPool}; +use sqlx::{ + postgres::{PgHasArrayType, PgTypeInfo}, + query, PgPool, +}; use crate::utils::ApplicationError; @@ -13,10 +16,23 @@ pub struct ExportEventRow { pub voluntary_wachhabender: bool, pub location_name: String, pub event_name: String, - pub assignments: Vec<(String, Function)>, + pub assignments: Vec, pub vehicles: Vec, } +#[derive(Debug, sqlx::Type)] +#[sqlx(type_name = "function", no_pg_array)] +pub struct SimpleAssignment { + pub name: String, + pub function: Function, +} + +impl PgHasArrayType for SimpleAssignment { + fn array_type_info() -> sqlx::postgres::PgTypeInfo { + PgTypeInfo::with_name("simpleAssignment[]") + } +} + impl ExportEventRow { pub async fn read(pool: &PgPool) -> Result, ApplicationError> { let rows = query!( @@ -30,7 +46,7 @@ impl ExportEventRow { event.name as eventName, array ( select - row (user_.name, assignment.function) + row (user_.name, assignment.function) ::simpleAssignment from assignment join availability on @@ -38,7 +54,7 @@ impl ExportEventRow { join user_ on availability.userid = user_.id where - assignment.eventId = event.id) as \"assignments: Vec<(String, Function)>\", + assignment.eventId = event.id) as \"assignments: Vec\", array ( select vehicle.station || ' ' || vehicle.radiocallname diff --git a/web/src/models/function.rs b/web/src/models/function.rs index 4be83532..f0167064 100644 --- a/web/src/models/function.rs +++ b/web/src/models/function.rs @@ -44,11 +44,11 @@ impl Default for Function { } impl Function { - pub fn short_display(&self) -> &'static str { + pub fn short_display(&self) -> String { match self { - Function::Posten => "PO", - Function::Fuehrungsassistent => "FüAss", - Function::Wachhabender => "WH", + Function::Posten => "PO".to_string(), + Function::Fuehrungsassistent => "FüAss".to_string(), + Function::Wachhabender => "WH".to_string(), } } } diff --git a/web/src/models/mod.rs b/web/src/models/mod.rs index 8bc6a698..7d1ab438 100644 --- a/web/src/models/mod.rs +++ b/web/src/models/mod.rs @@ -30,7 +30,7 @@ pub use availability_changeset::{ pub use clothing::Clothing; pub use event::Event; pub use event_changeset::{EventChangeset, EventContext}; -pub use export_event_row::ExportEventRow; +pub use export_event_row::{ExportEventRow, SimpleAssignment}; pub use function::Function; pub use location::Location; pub use password_reset::{NoneToken, PasswordReset, Token};