diff --git a/web/snapshots/brass_web__endpoints__vehicle__get_edit__tests__inner_produces_template_fine_when_user_is_admin.snap b/web/snapshots/brass_web__endpoints__vehicle__get_edit__tests__inner_produces_template_fine_when_user_is_admin.snap new file mode 100644 index 00000000..56d5af59 --- /dev/null +++ b/web/snapshots/brass_web__endpoints__vehicle__get_edit__tests__inner_produces_template_fine_when_user_is_admin.snap @@ -0,0 +1,62 @@ +--- +source: web/src/endpoints/vehicle/get_edit.rs +expression: body +snapshot_kind: text +--- +
+
+

Fahrzeug '11.49.1' bearbeiten

+ +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+ +
+ +
+
+
+ +
+
+
diff --git a/web/src/endpoints/vehicle/get_edit.rs b/web/src/endpoints/vehicle/get_edit.rs index 1add5d0a..a9e59758 100644 --- a/web/src/endpoints/vehicle/get_edit.rs +++ b/web/src/endpoints/vehicle/get_edit.rs @@ -13,7 +13,7 @@ pub async fn get( pool: web::Data, path: web::Path, ) -> Result { - if user.role != Role::Admin { + if user.role != Role::Admin && user.role != Role::AreaManager { return Err(ApplicationError::Unauthorized); } @@ -28,3 +28,68 @@ pub async fn get( Ok(template.to_response()?) } + +#[cfg(test)] +mod tests { + use crate::{ + models::{Function, Role, Vehicle}, + utils::test_helper::{ + assert_snapshot, read_body, test_get, DbTestContext, RequestConfig, StatusCode, + }, + }; + use brass_macros::db_test; + + #[db_test] + async fn returns_not_found_for_user(context: &DbTestContext) { + Vehicle::create(&context.db_pool, "11.49.1", "FF Leipzig Ost") + .await + .unwrap(); + + let app = context.app().await; + + let config = RequestConfig::new("/vehicles/1"); + + let response = test_get(&context.db_pool, &app, &config).await; + assert_eq!(StatusCode::UNAUTHORIZED, response.status()); + } + + #[db_test] + async fn area_manager_can_edit(context: &DbTestContext) { + Vehicle::create(&context.db_pool, "11.49.1", "FF Leipzig Ost") + .await + .unwrap(); + + let app = context.app().await; + + let config = RequestConfig { + uri: "/vehicles/1".to_string(), + role: Role::AreaManager, + function: vec![Function::Posten], + user_area: 1, + }; + + let response = test_get(&context.db_pool, &app, &config).await; + assert_eq!(StatusCode::OK, response.status()); + } + + #[db_test] + async fn produces_template_fine_when_user_is_admin(context: &DbTestContext) { + let app = context.app().await; + Vehicle::create(&context.db_pool, "11.49.1", "FF Leipzig Ost") + .await + .unwrap(); + + let config = RequestConfig { + uri: "/vehicles/1".to_string(), + role: Role::Admin, + function: vec![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/vehicle/mod.rs b/web/src/endpoints/vehicle/mod.rs index 3aceb5f4..65edb438 100644 --- a/web/src/endpoints/vehicle/mod.rs +++ b/web/src/endpoints/vehicle/mod.rs @@ -11,13 +11,19 @@ pub mod post_edit; pub mod post_new; #[derive(Template)] -#[template(path = "vehicles/new_or_edit.html")] +#[cfg_attr(not(test), template(path = "vehicles/new_or_edit.html"))] +#[cfg_attr( + test, + template(path = "vehicles/new_or_edit.html", block = "content"), + allow(dead_code) +)] pub struct VehicleNewOrEditTemplate { user: User, vehicle: Option, } #[derive(Deserialize)] +#[cfg_attr(test, derive(serde::Serialize))] pub struct VehicleForm { radio_call_name: String, station: String, diff --git a/web/src/endpoints/vehicle/post_edit.rs b/web/src/endpoints/vehicle/post_edit.rs index c1186bc3..38545d4c 100644 --- a/web/src/endpoints/vehicle/post_edit.rs +++ b/web/src/endpoints/vehicle/post_edit.rs @@ -14,7 +14,7 @@ pub async fn post( path: web::Path, form: web::Form, ) -> Result { - if user.role != Role::Admin { + if user.role != Role::Admin && user.role != Role::AreaManager { return Err(ApplicationError::Unauthorized); } @@ -37,3 +37,80 @@ pub async fn post( .insert_header(("HX-LOCATION", "/vehicles")) .finish()) } + +#[cfg(test)] +mod tests { + use actix_http::StatusCode; + use brass_macros::db_test; + + use crate::{ + endpoints::vehicle::VehicleForm, + models::{Role, Vehicle}, + utils::test_helper::{test_post, DbTestContext, RequestConfig}, + }; + + #[db_test] + async fn updates_vehicle_when_user_is_admin_and_vehicle_exists(context: &DbTestContext) { + works_for_role(context, Role::Admin).await; + } + + #[db_test] + async fn updates_vehicle_when_user_is_area_manager_and_vehicle_exists(context: &DbTestContext) { + works_for_role(context, Role::AreaManager).await; + } + + async fn works_for_role(context: &DbTestContext, role: Role) { + Vehicle::create(&context.db_pool, "11.49.1", "FF Leipzig Ost") + .await + .unwrap(); + + let app = context.app().await; + + let config = RequestConfig::new("/vehicles/1").with_role(role); + + let request = VehicleForm { + station: "FF Leipzig Ost".to_string(), + radio_call_name: "11.49.2".to_string(), + }; + + let response = test_post(&context.db_pool, app, &config, request).await; + + assert_eq!(StatusCode::FOUND, response.status()); + + let updated_vehicle = Vehicle::read(&context.db_pool, 1).await.unwrap().unwrap(); + + assert_eq!("11.49.2".to_string(), updated_vehicle.radio_call_name); + } + + #[db_test] + async fn returns_unauthorized_when_user_is_staff(context: &DbTestContext) { + let app = context.app().await; + + let config = RequestConfig::new("/vehicles/1"); + + let request = VehicleForm { + station: "FF Leipzig Ost".to_string(), + radio_call_name: "11.49.2".to_string(), + }; + + let response = test_post(&context.db_pool, app, &config, request).await; + + assert_eq!(StatusCode::UNAUTHORIZED, response.status()); + } + + #[db_test] + async fn returns_not_found_when_vehicle_does_not_exist(context: &DbTestContext) { + let app = context.app().await; + + let config = RequestConfig::new("/vehicles/1").with_role(Role::Admin); + + let request = VehicleForm { + station: "FF Leipzig Ost".to_string(), + radio_call_name: "11.49.2".to_string(), + }; + + let response = test_post(&context.db_pool, app, &config, request).await; + + assert_eq!(StatusCode::NOT_FOUND, response.status()); + } +} diff --git a/web/src/utils/test_helper/test_requests.rs b/web/src/utils/test_helper/test_requests.rs index 860d75e8..f7a33cc0 100644 --- a/web/src/utils/test_helper/test_requests.rs +++ b/web/src/utils/test_helper/test_requests.rs @@ -29,6 +29,24 @@ impl RequestConfig { user_area: 1, } } + + pub fn with_role(self, role: Role) -> Self { + let mut obj = self; + obj.role = role; + obj + } + + pub fn with_functions(self, functions: &[Function]) -> Self { + let mut obj = self; + obj.function = functions.to_vec(); + obj + } + + pub fn with_user_area(self, user_area: i32) -> Self { + let mut obj = self; + obj.user_area = user_area; + obj + } } async fn create_user_and_get_login_cookie<'a, T, R>( diff --git a/web/templates/vehicles/new_or_edit.html b/web/templates/vehicles/new_or_edit.html index dc5f517a..4e4ff2f1 100644 --- a/web/templates/vehicles/new_or_edit.html +++ b/web/templates/vehicles/new_or_edit.html @@ -3,13 +3,13 @@ {% block content %}
- {% if vehicle.is_some() %} + {%- if vehicle.is_some() -%}

Fahrzeug '{{ vehicle.as_ref().unwrap().radio_call_name }}' bearbeiten

- {% else %} + {%- else -%}

Neues Fahrzeug anlegen

- {% endif %} + {%- endif %}
@@ -49,11 +49,11 @@ - {% if vehicle.is_some() %} + {%- if vehicle.is_some() -%} Speichern - {% else %} + {%- else -%} Erstellen - {% endif %} + {%- endif -%}