test: crossarea and delete availability

This commit is contained in:
Max Hohlfeld 2025-07-26 22:54:55 +02:00
parent 290e610058
commit 18875a9e0c
4 changed files with 397 additions and 46 deletions

View File

@ -0,0 +1,13 @@
---
source: web/src/endpoints/availability/put_cross_areal.rs
expression: disable_body
snapshot_kind: text
---
<button class="button is-link is-light" hx-swap="outerHTML"
hx-put="/availability/1/makeCrossAreal"
title="Bereichsübergreifend verfügbar machen">
<svg class="icon">
<use
href="/static/feather-sprite.svg#globe" />
</svg>
</button>

View File

@ -0,0 +1,13 @@
---
source: web/src/endpoints/availability/put_cross_areal.rs
expression: enable_body
snapshot_kind: text
---
<button class="button is-link is-light" hx-swap="outerHTML"
hx-put="/availability/1/makeNonCrossAreal"
title="nur im Hauptbereich verfügbar machen">
<svg class="icon">
<use
href="/static/feather-sprite.svg#home" />
</svg>
</button>

View File

@ -10,11 +10,14 @@ pub async fn delete(
pool: web::Data<PgPool>,
path: web::Path<IdPath>,
) -> Result<impl Responder, ApplicationError> {
let Some(availability) = Availability::read(pool.get_ref(), path.id).await? else {
let Some(availability) = Availability::read_including_user(pool.get_ref(), path.id).await?
else {
return Ok(HttpResponse::NotFound().finish());
};
if user.role != Role::Admin && user.role != Role::AreaManager && availability.user_id != user.id
if availability.user_id != user.id
&& user.role != Role::Admin
&& (user.role != Role::AreaManager || user.area_id != availability.user.unwrap().area_id)
{
return Err(ApplicationError::Unauthorized);
}
@ -27,16 +30,17 @@ pub async fn delete(
#[cfg(test)]
mod tests {
use actix_http::StatusCode;
use brass_db::models::{Availability, AvailabilityChangeset};
use brass_db::models::{Area, Availability, AvailabilityChangeset, Role, User, UserChangeset};
use brass_macros::db_test;
use chrono::NaiveDateTime;
use fake::{Fake, Faker};
use crate::utils::test_helper::{
create_test_login_user, test_delete, DbTestContext, NaiveDateTimeExt, RequestConfig,
};
#[db_test]
async fn deletes_when_availability_is_from_user(context: &DbTestContext) {
async fn deletes_when_availability_is_from_user_itself(context: &DbTestContext) {
let app = context.app().await;
let config = RequestConfig::new("/availability/delete/1");
create_test_login_user(&context.db_pool, &config).await;
@ -57,10 +61,115 @@ mod tests {
let response = test_delete(&app, &config).await;
assert_eq!(StatusCode::OK, response.status());
let availability = Availability::read(&context.db_pool, 1).await.unwrap();
assert!(availability.is_none());
}
// test deletes availability_from_another_But_area_manager_in_area
// test doesnt_delete availability_from_another_But_area_manager_is_not_in_area
// test deletest_availability_from_another_user_when_user_admin
// test doesnt_delete availability_when_not_existing
#[db_test]
async fn deletes_when_availability_is_from_other_user_and_requester_is_area_manager_in_area(
context: &DbTestContext,
) {
let app = context.app().await;
let config = RequestConfig::new("/availability/delete/1").with_role(Role::AreaManager);
create_test_login_user(&context.db_pool, &config).await;
User::create(&context.db_pool, &Faker.fake()).await.unwrap();
Availability::create(
&context.db_pool,
2,
AvailabilityChangeset {
time: (
NaiveDateTime::from_ymd_and_hms(2025, 01, 01, 10, 0, 0).unwrap(),
NaiveDateTime::from_ymd_and_hms(2025, 02, 01, 10, 0, 0).unwrap(),
),
comment: None,
},
)
.await
.unwrap();
let response = test_delete(&app, &config).await;
assert_eq!(StatusCode::OK, response.status());
let availability = Availability::read(&context.db_pool, 1).await.unwrap();
assert!(availability.is_none());
}
#[db_test]
async fn deletes_not_when_availability_is_from_other_user_and_requester_is_area_manager_in_other_area(
context: &DbTestContext,
) {
let app = context.app().await;
let config = RequestConfig::new("/availability/delete/1").with_role(Role::AreaManager);
create_test_login_user(&context.db_pool, &config).await;
Area::create(&context.db_pool, "Süd").await.unwrap();
let mut changeset: UserChangeset = Faker.fake();
changeset.area_id = 2;
User::create(&context.db_pool, &changeset).await.unwrap();
Availability::create(
&context.db_pool,
2,
AvailabilityChangeset {
time: (
NaiveDateTime::from_ymd_and_hms(2025, 01, 01, 10, 0, 0).unwrap(),
NaiveDateTime::from_ymd_and_hms(2025, 02, 01, 10, 0, 0).unwrap(),
),
comment: None,
},
)
.await
.unwrap();
let response = test_delete(&app, &config).await;
assert_eq!(StatusCode::UNAUTHORIZED, response.status());
let availability = Availability::read(&context.db_pool, 1).await.unwrap();
assert!(availability.is_some());
}
#[db_test]
async fn deletes_when_availability_is_from_other_user_and_requester_is_admin(
context: &DbTestContext,
) {
let app = context.app().await;
let config = RequestConfig::new("/availability/delete/1").with_role(Role::Admin);
create_test_login_user(&context.db_pool, &config).await;
User::create(&context.db_pool, &Faker.fake()).await.unwrap();
Availability::create(
&context.db_pool,
2,
AvailabilityChangeset {
time: (
NaiveDateTime::from_ymd_and_hms(2025, 01, 01, 10, 0, 0).unwrap(),
NaiveDateTime::from_ymd_and_hms(2025, 02, 01, 10, 0, 0).unwrap(),
),
comment: None,
},
)
.await
.unwrap();
let response = test_delete(&app, &config).await;
assert_eq!(StatusCode::OK, response.status());
let availability = Availability::read(&context.db_pool, 1).await.unwrap();
assert!(availability.is_none());
}
#[db_test]
async fn deletes_not_when_availability_doesnt_exist(context: &DbTestContext) {
let app = context.app().await;
let config = RequestConfig::new("/availability/delete/1");
create_test_login_user(&context.db_pool, &config).await;
let response = test_delete(&app, &config).await;
assert_eq!(StatusCode::NOT_FOUND, response.status());
}
}

View File

@ -81,42 +81,258 @@ async fn handle_cross_areal(
#[cfg(test)]
mod tests {
// use crate::utils::test_helper::{
// assert_snapshot, create_test_login_user, read_body, test_put, DbTestContext, RequestConfig,
// StatusCode,
// };
// use brass_macros::db_test;
//
// #[db_test]
// async fn user_can_toggle_subscription_for_himself(context: &DbTestContext) {
// let app = context.app().await;
//
// let unsubscribe_config = RequestConfig::new("/users/1/unsubscribeNotifications");
// create_test_login_user(&context.db_pool, &unsubscribe_config).await;
// let unsubscribe_response = test_put::<_, _, String>(&app, &unsubscribe_config, None).await;
//
// assert_eq!(StatusCode::OK, unsubscribe_response.status());
//
// let unsubscribe_body = read_body(unsubscribe_response).await;
// assert_snapshot!(unsubscribe_body);
//
// let subscribe_config = RequestConfig::new("/users/1/subscribeNotifications");
// let subscribe_response = test_put::<_, _, String>(&app, &subscribe_config, None).await;
//
// assert_eq!(StatusCode::OK, subscribe_response.status());
//
// let subscribe_body = read_body(subscribe_response).await;
// assert_snapshot!(subscribe_body);
// }
//
// #[db_test]
// async fn user_cant_toggle_subscription_for_someone_else(context: &DbTestContext) {
// let app = context.app().await;
//
// let unsubscribe_config = RequestConfig::new("/users/3/unsubscribeNotifications");
// create_test_login_user(&context.db_pool, &unsubscribe_config).await;
// let unsubscribe_response = test_put::<_, _, String>(&app, &unsubscribe_config, None).await;
//
// assert_eq!(StatusCode::UNAUTHORIZED, unsubscribe_response.status());
// }
use crate::utils::test_helper::{
assert_snapshot, create_test_login_user, test_put, DbTestContext, NaiveDateTimeExt,
RequestConfig, ServiceResponseExt, StatusCode,
};
use brass_db::models::{
Area, Assignment, AssignmentChangeset, Availability, AvailabilityChangeset, Event,
EventChangeset, Location, Role, User, UserChangeset,
};
use brass_macros::db_test;
use chrono::NaiveDateTime;
use fake::{Fake, Faker};
#[db_test]
async fn area_manager_can_toggle_cross_areal_for_availabilities_in_his_area(
context: &DbTestContext,
) {
let app = context.app().await;
let mut config =
RequestConfig::new("/availability/1/makeCrossAreal").with_role(Role::AreaManager);
create_test_login_user(&context.db_pool, &config).await;
User::create(&context.db_pool, &Faker.fake()).await.unwrap();
Availability::create(
&context.db_pool,
2,
AvailabilityChangeset {
time: (
NaiveDateTime::from_ymd_and_hms(2025, 01, 01, 10, 0, 0).unwrap(),
NaiveDateTime::from_ymd_and_hms(2025, 02, 01, 10, 0, 0).unwrap(),
),
comment: None,
},
)
.await
.unwrap();
let (enable_status, enable_body) = test_put::<_, _, String>(&app, &config, None)
.await
.into_status_and_body()
.await;
assert_eq!(StatusCode::OK, enable_status);
assert_snapshot!(enable_body);
assert!(
Availability::read(&context.db_pool, 1)
.await
.unwrap()
.unwrap()
.cross_areal
);
config.uri = "/availability/1/makeNonCrossAreal".to_string();
let (disable_status, disable_body) = test_put::<_, _, String>(&app, &config, None)
.await
.into_status_and_body()
.await;
assert_eq!(StatusCode::OK, disable_status);
assert_snapshot!(disable_body);
assert!(
!Availability::read(&context.db_pool, 1)
.await
.unwrap()
.unwrap()
.cross_areal
);
}
#[db_test]
async fn area_manager_cant_toggle_cross_areal_for_availabilities_outside_his_area(
context: &DbTestContext,
) {
let app = context.app().await;
let mut config = RequestConfig::new("/availability/1/makeCrossAreal");
create_test_login_user(&context.db_pool, &config).await;
Area::create(&context.db_pool, "Süd").await.unwrap();
let mut changeset: UserChangeset = Faker.fake();
changeset.area_id = 2;
User::create(&context.db_pool, &changeset).await.unwrap();
Availability::create(
&context.db_pool,
2,
AvailabilityChangeset {
time: (
NaiveDateTime::from_ymd_and_hms(2025, 01, 01, 10, 0, 0).unwrap(),
NaiveDateTime::from_ymd_and_hms(2025, 02, 01, 10, 0, 0).unwrap(),
),
comment: None,
},
)
.await
.unwrap();
let response = test_put::<_, _, String>(&app, &config, None).await;
assert_eq!(StatusCode::UNAUTHORIZED, response.status());
assert!(
!Availability::read(&context.db_pool, 1)
.await
.unwrap()
.unwrap()
.cross_areal
);
Availability::update_cross_areal(&context.db_pool, 1, true)
.await
.unwrap();
config.uri = "/availability/1/makeNonCrossAreal".to_string();
let response = test_put::<_, _, String>(&app, &config, None).await;
assert_eq!(StatusCode::UNAUTHORIZED, response.status());
assert!(
Availability::read(&context.db_pool, 1)
.await
.unwrap()
.unwrap()
.cross_areal
);
}
#[db_test]
async fn user_cant_toggle_cross_areal(context: &DbTestContext) {
let app = context.app().await;
let mut config = RequestConfig::new("/availability/1/makeCrossAreal");
create_test_login_user(&context.db_pool, &config).await;
Availability::create(
&context.db_pool,
1,
AvailabilityChangeset {
time: (
NaiveDateTime::from_ymd_and_hms(2025, 01, 01, 10, 0, 0).unwrap(),
NaiveDateTime::from_ymd_and_hms(2025, 02, 01, 10, 0, 0).unwrap(),
),
comment: None,
},
)
.await
.unwrap();
let response = test_put::<_, _, String>(&app, &config, None).await;
assert_eq!(StatusCode::UNAUTHORIZED, response.status());
assert!(
!Availability::read(&context.db_pool, 1)
.await
.unwrap()
.unwrap()
.cross_areal
);
Availability::update_cross_areal(&context.db_pool, 1, true)
.await
.unwrap();
config.uri = "/availability/1/makeNonCrossAreal".to_string();
let response = test_put::<_, _, String>(&app, &config, None).await;
assert_eq!(StatusCode::UNAUTHORIZED, response.status());
assert!(
Availability::read(&context.db_pool, 1)
.await
.unwrap()
.unwrap()
.cross_areal
);
}
#[db_test]
async fn area_manager_cant_toggle_cross_areal_for_availability_already_planned(
context: &DbTestContext,
) {
let app = context.app().await;
let config =
RequestConfig::new("/availability/1/makeNonCrossAreal").with_role(Role::AreaManager);
create_test_login_user(&context.db_pool, &config).await;
User::create(&context.db_pool, &Faker.fake()).await.unwrap();
Availability::create(
&context.db_pool,
2,
AvailabilityChangeset {
time: (
NaiveDateTime::from_ymd_and_hms(2025, 01, 01, 10, 0, 0).unwrap(),
NaiveDateTime::from_ymd_and_hms(2025, 02, 01, 10, 0, 0).unwrap(),
),
comment: None,
},
)
.await
.unwrap();
Availability::update_cross_areal(&context.db_pool, 1, true)
.await
.unwrap();
Location::create(&context.db_pool, "Ort", 1).await.unwrap();
Event::create(
&context.db_pool,
EventChangeset::create_for_test(
NaiveDateTime::from_ymd_and_hms(2025, 01, 01, 10, 0, 0).unwrap(),
NaiveDateTime::from_ymd_and_hms(2025, 02, 01, 10, 0, 0).unwrap(),
),
)
.await
.unwrap();
Assignment::create(
&context.db_pool,
1,
1,
AssignmentChangeset {
time: (
NaiveDateTime::from_ymd_and_hms(2025, 01, 01, 10, 0, 0).unwrap(),
NaiveDateTime::from_ymd_and_hms(2025, 02, 01, 10, 0, 0).unwrap(),
),
function: brass_db::models::Function::Posten,
},
)
.await
.unwrap();
let response = test_put::<_, _, String>(&app, &config, None).await;
assert_eq!(StatusCode::UNPROCESSABLE_ENTITY, response.status());
assert!(
Availability::read(&context.db_pool, 1)
.await
.unwrap()
.unwrap()
.cross_areal
);
}
#[db_test]
async fn area_manager_cant_toggle_cross_areal_when_availability_doesnt_exist(
context: &DbTestContext,
) {
let app = context.app().await;
let config =
RequestConfig::new("/availability/1/makeNonCrossAreal").with_role(Role::AreaManager);
create_test_login_user(&context.db_pool, &config).await;
let response = test_put::<_, _, String>(&app, &config, None).await;
assert_eq!(StatusCode::NOT_FOUND, response.status());
}
}