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}; use rust_xlsxwriter::workbook::Workbook; use serde::Deserialize; use sqlx::PgPool; use crate::{ models::{Role, User}, utils::{ApplicationError, DateTimeFormat}, }; #[derive(Deserialize)] struct ExportQuery { start: NaiveDate, end: NaiveDate, area: Option, } #[derive(PartialEq)] struct EventExportEntry { date: String, weekday: String, start_time: String, end_time: String, hours: f32, location: String, name: String, assigned_name: Option, assigned_function: Option, } fn read(rows: Vec) -> Vec { let mut entries = Vec::new(); for r in rows { 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())), }; 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" }; entries.push(create_new_entry(None, Some(function))); } 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()), )); } 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 { entries.push(create_new_entry(Some(&v), Some("Fzg"))); } } entries } #[actix_web::get("/export/eventsdata")] pub async fn get( pool: web::Data, user: web::ReqData, query: web::Query, ) -> Result { if user.role != Role::Admin && user.role != Role::AreaManager { return Err(ApplicationError::Unauthorized); } let rows_to_export = ExportEventRow::read(pool.get_ref()).await?; let entries = read(rows_to_export); let mut workbook = Workbook::new(); let worksheet = workbook.add_worksheet(); // let time_format = Format::new(); // time_format.set_num_format(num_format) const HEADER: [&str; 10] = [ "Datum", "Wochentag", "Beginn", "Ende", "Stunden", "Ort", "VA", "Namen", "Fkt", "Reserve", ]; worksheet.write_row(2, 0, HEADER).unwrap(); for (i, entry) in entries.iter().enumerate() { let i = (i + 3) as u32; worksheet.write(i, 0, &entry.date).unwrap(); worksheet.write(i, 1, &entry.weekday).unwrap(); worksheet.write(i, 2, &entry.start_time).unwrap(); worksheet.write(i, 3, &entry.end_time).unwrap(); worksheet.write(i, 4, entry.hours).unwrap(); worksheet .write(i, 4, format!("{:.1}", entry.hours)) .unwrap(); worksheet.write(i, 5, &entry.location).unwrap(); worksheet.write(i, 6, &entry.name).unwrap(); worksheet.write(i, 7, entry.assigned_name.as_ref()).unwrap(); worksheet .write(i, 8, entry.assigned_function.as_ref()) .unwrap(); } worksheet.autofit(); let buffer = workbook.save_to_buffer().unwrap(); return Ok(HttpResponse::Ok() .content_type("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") .insert_header(( CONTENT_DISPOSITION, ContentDisposition::attachment("export.xlsx"), )) .body(buffer)); }