feat: export events into xlsx
This commit is contained in:
parent
4af004456f
commit
01cf373b98
78
Cargo.lock
generated
78
Cargo.lock
generated
@ -416,6 +416,15 @@ version = "1.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
|
||||
dependencies = [
|
||||
"derive_arbitrary",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "argon2"
|
||||
version = "0.5.3"
|
||||
@ -814,6 +823,7 @@ dependencies = [
|
||||
"quick-xml",
|
||||
"rand 0.9.1",
|
||||
"regex",
|
||||
"rust_xlsxwriter",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
@ -1191,6 +1201,17 @@ dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_arbitrary"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder"
|
||||
version = "0.20.2"
|
||||
@ -1463,6 +1484,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"libz-rs-sys",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
@ -2153,6 +2175,15 @@ dependencies = [
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libz-rs-sys"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6489ca9bd760fe9642d7644e827b0c9add07df89857b0416ee15c1cc1a3b8c5a"
|
||||
dependencies = [
|
||||
"zlib-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.3.8"
|
||||
@ -2828,6 +2859,15 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust_xlsxwriter"
|
||||
version = "0.87.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8079587c37b35a067846a853a524cfde7012754650de7274beecc35e43acd44b"
|
||||
dependencies = [
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.24"
|
||||
@ -3048,6 +3088,12 @@ dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simd-adler32"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||
|
||||
[[package]]
|
||||
name = "similar"
|
||||
version = "2.7.0"
|
||||
@ -4228,6 +4274,38 @@ dependencies = [
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12598812502ed0105f607f941c386f43d441e00148fce9dec3ca5ffb0bde9308"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"crc32fast",
|
||||
"flate2",
|
||||
"indexmap",
|
||||
"memchr",
|
||||
"zopfli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zlib-rs"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "868b928d7949e09af2f6086dfc1e01936064cc7a819253bce650d4e2a2d63ba8"
|
||||
|
||||
[[package]]
|
||||
name = "zopfli"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"crc32fast",
|
||||
"log",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.13.3"
|
||||
|
@ -36,6 +36,7 @@ tracing-actix-web = "0.7.18"
|
||||
tracing = "0.1.41"
|
||||
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
|
||||
tracing-panic = "0.1.2"
|
||||
rust_xlsxwriter = "0.87.0"
|
||||
|
||||
[build-dependencies]
|
||||
built = "0.7.4"
|
||||
|
@ -1,11 +1,13 @@
|
||||
use actix_web::{web, HttpResponse, Responder};
|
||||
use chrono::NaiveDate;
|
||||
use actix_http::header::CONTENT_DISPOSITION;
|
||||
use actix_web::{http::header::ContentDisposition, web, HttpResponse, Responder};
|
||||
use chrono::{Datelike, NaiveDate};
|
||||
use rust_xlsxwriter::{workbook::Workbook, Format};
|
||||
use serde::Deserialize;
|
||||
use sqlx::PgPool;
|
||||
use sqlx::{query, PgPool};
|
||||
|
||||
use crate::{
|
||||
models::{Role, User},
|
||||
utils::ApplicationError,
|
||||
utils::{ApplicationError, DateTimeFormat},
|
||||
};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@ -15,6 +17,135 @@ struct ExportQuery {
|
||||
area: Option<i32>,
|
||||
}
|
||||
|
||||
struct EventExportEntry {
|
||||
date: String,
|
||||
weekday: String,
|
||||
start_time: String,
|
||||
end_time: String,
|
||||
hours: f32,
|
||||
location: String,
|
||||
name: String,
|
||||
assigned_name: Option<String>,
|
||||
assigned_function: Option<String>,
|
||||
}
|
||||
|
||||
async fn read(pool: &PgPool) -> Result<Vec<EventExportEntry>, ApplicationError> {
|
||||
let results = query!("select
|
||||
event.starttimestamp,
|
||||
event.endtimestamp,
|
||||
(event.amountofposten + event.voluntaryfuehrungsassistent::int + event.voluntarywachhabender::int) as expectedPeople,
|
||||
location.name as locationName,
|
||||
event.name as eventName,
|
||||
array (
|
||||
select
|
||||
user_.name || ' --- ' || assignment.function
|
||||
from
|
||||
assignment
|
||||
join availability on
|
||||
assignment.availabilityid = availability.id
|
||||
join user_ on
|
||||
availability.userid = user_.id
|
||||
where
|
||||
assignment.eventId = event.id) as assignments,
|
||||
array (
|
||||
select
|
||||
vehicle.station || ' ' || vehicle.radiocallname
|
||||
from
|
||||
vehicleassignment
|
||||
join vehicle on
|
||||
vehicleassignment.vehicleId = vehicle.id
|
||||
where
|
||||
vehicleassignment.eventId = event.id) as vehicles
|
||||
from
|
||||
event
|
||||
join location on
|
||||
event.locationId = location.id").fetch_all(pool).await?;
|
||||
|
||||
let mut entries = Vec::new();
|
||||
|
||||
for r in results {
|
||||
let date = r
|
||||
.starttimestamp
|
||||
.date_naive()
|
||||
.format(DateTimeFormat::DayMonthYear.into());
|
||||
let weekday = r.starttimestamp.date_naive().weekday();
|
||||
let start_time = r
|
||||
.starttimestamp
|
||||
.time()
|
||||
.format(DateTimeFormat::HourMinute.into());
|
||||
let end_time = r
|
||||
.endtimestamp
|
||||
.time()
|
||||
.format(DateTimeFormat::HourMinute.into());
|
||||
let hours = (r.endtimestamp - r.starttimestamp).as_seconds_f32() / 3600.0 + 1.0;
|
||||
let location = r.locationname;
|
||||
let name = r.eventname;
|
||||
|
||||
let mut event_new: Vec<EventExportEntry> = Vec::new();
|
||||
|
||||
if let Some(assignments) = r.assignments {
|
||||
for a in assignments {
|
||||
let (assigned_name, assigned_function) = a.split_once("---").unwrap();
|
||||
let assigned_function = match assigned_function.trim() {
|
||||
"posten" => "PO",
|
||||
"wachhabender" => "WH",
|
||||
"fuehrungsassistent" => "FüAss",
|
||||
_ => assigned_function.trim(),
|
||||
};
|
||||
|
||||
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: location.to_string(),
|
||||
name: name.to_string(),
|
||||
assigned_name: Some(assigned_name.trim().to_string()),
|
||||
assigned_function: Some(assigned_function.to_string()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let expected = r.expectedpeople.unwrap_or(0) as usize;
|
||||
if event_new.len() < expected {
|
||||
for _ in 0..(expected - event_new.len()) {
|
||||
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: location.to_string(),
|
||||
name: name.to_string(),
|
||||
assigned_name: None,
|
||||
assigned_function: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(vehicles) = r.vehicles {
|
||||
for v in 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: location.to_string(),
|
||||
name: name.to_string(),
|
||||
assigned_name: Some(v.to_string()),
|
||||
assigned_function: Some(String::from("Fzg")),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
entries.append(&mut event_new);
|
||||
}
|
||||
|
||||
Ok(entries)
|
||||
}
|
||||
|
||||
#[actix_web::get("/export/eventsdata")]
|
||||
pub async fn get(
|
||||
pool: web::Data<PgPool>,
|
||||
@ -25,5 +156,38 @@ pub async fn get(
|
||||
return Err(ApplicationError::Unauthorized);
|
||||
}
|
||||
|
||||
Ok(HttpResponse::BadRequest().finish())
|
||||
let entries = read(pool.get_ref()).await?;
|
||||
|
||||
let mut workbook = Workbook::new();
|
||||
let worksheet = workbook.add_worksheet();
|
||||
// let time_format = Format::new();
|
||||
// time_format.set_num_format(num_format)
|
||||
|
||||
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, 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));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user