parent
b2fccdfa29
commit
e1b5d593f5
@ -0,0 +1,62 @@
|
||||
---
|
||||
source: web/src/endpoints/vehicle/get_edit.rs
|
||||
expression: body
|
||||
snapshot_kind: text
|
||||
---
|
||||
<section class="section">
|
||||
<div class="container"><form method="post" action="/vehicles/1">
|
||||
<h1 class="title">Fahrzeug '11.49.1' bearbeiten</h1>
|
||||
|
||||
<div class="field is-horizontal">
|
||||
<div class="field-label">
|
||||
<label class="label">Funkkenner</label>
|
||||
</div>
|
||||
<div class="field-body">
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input class="input" type="text" name="radio_call_name" required placeholder="11.49.1" value="11.49.1" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field is-horizontal">
|
||||
<div class="field-label">
|
||||
<label class="label">Wache</label>
|
||||
</div>
|
||||
<div class="field-body">
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input class="input" type="text" name="station" required placeholder="FF Leipzig Ost" value="FF Leipzig Ost" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field is-horizontal">
|
||||
<div class="field-label"></div>
|
||||
<div class="field-body">
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<button class="button is-success">
|
||||
<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#check-circle" />
|
||||
</svg>
|
||||
<span>Speichern</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="control">
|
||||
<a class="button is-link is-light" hx-boost="true" href="/vehicles">
|
||||
<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#arrow-left" />
|
||||
</svg>
|
||||
<span>Zurück</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
@ -13,7 +13,7 @@ pub async fn get(
|
||||
pool: web::Data<PgPool>,
|
||||
path: web::Path<IdPath>,
|
||||
) -> Result<impl Responder, ApplicationError> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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<Vehicle>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[cfg_attr(test, derive(serde::Serialize))]
|
||||
pub struct VehicleForm {
|
||||
radio_call_name: String,
|
||||
station: String,
|
||||
|
@ -14,7 +14,7 @@ pub async fn post(
|
||||
path: web::Path<IdPath>,
|
||||
form: web::Form<VehicleForm>,
|
||||
) -> Result<impl Responder, ApplicationError> {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
@ -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>(
|
||||
|
@ -3,13 +3,13 @@
|
||||
{% block content %}
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
{% if vehicle.is_some() %}
|
||||
{%- if vehicle.is_some() -%}
|
||||
<form method="post" action="/vehicles/{{ vehicle.as_ref().unwrap().id }}">
|
||||
<h1 class="title">Fahrzeug '{{ vehicle.as_ref().unwrap().radio_call_name }}' bearbeiten</h1>
|
||||
{% else %}
|
||||
{%- else -%}
|
||||
<form method="post" action="/vehicles/new">
|
||||
<h1 class="title">Neues Fahrzeug anlegen</h1>
|
||||
{% endif %}
|
||||
{%- endif %}
|
||||
|
||||
<div class="field is-horizontal">
|
||||
<div class="field-label">
|
||||
@ -49,11 +49,11 @@
|
||||
<use href="/static/feather-sprite.svg#check-circle" />
|
||||
</svg>
|
||||
<span>
|
||||
{% if vehicle.is_some() %}
|
||||
{%- if vehicle.is_some() -%}
|
||||
Speichern
|
||||
{% else %}
|
||||
{%- else -%}
|
||||
Erstellen
|
||||
{% endif %}
|
||||
{%- endif -%}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user