diff --git a/.sqlx/query-70850ec3f7c519c1fc104fead6a44d07ba76023567bc6ea0eec2267d1c592479.json b/.sqlx/query-70850ec3f7c519c1fc104fead6a44d07ba76023567bc6ea0eec2267d1c592479.json new file mode 100644 index 00000000..c7f56058 --- /dev/null +++ b/.sqlx/query-70850ec3f7c519c1fc104fead6a44d07ba76023567bc6ea0eec2267d1c592479.json @@ -0,0 +1,46 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT location.id AS locationId, location.name, location.areaId, area.id, area.name AS areaName FROM location JOIN area ON location.areaId = area.id WHERE areaId = $1;", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "locationid", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "name", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "areaid", + "type_info": "Int4" + }, + { + "ordinal": 3, + "name": "id", + "type_info": "Int4" + }, + { + "ordinal": 4, + "name": "areaname", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Int4" + ] + }, + "nullable": [ + false, + false, + false, + false, + false + ] + }, + "hash": "70850ec3f7c519c1fc104fead6a44d07ba76023567bc6ea0eec2267d1c592479" +} diff --git a/Cargo.lock b/Cargo.lock index 01f28791..dd1f99ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1337,6 +1337,7 @@ version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "661cb0601b5f4050d1e65452c5b0ea555c0b3e88fb5ed7855906adc6c42523ef" dependencies = [ + "chrono", "deunicode", "rand", ] diff --git a/web/Cargo.toml b/web/Cargo.toml index 26098661..3149cae8 100644 --- a/web/Cargo.toml +++ b/web/Cargo.toml @@ -41,4 +41,4 @@ change-detection = "1.2.0" [dev-dependencies] insta = "1.41.1" -fake = "3.0.1" +fake = { version = "3.0.1", features = ["chrono"]} diff --git a/web/snapshots/brass_web__endpoints__events__get_edit__inner_produces_template.snap b/web/snapshots/brass_web__endpoints__events__get_edit__inner_produces_template.snap new file mode 100644 index 00000000..f00f3a92 --- /dev/null +++ b/web/snapshots/brass_web__endpoints__events__get_edit__inner_produces_template.snap @@ -0,0 +1,158 @@ +--- +source: web/src/endpoints/events/get_edit.rs +expression: body +snapshot_kind: text +--- +
+
+ +
+

Event 'Vorstellung' bearbeiten

