diff --git a/db/.sqlx/query-10b4b80f351b66ac5e778a3031288ac5dc66efd0a66b38b7e30f4c954df91bdf.json b/db/.sqlx/query-10b4b80f351b66ac5e778a3031288ac5dc66efd0a66b38b7e30f4c954df91bdf.json new file mode 100644 index 00000000..940e6e4b --- /dev/null +++ b/db/.sqlx/query-10b4b80f351b66ac5e778a3031288ac5dc66efd0a66b38b7e30f4c954df91bdf.json @@ -0,0 +1,114 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n event.id AS eventId,\n event.startTimestamp,\n event.endTimestamp,\n event.name,\n event.locationId,\n event.voluntaryWachhabender,\n event.voluntaryFuehrungsassistent,\n event.amountOfPosten,\n event.clothing,\n event.canceled,\n event.note,\n location.id,\n location.name AS locationName,\n location.areaId AS locationAreaId,\n clothing.id AS clothingId,\n clothing.name AS clothingName\n FROM event\n JOIN location ON event.locationId = location.id\n JOIN clothing ON event.clothing = clothing.id\n WHERE starttimestamp::date >= $1\n AND starttimestamp::date <= $2\n AND location.areaId = $3;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "eventid", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "starttimestamp", + "type_info": "Timestamptz" + }, + { + "ordinal": 2, + "name": "endtimestamp", + "type_info": "Timestamptz" + }, + { + "ordinal": 3, + "name": "name", + "type_info": "Text" + }, + { + "ordinal": 4, + "name": "locationid", + "type_info": "Int4" + }, + { + "ordinal": 5, + "name": "voluntarywachhabender", + "type_info": "Bool" + }, + { + "ordinal": 6, + "name": "voluntaryfuehrungsassistent", + "type_info": "Bool" + }, + { + "ordinal": 7, + "name": "amountofposten", + "type_info": "Int2" + }, + { + "ordinal": 8, + "name": "clothing", + "type_info": "Int4" + }, + { + "ordinal": 9, + "name": "canceled", + "type_info": "Bool" + }, + { + "ordinal": 10, + "name": "note", + "type_info": "Text" + }, + { + "ordinal": 11, + "name": "id", + "type_info": "Int4" + }, + { + "ordinal": 12, + "name": "locationname", + "type_info": "Text" + }, + { + "ordinal": 13, + "name": "locationareaid", + "type_info": "Int4" + }, + { + "ordinal": 14, + "name": "clothingid", + "type_info": "Int4" + }, + { + "ordinal": 15, + "name": "clothingname", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Date", + "Date", + "Int4" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false + ] + }, + "hash": "10b4b80f351b66ac5e778a3031288ac5dc66efd0a66b38b7e30f4c954df91bdf" +} diff --git a/db/.sqlx/query-f60053118df6a791d31fa258ee3737881f8f97ca41cbebd92eb22c967292d2ee.json b/db/.sqlx/query-f60053118df6a791d31fa258ee3737881f8f97ca41cbebd92eb22c967292d2ee.json new file mode 100644 index 00000000..20d9da9e --- /dev/null +++ b/db/.sqlx/query-f60053118df6a791d31fa258ee3737881f8f97ca41cbebd92eb22c967292d2ee.json @@ -0,0 +1,48 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n availability.id,\n availability.userId,\n availability.startTimestamp,\n availability.endTimestamp,\n availability.comment\n FROM availability\n WHERE availability.userId = $1\n AND availability.starttimestamp::date >= $2\n AND availability.endtimestamp::date <= $3;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "userid", + "type_info": "Int4" + }, + { + "ordinal": 2, + "name": "starttimestamp", + "type_info": "Timestamptz" + }, + { + "ordinal": 3, + "name": "endtimestamp", + "type_info": "Timestamptz" + }, + { + "ordinal": 4, + "name": "comment", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Int4", + "Date", + "Date" + ] + }, + "nullable": [ + false, + false, + false, + false, + true + ] + }, + "hash": "f60053118df6a791d31fa258ee3737881f8f97ca41cbebd92eb22c967292d2ee" +} diff --git a/db/src/models/availability.rs b/db/src/models/availability.rs index 8b3f04d2..b56d71cf 100644 --- a/db/src/models/availability.rs +++ b/db/src/models/availability.rs @@ -341,6 +341,46 @@ impl Availability { Ok(availabilities) } + pub async fn read_by_user_and_daterange( + pool: &PgPool, + user_id: i32, + date_range: (&NaiveDate, &NaiveDate), + ) -> Result> { + let records = query!( + r##" + SELECT + availability.id, + availability.userId, + availability.startTimestamp, + availability.endTimestamp, + availability.comment + FROM availability + WHERE availability.userId = $1 + AND availability.starttimestamp::date >= $2 + AND availability.endtimestamp::date <= $3; + "##, + user_id, + date_range.0, + date_range.1 + ) + .fetch_all(pool) + .await?; + + let availabilities = records + .iter() + .map(|r| Availability { + id: r.id, + user_id: r.userid, + user: None, + start: r.starttimestamp.naive_utc(), + end: r.endtimestamp.naive_utc(), + comment: r.comment.clone(), + }) + .collect(); + + Ok(availabilities) + } + pub async fn find_adjacent_by_time_for_user( pool: &PgPool, start: &NaiveDateTime, diff --git a/db/src/models/event.rs b/db/src/models/event.rs index 5b28f729..94f6d05c 100644 --- a/db/src/models/event.rs +++ b/db/src/models/event.rs @@ -95,6 +95,73 @@ impl Event { Ok(events) } + pub async fn read_all_by_daterange_and_area_including_location( + pool: &PgPool, + date_range: (&NaiveDate, &NaiveDate), + area_id: i32, + ) -> Result> { + let records = query!( + r#" + SELECT + event.id AS eventId, + event.startTimestamp, + event.endTimestamp, + event.name, + event.locationId, + event.voluntaryWachhabender, + event.voluntaryFuehrungsassistent, + event.amountOfPosten, + event.clothing, + event.canceled, + event.note, + location.id, + location.name AS locationName, + location.areaId AS locationAreaId, + clothing.id AS clothingId, + clothing.name AS clothingName + FROM event + JOIN location ON event.locationId = location.id + JOIN clothing ON event.clothing = clothing.id + WHERE starttimestamp::date >= $1 + AND starttimestamp::date <= $2 + AND location.areaId = $3; + "#, + date_range.0, + date_range.1, + area_id + ) + .fetch_all(pool) + .await?; + + let events = records + .into_iter() + .map(|record| Event { + id: record.eventid, + start: record.starttimestamp.naive_utc(), + end: record.endtimestamp.naive_utc(), + name: record.name.to_string(), + location_id: record.locationid, + location: Some(Location { + id: record.locationid, + name: record.locationname.to_string(), + area_id: record.locationareaid, + area: None, + }), + voluntary_wachhabender: record.voluntarywachhabender, + voluntary_fuehrungsassistent: record.voluntaryfuehrungsassistent, + amount_of_posten: record.amountofposten, + clothing: Clothing { + id: record.clothingid, + name: record.clothingname, + }, + canceled: record.canceled, + note: record.note, + }) + .collect(); + + Ok(events) + } + pub async fn read_by_id_including_location(pool: &PgPool, id: i32) -> Result> { let record = query!( r#" diff --git a/web/src/endpoints/availability/get_overview.rs b/web/src/endpoints/availability/get_overview.rs new file mode 100644 index 00000000..b3309f86 --- /dev/null +++ b/web/src/endpoints/availability/get_overview.rs @@ -0,0 +1,50 @@ +use actix_web::{web, Responder}; +use askama::Template; +use chrono::{Months, Utc}; +use sqlx::PgPool; + +use crate::{ + filters, + utils::{ + ApplicationError, + DateTimeFormat::{DayMonthYearHourMinute, HourMinute, WeekdayDayMonthYear}, + TemplateResponse, + }, +}; +use brass_db::models::{Assignment, Availability, Event, Function, Role, User}; + +#[derive(Template)] +#[template(path = "overview.html")] +struct OverviewTemplate { + user: User, + events: Vec, + availabilities: Vec, +} + +#[actix_web::get("/")] +async fn get( + user: web::ReqData, + pool: web::Data, +) -> Result { + let today = Utc::now().date_naive(); + let next_month = today.checked_add_months(Months::new(1)).unwrap(); + + let events = Event::read_all_by_daterange_and_area_including_location( + pool.get_ref(), + (&today, &next_month), + user.area_id, + ) + .await?; + + let availabilities = + Availability::read_by_user_and_daterange(pool.get_ref(), user.id, (&today, &next_month)) + .await?; + + let template = OverviewTemplate { + user: user.into_inner(), + events, + availabilities, + }; + + Ok(template.to_response()?) +} diff --git a/web/src/endpoints/availability/mod.rs b/web/src/endpoints/availability/mod.rs index d1632d81..e633d2fd 100644 --- a/web/src/endpoints/availability/mod.rs +++ b/web/src/endpoints/availability/mod.rs @@ -11,6 +11,7 @@ use brass_db::models::{Role, User}; pub mod delete; pub mod get_calendar; pub mod get_new; +pub mod get_overview; pub mod get_update; pub mod post_new; pub mod post_update; diff --git a/web/src/endpoints/mod.rs b/web/src/endpoints/mod.rs index 92c4ade0..d413b2f3 100644 --- a/web/src/endpoints/mod.rs +++ b/web/src/endpoints/mod.rs @@ -60,6 +60,7 @@ pub fn init(cfg: &mut ServiceConfig) { cfg.service(availability::get_update::get); cfg.service(availability::post_new::post); cfg.service(availability::post_update::post); + cfg.service(availability::get_overview::get); cfg.service(events::put_cancelation::put_cancel); cfg.service(events::put_cancelation::put_uncancel); diff --git a/web/templates/overview.html b/web/templates/overview.html new file mode 100644 index 00000000..fb4a6675 --- /dev/null +++ b/web/templates/overview.html @@ -0,0 +1,9 @@ +{% extends "nav.html" %} + +{% block content %} +
+
+ Übersicht +
+
+{% endblock %}