diff --git a/db/.sqlx/query-10b4b80f351b66ac5e778a3031288ac5dc66efd0a66b38b7e30f4c954df91bdf.json b/db/.sqlx/query-65367483e39e07cd0aa142f9bb76c7a5d6dd0611e6b41edd5a593c9f955b5d04.json similarity index 94% rename from db/.sqlx/query-10b4b80f351b66ac5e778a3031288ac5dc66efd0a66b38b7e30f4c954df91bdf.json rename to db/.sqlx/query-65367483e39e07cd0aa142f9bb76c7a5d6dd0611e6b41edd5a593c9f955b5d04.json index 940e6e4b..88b15e01 100644 --- a/db/.sqlx/query-10b4b80f351b66ac5e778a3031288ac5dc66efd0a66b38b7e30f4c954df91bdf.json +++ b/db/.sqlx/query-65367483e39e07cd0aa142f9bb76c7a5d6dd0611e6b41edd5a593c9f955b5d04.json @@ -1,6 +1,6 @@ { "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 ", + "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 ORDER BY event.starttimestamp;\n ", "describe": { "columns": [ { @@ -110,5 +110,5 @@ false ] }, - "hash": "10b4b80f351b66ac5e778a3031288ac5dc66efd0a66b38b7e30f4c954df91bdf" + "hash": "65367483e39e07cd0aa142f9bb76c7a5d6dd0611e6b41edd5a593c9f955b5d04" } diff --git a/db/.sqlx/query-f60053118df6a791d31fa258ee3737881f8f97ca41cbebd92eb22c967292d2ee.json b/db/.sqlx/query-66638de4a321ba610206a9f5c237cb17eb5221c1dbe4d4c5e83167b2d2807db4.json similarity index 88% rename from db/.sqlx/query-f60053118df6a791d31fa258ee3737881f8f97ca41cbebd92eb22c967292d2ee.json rename to db/.sqlx/query-66638de4a321ba610206a9f5c237cb17eb5221c1dbe4d4c5e83167b2d2807db4.json index 20d9da9e..dd497d36 100644 --- a/db/.sqlx/query-f60053118df6a791d31fa258ee3737881f8f97ca41cbebd92eb22c967292d2ee.json +++ b/db/.sqlx/query-66638de4a321ba610206a9f5c237cb17eb5221c1dbe4d4c5e83167b2d2807db4.json @@ -1,6 +1,6 @@ { "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 ", + "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 ORDER BY availability.starttimestamp;\n ", "describe": { "columns": [ { @@ -44,5 +44,5 @@ true ] }, - "hash": "f60053118df6a791d31fa258ee3737881f8f97ca41cbebd92eb22c967292d2ee" + "hash": "66638de4a321ba610206a9f5c237cb17eb5221c1dbe4d4c5e83167b2d2807db4" } diff --git a/db/.sqlx/query-6788747f70812d6a87833d821c9845f59b4338bc42a40050a68736ba30d937d5.json b/db/.sqlx/query-6788747f70812d6a87833d821c9845f59b4338bc42a40050a68736ba30d937d5.json new file mode 100644 index 00000000..afbbfd95 --- /dev/null +++ b/db/.sqlx/query-6788747f70812d6a87833d821c9845f59b4338bc42a40050a68736ba30d937d5.json @@ -0,0 +1,59 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n assignment.eventId,\n assignment.availabilityId,\n assignment.function AS \"function: Function\",\n assignment.startTimestamp,\n assignment.endTimestamp\n FROM assignment\n JOIN availability ON assignment.availabilityId = availability.id\n WHERE assignment.starttimestamp::date >= $1\n AND assignment.starttimestamp::date <= $2\n AND availability.userId = $3\n ORDER BY assignment.starttimestamp;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "eventid", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "availabilityid", + "type_info": "Int4" + }, + { + "ordinal": 2, + "name": "function: Function", + "type_info": { + "Custom": { + "name": "function", + "kind": { + "Enum": [ + "posten", + "fuehrungsassistent", + "wachhabender" + ] + } + } + } + }, + { + "ordinal": 3, + "name": "starttimestamp", + "type_info": "Timestamptz" + }, + { + "ordinal": 4, + "name": "endtimestamp", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Date", + "Date", + "Int4" + ] + }, + "nullable": [ + false, + false, + false, + false, + false + ] + }, + "hash": "6788747f70812d6a87833d821c9845f59b4338bc42a40050a68736ba30d937d5" +} diff --git a/db/src/models/assignment.rs b/db/src/models/assignment.rs index ba1981cb..90009407 100644 --- a/db/src/models/assignment.rs +++ b/db/src/models/assignment.rs @@ -1,4 +1,4 @@ -use chrono::NaiveDateTime; +use chrono::{NaiveDate, NaiveDateTime}; use sqlx::{PgPool, query}; use super::{AssignmentChangeset, Function, Result}; @@ -101,6 +101,47 @@ impl Assignment { Ok(assignemnets) } + pub async fn read_all_by_daterange_and_user( + pool: &PgPool, + date_range: (&NaiveDate, &NaiveDate), + user_id: i32, + ) -> Result> { + let records = query!( + r##" + SELECT + assignment.eventId, + assignment.availabilityId, + assignment.function AS "function: Function", + assignment.startTimestamp, + assignment.endTimestamp + FROM assignment + JOIN availability ON assignment.availabilityId = availability.id + WHERE assignment.starttimestamp::date >= $1 + AND assignment.starttimestamp::date <= $2 + AND availability.userId = $3 + ORDER BY assignment.starttimestamp; + "##, + date_range.0, + date_range.1, + user_id + ) + .fetch_all(pool) + .await?; + + let assignemnets = records + .iter() + .map(|r| Assignment { + event_id: r.eventid, + availability_id: r.availabilityid, + function: r.function, + start: r.starttimestamp.naive_utc(), + end: r.endtimestamp.naive_utc(), + }) + .collect(); + + Ok(assignemnets) + } + pub async fn read( pool: &PgPool, event_id: i32, diff --git a/db/src/models/availability.rs b/db/src/models/availability.rs index b56d71cf..7fbcb1da 100644 --- a/db/src/models/availability.rs +++ b/db/src/models/availability.rs @@ -357,7 +357,8 @@ impl Availability { FROM availability WHERE availability.userId = $1 AND availability.starttimestamp::date >= $2 - AND availability.endtimestamp::date <= $3; + AND availability.endtimestamp::date <= $3 + ORDER BY availability.starttimestamp; "##, user_id, date_range.0, diff --git a/db/src/models/event.rs b/db/src/models/event.rs index 94f6d05c..305616b3 100644 --- a/db/src/models/event.rs +++ b/db/src/models/event.rs @@ -124,7 +124,8 @@ impl Event { JOIN clothing ON event.clothing = clothing.id WHERE starttimestamp::date >= $1 AND starttimestamp::date <= $2 - AND location.areaId = $3; + AND location.areaId = $3 + ORDER BY event.starttimestamp; "#, date_range.0, date_range.1, diff --git a/web/src/endpoints/availability/get_overview.rs b/web/src/endpoints/availability/get_overview.rs index b3309f86..773502dc 100644 --- a/web/src/endpoints/availability/get_overview.rs +++ b/web/src/endpoints/availability/get_overview.rs @@ -7,11 +7,11 @@ use crate::{ filters, utils::{ ApplicationError, - DateTimeFormat::{DayMonthYearHourMinute, HourMinute, WeekdayDayMonthYear}, + DateTimeFormat::{HourMinute, WeekdayDayMonthYearHourMinute}, TemplateResponse, }, }; -use brass_db::models::{Assignment, Availability, Event, Function, Role, User}; +use brass_db::models::{Assignment, Availability, Event, Role, User}; #[derive(Template)] #[template(path = "overview.html")] @@ -19,6 +19,7 @@ struct OverviewTemplate { user: User, events: Vec, availabilities: Vec, + assignments: Vec<(Assignment, String)>, } #[actix_web::get("/")] @@ -28,22 +29,36 @@ async fn get( ) -> Result { let today = Utc::now().date_naive(); let next_month = today.checked_add_months(Months::new(1)).unwrap(); + let date_range = (&today, &next_month); let events = Event::read_all_by_daterange_and_area_including_location( pool.get_ref(), - (&today, &next_month), + date_range, user.area_id, ) .await?; let availabilities = - Availability::read_by_user_and_daterange(pool.get_ref(), user.id, (&today, &next_month)) - .await?; + Availability::read_by_user_and_daterange(pool.get_ref(), user.id, date_range).await?; + + let assignments = + Assignment::read_all_by_daterange_and_user(pool.get_ref(), date_range, user.id) + .await? + .into_iter() + .map(|a| { + if let Some(e) = events.iter().find(|e| e.id == a.event_id) { + (a, e.name.clone()) + } else { + (a, String::new()) + } + }) + .collect(); let template = OverviewTemplate { user: user.into_inner(), events, availabilities, + assignments, }; Ok(template.to_response()?) diff --git a/web/src/utils/date_time_format.rs b/web/src/utils/date_time_format.rs index a71cdb15..e3cd6d09 100644 --- a/web/src/utils/date_time_format.rs +++ b/web/src/utils/date_time_format.rs @@ -8,6 +8,7 @@ pub enum DateTimeFormat { HourMinute, WeekdayDayMonth, WeekdayDayMonthYear, + WeekdayDayMonthYearHourMinute, } impl From for &'static str { @@ -21,6 +22,7 @@ impl From for &'static str { DateTimeFormat::HourMinute => "%H:%M", DateTimeFormat::WeekdayDayMonth => "%A, %d.%m.", DateTimeFormat::WeekdayDayMonthYear => "%A, %d.%m.%Y", + DateTimeFormat::WeekdayDayMonthYearHourMinute => "%A, %d.%m.%Y %H:%M", } } } diff --git a/web/templates/overview.html b/web/templates/overview.html index fb4a6675..b0bb02ae 100644 --- a/web/templates/overview.html +++ b/web/templates/overview.html @@ -1,9 +1,95 @@ {% extends "nav.html" %} {% block content %} -
+
- Übersicht +

Übersicht

+

geplante Veranstaltungen

+

in den nächsten 31 Tagen

+ {% if events.len() == 0 %} +
+ Keine Veranstaltungen für diesen Zeitraum geplant. +
+ {% else %} +
+ {% for e in events %} +
+ + {{ e.name }}   {{ e.start|fmt_datetime(WeekdayDayMonthYearHourMinute) }} - {{ + e.end|fmt_datetime(HourMinute) }} + + + + + + im Kalender anzeigen + +
+ {% endfor %} +
+ {% endif %} + +

Deine Verfügbarkeiten

+

in den nächsten 31 Tagen

+ {% if availabilities.len() == 0 %} +
+ Keine Verfügbarkeiten für diesen Zeitraum hinterlegt. +
+ {% else %} +
+ {% for a in availabilities %} +
+ + {{ a.start|fmt_datetime(WeekdayDayMonthYearHourMinute) }} - {{ + a.end|fmt_datetime(HourMinute) }} {% if let Some(comment) = a.comment %}  Kommentar:   {{ comment }} + {% endif %} + + +
+ {% endfor %} +
+ {% endif %} + +

Deine Einteilungen

+

in den nächsten 31 Tagen

+ {% if assignments.len() == 0 %} +
+ Keine Einteilungen für diesen Zeitraum vorhanden. +
+ {% else %} +
+ {% for (a, event_name) in assignments %} +
+ + {{ a.start|fmt_datetime(WeekdayDayMonthYearHourMinute) }} - {{ + a.end|fmt_datetime(HourMinute) }} bei {{ event_name }} als {{ a.function }} + + + + + + im Kalender anzeigen + +
+ {% endfor %} +
+ {% endif %} +
{% endblock %}