From b4b926a8e4a203b2174404924a9264def9542781 Mon Sep 17 00:00:00 2001 From: Simon Goller Date: Fri, 14 Jun 2024 13:23:12 +0200 Subject: [PATCH] Adjust shift plan based on authentication --- dao_impl/src/booking.rs | 1 - .../20240614075633_shiftplanner-role.sql | 8 + service/src/permission.rs | 9 + service_impl/src/booking.rs | 93 ++++-- service_impl/src/permission.rs | 18 ++ service_impl/src/sales_person.rs | 25 +- service_impl/src/slot.rs | 30 +- service_impl/src/test/booking.rs | 292 ++++++++++++++++-- service_impl/src/test/sales_person.rs | 64 +++- service_impl/src/test/slot.rs | 56 ++-- 10 files changed, 499 insertions(+), 97 deletions(-) create mode 100644 migrations/20240614075633_shiftplanner-role.sql diff --git a/dao_impl/src/booking.rs b/dao_impl/src/booking.rs index dd92fd8..a37c378 100644 --- a/dao_impl/src/booking.rs +++ b/dao_impl/src/booking.rs @@ -24,7 +24,6 @@ struct BookingDb { impl TryFrom<&BookingDb> for BookingEntity { type Error = DaoError; fn try_from(booking: &BookingDb) -> Result { - dbg!(&booking); Ok(Self { id: Uuid::from_slice(booking.id.as_ref()).unwrap(), sales_person_id: Uuid::from_slice(booking.sales_person_id.as_ref()).unwrap(), diff --git a/migrations/20240614075633_shiftplanner-role.sql b/migrations/20240614075633_shiftplanner-role.sql new file mode 100644 index 0000000..48b5996 --- /dev/null +++ b/migrations/20240614075633_shiftplanner-role.sql @@ -0,0 +1,8 @@ +-- Add migration script here + +INSERT INTO role (name, update_process) VALUES ('shiftplanner', 'update-2024-06-14'); + +INSERT INTO privilege (name, update_process) VALUES ('shiftplanner', 'update-2024-06-14'); + +INSERT INTO role_privilege (role_name, privilege_name, update_process) VALUES ('shiftplanner', 'shiftplanner', 'update-2024-06-14'); +INSERT INTO role_privilege (role_name, privilege_name, update_process) VALUES ('admin', 'shiftplanner', 'update-2024-06-14'); \ No newline at end of file diff --git a/service/src/permission.rs b/service/src/permission.rs index decea17..3b7f5b9 100644 --- a/service/src/permission.rs +++ b/service/src/permission.rs @@ -6,6 +6,10 @@ use mockall::automock; use crate::ServiceError; +pub const SALES_PRIVILEGE: &str = "sales"; +pub const HR_PRIVILEGE: &str = "hr"; +pub const SHIFTPLANNER_PRIVILEGE: &str = "shiftplanner"; + /// For mocking the context locally since there is actually /// no context. #[derive(Clone, Debug, PartialEq, Eq)] @@ -74,6 +78,11 @@ pub trait PermissionService { privilege: &str, context: Authentication, ) -> Result<(), ServiceError>; + async fn check_user( + &self, + user: &str, + context: Authentication, + ) -> Result<(), ServiceError>; async fn get_privileges_for_current_user( &self, context: Authentication, diff --git a/service_impl/src/booking.rs b/service_impl/src/booking.rs index 5148cf7..463cdfd 100644 --- a/service_impl/src/booking.rs +++ b/service_impl/src/booking.rs @@ -1,7 +1,7 @@ use async_trait::async_trait; use service::{ booking::{Booking, BookingService}, - permission::Authentication, + permission::{Authentication, SALES_PRIVILEGE, SHIFTPLANNER_PRIVILEGE}, ServiceError, ValidationFailureItem, }; use std::sync::Arc; @@ -66,6 +66,51 @@ where slot_service, } } + + pub async fn check_booking_permission( + &self, + sales_person_id: Uuid, + context: AuthContext, + ) -> Result<(), ServiceError> + where + AuthContext: Clone + + Send + + Sync + + std::fmt::Debug + + Eq + + 'static + + Into> + + Into>, + { + let (shiftplanner_permission, sales_permission) = join!( + self.permission_service + .check_permission(SHIFTPLANNER_PRIVILEGE, context.clone().into()), + self.permission_service + .check_permission(SALES_PRIVILEGE, context.clone().into()), + ); + shiftplanner_permission.or(sales_permission)?; + + if self + .permission_service + .check_permission(SHIFTPLANNER_PRIVILEGE, context.clone().into()) + .await + .is_err() + { + if let Some(username) = self + .sales_person_service + .get_assigned_user(sales_person_id, Authentication::Full) + .await? + { + self.permission_service + .check_user(username.as_ref(), context.clone().into()) + .await?; + } else { + return Err(ServiceError::Forbidden); + } + } + + Ok(()) + } } #[async_trait] @@ -95,9 +140,13 @@ where &self, context: Authentication, ) -> Result, ServiceError> { - self.permission_service - .check_permission("hr", context) - .await?; + let (shiftplanner, sales) = join!( + self.permission_service + .check_permission(SHIFTPLANNER_PRIVILEGE, context.clone()), + self.permission_service + .check_permission(SALES_PRIVILEGE, context) + ); + shiftplanner.or(sales)?; Ok(self .booking_dao .all() @@ -112,9 +161,14 @@ where id: Uuid, context: Authentication, ) -> Result { - self.permission_service - .check_permission("hr", context) - .await?; + let (shiftplanner, sales) = join!( + self.permission_service + .check_permission(SHIFTPLANNER_PRIVILEGE, context.clone()), + self.permission_service + .check_permission(SALES_PRIVILEGE, context) + ); + shiftplanner.or(sales)?; + let booking_entity = self.booking_dao.find_by_id(id).await?; let booking = booking_entity .as_ref() @@ -129,12 +183,13 @@ where year: u32, context: Authentication, ) -> Result, ServiceError> { - let (hr_permission, sales_permission) = join!( + let (shiftplanner_permission, sales_permission) = join!( self.permission_service - .check_permission("hr", context.clone()), - self.permission_service.check_permission("sales", context), + .check_permission(SHIFTPLANNER_PRIVILEGE, context.clone()), + self.permission_service + .check_permission(SALES_PRIVILEGE, context), ); - hr_permission.or(sales_permission)?; + shiftplanner_permission.or(sales_permission)?; Ok(self .booking_dao @@ -150,8 +205,7 @@ where booking: &Booking, context: Authentication, ) -> Result { - self.permission_service - .check_permission("hr", context.clone()) + self.check_booking_permission(booking.sales_person_id, context) .await?; if booking.id != Uuid::nil() { @@ -181,7 +235,7 @@ where } if !self .sales_person_service - .exists(booking.sales_person_id, context.clone()) + .exists(booking.sales_person_id, Authentication::Full) .await? { validation.push(ValidationFailureItem::IdDoesNotExist( @@ -191,7 +245,7 @@ where } if !self .slot_service - .exists(booking.slot_id, context.clone()) + .exists(booking.slot_id, Authentication::Full) .await? { validation.push(ValidationFailureItem::IdDoesNotExist( @@ -242,7 +296,7 @@ where context: Authentication, ) -> Result<(), ServiceError> { self.permission_service - .check_permission("hr", context.clone()) + .check_permission(SHIFTPLANNER_PRIVILEGE, context.clone()) .await?; let from_week = self .get_for_week(from_calendar_week, from_year, Authentication::Full) @@ -281,16 +335,15 @@ where id: Uuid, context: Authentication, ) -> Result<(), ServiceError> { - self.permission_service - .check_permission("hr", context) - .await?; - let mut booking_entity = self .booking_dao .find_by_id(id) .await? .ok_or_else(move || ServiceError::EntityNotFound(id))?; + self.check_booking_permission(booking_entity.sales_person_id, context) + .await?; + booking_entity.deleted = Some(self.clock_service.date_time_now()); booking_entity.version = self.uuid_service.new_uuid("booking-version"); self.booking_dao diff --git a/service_impl/src/permission.rs b/service_impl/src/permission.rs index 4db9bc2..e54d0e6 100644 --- a/service_impl/src/permission.rs +++ b/service_impl/src/permission.rs @@ -70,6 +70,24 @@ where } } + async fn check_user( + &self, + user: &str, + context: Authentication, + ) -> Result<(), ServiceError> { + match context { + Authentication::Full => Ok(()), + Authentication::Context(context) => { + let current_user = self.user_service.current_user(context).await?; + if current_user.as_ref() == user { + Ok(()) + } else { + Err(service::ServiceError::Forbidden) + } + } + } + } + async fn get_privileges_for_current_user( &self, context: Authentication, diff --git a/service_impl/src/sales_person.rs b/service_impl/src/sales_person.rs index 36d50a7..fc3dae5 100644 --- a/service_impl/src/sales_person.rs +++ b/service_impl/src/sales_person.rs @@ -3,8 +3,11 @@ use std::sync::Arc; use async_trait::async_trait; use dao::sales_person::SalesPersonEntity; use service::{ - permission::Authentication, sales_person::SalesPerson, ServiceError, ValidationFailureItem, + permission::{Authentication, SALES_PRIVILEGE, SHIFTPLANNER_PRIVILEGE}, + sales_person::SalesPerson, + ServiceError, ValidationFailureItem, }; +use tokio::join; use uuid::Uuid; pub struct SalesPersonServiceImpl @@ -60,9 +63,13 @@ where &self, context: Authentication, ) -> Result, service::ServiceError> { - self.permission_service - .check_permission("hr", context) - .await?; + let (shiftplanner, sales) = join!( + self.permission_service + .check_permission(SHIFTPLANNER_PRIVILEGE, context.clone()), + self.permission_service + .check_permission(SALES_PRIVILEGE, context) + ); + shiftplanner.or(sales)?; Ok(self .sales_person_dao .all() @@ -77,9 +84,13 @@ where id: Uuid, context: Authentication, ) -> Result { - self.permission_service - .check_permission("hr", context) - .await?; + let (shiftplanner, sales) = join!( + self.permission_service + .check_permission(SHIFTPLANNER_PRIVILEGE, context.clone()), + self.permission_service + .check_permission(SALES_PRIVILEGE, context) + ); + shiftplanner.or(sales)?; self.sales_person_dao .find_by_id(id) .await? diff --git a/service_impl/src/slot.rs b/service_impl/src/slot.rs index b3ff026..8fd0c9a 100644 --- a/service_impl/src/slot.rs +++ b/service_impl/src/slot.rs @@ -1,7 +1,11 @@ use std::sync::Arc; use async_trait::async_trait; -use service::{permission::Authentication, slot::Slot, ServiceError, ValidationFailureItem}; +use service::{ + permission::{Authentication, SALES_PRIVILEGE, SHIFTPLANNER_PRIVILEGE}, + slot::Slot, + ServiceError, ValidationFailureItem, +}; use tokio::join; use uuid::Uuid; @@ -64,12 +68,13 @@ where &self, context: Authentication, ) -> Result, ServiceError> { - let (hr_permission, sales_permission) = join!( + let (shiftplanner_permission, sales_permission) = join!( self.permission_service - .check_permission("hr", context.clone()), - self.permission_service.check_permission("sales", context), + .check_permission(SHIFTPLANNER_PRIVILEGE, context.clone()), + self.permission_service + .check_permission(SALES_PRIVILEGE, context), ); - hr_permission.or(sales_permission)?; + shiftplanner_permission.or(sales_permission)?; Ok(self .slot_dao @@ -84,12 +89,13 @@ where id: &Uuid, context: Authentication, ) -> Result { - let (hr_permission, sales_permission) = join!( + let (shiftplanner_permission, sales_permission) = join!( self.permission_service - .check_permission("hr", context.clone()), - self.permission_service.check_permission("sales", context), + .check_permission(SHIFTPLANNER_PRIVILEGE, context.clone()), + self.permission_service + .check_permission(SALES_PRIVILEGE, context), ); - hr_permission.or(sales_permission)?; + shiftplanner_permission.or(sales_permission)?; let slot_entity = self.slot_dao.get_slot(id).await?; let slot = slot_entity @@ -113,7 +119,7 @@ where context: Authentication, ) -> Result { self.permission_service - .check_permission("hr", context.clone()) + .check_permission(SHIFTPLANNER_PRIVILEGE, context.clone()) .await?; if slot.id != Uuid::nil() { @@ -158,7 +164,7 @@ where context: Authentication, ) -> Result<(), ServiceError> { self.permission_service - .check_permission("hr", context) + .check_permission(SHIFTPLANNER_PRIVILEGE, context) .await?; let mut slot = self .slot_dao @@ -177,7 +183,7 @@ where context: Authentication, ) -> Result<(), ServiceError> { self.permission_service - .check_permission("hr", context) + .check_permission(SHIFTPLANNER_PRIVILEGE, context) .await?; let persisted_slot = self .slot_dao diff --git a/service_impl/src/test/booking.rs b/service_impl/src/test/booking.rs index 19b8fc0..d6b1abd 100644 --- a/service_impl/src/test/booking.rs +++ b/service_impl/src/test/booking.rs @@ -1,10 +1,10 @@ use crate::test::error_test::*; use dao::booking::{BookingEntity, MockBookingDao}; -use mockall::predicate::eq; +use mockall::predicate::{always, eq}; use service::{ - booking::Booking, clock::MockClockService, sales_person::MockSalesPersonService, - slot::MockSlotService, uuid_service::MockUuidService, MockPermissionService, - ValidationFailureItem, + booking::Booking, clock::MockClockService, permission::Authentication, + sales_person::MockSalesPersonService, slot::MockSlotService, uuid_service::MockUuidService, + MockPermissionService, ValidationFailureItem, }; use time::{Date, Month, PrimitiveDateTime, Time}; use uuid::{uuid, Uuid}; @@ -147,7 +147,7 @@ pub fn build_dependencies(permission: bool, role: &'static str) -> BookingServic #[tokio::test] async fn test_get_all() { - let mut deps = build_dependencies(true, "hr"); + let mut deps = build_dependencies(true, "shiftplanner"); deps.booking_dao.expect_all().returning(|| { Ok([ default_booking_entity(), @@ -160,6 +160,7 @@ async fn test_get_all() { }); let service = deps.build_service(); let result = service.get_all(().auth()).await; + dbg!(&result); assert!(result.is_ok()); let result = result.unwrap(); assert_eq!(result.len(), 2); @@ -175,7 +176,7 @@ async fn test_get_all() { #[tokio::test] async fn test_get_all_no_permission() { - let deps = build_dependencies(false, "hr"); + let deps = build_dependencies(false, "shiftplanner"); let service = deps.build_service(); let result = service.get_all(().auth()).await; test_forbidden(&result); @@ -183,7 +184,7 @@ async fn test_get_all_no_permission() { #[tokio::test] async fn test_get() { - let mut deps = build_dependencies(true, "hr"); + let mut deps = build_dependencies(true, "shiftplanner"); deps.booking_dao .expect_find_by_id() .with(eq(default_id())) @@ -196,7 +197,7 @@ async fn test_get() { #[tokio::test] async fn test_get_not_found() { - let mut deps = build_dependencies(true, "hr"); + let mut deps = build_dependencies(true, "shiftplanner"); deps.booking_dao .expect_find_by_id() .with(eq(default_id())) @@ -208,7 +209,7 @@ async fn test_get_not_found() { #[tokio::test] async fn test_get_no_permission() { - let deps = build_dependencies(false, "hr"); + let deps = build_dependencies(false, "shiftplanner"); let service = deps.build_service(); let result = service.get(default_id(), ().auth()).await; test_forbidden(&result); @@ -227,8 +228,8 @@ async fn test_get_for_week() { } #[tokio::test] -async fn test_get_for_week_hr_role() { - let mut deps = build_dependencies(true, "hr"); +async fn test_get_for_week_shiftplanner_role() { + let mut deps = build_dependencies(true, "shiftplanner"); deps.booking_dao .expect_find_by_week() .with(eq(3), eq(2024)) @@ -240,7 +241,7 @@ async fn test_get_for_week_hr_role() { #[tokio::test] async fn test_get_for_week_no_permission() { - let deps = build_dependencies(false, "hr"); + let deps = build_dependencies(false, "shiftplanner"); let service = deps.build_service(); let result = service.get_for_week(3, 2024, ().auth()).await; test_forbidden(&result); @@ -248,7 +249,7 @@ async fn test_get_for_week_no_permission() { #[tokio::test] async fn test_create() { - let mut deps = build_dependencies(true, "hr"); + let mut deps = build_dependencies(true, "shiftplanner"); deps.booking_dao .expect_create() .with( @@ -289,9 +290,144 @@ async fn test_create() { ); } +#[tokio::test] +async fn test_create_sales_user() { + let mut deps = build_dependencies(true, "sales"); + deps.booking_dao + .expect_create() + .with( + eq(BookingEntity { + created: generate_default_datetime(), + ..default_booking_entity() + }), + eq("booking-service"), + ) + .returning(|_, _| Ok(())); + deps.uuid_service + .expect_new_uuid() + .with(eq("booking-id")) + .returning(|_| default_id()); + deps.uuid_service + .expect_new_uuid() + .with(eq("booking-version")) + .returning(|_| default_version()); + deps.sales_person_service + .expect_get_assigned_user() + .with(eq(default_sales_person_id()), always()) + .returning(|_, _| Ok(Some("TESTUSER".into()))); + deps.permission_service + .expect_check_user() + .with(eq("TESTUSER"), always()) + .returning(|_, _| Ok(())); + let service = deps.build_service(); + let result = service + .create( + &Booking { + id: Uuid::nil(), + version: Uuid::nil(), + created: None, + ..default_booking() + }, + ().auth(), + ) + .await; + assert!(result.is_ok()); + assert_eq!( + result.unwrap(), + Booking { + created: Some(generate_default_datetime()), + ..default_booking() + } + ); +} + +#[tokio::test] +async fn test_create_sales_user_not_exist() { + let mut deps = build_dependencies(true, "sales"); + deps.booking_dao + .expect_create() + .with( + eq(BookingEntity { + created: generate_default_datetime(), + ..default_booking_entity() + }), + eq("booking-service"), + ) + .returning(|_, _| Ok(())); + deps.uuid_service + .expect_new_uuid() + .with(eq("booking-id")) + .returning(|_| default_id()); + deps.uuid_service + .expect_new_uuid() + .with(eq("booking-version")) + .returning(|_| default_version()); + deps.sales_person_service + .expect_get_assigned_user() + .with(eq(default_sales_person_id()), always()) + .returning(|_, _| Ok(Some("TESTUSER".into()))); + deps.permission_service + .expect_check_user() + .with(eq("TESTUSER"), always()) + .returning(|_, _| Err(service::ServiceError::Forbidden)); + let service = deps.build_service(); + let result = service + .create( + &Booking { + id: Uuid::nil(), + version: Uuid::nil(), + created: None, + ..default_booking() + }, + ().auth(), + ) + .await; + test_forbidden(&result); +} + +#[tokio::test] +async fn test_create_sales_user_no_permission() { + let mut deps = build_dependencies(true, "sales"); + deps.booking_dao + .expect_create() + .with( + eq(BookingEntity { + created: generate_default_datetime(), + ..default_booking_entity() + }), + eq("booking-service"), + ) + .returning(|_, _| Ok(())); + deps.uuid_service + .expect_new_uuid() + .with(eq("booking-id")) + .returning(|_| default_id()); + deps.uuid_service + .expect_new_uuid() + .with(eq("booking-version")) + .returning(|_| default_version()); + deps.sales_person_service + .expect_get_assigned_user() + .with(eq(default_sales_person_id()), always()) + .returning(|_, _| Ok(None)); + let service = deps.build_service(); + let result = service + .create( + &Booking { + id: Uuid::nil(), + version: Uuid::nil(), + created: None, + ..default_booking() + }, + ().auth(), + ) + .await; + test_forbidden(&result); +} + #[tokio::test] async fn test_create_no_permission() { - let deps = build_dependencies(false, "hr"); + let deps = build_dependencies(false, "shiftplanner"); let service = deps.build_service(); let result = service .create( @@ -308,7 +444,7 @@ async fn test_create_no_permission() { #[tokio::test] async fn test_create_with_id() { - let deps = build_dependencies(true, "hr"); + let deps = build_dependencies(true, "shiftplanner"); let service = deps.build_service(); let result = service .create( @@ -324,7 +460,7 @@ async fn test_create_with_id() { #[tokio::test] async fn test_create_with_version() { - let deps = build_dependencies(true, "hr"); + let deps = build_dependencies(true, "shiftplanner"); let service = deps.build_service(); let result = service .create( @@ -340,7 +476,7 @@ async fn test_create_with_version() { #[tokio::test] async fn test_create_with_created_fail() { - let deps = build_dependencies(true, "hr"); + let deps = build_dependencies(true, "shiftplanner"); let service = deps.build_service(); let result = service .create( @@ -361,11 +497,11 @@ async fn test_create_with_created_fail() { #[tokio::test] async fn test_create_sales_person_does_not_exist() { - let mut deps = build_dependencies(true, "hr"); + let mut deps = build_dependencies(true, "shiftplanner"); deps.sales_person_service.checkpoint(); deps.sales_person_service .expect_exists() - .with(eq(default_sales_person_id()), eq(().auth())) + .with(eq(default_sales_person_id()), eq(Authentication::Full)) .returning(|_, _| Ok(false)); let service = deps.build_service(); let result = service @@ -389,7 +525,7 @@ async fn test_create_sales_person_does_not_exist() { #[tokio::test] async fn test_create_booking_data_already_exists() { - let mut deps = build_dependencies(true, "hr"); + let mut deps = build_dependencies(true, "shiftplanner"); deps.booking_dao.checkpoint(); deps.booking_dao .expect_find_by_booking_data() @@ -417,11 +553,11 @@ async fn test_create_booking_data_already_exists() { #[tokio::test] async fn test_create_slot_does_not_exist() { - let mut deps = build_dependencies(true, "hr"); + let mut deps = build_dependencies(true, "shiftplanner"); deps.slot_service.checkpoint(); deps.slot_service .expect_exists() - .with(eq(default_slot_id()), eq(().auth())) + .with(eq(default_slot_id()), eq(Authentication::Full)) .returning(|_, _| Ok(false)); let service = deps.build_service(); let result = service @@ -444,7 +580,11 @@ async fn test_create_slot_does_not_exist() { #[tokio::test] async fn test_delete_no_permission() { - let deps = build_dependencies(false, "hr"); + let mut deps = build_dependencies(false, "shiftplanner"); + deps.booking_dao + .expect_find_by_id() + .with(eq(default_id())) + .returning(|_| Ok(Some(default_booking_entity()))); let service = deps.build_service(); let result = service.delete(default_id(), ().auth()).await; test_forbidden(&result); @@ -452,7 +592,7 @@ async fn test_delete_no_permission() { #[tokio::test] async fn test_delete_not_found() { - let mut deps = build_dependencies(true, "hr"); + let mut deps = build_dependencies(true, "shiftplanner"); deps.booking_dao .expect_find_by_id() .with(eq(default_id())) @@ -464,7 +604,7 @@ async fn test_delete_not_found() { #[tokio::test] async fn test_delete() { - let mut deps = build_dependencies(true, "hr"); + let mut deps = build_dependencies(true, "shiftplanner"); deps.booking_dao .expect_find_by_id() .with(eq(default_id())) @@ -489,3 +629,105 @@ async fn test_delete() { assert!(result.is_ok()); assert_eq!(result.unwrap(), ()); } + +#[tokio::test] +async fn test_delete_sales_user() { + let mut deps = build_dependencies(true, "sales"); + deps.booking_dao + .expect_find_by_id() + .with(eq(default_id())) + .returning(|_| Ok(Some(default_booking_entity()))); + deps.booking_dao + .expect_update() + .with( + eq(BookingEntity { + deleted: Some(generate_default_datetime()), + version: alternate_version(), + ..default_booking_entity() + }), + eq("booking-service"), + ) + .returning(|_, _| Ok(())); + deps.uuid_service + .expect_new_uuid() + .with(eq("booking-version")) + .returning(|_| alternate_version()); + deps.sales_person_service + .expect_get_assigned_user() + .with(eq(default_sales_person_id()), always()) + .returning(|_, _| Ok(Some("TESTUSER".into()))); + deps.permission_service + .expect_check_user() + .with(eq("TESTUSER"), always()) + .returning(|_, _| Ok(())); + let service = deps.build_service(); + let result = service.delete(default_id(), ().auth()).await; + assert!(result.is_ok()); + assert_eq!(result.unwrap(), ()); +} + +#[tokio::test] +async fn test_delete_sales_user_not_exists() { + let mut deps = build_dependencies(true, "sales"); + deps.booking_dao + .expect_find_by_id() + .with(eq(default_id())) + .returning(|_| Ok(Some(default_booking_entity()))); + deps.booking_dao + .expect_update() + .with( + eq(BookingEntity { + deleted: Some(generate_default_datetime()), + version: alternate_version(), + ..default_booking_entity() + }), + eq("booking-service"), + ) + .returning(|_, _| Ok(())); + deps.uuid_service + .expect_new_uuid() + .with(eq("booking-version")) + .returning(|_| alternate_version()); + deps.sales_person_service + .expect_get_assigned_user() + .with(eq(default_sales_person_id()), always()) + .returning(|_, _| Ok(None)); + let service = deps.build_service(); + let result = service.delete(default_id(), ().auth()).await; + test_forbidden(&result); +} + +#[tokio::test] +async fn test_delete_sales_user_not_allowed() { + let mut deps = build_dependencies(true, "sales"); + deps.booking_dao + .expect_find_by_id() + .with(eq(default_id())) + .returning(|_| Ok(Some(default_booking_entity()))); + deps.booking_dao + .expect_update() + .with( + eq(BookingEntity { + deleted: Some(generate_default_datetime()), + version: alternate_version(), + ..default_booking_entity() + }), + eq("booking-service"), + ) + .returning(|_, _| Ok(())); + deps.uuid_service + .expect_new_uuid() + .with(eq("booking-version")) + .returning(|_| alternate_version()); + deps.sales_person_service + .expect_get_assigned_user() + .with(eq(default_sales_person_id()), always()) + .returning(|_, _| Ok(Some("TESTUSER".into()))); + deps.permission_service + .expect_check_user() + .with(eq("TESTUSER"), always()) + .returning(|_, _| Err(service::ServiceError::Forbidden)); + let service = deps.build_service(); + let result = service.delete(default_id(), ().auth()).await; + test_forbidden(&result); +} diff --git a/service_impl/src/test/sales_person.rs b/service_impl/src/test/sales_person.rs index 116637e..2fe438f 100644 --- a/service_impl/src/test/sales_person.rs +++ b/service_impl/src/test/sales_person.rs @@ -112,7 +112,35 @@ pub fn default_sales_person() -> service::sales_person::SalesPerson { #[tokio::test] async fn test_get_all() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); + dependencies.sales_person_dao.expect_all().returning(|| { + Ok([ + default_sales_person_entity(), + SalesPersonEntity { + id: alternate_id(), + name: "Jane Doe".into(), + ..default_sales_person_entity() + }, + ] + .into()) + }); + let sales_person_service = dependencies.build_service(); + let result = sales_person_service.get_all(().auth()).await.unwrap(); + assert_eq!(2, result.len()); + assert_eq!(default_sales_person(), result[0]); + assert_eq!( + service::sales_person::SalesPerson { + id: alternate_id(), + name: "Jane Doe".into(), + ..default_sales_person() + }, + result[1] + ); +} + +#[tokio::test] +async fn test_get_all_sales_user() { + let mut dependencies = build_dependencies(true, "sales"); dependencies.sales_person_dao.expect_all().returning(|| { Ok([ default_sales_person_entity(), @@ -148,7 +176,21 @@ async fn test_get_all_no_permission() { #[tokio::test] async fn test_get() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); + dependencies + .sales_person_dao + .expect_find_by_id() + .with(eq(default_id())) + .times(1) + .returning(|_| Ok(Some(default_sales_person_entity()))); + let sales_person_service = dependencies.build_service(); + let result = sales_person_service.get(default_id(), ().auth()).await; + assert_eq!(default_sales_person(), result.unwrap()); +} + +#[tokio::test] +async fn test_get_sales_user() { + let mut dependencies = build_dependencies(true, "sales"); dependencies .sales_person_dao .expect_find_by_id() @@ -162,7 +204,7 @@ async fn test_get() { #[tokio::test] async fn test_get_no_permission() { - let dependencies = build_dependencies(false, "hr"); + let dependencies = build_dependencies(false, "sales"); let sales_person_service = dependencies.build_service(); let result = sales_person_service.get(default_id(), ().auth()).await; test_forbidden(&result); @@ -170,7 +212,21 @@ async fn test_get_no_permission() { #[tokio::test] async fn test_get_not_found() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); + dependencies + .sales_person_dao + .expect_find_by_id() + .with(eq(default_id())) + .times(1) + .returning(|_| Ok(None)); + let sales_person_service = dependencies.build_service(); + let result = sales_person_service.get(default_id(), ().auth()).await; + test_not_found(&result, &default_id()); +} + +#[tokio::test] +async fn test_get_not_found_sales_user() { + let mut dependencies = build_dependencies(true, "sales"); dependencies .sales_person_dao .expect_find_by_id() diff --git a/service_impl/src/test/slot.rs b/service_impl/src/test/slot.rs index fa79f72..59bf115 100644 --- a/service_impl/src/test/slot.rs +++ b/service_impl/src/test/slot.rs @@ -108,7 +108,7 @@ pub fn build_dependencies(permission: bool, role: &'static str) -> SlotServiceDe #[tokio::test] async fn test_get_slots() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); dependencies.slot_dao.expect_get_slots().returning(|| { Ok(Arc::new([ SlotEntity { @@ -140,7 +140,7 @@ async fn test_get_slots() { #[tokio::test] async fn test_get_slots_sales_role() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); dependencies .slot_dao .expect_get_slots() @@ -152,7 +152,7 @@ async fn test_get_slots_sales_role() { #[tokio::test] async fn test_get_slots_no_permission() { - let mut dependencies = build_dependencies(false, "hr"); + let mut dependencies = build_dependencies(false, "shiftplanner"); dependencies .slot_dao .expect_get_slots() @@ -164,7 +164,7 @@ async fn test_get_slots_no_permission() { #[tokio::test] async fn test_get_slot() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); dependencies .slot_dao .expect_get_slot() @@ -194,7 +194,7 @@ async fn test_get_slot_sales_role() { #[tokio::test] async fn test_get_slot_not_found() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); dependencies .slot_dao .expect_get_slot() @@ -208,7 +208,7 @@ async fn test_get_slot_not_found() { #[tokio::test] async fn test_get_slot_no_permission() { - let dependencies = build_dependencies(false, "hr"); + let dependencies = build_dependencies(false, "shiftplanner"); let slot_service = dependencies.build_service(); let result = slot_service.get_slot(&default_id(), ().auth()).await; test_forbidden(&result); @@ -216,7 +216,7 @@ async fn test_get_slot_no_permission() { #[tokio::test] async fn test_create_slot() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); dependencies .slot_dao .expect_create_slot() @@ -255,7 +255,7 @@ async fn test_create_slot() { #[tokio::test] async fn test_create_slot_no_permission() { - let dependencies = build_dependencies(false, "hr"); + let dependencies = build_dependencies(false, "shiftplanner"); let slot_service = dependencies.build_service(); let result = slot_service .create_slot(&generate_default_slot(), ().auth()) @@ -265,7 +265,7 @@ async fn test_create_slot_no_permission() { #[tokio::test] async fn test_create_slot_non_zero_id() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); dependencies .uuid_service .expect_new_uuid() @@ -291,7 +291,7 @@ async fn test_create_slot_non_zero_id() { #[tokio::test] async fn test_create_slot_non_zero_version() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); dependencies .uuid_service .expect_new_uuid() @@ -317,7 +317,7 @@ async fn test_create_slot_non_zero_version() { #[tokio::test] async fn test_create_slot_intersects() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); dependencies.slot_dao.expect_get_slots().returning(|| { Ok(Arc::new([ generate_default_slot_entity(), @@ -460,7 +460,7 @@ async fn test_create_slot_intersects() { #[tokio::test] async fn test_create_slot_time_order() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); dependencies .slot_dao .expect_create_slot() @@ -488,7 +488,7 @@ async fn test_create_slot_time_order() { #[tokio::test] async fn test_create_slot_date_order() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); dependencies .slot_dao .expect_create_slot() @@ -516,7 +516,7 @@ async fn test_create_slot_date_order() { #[tokio::test] async fn test_delete_slot() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); dependencies .slot_dao .expect_get_slot() @@ -546,7 +546,7 @@ async fn test_delete_slot() { #[tokio::test] async fn test_delete_slot_no_permission() { - let dependencies = build_dependencies(false, "hr"); + let dependencies = build_dependencies(false, "shiftplanner"); let slot_service = dependencies.build_service(); let result = slot_service.delete_slot(&default_id(), ().auth()).await; test_forbidden(&result); @@ -554,7 +554,7 @@ async fn test_delete_slot_no_permission() { #[tokio::test] async fn test_delete_slot_not_found() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); dependencies .slot_dao .expect_get_slot() @@ -568,7 +568,7 @@ async fn test_delete_slot_not_found() { #[tokio::test] async fn test_update_slot_no_permission() { - let dependencies = build_dependencies(false, "hr"); + let dependencies = build_dependencies(false, "shiftplanner"); let slot_service = dependencies.build_service(); let result = slot_service .update_slot(&generate_default_slot(), ().auth()) @@ -578,7 +578,7 @@ async fn test_update_slot_no_permission() { #[tokio::test] async fn test_update_slot_not_found() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); dependencies .slot_dao .expect_get_slot() @@ -594,7 +594,7 @@ async fn test_update_slot_not_found() { #[tokio::test] async fn test_update_slot_version_mismatch() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); dependencies .slot_dao .expect_get_slot() @@ -620,7 +620,7 @@ async fn test_update_slot_version_mismatch() { #[tokio::test] async fn test_update_slot_valid_to() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); dependencies .slot_dao .expect_update_slot() @@ -666,7 +666,7 @@ async fn test_update_slot_valid_to() { #[tokio::test] async fn test_update_slot_valid_to_before_valid_from() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); dependencies .slot_dao .expect_get_slot() @@ -690,7 +690,7 @@ async fn test_update_slot_valid_to_before_valid_from() { #[tokio::test] async fn test_update_slot_deleted() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); dependencies .slot_dao .expect_get_slot() @@ -736,7 +736,7 @@ async fn test_update_slot_deleted() { #[tokio::test] async fn test_update_slot_day_of_week_forbidden() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); dependencies .slot_dao .expect_get_slot() @@ -761,7 +761,7 @@ async fn test_update_slot_day_of_week_forbidden() { #[tokio::test] async fn test_update_to_forbidden_when_not_none() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); dependencies .slot_dao .expect_get_slot() @@ -795,7 +795,7 @@ async fn test_update_to_forbidden_when_not_none() { #[tokio::test] async fn test_update_from_forbidden() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); dependencies .slot_dao .expect_get_slot() @@ -820,7 +820,7 @@ async fn test_update_from_forbidden() { #[tokio::test] async fn test_update_to_forbidden() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); dependencies .slot_dao .expect_get_slot() @@ -845,7 +845,7 @@ async fn test_update_to_forbidden() { #[tokio::test] async fn test_update_valid_from_forbidden() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); dependencies .slot_dao .expect_get_slot() @@ -871,7 +871,7 @@ async fn test_update_valid_from_forbidden() { #[tokio::test] async fn test_update_valid_multiple_forbidden_changes() { - let mut dependencies = build_dependencies(true, "hr"); + let mut dependencies = build_dependencies(true, "shiftplanner"); dependencies .slot_dao .expect_get_slot()