diff --git a/dao/src/booking.rs b/dao/src/booking.rs index a1a6e62..72ef603 100644 --- a/dao/src/booking.rs +++ b/dao/src/booking.rs @@ -31,6 +31,11 @@ pub trait BookingDao { calendar_week: i32, year: u32, ) -> Result, DaoError>; + async fn find_by_week( + &self, + calendar_week: i32, + year: u32, + ) -> Result, DaoError>; async fn create(&self, entity: &BookingEntity, process: &str) -> Result<(), DaoError>; async fn update(&self, entity: &BookingEntity, process: &str) -> Result<(), DaoError>; } diff --git a/dao_impl/src/booking.rs b/dao_impl/src/booking.rs index 96de639..ee6d8aa 100644 --- a/dao_impl/src/booking.rs +++ b/dao_impl/src/booking.rs @@ -106,6 +106,26 @@ impl BookingDao for BookingDaoImpl { .transpose()?) } + async fn find_by_week( + &self, + calendar_week: i32, + year: u32, + ) -> Result, DaoError> { + Ok(query_as!( + BookingDb, + "SELECT id, sales_person_id, slot_id, calendar_week, year, created, deleted, update_version FROM booking WHERE calendar_week = ? AND year = ? AND deleted IS NULL", + calendar_week, + year, + ) + .fetch_all(self.pool.as_ref()) + .await + .map_db_error()? + .iter() + .map(BookingEntity::try_from) + .collect::, DaoError>>()? + ) + } + async fn create(&self, entity: &BookingEntity, process: &str) -> Result<(), DaoError> { let id_vec = entity.id.as_bytes().to_vec(); let sales_person_id_vec = entity.sales_person_id.as_bytes().to_vec(); diff --git a/rest/src/booking.rs b/rest/src/booking.rs index c70ecb1..2776f63 100644 --- a/rest/src/booking.rs +++ b/rest/src/booking.rs @@ -14,6 +14,7 @@ use service::booking::{Booking, BookingService}; pub fn generate_route() -> Router { Router::new() .route("/", get(get_all_bookings::)) + .route("/week/:year/:calendar_week", get(get_by_week::)) .route("/:id", get(get_booking::)) .route("/", post(create_booking::)) .route("/:id", delete(delete_booking::)) @@ -41,6 +42,29 @@ pub async fn get_all_bookings( ) } +pub async fn get_by_week( + rest_state: State, + Extension(context): Extension, + Path((calendar_week, year)): Path<(i32, u32)>, +) -> Response { + error_handler( + (async { + let bookings: Arc<[BookingTO]> = rest_state + .booking_service() + .get_for_week(calendar_week, year, context.into()) + .await? + .iter() + .map(BookingTO::from) + .collect(); + Ok(Response::builder() + .status(200) + .body(Body::new(serde_json::to_string(&bookings).unwrap())) + .unwrap()) + }) + .await, + ) +} + pub async fn get_booking( rest_state: State, Extension(context): Extension, diff --git a/service/src/booking.rs b/service/src/booking.rs index dab4e19..42ff22e 100644 --- a/service/src/booking.rs +++ b/service/src/booking.rs @@ -64,6 +64,12 @@ pub trait BookingService { id: Uuid, context: Authentication, ) -> Result; + async fn get_for_week( + &self, + calendar_week: i32, + year: u32, + context: Authentication, + ) -> Result, ServiceError>; async fn create( &self, booking: &Booking, diff --git a/service_impl/src/booking.rs b/service_impl/src/booking.rs index 740c5ef..6748c18 100644 --- a/service_impl/src/booking.rs +++ b/service_impl/src/booking.rs @@ -5,6 +5,7 @@ use service::{ ServiceError, ValidationFailureItem, }; use std::sync::Arc; +use tokio::join; use uuid::Uuid; const BOOKING_SERVICE_PROCESS: &str = "booking-service"; @@ -122,6 +123,28 @@ where Ok(booking) } + async fn get_for_week( + &self, + calendar_week: i32, + year: u32, + context: Authentication, + ) -> Result, ServiceError> { + let (hr_permission, sales_permission) = join!( + self.permission_service + .check_permission("hr", context.clone()), + self.permission_service.check_permission("sales", context), + ); + hr_permission.or(sales_permission)?; + + Ok(self + .booking_dao + .find_by_week(calendar_week, year) + .await? + .iter() + .map(Booking::from) + .collect()) + } + async fn create( &self, booking: &Booking, diff --git a/service_impl/src/test/booking.rs b/service_impl/src/test/booking.rs index a262689..19b8fc0 100644 --- a/service_impl/src/test/booking.rs +++ b/service_impl/src/test/booking.rs @@ -214,6 +214,38 @@ async fn test_get_no_permission() { test_forbidden(&result); } +#[tokio::test] +async fn test_get_for_week() { + let mut deps = build_dependencies(true, "sales"); + deps.booking_dao + .expect_find_by_week() + .with(eq(3), eq(2024)) + .returning(|_, _| Ok([default_booking_entity()].into())); + let service = deps.build_service(); + let result = service.get_for_week(3, 2024, ().auth()).await; + assert_eq!(result.unwrap(), [default_booking()].into()); +} + +#[tokio::test] +async fn test_get_for_week_hr_role() { + let mut deps = build_dependencies(true, "hr"); + deps.booking_dao + .expect_find_by_week() + .with(eq(3), eq(2024)) + .returning(|_, _| Ok([default_booking_entity()].into())); + let service = deps.build_service(); + let result = service.get_for_week(3, 2024, ().auth()).await; + assert_eq!(result.unwrap(), [default_booking()].into()); +} + +#[tokio::test] +async fn test_get_for_week_no_permission() { + let deps = build_dependencies(false, "hr"); + let service = deps.build_service(); + let result = service.get_for_week(3, 2024, ().auth()).await; + test_forbidden(&result); +} + #[tokio::test] async fn test_create() { let mut deps = build_dependencies(true, "hr");