test: new availability

This commit is contained in:
Max Hohlfeld 2025-08-02 12:52:47 +02:00
parent 760897b301
commit 98e42e20c8
3 changed files with 216 additions and 2 deletions

View File

@ -1,4 +1,4 @@
use chrono::{Days, NaiveDateTime};
use chrono::{Days, NaiveDate, NaiveDateTime};
use sqlx::PgPool;
use super::Availability;
@ -150,3 +150,20 @@ pub fn find_free_date_time_slots(
available_slots
}
#[cfg(feature = "test-helpers")]
impl AvailabilityChangeset {
pub fn create_for_test(
date: &NaiveDate,
start_hour: u32,
end_hour: u32,
) -> AvailabilityChangeset {
AvailabilityChangeset {
time: (
date.and_hms_opt(start_hour, 0, 0).unwrap(),
date.and_hms_opt(end_hour, 0, 0).unwrap(),
),
comment: None,
}
}
}

View File

@ -35,6 +35,7 @@ struct NewOrEditAvailabilityTemplate<'a> {
}
#[derive(Deserialize)]
#[cfg_attr(test, derive(serde::Serialize))]
pub struct AvailabilityForm {
pub startdate: NaiveDate,
pub enddate: NaiveDate,

View File

@ -7,7 +7,7 @@ use crate::{
utils::{self, ApplicationError},
};
use brass_db::{
models::{Availability, AvailabilityChangeset, AvailabilityContext, User},
models::{Availability, AvailabilityChangeset, AvailabilityContext, Role, User},
validation::AsyncValidate,
};
@ -20,6 +20,13 @@ pub async fn post(
let start = form.startdate.and_time(form.starttime);
let end = form.enddate.and_time(form.endtime);
let user_for_availability = form.user.unwrap_or(user.id);
let Some(other_user) = User::read_by_id(pool.get_ref(), user_for_availability).await? else {
return Ok(HttpResponse::UnprocessableEntity().body("Nutzer existiert nicht."));
};
if other_user.area_id != user.area_id && user.role != Role::Admin {
return Err(ApplicationError::Unauthorized);
}
let context = AvailabilityContext {
pool: pool.get_ref(),
@ -75,3 +82,192 @@ pub async fn post(
.insert_header(("HX-LOCATION", url))
.finish())
}
#[cfg(test)]
mod tests {
use actix_http::StatusCode;
use brass_db::models::{Area, Availability, AvailabilityChangeset, Role, User, UserChangeset};
use brass_macros::db_test;
use chrono::{NaiveDate, NaiveTime};
use fake::{Fake, Faker};
use crate::{
endpoints::availability::AvailabilityForm,
utils::test_helper::{create_test_login_user, test_post, DbTestContext, RequestConfig},
};
fn create_form(
date: &NaiveDate,
start_hour: u32,
end_hour: u32,
user: Option<i32>,
) -> AvailabilityForm {
AvailabilityForm {
startdate: *date,
enddate: *date,
starttime: NaiveTime::from_hms_opt(start_hour, 0, 0).unwrap(),
endtime: NaiveTime::from_hms_opt(end_hour, 0, 0).unwrap(),
comment: None,
user,
}
}
#[db_test]
async fn can_create_availability_for_myself_fine(context: &DbTestContext) {
let app = context.app().await;
let config = RequestConfig::new("/availability/new");
create_test_login_user(&context.db_pool, &config).await;
let date = Faker.fake();
let form = create_form(&date, 10, 20, None);
let response = test_post(app, &config, Some(form)).await;
assert_eq!(StatusCode::FOUND, response.status());
assert!(Availability::read(&context.db_pool, 1)
.await
.unwrap()
.is_some())
}
#[db_test]
async fn cant_create_availability_for_myself_when_time_slot_already_present(
context: &DbTestContext,
) {
let app = context.app().await;
let config = RequestConfig::new("/availability/new");
create_test_login_user(&context.db_pool, &config).await;
let date = Faker.fake();
let changeset = AvailabilityChangeset::create_for_test(&date, 10, 20);
Availability::create(&context.db_pool, 1, &changeset)
.await
.unwrap();
let form = create_form(&date, 10, 20, None);
let response = test_post(app, &config, Some(form)).await;
assert_eq!(StatusCode::UNPROCESSABLE_ENTITY, response.status());
}
#[db_test]
async fn create_new_updates_existing_when_time_slots_connect(context: &DbTestContext) {
let app = context.app().await;
let config = RequestConfig::new("/availability/new");
create_test_login_user(&context.db_pool, &config).await;
let date = Faker.fake();
let changeset = AvailabilityChangeset::create_for_test(&date, 4, 10);
Availability::create(&context.db_pool, 1, &changeset)
.await
.unwrap();
let form = create_form(&date, 10, 20, None);
let response = test_post(app, &config, Some(form)).await;
assert_eq!(StatusCode::FOUND, response.status());
assert_eq!(
1,
Availability::read_all_by_user_and_date(&context.db_pool, 1, &date)
.await
.unwrap()
.len()
)
}
#[db_test]
async fn cant_create_availability_for_myself_when_start_time_before_end_time(
context: &DbTestContext,
) {
let app = context.app().await;
let config = RequestConfig::new("/availability/new");
create_test_login_user(&context.db_pool, &config).await;
let date = Faker.fake();
let form = create_form(&date, 20, 10, None);
let response = test_post(app, &config, Some(form)).await;
assert_eq!(StatusCode::UNPROCESSABLE_ENTITY, response.status());
}
#[db_test]
async fn can_create_availability_for_other_user_in_same_area_as_area_manager(
context: &DbTestContext,
) {
let app = context.app().await;
let config = RequestConfig::new("/availability/new").with_role(Role::AreaManager);
create_test_login_user(&context.db_pool, &config).await;
User::create(&context.db_pool, &Faker.fake()).await.unwrap();
let date = Faker.fake();
let form = create_form(&date, 10, 20, Some(2));
let response = test_post(app, &config, Some(form)).await;
assert_eq!(StatusCode::FOUND, response.status());
assert_eq!(
1,
Availability::read_all_by_user_and_date(&context.db_pool, 2, &date)
.await
.unwrap()
.len()
)
}
#[db_test]
async fn cant_create_availability_for_other_user_in_other_area_as_area_manager(
context: &DbTestContext,
) {
let app = context.app().await;
let config = RequestConfig::new("/availability/new").with_role(Role::AreaManager);
create_test_login_user(&context.db_pool, &config).await;
Area::create(&context.db_pool, "Süd").await.unwrap();
let mut user_changeset: UserChangeset = Faker.fake();
user_changeset.area_id = 2;
User::create(&context.db_pool, &user_changeset)
.await
.unwrap();
let date = Faker.fake();
let form = create_form(&date, 10, 20, Some(2));
let response = test_post(app, &config, Some(form)).await;
assert_eq!(StatusCode::UNAUTHORIZED, response.status());
}
#[db_test]
async fn can_create_availability_for_other_user_in_other_area_as_admin(
context: &DbTestContext,
) {
let app = context.app().await;
let config = RequestConfig::new("/availability/new").with_role(Role::Admin);
create_test_login_user(&context.db_pool, &config).await;
Area::create(&context.db_pool, "Süd").await.unwrap();
let mut user_changeset: UserChangeset = Faker.fake();
user_changeset.area_id = 2;
User::create(&context.db_pool, &user_changeset)
.await
.unwrap();
let date = Faker.fake();
let form = create_form(&date, 10, 20, Some(2));
let response = test_post(app, &config, Some(form)).await;
assert_eq!(StatusCode::FOUND, response.status());
assert_eq!(
1,
Availability::read_all_by_user_and_date(&context.db_pool, 2, &date)
.await
.unwrap()
.len()
)
}
}