diff --git a/Cargo.lock b/Cargo.lock index 68210a0c..b170d0d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -379,60 +379,6 @@ dependencies = [ "password-hash", ] -[[package]] -name = "askama" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" -dependencies = [ - "askama_derive", - "askama_escape", - "humansize", - "num-traits", - "percent-encoding", -] - -[[package]] -name = "askama_actix" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4b0dd17cfe203b00ba3853a89fba459ecf24c759b738b244133330607c78e55" -dependencies = [ - "actix-web", - "askama", -] - -[[package]] -name = "askama_derive" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" -dependencies = [ - "askama_parser", - "basic-toml", - "mime", - "mime_guess", - "proc-macro2", - "quote", - "serde", - "syn", -] - -[[package]] -name = "askama_escape" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" - -[[package]] -name = "askama_parser" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" -dependencies = [ - "nom", -] - [[package]] name = "async-channel" version = "1.9.0" @@ -738,8 +684,6 @@ dependencies = [ "actix-web-static-files", "anyhow", "argon2", - "askama", - "askama_actix", "async-trait", "brass-config", "brass-macros", @@ -754,6 +698,7 @@ dependencies = [ "quick-xml", "rand", "regex", + "rinja", "serde", "serde_json", "sqlx", @@ -818,9 +763,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.3" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" +checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" dependencies = [ "jobserver", "libc", @@ -2568,6 +2513,47 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rinja" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dc4940d00595430b3d7d5a01f6222b5e5b51395d1120bdb28d854bb8abb17a5" +dependencies = [ + "humansize", + "itoa", + "percent-encoding", + "rinja_derive", +] + +[[package]] +name = "rinja_derive" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d9ed0146aef6e2825f1b1515f074510549efba38d71f4554eec32eb36ba18b" +dependencies = [ + "basic-toml", + "memchr", + "mime", + "mime_guess", + "proc-macro2", + "quote", + "rinja_parser", + "rustc-hash", + "serde", + "syn", +] + +[[package]] +name = "rinja_parser" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f9a866e2e00a7a1fb27e46e9e324a6f7c0e7edc4543cae1d38f4e4a100c610" +dependencies = [ + "memchr", + "nom", + "serde", +] + [[package]] name = "rsa" version = "0.9.7" @@ -2594,6 +2580,12 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" + [[package]] name = "rustc_version" version = "0.4.1" @@ -2716,9 +2708,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" [[package]] name = "serde" diff --git a/web/Cargo.toml b/web/Cargo.toml index f2270d35..3adcad9c 100644 --- a/web/Cargo.toml +++ b/web/Cargo.toml @@ -10,7 +10,8 @@ publish = false [dependencies] sqlx = { version = "^0.8", features = ["runtime-async-std-rustls", "postgres", "chrono"] } actix-web = { version = "4" } -askama = { version = "0.12.0", features = ["with-actix-web"] } +# askama = { version = "0.13.0", git = "https://github.com/rinja-rs/askama", branch = "main", features = ["with-actix-web"] } +# askama_actix = { git = "https://github.com/rinja-rs/askama", branch = "main" } serde = { version = "1.0.164", features = ["derive"] } argon2 = { version = "0.5.0", features = [ "std"]} anyhow = "1.0.71" @@ -19,7 +20,6 @@ actix-session = { version = "0.10.1", features = ["cookie-session"] } actix-identity = "0.8.0" chrono = { version = "0.4.33", features = ["serde", "now"] } actix-files = "0.6.5" -askama_actix = "0.14.0" futures-util = "0.3.30" serde_json = "1.0.114" pico-args = "0.5.0" @@ -36,6 +36,7 @@ regex = "1.11.1" brass-macros = { path = "../macros" } brass-config = { path = "../config" } actix-http = "3.9.0" +rinja = "0.3.5" [build-dependencies] built = "0.7.4" @@ -44,8 +45,5 @@ static-files = "0.2.1" [dev-dependencies] insta = "1.41.1" -# [dev-dependencies] -# brass-web = { path = "." } - # [profile.dev.package.askama_derive] # opt-level = 3 diff --git a/web/snapshots/brass_web__endpoints__area__get_new__inner_produces_template.snap b/web/snapshots/brass_web__endpoints__area__get_new__inner_produces_template.snap new file mode 100644 index 00000000..24b093ea --- /dev/null +++ b/web/snapshots/brass_web__endpoints__area__get_new__inner_produces_template.snap @@ -0,0 +1,56 @@ +--- +source: web/src/endpoints/area/get_new.rs +expression: body +snapshot_kind: text +--- +
+
+ +
+

Neuen Bereich anlegen

+ + +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+ +
+ +
+
+
+ +
+
+
diff --git a/web/src/endpoints/area/get_edit.rs b/web/src/endpoints/area/get_edit.rs index 1e58fd76..afb77c9a 100644 --- a/web/src/endpoints/area/get_edit.rs +++ b/web/src/endpoints/area/get_edit.rs @@ -1,5 +1,5 @@ use actix_web::{web, HttpResponse, Responder}; -use askama_actix::TemplateToResponse; +use rinja::Template; use sqlx::PgPool; use crate::{ @@ -24,7 +24,7 @@ async fn get( area: Some(area_in_db), }; - return Ok(template.to_response()); + return Ok(HttpResponse::Ok().body(template.render()?)) } else { return Ok(HttpResponse::NotFound().finish()); } diff --git a/web/src/endpoints/area/get_new.rs b/web/src/endpoints/area/get_new.rs index 6599bfd3..4cc98389 100644 --- a/web/src/endpoints/area/get_new.rs +++ b/web/src/endpoints/area/get_new.rs @@ -1,23 +1,23 @@ -use actix_web::{body::MessageBody, test::read_body, web, HttpResponse, Responder}; -use askama_actix::TemplateToResponse; -use brass_macros::db_test; -use insta::assert_snapshot; - use crate::{ endpoints::area::NewOrEditAreaTemplate, models::{Role, User}, - utils::test_helper::DbTestContext, + utils::ApplicationError, }; +use actix_web::{web, HttpResponse, Responder}; +use brass_macros::db_test; +use rinja::Template; #[cfg(test)] -use crate::utils::test_helper::{test_get, RequestConfig}; +use crate::utils::test_helper::{ + assert_snapshot, read_body, test_get, DbTestContext, RequestConfig, +}; #[cfg(test)] use actix_http::StatusCode; #[actix_web::get("/area/new")] -async fn get(user: web::ReqData) -> impl Responder { +async fn get(user: web::ReqData) -> Result { if user.role != Role::Admin { - return HttpResponse::Unauthorized().finish(); + return Err(ApplicationError::Unauthorized); } let template = NewOrEditAreaTemplate { @@ -25,7 +25,7 @@ async fn get(user: web::ReqData) -> impl Responder { area: None, }; - template.to_response() + Ok(HttpResponse::Ok().body(template.render()?)) } #[db_test] @@ -41,6 +41,6 @@ async fn produces_template(context: &DbTestContext) { assert_eq!(StatusCode::OK, response.status()); - let body = String::from_utf8(read_body(response).await.to_vec()).unwrap(); + let body = read_body(response).await; assert_snapshot!(body); } diff --git a/web/src/endpoints/area/mod.rs b/web/src/endpoints/area/mod.rs index 5a54fb0b..8c49a177 100644 --- a/web/src/endpoints/area/mod.rs +++ b/web/src/endpoints/area/mod.rs @@ -4,13 +4,14 @@ pub mod get_edit; pub mod post_edit; pub mod delete; -use askama::Template; +use rinja::Template; use serde::Deserialize; use crate::models::{Area, Role, User}; #[derive(Template)] -#[template(path = "area/new_or_edit.html")] +#[cfg_attr(not(test), template(path = "area/new_or_edit.html"))] +#[cfg_attr(test, template(path = "area/new_or_edit.html", block = "content"))] struct NewOrEditAreaTemplate { user: User, area: Option, diff --git a/web/src/endpoints/assignment/delete.rs b/web/src/endpoints/assignment/delete.rs index dd4e1c31..819aa2b6 100644 --- a/web/src/endpoints/assignment/delete.rs +++ b/web/src/endpoints/assignment/delete.rs @@ -1,5 +1,5 @@ use actix_web::{web, HttpResponse, Responder}; -use askama_actix::TemplateToResponse; +use rinja::Template; use serde::Deserialize; use sqlx::PgPool; @@ -61,5 +61,5 @@ pub async fn delete( further_wachhabender_required, }; - Ok(template.to_response()) + Ok(HttpResponse::Ok().body(template.render()?)) } diff --git a/web/src/endpoints/assignment/mod.rs b/web/src/endpoints/assignment/mod.rs index 2a3db9c2..36667edb 100644 --- a/web/src/endpoints/assignment/mod.rs +++ b/web/src/endpoints/assignment/mod.rs @@ -1,4 +1,4 @@ -use askama::Template; +use rinja::Template; use crate::{ filters, diff --git a/web/src/endpoints/assignment/post_new.rs b/web/src/endpoints/assignment/post_new.rs index 4aec4261..94f831d5 100644 --- a/web/src/endpoints/assignment/post_new.rs +++ b/web/src/endpoints/assignment/post_new.rs @@ -1,7 +1,5 @@ -use std::ops::AddAssign; - use actix_web::{web, HttpResponse, Responder}; -use askama_actix::TemplateToResponse; +use rinja::Template; use serde::Deserialize; use sqlx::PgPool; @@ -108,5 +106,5 @@ pub async fn post( further_wachhabender_required, }; - Ok(template.to_response()) + Ok(HttpResponse::Ok().body(template.render()?)) } diff --git a/web/src/endpoints/availability/get_new.rs b/web/src/endpoints/availability/get_new.rs index 51efd313..7a6e579c 100644 --- a/web/src/endpoints/availability/get_new.rs +++ b/web/src/endpoints/availability/get_new.rs @@ -1,10 +1,11 @@ -use actix_web::{web, Responder}; -use askama_actix::TemplateToResponse; +use actix_web::{web, HttpResponse, Responder}; use chrono::NaiveDate; +use rinja::Template; use serde::Deserialize; use crate::endpoints::availability::NewOrEditAvailabilityTemplate; use crate::models::User; +use crate::utils::ApplicationError; #[derive(Deserialize)] struct AvailabilityNewQuery { @@ -17,7 +18,7 @@ struct AvailabilityNewQuery { pub async fn get( user: web::ReqData, query: web::Query, -) -> impl Responder { +) -> Result { let template = NewOrEditAvailabilityTemplate { user: user.into_inner(), date: query.date, @@ -28,5 +29,5 @@ pub async fn get( comment: None, }; - template.to_response() + Ok(HttpResponse::Ok().body(template.render()?)) } diff --git a/web/src/endpoints/availability/get_overview.rs b/web/src/endpoints/availability/get_overview.rs index 509f88a5..680a76e4 100644 --- a/web/src/endpoints/availability/get_overview.rs +++ b/web/src/endpoints/availability/get_overview.rs @@ -1,8 +1,7 @@ -use crate::filters; +use crate::{filters, utils::ApplicationError}; use actix_web::{web, HttpResponse, Responder}; -use askama::Template; -use askama_actix::TemplateToResponse; use chrono::{NaiveDate, Utc}; +use rinja::Template; use serde::Deserialize; use sqlx::PgPool; @@ -30,18 +29,18 @@ async fn get( user: web::ReqData, pool: web::Data, query: web::Query, -) -> impl Responder { +) -> Result { let date = match query.date { Some(given_date) => given_date, None => Utc::now().date_naive(), }; - let areas = Area::read_all(pool.get_ref()).await.unwrap(); + let areas = Area::read_all(pool.get_ref()).await?; let selected_area = match query.area { Some(id) => { if !areas.iter().any(|a| a.id == id) { - return HttpResponse::BadRequest().finish(); + return Ok(HttpResponse::BadRequest().finish()); } Some(id) @@ -54,16 +53,14 @@ async fn get( date, query.area.unwrap_or(user.area_id), ) - .await - .unwrap(); + .await?; let availabillities = Availabillity::read_by_date_and_area_including_user( pool.get_ref(), date, query.area.unwrap_or(user.area_id), ) - .await - .unwrap(); + .await?; let template = CalendarTemplate { user: user.into_inner(), @@ -74,5 +71,5 @@ async fn get( availabillities, }; - template.to_response() + Ok(HttpResponse::Ok().body(template.render()?)) } diff --git a/web/src/endpoints/availability/get_update.rs b/web/src/endpoints/availability/get_update.rs index d5758c5f..131736a5 100644 --- a/web/src/endpoints/availability/get_update.rs +++ b/web/src/endpoints/availability/get_update.rs @@ -1,5 +1,5 @@ use actix_web::{web, HttpResponse, Responder}; -use askama_actix::TemplateToResponse; +use rinja::Template; use serde::Deserialize; use sqlx::PgPool; @@ -50,5 +50,5 @@ pub async fn get( comment: availabillity.comment.as_deref(), }; - Ok(template.to_response()) + Ok(HttpResponse::Ok().body(template.render()?)) } diff --git a/web/src/endpoints/availability/mod.rs b/web/src/endpoints/availability/mod.rs index 16b21b7b..d96667be 100644 --- a/web/src/endpoints/availability/mod.rs +++ b/web/src/endpoints/availability/mod.rs @@ -1,4 +1,4 @@ -use askama::Template; +use rinja::Template; use chrono::NaiveDate; use crate::filters; diff --git a/web/src/endpoints/events/get_new.rs b/web/src/endpoints/events/get_new.rs index 198d4f84..79739705 100644 --- a/web/src/endpoints/events/get_new.rs +++ b/web/src/endpoints/events/get_new.rs @@ -1,7 +1,6 @@ -use actix_web::{web, Responder}; -use askama::Template; -use askama_actix::TemplateToResponse; +use actix_web::{web, HttpResponse, Responder}; use chrono::NaiveDate; +use rinja::Template; use sqlx::PgPool; use crate::{ @@ -40,5 +39,5 @@ pub async fn get( locations, }; - Ok(template.to_response()) + Ok(HttpResponse::Ok().body(template.render()?)) } diff --git a/web/src/endpoints/events/get_plan.rs b/web/src/endpoints/events/get_plan.rs index b5717bc1..4f8c02df 100644 --- a/web/src/endpoints/events/get_plan.rs +++ b/web/src/endpoints/events/get_plan.rs @@ -1,6 +1,5 @@ use actix_web::{web, HttpResponse, Responder}; -use askama::Template; -use askama_actix::TemplateToResponse; +use rinja::Template; use sqlx::PgPool; use crate::{ @@ -61,5 +60,5 @@ pub async fn get( further_wachhabender_required, }; - Ok(template.to_response()) + Ok(HttpResponse::Ok().body(template.render()?)) } diff --git a/web/src/endpoints/export/get_availability.rs b/web/src/endpoints/export/get_availability.rs index 89ed014a..f7648982 100644 --- a/web/src/endpoints/export/get_availability.rs +++ b/web/src/endpoints/export/get_availability.rs @@ -1,9 +1,8 @@ use actix_web::{web, HttpResponse, Responder}; -use askama::Template; -use askama_actix::TemplateToResponse; +use rinja::Template; use sqlx::PgPool; -use crate::models::{Area, User, Role}; +use crate::{models::{Area, Role, User}, utils::ApplicationError}; #[derive(Template)] #[template(path = "export/availability.html")] @@ -16,13 +15,13 @@ struct AvailabilityExportTemplate { pub async fn get( user: web::ReqData, pool: web::Data -) -> impl Responder { +) -> Result { if user.role != Role::Admin && user.role != Role::AreaManager { - return HttpResponse::Unauthorized().finish(); + return Err(ApplicationError::Unauthorized); } let areas = if user.role == Role::Admin { - Some(Area::read_all(pool.get_ref()).await.unwrap()) + Some(Area::read_all(pool.get_ref()).await?) } else { None }; @@ -32,5 +31,5 @@ pub async fn get( areas }; - return template.to_response(); + Ok(HttpResponse::Ok().body(template.render()?)) } diff --git a/web/src/endpoints/export/get_availability_data.rs b/web/src/endpoints/export/get_availability_data.rs index bfa3aaa7..8729cbc2 100644 --- a/web/src/endpoints/export/get_availability_data.rs +++ b/web/src/endpoints/export/get_availability_data.rs @@ -40,9 +40,10 @@ pub async fn get( user: Identity, query: web::Query, ) -> impl Responder { + // TODO: rerwrite let current_user = User::read_by_id(pool.get_ref(), user.id().unwrap().parse().unwrap()) .await - .unwrap(); + .unwrap().unwrap(); if current_user.role != Role::Admin && current_user.role != Role::AreaManager { return HttpResponse::Unauthorized().finish(); diff --git a/web/src/endpoints/imprint.rs b/web/src/endpoints/imprint.rs index cee38c27..07dc2c3b 100644 --- a/web/src/endpoints/imprint.rs +++ b/web/src/endpoints/imprint.rs @@ -1,14 +1,15 @@ -use actix_web::Responder; -use askama::Template; -use askama_actix::TemplateToResponse; +use actix_web::{HttpResponse, Responder}; +use rinja::Template; + +use crate::utils::ApplicationError; #[derive(Template)] #[template(path = "imprint.html")] struct ImprintTemplate {} #[actix_web::get("/imprint")] -pub async fn get_imprint() -> impl Responder { +pub async fn get_imprint() -> Result { let template = ImprintTemplate {}; - template.to_response() + Ok(HttpResponse::Ok().body(template.render()?)) } diff --git a/web/src/endpoints/location/get_edit.rs b/web/src/endpoints/location/get_edit.rs index d3573511..6776c4e7 100644 --- a/web/src/endpoints/location/get_edit.rs +++ b/web/src/endpoints/location/get_edit.rs @@ -1,5 +1,5 @@ use actix_web::{web, HttpResponse, Responder}; -use askama_actix::TemplateToResponse; +use rinja::Template; use sqlx::PgPool; use crate::{ @@ -38,5 +38,5 @@ pub async fn get( location: Some(location), }; - Ok(template.to_response()) + Ok(HttpResponse::Ok().body(template.render()?)) } diff --git a/web/src/endpoints/location/get_new.rs b/web/src/endpoints/location/get_new.rs index e14c5de4..94842eac 100644 --- a/web/src/endpoints/location/get_new.rs +++ b/web/src/endpoints/location/get_new.rs @@ -1,26 +1,33 @@ use actix_web::{web, HttpResponse, Responder}; -use askama_actix::TemplateToResponse; +use rinja::Template; use sqlx::PgPool; -use crate::{endpoints::location::LocationTemplate, models::{Area, Role, User}}; +use crate::{ + endpoints::location::LocationTemplate, + models::{Area, Role, User}, + utils::ApplicationError, +}; #[actix_web::get("/locations/new")] -pub async fn get(user: web::ReqData, pool: web::Data) -> impl Responder { - if user.role == Role::AreaManager || user.role == Role::Admin { - let mut areas = None; - - if user.role == Role::Admin { - areas = Some(Area::read_all(pool.get_ref()).await.unwrap()); - } - - let template = LocationTemplate { - user: user.into_inner(), - areas, - location: None - }; - - return template.to_response(); +pub async fn get( + user: web::ReqData, + pool: web::Data, +) -> Result { + if user.role != Role::AreaManager && user.role != Role::Admin { + return Err(ApplicationError::Unauthorized); } - return HttpResponse::Unauthorized().finish(); + let mut areas = None; + + if user.role == Role::Admin { + areas = Some(Area::read_all(pool.get_ref()).await?); + } + + let template = LocationTemplate { + user: user.into_inner(), + areas, + location: None, + }; + + Ok(HttpResponse::Ok().body(template.render()?)) } diff --git a/web/src/endpoints/location/get_overview.rs b/web/src/endpoints/location/get_overview.rs index 5a513144..edb03fcf 100644 --- a/web/src/endpoints/location/get_overview.rs +++ b/web/src/endpoints/location/get_overview.rs @@ -1,9 +1,11 @@ use actix_web::{web, HttpResponse, Responder}; -use askama::Template; -use askama_actix::TemplateToResponse; +use rinja::Template; use sqlx::PgPool; -use crate::models::{Area, Location, Role, User}; +use crate::{ + models::{Area, Location, Role, User}, + utils::ApplicationError, +}; #[derive(Template)] #[template(path = "location/overview.html")] @@ -13,45 +15,45 @@ pub struct LocationsTemplate { } #[actix_web::get("/locations")] -pub async fn get(user: web::ReqData, pool: web::Data) -> impl Responder { - if user.role == Role::AreaManager || user.role == Role::Admin { - let mut locations; - let mut grouped_locations: Vec<(Area, Vec)>; - - if user.role == Role::Admin { - locations = Location::read_all(pool.get_ref()).await.unwrap(); - grouped_locations = Area::read_all(pool.get_ref()) - .await - .unwrap() - .into_iter() - .map(|a| (a, Vec::new())) - .collect(); - } else { - locations = Location::read_by_area(pool.get_ref(), user.area_id) - .await - .unwrap(); - let area = Area::read_by_id(pool.get_ref(), user.area_id) - .await - .unwrap().unwrap(); - - grouped_locations = vec![(area, Vec::new())]; - } - - for entry in grouped_locations.iter_mut() { - let (mut locations_in_this_area, rest): (Vec<_>, Vec<_>) = - locations.into_iter().partition(|l| l.area_id == entry.0.id); - locations = rest; - - entry.1.append(&mut locations_in_this_area); - } - - let template = LocationsTemplate { - user: user.into_inner(), - grouped_locations, - }; - - return template.to_response(); +pub async fn get( + user: web::ReqData, + pool: web::Data, +) -> Result { + if user.role != Role::AreaManager && user.role != Role::Admin { + return Err(ApplicationError::Unauthorized); } - return HttpResponse::Unauthorized().finish(); + let mut locations; + let mut grouped_locations: Vec<(Area, Vec)>; + + if user.role == Role::Admin { + locations = Location::read_all(pool.get_ref()).await.unwrap(); + grouped_locations = Area::read_all(pool.get_ref()) + .await? + .into_iter() + .map(|a| (a, Vec::new())) + .collect(); + } else { + locations = Location::read_by_area(pool.get_ref(), user.area_id).await?; + let area = Area::read_by_id(pool.get_ref(), user.area_id) + .await? + .unwrap(); + + grouped_locations = vec![(area, Vec::new())]; + } + + for entry in grouped_locations.iter_mut() { + let (mut locations_in_this_area, rest): (Vec<_>, Vec<_>) = + locations.into_iter().partition(|l| l.area_id == entry.0.id); + locations = rest; + + entry.1.append(&mut locations_in_this_area); + } + + let template = LocationsTemplate { + user: user.into_inner(), + grouped_locations, + }; + + Ok(HttpResponse::Ok().body(template.render()?)) } diff --git a/web/src/endpoints/location/mod.rs b/web/src/endpoints/location/mod.rs index 0a6dc649..2c831ffd 100644 --- a/web/src/endpoints/location/mod.rs +++ b/web/src/endpoints/location/mod.rs @@ -1,4 +1,4 @@ -use askama::Template; +use rinja::Template; use serde::Deserialize; use crate::models::{Area, Location, Role, User}; diff --git a/web/src/endpoints/user/delete.rs b/web/src/endpoints/user/delete.rs index e1a2bbc8..ce5fb9df 100644 --- a/web/src/endpoints/user/delete.rs +++ b/web/src/endpoints/user/delete.rs @@ -16,7 +16,9 @@ pub async fn delete( return Err(ApplicationError::Unauthorized); } - let user_in_db = User::read_by_id(pool.get_ref(), path.id).await?; + let Some(user_in_db) = User::read_by_id(pool.get_ref(), path.id).await? else { + return Ok(HttpResponse::NotFound().finish()); + }; if user.role == Role::AreaManager && user.area_id != user_in_db.area_id { return Err(ApplicationError::Unauthorized); diff --git a/web/src/endpoints/user/get_changepassword.rs b/web/src/endpoints/user/get_changepassword.rs index 8e508012..b26e22da 100644 --- a/web/src/endpoints/user/get_changepassword.rs +++ b/web/src/endpoints/user/get_changepassword.rs @@ -1,16 +1,15 @@ -use actix_web::{web, Responder}; -use askama::Template; -use askama_actix::TemplateToResponse; +use actix_web::{web, HttpResponse, Responder}; +use rinja::Template; -use crate::models::User; +use crate::{models::User, utils::ApplicationError}; #[derive(Template)] #[template(path = "user/profile_change_password.html")] struct ProfileChangePasswordTemplate {} #[actix_web::get("/users/changepassword")] -pub async fn get(_user: web::ReqData) -> impl Responder { +pub async fn get(_user: web::ReqData) -> Result { let template = ProfileChangePasswordTemplate {}; - template.to_response() + Ok(HttpResponse::Ok().body(template.render()?)) } diff --git a/web/src/endpoints/user/get_edit.rs b/web/src/endpoints/user/get_edit.rs index d212d319..1076049b 100644 --- a/web/src/endpoints/user/get_edit.rs +++ b/web/src/endpoints/user/get_edit.rs @@ -1,10 +1,11 @@ use actix_web::{web, HttpResponse, Responder}; -use askama_actix::TemplateToResponse; +use rinja::Template; use sqlx::PgPool; use crate::{ endpoints::{user::NewOrEditUserTemplate, IdPath}, models::{Area, Role, User}, + utils::ApplicationError, }; #[actix_web::get("/users/edit/{id}")] @@ -12,19 +13,22 @@ pub async fn get_edit( user: web::ReqData, pool: web::Data, path: web::Path, -) -> impl Responder { +) -> Result { let mut areas = None; if user.role != Role::AreaManager && user.role != Role::Admin { - return HttpResponse::Unauthorized().finish(); + return Err(ApplicationError::Unauthorized); } if user.role == Role::Admin { - areas = Some(Area::read_all(pool.get_ref()).await.unwrap()); + areas = Some(Area::read_all(pool.get_ref()).await?); } - if let Ok(user_in_db) = User::read_by_id(pool.get_ref(), path.id).await { - let template = NewOrEditUserTemplate { + let Some(user_in_db) = User::read_by_id(pool.get_ref(), path.id).await? else { + return Ok(HttpResponse::NotFound().finish()); + }; + + let template = NewOrEditUserTemplate { user: user.into_inner(), id: Some(user_in_db.id), areas, @@ -35,8 +39,5 @@ pub async fn get_edit( area_id: Some(user_in_db.area_id), }; - return template.to_response(); - } - - HttpResponse::BadRequest().body("Fehler beim Bearbeiten des Nutzers") + Ok(HttpResponse::Ok().body(template.render()?)) } diff --git a/web/src/endpoints/user/get_login.rs b/web/src/endpoints/user/get_login.rs index 17ad1ce7..9ad1fe77 100644 --- a/web/src/endpoints/user/get_login.rs +++ b/web/src/endpoints/user/get_login.rs @@ -1,21 +1,22 @@ use actix_identity::Identity; use actix_web::{http::header::LOCATION, HttpResponse, Responder}; -use askama::Template; -use askama_actix::TemplateToResponse; +use rinja::Template; + +use crate::utils::ApplicationError; #[derive(Template)] #[template(path = "user/login.html")] struct LoginTemplate {} #[actix_web::get("/login")] -async fn get(user: Option) -> impl Responder { +async fn get(user: Option) -> Result { if let Some(_) = user { - return HttpResponse::Found() + Ok(HttpResponse::Found() .insert_header((LOCATION, "/")) - .finish(); + .finish()) } else { let template = LoginTemplate {}; - return template.to_response(); + Ok(HttpResponse::Ok().body(template.render()?)) } } diff --git a/web/src/endpoints/user/get_new.rs b/web/src/endpoints/user/get_new.rs index 45d296b9..ae00a75d 100644 --- a/web/src/endpoints/user/get_new.rs +++ b/web/src/endpoints/user/get_new.rs @@ -1,18 +1,22 @@ -use actix_web::{web, Responder}; -use askama_actix::TemplateToResponse; +use actix_web::{web, HttpResponse, Responder}; +use rinja::Template; use sqlx::PgPool; use crate::{ endpoints::user::NewOrEditUserTemplate, models::{Area, Role, User}, + utils::ApplicationError, }; #[actix_web::get("/users/new")] -pub async fn get_new(user: web::ReqData, pool: web::Data) -> impl Responder { +pub async fn get_new( + user: web::ReqData, + pool: web::Data, +) -> Result { let mut areas: Option> = None; if user.role == Role::Admin { - areas = Some(Area::read_all(pool.get_ref()).await.unwrap()) + areas = Some(Area::read_all(pool.get_ref()).await?) } let template = NewOrEditUserTemplate { @@ -26,5 +30,5 @@ pub async fn get_new(user: web::ReqData, pool: web::Data) -> impl area_id: None, }; - template.to_response() + Ok(HttpResponse::Ok().body(template.render()?)) } diff --git a/web/src/endpoints/user/get_overview.rs b/web/src/endpoints/user/get_overview.rs index 4634796c..94f0e956 100644 --- a/web/src/endpoints/user/get_overview.rs +++ b/web/src/endpoints/user/get_overview.rs @@ -1,8 +1,10 @@ -use crate::models::{Area, Role, User, Function}; -use actix_identity::Identity; +use crate::{ + models::{Area, Function, Role, User}, + utils::ApplicationError, +}; + use actix_web::{web, HttpResponse, Responder}; -use askama::Template; -use askama_actix::TemplateToResponse; +use rinja::Template; use sqlx::PgPool; #[derive(Template)] @@ -14,36 +16,33 @@ pub struct UsersTemplate { } #[actix_web::get("/users")] -pub async fn get_overview(user: Identity, pool: web::Data) -> impl Responder { - let current_user = User::read_by_id(pool.get_ref(), user.id().unwrap().parse().unwrap()) - .await - .unwrap(); - - if current_user.role == Role::AreaManager || current_user.role == Role::Admin { - let mut area = None; - let users; - - if current_user.role == Role::AreaManager { - area = Some( - Area::read_by_id(pool.get_ref(), current_user.area_id) - .await - .unwrap().unwrap(), - ); - users = User::read_all_by_area(pool.get_ref(), current_user.area_id) - .await - .unwrap(); - } else { - users = User::read_all_including_area(pool.get_ref()).await.unwrap(); - } - - let template = UsersTemplate { - user: current_user, - area, - users, - }; - - return template.to_response(); +pub async fn get_overview( + user: web::ReqData, + pool: web::Data, +) -> Result { + if user.role != Role::AreaManager && user.role != Role::Admin { + return Err(ApplicationError::Unauthorized); } - return HttpResponse::BadRequest().body("Fehler beim Zugriff auf die Nutzerverwaltung!"); + let mut area = None; + let users; + + if user.role == Role::AreaManager { + area = Some( + Area::read_by_id(pool.get_ref(), user.area_id) + .await? + .unwrap(), + ); + users = User::read_all_by_area(pool.get_ref(), user.area_id).await?; + } else { + users = User::read_all_including_area(pool.get_ref()).await?; + } + + let template = UsersTemplate { + user: user.into_inner(), + area, + users, + }; + + Ok(HttpResponse::Ok().body(template.render()?)) } diff --git a/web/src/endpoints/user/get_profile.rs b/web/src/endpoints/user/get_profile.rs index 5c1224db..ac9b5ac4 100644 --- a/web/src/endpoints/user/get_profile.rs +++ b/web/src/endpoints/user/get_profile.rs @@ -1,11 +1,11 @@ -use actix_web::{web, Responder}; -use askama::Template; -use askama_actix::TemplateToResponse; +use actix_web::{web, HttpResponse, Responder}; +use rinja::Template; use sqlx::PgPool; use crate::{ filters, models::{Area, Role, User}, + utils::ApplicationError, }; #[derive(Template)] @@ -15,15 +15,16 @@ struct ProfileTemplate { } #[actix_web::get("/profile")] -pub async fn get(user: web::ReqData, pool: web::Data) -> impl Responder { - let area = Area::read_by_id(pool.get_ref(), user.area_id) - .await - .unwrap(); +pub async fn get( + user: web::ReqData, + pool: web::Data, +) -> Result { + let area = Area::read_by_id(pool.get_ref(), user.area_id).await?; let mut user = user.into_inner(); user.area = area; let template = ProfileTemplate { user }; - return template.to_response(); + Ok(HttpResponse::Ok().body(template.render()?)) } diff --git a/web/src/endpoints/user/get_register.rs b/web/src/endpoints/user/get_register.rs index 773922b5..0ff0982c 100644 --- a/web/src/endpoints/user/get_register.rs +++ b/web/src/endpoints/user/get_register.rs @@ -1,6 +1,6 @@ use actix_identity::Identity; use actix_web::{get, http::header::LOCATION, web, HttpResponse, Responder}; -use askama_actix::TemplateToResponse; +use rinja::Template; use serde::Deserialize; use sqlx::PgPool; @@ -25,18 +25,18 @@ pub async fn get( .finish()); } - if let Some(_) = Registration::does_token_exist(pool.get_ref(), &query.token).await? { - let template = ResetPasswordTemplate { - token: &query.token, - title: "Brass - Registrierung", - endpoint: "/register", - new_password_label: "Passwort:", - retype_label: "Passwort wiederholen:", - submit_button_label: "Registrieren", - }; + let Some(_) = Registration::does_token_exist(pool.get_ref(), &query.token).await? else { + return Ok(HttpResponse::NotFound().finish()); + }; - return Ok(template.to_response()); - } + let template = ResetPasswordTemplate { + token: &query.token, + title: "Brass - Registrierung", + endpoint: "/register", + new_password_label: "Passwort:", + retype_label: "Passwort wiederholen:", + submit_button_label: "Registrieren", + }; - Ok(HttpResponse::NotFound().finish()) + Ok(HttpResponse::Ok().body(template.render()?)) } diff --git a/web/src/endpoints/user/get_reset.rs b/web/src/endpoints/user/get_reset.rs index 4881c4a5..14168a19 100644 --- a/web/src/endpoints/user/get_reset.rs +++ b/web/src/endpoints/user/get_reset.rs @@ -1,11 +1,10 @@ use actix_identity::Identity; use actix_web::{get, http::header::LOCATION, web, HttpResponse, Responder}; -use askama::Template; -use askama_actix::TemplateToResponse; +use rinja::Template; use serde::Deserialize; use sqlx::PgPool; -use crate::models::PasswordReset; +use crate::{models::PasswordReset, utils::ApplicationError}; use super::ResetPasswordTemplate; @@ -23,13 +22,13 @@ pub async fn get( user: Option, pool: web::Data, query: web::Query, -) -> impl Responder { +) -> Result { if let Some(_) = user { - return HttpResponse::Found() + return Ok(HttpResponse::Found() .insert_header((LOCATION, "/")) - .finish(); + .finish()); } else if let Some(token) = &query.token { - if let Ok(_) = PasswordReset::does_token_exist(pool.get_ref(), token).await { + if let Some(_) = PasswordReset::does_token_exist(pool.get_ref(), token).await? { let template = ResetPasswordTemplate { token, title: "Brass - Passwort zurücksetzen", @@ -39,11 +38,10 @@ pub async fn get( submit_button_label: "Passwort zurücksetzen", }; - return template.to_response(); + return Ok(HttpResponse::Ok().body(template.render()?)) } } let template = ForgotPasswordTemplate {}; - - return template.to_response(); + Ok(HttpResponse::Ok().body(template.render()?)) } diff --git a/web/src/endpoints/user/mod.rs b/web/src/endpoints/user/mod.rs index 91f8674b..d9e9a8ab 100644 --- a/web/src/endpoints/user/mod.rs +++ b/web/src/endpoints/user/mod.rs @@ -3,7 +3,7 @@ use crate::models::{Area, Role, Token, User}; use crate::utils::{password_help, ApplicationError}; use crate::{auth, filters}; use actix_web::HttpResponse; -use askama::Template; +use rinja::Template; use sqlx::PgPool; use zxcvbn::{zxcvbn, Score}; @@ -73,7 +73,8 @@ async fn handle_password_change_request( return Ok(no_message); } - let user = User::read_by_id(pool, user_id).await?; + // TODO: make sure this unwrap is safe + let user = User::read_by_id(pool, user_id).await?.unwrap(); let mut split_names: Vec<&str> = user.name.as_str().split_whitespace().collect(); let mut user_inputs = vec![user.email.as_str()]; user_inputs.append(&mut split_names); diff --git a/web/src/endpoints/user/post_edit.rs b/web/src/endpoints/user/post_edit.rs index 583a1c30..617c90e0 100644 --- a/web/src/endpoints/user/post_edit.rs +++ b/web/src/endpoints/user/post_edit.rs @@ -24,15 +24,16 @@ pub async fn post_edit( path: web::Path, form: web::Form, ) -> impl Responder { + // TODO: rewrite let current_user = User::read_by_id(pool.get_ref(), user.id().unwrap().parse().unwrap()) .await - .unwrap(); + .unwrap().unwrap(); if current_user.role != Role::AreaManager && current_user.role != Role::Admin { return HttpResponse::Unauthorized().finish(); } - if let Ok(user_in_db) = User::read_by_id(pool.get_ref(), path.id).await { + if let Some(user_in_db) = User::read_by_id(pool.get_ref(), path.id).await.unwrap() { if current_user.role == Role::AreaManager && current_user.area_id != user_in_db.area_id { return HttpResponse::Unauthorized().finish(); } diff --git a/web/src/endpoints/user/post_new.rs b/web/src/endpoints/user/post_new.rs index 80a2a786..8a961355 100644 --- a/web/src/endpoints/user/post_new.rs +++ b/web/src/endpoints/user/post_new.rs @@ -48,7 +48,7 @@ pub async fn post_new( .await?; let registration = Registration::insert_new_for_user(pool.get_ref(), id).await?; - let new_user = User::read_by_id(pool.get_ref(), id).await?; + let new_user = User::read_by_id(pool.get_ref(), id).await?.unwrap(); let message = email::build_registration_message(&new_user, ®istration.token)?; mailer.send(&message)?; diff --git a/web/src/endpoints/user/post_toggle.rs b/web/src/endpoints/user/post_toggle.rs index 214ca85a..0036b512 100644 --- a/web/src/endpoints/user/post_toggle.rs +++ b/web/src/endpoints/user/post_toggle.rs @@ -19,12 +19,13 @@ pub async fn post( path: web::Path, query: web::Query, ) -> impl Responder { + // Todo: rewrite if user.id != path.id && user.role != Role::Admin && user.role != Role::AreaManager { return HttpResponse::Unauthorized().finish(); } let user = if user.id != path.id { - User::read_by_id(pool.get_ref(), path.id).await.unwrap() + User::read_by_id(pool.get_ref(), path.id).await.unwrap().unwrap() } else { user.into_inner() }; diff --git a/web/src/endpoints/vehicle/get_edit.rs b/web/src/endpoints/vehicle/get_edit.rs index 392f6e61..33215a3c 100644 --- a/web/src/endpoints/vehicle/get_edit.rs +++ b/web/src/endpoints/vehicle/get_edit.rs @@ -1,5 +1,5 @@ use actix_web::{web, HttpResponse, Responder}; -use askama_actix::TemplateToResponse; +use rinja::Template; use sqlx::PgPool; use crate::{ @@ -27,5 +27,5 @@ pub async fn get( vehicle: Some(vehicle), }; - Ok(template.to_response()) + Ok(HttpResponse::Ok().body(template.render()?)) } diff --git a/web/src/endpoints/vehicle/get_new.rs b/web/src/endpoints/vehicle/get_new.rs index 3f6a1a44..805462b7 100644 --- a/web/src/endpoints/vehicle/get_new.rs +++ b/web/src/endpoints/vehicle/get_new.rs @@ -1,5 +1,5 @@ -use actix_web::{web, Responder}; -use askama_actix::TemplateToResponse; +use actix_web::{web, HttpResponse, Responder}; +use rinja::Template; use crate::{ endpoints::vehicle::VehicleNewOrEditTemplate, @@ -18,5 +18,5 @@ pub async fn get(user: web::ReqData) -> Result, pool: web::Data) -> Result, first: bool) -> ::askama::Result { +pub fn show_area_query(a: &Option, first: bool) -> rinja::Result { let char = if first { '?' } else { '&' }; if let Some(a) = a { @@ -10,7 +10,7 @@ pub fn show_area_query(a: &Option, first: bool) -> ::askama::Result } } -pub fn cond_show(show: &bool, text: &str) -> askama::Result { +pub fn cond_show(show: &bool, text: &str) -> rinja::Result { return if *show { Ok(String::from(text)) } else { @@ -18,7 +18,7 @@ pub fn cond_show(show: &bool, text: &str) -> askama::Result { }; } -pub fn insert_value(option: &Option) -> askama::Result { +pub fn insert_value(option: &Option) -> rinja::Result { if let Some(val) = option { let s = format!(r#"value="{val}""#); return Ok(s); @@ -27,18 +27,18 @@ pub fn insert_value(option: &Option) -> askama::Result { Ok(String::new()) } -pub fn is_some_and_eq(option: &Option, other: &T) -> askama::Result +pub fn is_some_and_eq(option: &Option, other: &T) -> rinja::Result where T: Eq, { Ok(option.as_ref().is_some_and(|x| x == other)) } -pub fn invert(b: &bool) -> askama::Result { +pub fn invert(b: &bool) -> rinja::Result { return Ok(!b); } -pub fn show_tree(f: &Function) -> askama::Result { +pub fn show_tree(f: &Function) -> rinja::Result { let mut tags = String::from(r#"Posten"#); if f == &Function::Fuehrungsassistent || f == &Function::Wachhabender { diff --git a/web/src/middleware/load_current_user_from_db.rs b/web/src/middleware/load_current_user_from_db.rs index 0aaa44d6..2280fbb2 100644 --- a/web/src/middleware/load_current_user_from_db.rs +++ b/web/src/middleware/load_current_user_from_db.rs @@ -56,6 +56,7 @@ where let user = User::read_by_id(pool.get_ref(), id.parse().unwrap()) .await + .unwrap() .unwrap(); req.extensions_mut().insert::(user); diff --git a/web/src/models/user.rs b/web/src/models/user.rs index cf35b285..166eb5ad 100644 --- a/web/src/models/user.rs +++ b/web/src/models/user.rs @@ -76,7 +76,7 @@ impl User { b } - pub async fn read_by_id(pool: &PgPool, id: i32) -> Result { + pub async fn read_by_id(pool: &PgPool, id: i32) -> Result> { let record = sqlx::query!( r#" SELECT id, @@ -95,23 +95,23 @@ impl User { "#, id, ) - .fetch_one(pool) + .fetch_optional(pool) .await?; - let user = User { - id: record.id, - name: record.name, - email: record.email, - password: record.password, - salt: record.salt, - role: record.role, - function: record.function, - area_id: record.areaid, + let user = record.and_then(|u| Some(User { + id: u.id, + name: u.name, + email: u.email, + password: u.password, + salt: u.salt, + role: u.role, + function: u.function, + area_id: u.areaid, area: None, - locked: record.locked, - last_login: record.lastlogin, - receive_notifications: record.receivenotifications, - }; + locked: u.locked, + last_login: u.lastlogin, + receive_notifications: u.receivenotifications, + })); Ok(user) } @@ -197,7 +197,7 @@ impl User { Ok(result) } - pub async fn read_all_including_area(pool: &PgPool) -> anyhow::Result> { + pub async fn read_all_including_area(pool: &PgPool) -> Result> { let records = sqlx::query!( r#" SELECT @@ -245,7 +245,7 @@ impl User { Ok(results) } - pub async fn read_all_by_area(pool: &PgPool, area_id: i32) -> anyhow::Result> { + pub async fn read_all_by_area(pool: &PgPool, area_id: i32) -> Result> { let records = sqlx::query!( r#" SELECT id, diff --git a/web/src/utils/application_error.rs b/web/src/utils/application_error.rs index dd53c8c3..4c857d19 100644 --- a/web/src/utils/application_error.rs +++ b/web/src/utils/application_error.rs @@ -18,7 +18,9 @@ pub enum ApplicationError { #[error("email transport not working")] EmailTransport(#[from] lettre::transport::smtp::Error), #[error("hashfunction failed")] - Hash(#[from] argon2::password_hash::Error) + Hash(#[from] argon2::password_hash::Error), + #[error("templating failed")] + Template(#[from] rinja::Error), } impl actix_web::error::ResponseError for ApplicationError { @@ -32,6 +34,7 @@ impl actix_web::error::ResponseError for ApplicationError { ApplicationError::Email(_) => StatusCode::INTERNAL_SERVER_ERROR, ApplicationError::EmailTransport(_) => StatusCode::INTERNAL_SERVER_ERROR, ApplicationError::Hash(_) => StatusCode::INTERNAL_SERVER_ERROR, + ApplicationError::Template(_) => StatusCode::INTERNAL_SERVER_ERROR, } } @@ -43,6 +46,7 @@ impl actix_web::error::ResponseError for ApplicationError { ApplicationError::EmailAdress(e) => response.body(format!("{self} - {e}")), ApplicationError::Email(e) => response.body(format!("{self} - {e}")), ApplicationError::EmailTransport(e) => response.body(format!("{self} - {e}")), + ApplicationError::Template(e) => response.body(format!("{self} - {e}")), _ => response.body(self.to_string()), } } diff --git a/web/templates/area/new_or_edit.html b/web/templates/area/new_or_edit.html index 08fb1193..459b2968 100644 --- a/web/templates/area/new_or_edit.html +++ b/web/templates/area/new_or_edit.html @@ -45,9 +45,9 @@ @@ -58,7 +58,4 @@ - - {% endblock %} diff --git a/web/templates/availability/new_or_edit.html b/web/templates/availability/new_or_edit.html index a25ba418..e7d34f76 100644 --- a/web/templates/availability/new_or_edit.html +++ b/web/templates/availability/new_or_edit.html @@ -32,10 +32,10 @@ @@ -51,11 +51,11 @@
+ whole_day|cond_show("disabled") }} {{ whole_day|invert|ref|cond_show("required") }}>
+ whole_day|cond_show("disabled") }} {{ whole_day|invert|ref|cond_show("required") }}>
diff --git a/web/templates/events/plan.html b/web/templates/events/plan.html index bd43245e..2ebf007a 100644 --- a/web/templates/events/plan.html +++ b/web/templates/events/plan.html @@ -43,7 +43,7 @@
-