+ + + + +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+ +
+
+ +
+
+
+ +
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+ +
+
+
+ +
+ +
+ +
+
+
+ +
+
+ +
+
+
+ +
+ +
+ +
+
+
+ +
+
+ +
+
+
+ +
+ +
+ +
+
+
+ +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+ +
+
+ Zurück +
+
+
+
+ +
+
+
diff --git a/web/src/endpoints/availability/get_update.rs b/web/src/endpoints/availability/get_update.rs index 131736a5..669e5786 100644 --- a/web/src/endpoints/availability/get_update.rs +++ b/web/src/endpoints/availability/get_update.rs @@ -26,7 +26,7 @@ pub async fn get( return Ok(HttpResponse::NotFound().finish()); }; - if availabillity.user_id == user.id { + if availabillity.user_id != user.id { return Err(ApplicationError::Unauthorized); } diff --git a/web/src/endpoints/events/get_edit.rs b/web/src/endpoints/events/get_edit.rs index 0ef73107..31451ad6 100644 --- a/web/src/endpoints/events/get_edit.rs +++ b/web/src/endpoints/events/get_edit.rs @@ -1,7 +1,15 @@ use actix_web::{web, HttpResponse, Responder}; +use brass_macros::db_test; use rinja::Template; use sqlx::PgPool; +#[cfg(test)] +use crate::utils::test_helper::{ + assert_snapshot, read_body, test_get, DbTestContext, RequestConfig, StatusCode, +}; +#[cfg(test)] +use chrono::{NaiveDate, NaiveTime}; + use crate::{ endpoints::{events::NewEventTemplate, IdPath}, models::{Assignment, Event, Function, Location, Role, User}, @@ -22,11 +30,11 @@ pub async fn get( return Ok(HttpResponse::NotFound().finish()); }; - let locations = if user.role == Role::Admin { - Location::read_all_including_area(pool.get_ref()).await? - } else { - Location::read_by_area(pool.get_ref(), user.area_id).await? - }; + let locations = Location::read_by_area_including_area( + pool.get_ref(), + event.location.as_ref().unwrap().area_id, + ) + .await?; let assignments = Assignment::read_all_by_event(pool.get_ref(), event.id).await?; @@ -49,3 +57,62 @@ pub async fn get( Ok(HttpResponse::Ok().body(template.render()?)) } + +#[db_test] +async fn produces_template(context: &DbTestContext) { + //Location::create(&context.db_pool, &Industry().fake::(), 1) + // .await + // .unwrap(); + // + //let date: NaiveDate = Date().fake(); + //let time: NaiveTime = Time().fake(); + //let words: Vec = Words(3..5).fake(); + //Event::create( + // &context.db_pool, + // &date, + // &time, + // &time, + // &words.join(" "), + // 1, + // false, + // false, + // 2, + // &Word().fake(), + // None, + //) + //.await + //.unwrap(); + Location::create(&context.db_pool, "Hauptbahnhof", 1) + .await + .unwrap(); + + Event::create( + &context.db_pool, + &NaiveDate::parse_from_str("2025-01-01", "%F").unwrap(), + &NaiveTime::parse_from_str("08:00", "%R").unwrap(), + &NaiveTime::parse_from_str("10:00", "%R").unwrap(), + &"Vorstellung".to_string(), + 1, + false, + false, + 2, + &"Tuchuniform".to_string(), + None, + ) + .await + .unwrap(); + + let app = context.app().await; + let config = RequestConfig { + uri: "/events/1/edit".to_string(), + role: Role::Admin, + function: crate::models::Function::Posten, + user_area: 1, + }; + let response = test_get(&context.db_pool, app, &config).await; + + assert_eq!(StatusCode::OK, response.status()); + + let body = read_body(response).await; + assert_snapshot!(body); +} diff --git a/web/src/endpoints/events/mod.rs b/web/src/endpoints/events/mod.rs index f7ed6ec5..b7f7d995 100644 --- a/web/src/endpoints/events/mod.rs +++ b/web/src/endpoints/events/mod.rs @@ -1,3 +1,4 @@ +use crate::filters; use chrono::NaiveDate; use rinja::Template; @@ -9,7 +10,8 @@ pub mod get_plan; pub mod post_new; #[derive(Template)] -#[template(path = "events/new_or_edit.html")] +#[cfg_attr(not(test), template(path = "events/new_or_edit.html"))] +#[cfg_attr(test, template(path = "events/new_or_edit.html", block = "content"))] pub struct NewEventTemplate { user: User, date: NaiveDate, diff --git a/web/src/endpoints/mod.rs b/web/src/endpoints/mod.rs index 83067704..575a0889 100644 --- a/web/src/endpoints/mod.rs +++ b/web/src/endpoints/mod.rs @@ -59,6 +59,7 @@ pub fn init(cfg: &mut ServiceConfig) { cfg.service(events::get_new::get); cfg.service(events::post_new::post); cfg.service(events::get_plan::get); + cfg.service(events::get_edit::get); cfg.service(assignment::post_new::post); cfg.service(assignment::delete::delete); diff --git a/web/src/models/location.rs b/web/src/models/location.rs index 82c2bcc1..449ecf7f 100644 --- a/web/src/models/location.rs +++ b/web/src/models/location.rs @@ -43,6 +43,27 @@ impl Location { Ok(locations) } + pub async fn read_by_area_including_area(pool: &PgPool, area_id: i32) -> Result> { + let records = query!("SELECT location.id AS locationId, location.name, location.areaId, area.id, area.name AS areaName FROM location JOIN area ON location.areaId = area.id WHERE areaId = $1;", area_id) + .fetch_all(pool) + .await?; + + let locations = records + .iter() + .map(|lr| Location { + id: lr.id, + name: lr.name.to_string(), + area_id: lr.areaid, + area: Some(Area { + id: lr.id, + name: lr.areaname.to_string() + }), + }) + .collect(); + + Ok(locations) + } + pub async fn read_all(pool: &PgPool) -> Result> { let records = query!("SELECT * FROM location").fetch_all(pool).await?; diff --git a/web/templates/events/new_or_edit.html b/web/templates/events/new_or_edit.html index 57020a45..43d0e923 100644 --- a/web/templates/events/new_or_edit.html +++ b/web/templates/events/new_or_edit.html @@ -3,142 +3,181 @@ {% block content %}
-
-

Neues Event anlegen für den {{ date.format("%d.%m.%Y") }}

+ {% if let Some(event) = event %} + +

Event '{{ event.name }}' bearbeiten

+ {% else %} + +

Neues Event anlegen für den {{ date.format("%d.%m.%Y") }}

+ {% endif %} - + -
-
- -
-
-
-
- -
+
+
+
-
-
- -
-
- -
-
-
- -
-
- -
-
-
- -
-
- -
-
-
-
-
- +
+
+
+
-
-
-
- -
-
-
-
- +
+
+ +
+
+ {% let f = "%H:%M" %} +
+ +
+
+
-
-
-
- -
-
-
-
- +
+
+ +
+
+
+
+
+ +
+
-
-
-
- -
-
-
-
- +
+
+ +
+
+
+ {% let wh_disabled = event.is_some() && is_wachhabender_planned %} +
+ +
+ {% if wh_disabled %} +

+ Keine Änderung möglich, da ein Wachhabender bereits eingeplant ist. Diesen zuerst entplanen! +

+ {% endif %}
-
-
-
- -
-
-
-
- +
+
+ +
+
+
+ {% let fa_disabled = event.is_some() && is_fuehrungsassistent_planned %} +
+ +
+ {% if fa_disabled %} +

+ Keine Änderung möglich, da ein Führungsassistent bereits eingeplant ist. Diesen zuerst entplanen! +

+ {% endif %}
-
-
-
- -
-
-
-
- +
+
+ +
+
+
+ {% let posten_planned = event.is_some() && amount_of_planned_posten > 0 %} +
+ +
+ {% if posten_planned %} +

+ Mindestens {{ amount_of_planned_posten }} Posten, da bereits diese Anzahl eingeplant ist. Zum verringern + diese erst entplanen! +

+ {% endif %}
-
-
-
-
-
-
- -
-
- Zurück +
+
+ +
+
+
+
+ +
-
- +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+ +
+
+ Zurück +
+
+
+
+ +
{% endblock %}