Introduce is_paid attribute to SalesUser

This commit is contained in:
Simon Goller 2024-06-19 09:59:14 +02:00
parent 17e16d35a7
commit d48c97edac
8 changed files with 304 additions and 36 deletions

View file

@ -3,7 +3,7 @@ use std::sync::Arc;
use async_trait::async_trait;
use dao::sales_person::SalesPersonEntity;
use service::{
permission::{Authentication, SALES_PRIVILEGE, SHIFTPLANNER_PRIVILEGE},
permission::{Authentication, HR_PRIVILEGE, SALES_PRIVILEGE, SHIFTPLANNER_PRIVILEGE},
sales_person::SalesPerson,
ServiceError, ValidationFailureItem,
};
@ -63,19 +63,54 @@ where
&self,
context: Authentication<Self::Context>,
) -> Result<Arc<[service::sales_person::SalesPerson]>, service::ServiceError> {
let (shiftplanner, sales) = join!(
let (shiftplanner, sales, hr) = join!(
self.permission_service
.check_permission(SHIFTPLANNER_PRIVILEGE, context.clone()),
self.permission_service
.check_permission(SALES_PRIVILEGE, context)
.check_permission(SALES_PRIVILEGE, context.clone()),
self.permission_service
.check_permission(HR_PRIVILEGE, context.clone())
);
shiftplanner.or(sales)?;
Ok(self
shiftplanner.or(sales).or(hr)?;
let mut sales_persons = self
.sales_person_dao
.all()
.await?
.iter()
.map(SalesPerson::from)
.collect::<Box<[SalesPerson]>>();
// Remove sensitive information if user is not a sales user.
if self
.permission_service
.check_permission(HR_PRIVILEGE, context)
.await
.is_err()
{
println!("No HR Role - remove sensitive data");
sales_persons.iter_mut().for_each(|sales_person| {
sales_person.is_paid = None;
});
} else {
println!("HR ROLE - no sensitive data removal");
}
Ok(sales_persons.into())
}
async fn get_all_paid(
&self,
context: Authentication<Self::Context>,
) -> Result<Arc<[SalesPerson]>, ServiceError> {
self.permission_service
.check_permission(HR_PRIVILEGE, context)
.await?;
Ok(self
.sales_person_dao
.all_paid()
.await?
.iter()
.map(SalesPerson::from)
.collect())
}
@ -84,19 +119,53 @@ where
id: Uuid,
context: Authentication<Self::Context>,
) -> Result<service::sales_person::SalesPerson, service::ServiceError> {
let (shiftplanner, sales) = join!(
let (shiftplanner, sales, hr) = join!(
self.permission_service
.check_permission(SHIFTPLANNER_PRIVILEGE, context.clone()),
self.permission_service
.check_permission(SALES_PRIVILEGE, context)
.check_permission(SALES_PRIVILEGE, context.clone()),
self.permission_service
.check_permission(HR_PRIVILEGE, context.clone())
);
shiftplanner.or(sales)?;
self.sales_person_dao
shiftplanner.or(sales).or(hr)?;
println!("Has roles");
let mut sales_person = self
.sales_person_dao
.find_by_id(id)
.await?
.as_ref()
.map(SalesPerson::from)
.ok_or(ServiceError::EntityNotFound(id))
.ok_or(ServiceError::EntityNotFound(id))?;
let remove_sensitive_data = if self
.permission_service
.check_permission(HR_PRIVILEGE, context.clone())
.await
.is_err()
{
println!("No HR Role - futher checks required");
if let (Some(current_user_id), Some(assigned_user)) = (
self.permission_service
.current_user_id(context.clone())
.await?,
self.get_assigned_user(id, Authentication::Full).await?,
) {
println!("Check if user ID matches");
current_user_id != assigned_user
} else {
println!("UserID or assigned user is missing - must remove sensitive data");
true
}
} else {
println!("HR Role - no sensitive data removal");
false
};
if remove_sensitive_data {
sales_person.is_paid = None;
}
Ok(sales_person)
}
async fn exists(
@ -117,7 +186,7 @@ where
context: Authentication<Self::Context>,
) -> Result<SalesPerson, service::ServiceError> {
self.permission_service
.check_permission("hr", context)
.check_permission(HR_PRIVILEGE, context)
.await?;
if sales_person.id != Uuid::nil() {
@ -147,7 +216,7 @@ where
context: Authentication<Self::Context>,
) -> Result<SalesPerson, ServiceError> {
self.permission_service
.check_permission("hr", context)
.check_permission(HR_PRIVILEGE, context)
.await?;
let sales_person_entity = self
@ -195,7 +264,7 @@ where
context: Authentication<Self::Context>,
) -> Result<(), ServiceError> {
self.permission_service
.check_permission("hr", context)
.check_permission(HR_PRIVILEGE, context)
.await?;
let mut sales_person_entity = self
.sales_person_dao
@ -216,7 +285,7 @@ where
context: Authentication<Self::Context>,
) -> Result<Option<Arc<str>>, ServiceError> {
self.permission_service
.check_permission("hr", context)
.check_permission(HR_PRIVILEGE, context)
.await?;
Ok(self
.sales_person_dao
@ -231,7 +300,7 @@ where
context: Authentication<Self::Context>,
) -> Result<(), ServiceError> {
self.permission_service
.check_permission("hr", context)
.check_permission(HR_PRIVILEGE, context)
.await?;
self.sales_person_dao
.discard_assigned_user(sales_person_id)
@ -250,7 +319,7 @@ where
context: Authentication<Self::Context>,
) -> Result<Option<SalesPerson>, ServiceError> {
self.permission_service
.check_permission("hr", context)
.check_permission(HR_PRIVILEGE, context)
.await?;
Ok(self
.sales_person_dao

View file

@ -1,8 +1,9 @@
use super::error_test::*;
use dao::sales_person::{MockSalesPersonDao, SalesPersonEntity};
use mockall::predicate::eq;
use mockall::predicate::{always, eq};
use service::{
clock::MockClockService,
permission::Authentication,
sales_person::{SalesPerson, SalesPersonService},
uuid_service::MockUuidService,
MockPermissionService,
@ -42,17 +43,19 @@ pub fn build_dependencies(permission: bool, role: &'static str) -> SalesPersonSe
let mut permission_service = MockPermissionService::new();
permission_service
.expect_check_permission()
.with(eq(role), eq(().auth()))
.returning(move |_, _| {
if permission {
.with(always(), always())
.returning(move |inner_role, context| {
if context == Authentication::Full || (permission && inner_role == role) {
println!("Permission granted");
Ok(())
} else {
println!("Permission denied");
Err(service::ServiceError::Forbidden)
}
});
permission_service
.expect_check_permission()
.returning(move |_, _| Err(service::ServiceError::Forbidden));
.expect_current_user_id()
.returning(|_| Ok(Some("TESTUSER".into())));
let mut clock_service = MockClockService::new();
clock_service
.expect_time_now()
@ -95,6 +98,7 @@ pub fn default_sales_person_entity() -> dao::sales_person::SalesPersonEntity {
id: default_id(),
name: "John Doe".into(),
background_color: "#FFF".into(),
is_paid: false,
deleted: None,
inactive: false,
version: default_version(),
@ -106,6 +110,7 @@ pub fn default_sales_person() -> service::sales_person::SalesPerson {
id: default_id(),
name: "John Doe".into(),
background_color: "#FFF".into(),
is_paid: Some(false),
inactive: false,
deleted: None,
version: default_version(),
@ -113,7 +118,7 @@ pub fn default_sales_person() -> service::sales_person::SalesPerson {
}
#[tokio::test]
async fn test_get_all() {
async fn test_get_all_shiftplanner() {
let mut dependencies = build_dependencies(true, "shiftplanner");
dependencies.sales_person_dao.expect_all().returning(|| {
Ok([
@ -129,11 +134,18 @@ async fn test_get_all() {
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 {
is_paid: None,
..default_sales_person()
},
result[0]
);
assert_eq!(
service::sales_person::SalesPerson {
id: alternate_id(),
name: "Jane Doe".into(),
is_paid: None,
..default_sales_person()
},
result[1]
@ -157,6 +169,41 @@ async fn test_get_all_sales_user() {
let sales_person_service = dependencies.build_service();
let result = sales_person_service.get_all(().auth()).await.unwrap();
assert_eq!(2, result.len());
assert_eq!(
service::sales_person::SalesPerson {
is_paid: None,
..default_sales_person()
},
result[0]
);
assert_eq!(
service::sales_person::SalesPerson {
id: alternate_id(),
name: "Jane Doe".into(),
is_paid: None,
..default_sales_person()
},
result[1]
);
}
#[tokio::test]
async fn test_get_all_hr_user() {
let mut dependencies = build_dependencies(true, "hr");
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 {
@ -177,7 +224,26 @@ async fn test_get_all_no_permission() {
}
#[tokio::test]
async fn test_get() {
async fn test_get_hr_user() {
let mut dependencies = build_dependencies(true, "hr");
dependencies
.sales_person_dao
.expect_find_by_id()
.with(eq(default_id()))
.times(1)
.returning(|_| Ok(Some(default_sales_person_entity())));
dependencies
.sales_person_dao
.expect_get_assigned_user()
.with(eq(default_id()))
.returning(|_| Ok(Some("TESTUSER".into())));
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_shiftplanner_user_other_user() {
let mut dependencies = build_dependencies(true, "shiftplanner");
dependencies
.sales_person_dao
@ -185,13 +251,24 @@ async fn test_get() {
.with(eq(default_id()))
.times(1)
.returning(|_| Ok(Some(default_sales_person_entity())));
dependencies
.sales_person_dao
.expect_get_assigned_user()
.with(eq(default_id()))
.returning(|_| Ok(Some("OTHER".into())));
let sales_person_service = dependencies.build_service();
let result = sales_person_service.get(default_id(), ().auth()).await;
assert_eq!(default_sales_person(), result.unwrap());
assert_eq!(
SalesPerson {
is_paid: None,
..default_sales_person()
},
result.unwrap()
);
}
#[tokio::test]
async fn test_get_sales_user() {
async fn test_get_sales_user_other_user() {
let mut dependencies = build_dependencies(true, "sales");
dependencies
.sales_person_dao
@ -199,6 +276,60 @@ async fn test_get_sales_user() {
.with(eq(default_id()))
.times(1)
.returning(|_| Ok(Some(default_sales_person_entity())));
dependencies
.sales_person_dao
.expect_get_assigned_user()
.with(eq(default_id()))
.returning(|_| Ok(Some("OTHER".into())));
let sales_person_service = dependencies.build_service();
let result = sales_person_service.get(default_id(), ().auth()).await;
assert_eq!(
SalesPerson {
is_paid: None,
..default_sales_person()
},
result.unwrap()
);
}
#[tokio::test]
async fn test_get_shiftplanner_user_same_user() {
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())));
dependencies
.sales_person_dao
.expect_get_assigned_user()
.with(eq(default_id()))
.returning(|_| Ok(Some("TESTUSER".into())));
let sales_person_service = dependencies.build_service();
let result = sales_person_service.get(default_id(), ().auth()).await;
assert_eq!(
SalesPerson {
..default_sales_person()
},
result.unwrap()
);
}
#[tokio::test]
async fn test_get_sales_user_same_user() {
let mut dependencies = build_dependencies(true, "sales");
dependencies
.sales_person_dao
.expect_find_by_id()
.with(eq(default_id()))
.times(1)
.returning(|_| Ok(Some(default_sales_person_entity())));
dependencies
.sales_person_dao
.expect_get_assigned_user()
.with(eq(default_id()))
.returning(|_| Ok(Some("TESTUSER".into())));
let sales_person_service = dependencies.build_service();
let result = sales_person_service.get(default_id(), ().auth()).await;
assert_eq!(default_sales_person(), result.unwrap());