Anmerkungen: {{ event.note.as_ref().unwrap_or(String::new()|as_ref) }}

+

Anmerkungen: {{ event.note.as_ref().unwrap_or(String::new()|ref) }}

diff --git a/web/templates/events/plan_personal_table.html b/web/templates/events/plan_personal_table.html index b6bc9720..bbfad358 100644 --- a/web/templates/events/plan_personal_table.html +++ b/web/templates/events/plan_personal_table.html @@ -45,23 +45,23 @@
+ status !=AvailabillityAssignmentState::Unassigned|ref %}disabled{% endif %}>Posten {% if u.function == Function::Wachhabender || u.function == Function::Fuehrungsassistent %} {% endif %} {% if u.function == Function::Wachhabender %} + || status !=AvailabillityAssignmentState::Unassigned|ref %}disabled{% endif %}>Wachhabender {% endif %}
- {% if status != AvailabillityAssignmentState::Unassigned|as_ref && status != - AvailabillityAssignmentState::Conflicting|as_ref %} + {% if status != AvailabillityAssignmentState::Unassigned|ref && status != + AvailabillityAssignmentState::Conflicting|ref %} {% endif %} diff --git a/web/templates/location/new_or_edit.html b/web/templates/location/new_or_edit.html index 2de61549..0a9f15b2 100644 --- a/web/templates/location/new_or_edit.html +++ b/web/templates/location/new_or_edit.html @@ -40,7 +40,7 @@ {% let areaid = loc.area_id %} {% endif -%} {% for area in areas.as_ref().unwrap() %} - {% endfor %} diff --git a/web/templates/user/new_or_edit.html b/web/templates/user/new_or_edit.html index 837914f9..8ef7f6af 100644 --- a/web/templates/user/new_or_edit.html +++ b/web/templates/user/new_or_edit.html @@ -48,10 +48,10 @@
@@ -68,10 +68,10 @@
@@ -91,7 +91,7 @@