From b31d3cff75cb82d034bae6e0f5697fd29c13ea67 Mon Sep 17 00:00:00 2001 From: Aravinth Manivannan Date: Wed, 22 Jan 2025 18:05:03 +0530 Subject: [PATCH] feat: get roles for store service --- src/identity/adapters/mod.rs | 1 + .../port/output/db/get_roles_for_store.rs | 4 +- .../services/get_roles_for_store_service.rs | 121 ++++++++++++++++++ src/identity/application/services/mod.rs | 24 +++- src/identity/domain/aggregate.rs | 29 +++-- src/identity/domain/role_aggregate.rs | 22 +++- 6 files changed, 183 insertions(+), 18 deletions(-) create mode 100644 src/identity/application/services/get_roles_for_store_service.rs diff --git a/src/identity/adapters/mod.rs b/src/identity/adapters/mod.rs index 988068e..2c9c25d 100644 --- a/src/identity/adapters/mod.rs +++ b/src/identity/adapters/mod.rs @@ -52,6 +52,7 @@ pub fn load_adapters(pool: PgPool, settings: Settings) -> impl FnOnce(&mut web:: Arc::new(db.clone()), Arc::new(db.clone()), Arc::new(db.clone()), + Arc::new(db.clone()), Arc::new(mailer.clone()), Arc::new(phone.clone()), Arc::new(phone.clone()), diff --git a/src/identity/application/port/output/db/get_roles_for_store.rs b/src/identity/application/port/output/db/get_roles_for_store.rs index 12950f2..86deb3c 100644 --- a/src/identity/application/port/output/db/get_roles_for_store.rs +++ b/src/identity/application/port/output/db/get_roles_for_store.rs @@ -48,10 +48,10 @@ pub mod tests { if let Some(times) = times { m.expect_get_roles_for_store() .times(times) - .return_const(Ok(vec![Role::default()])); + .return_const(Ok(vec![Role::get_role()])); } else { m.expect_get_roles_for_store() - .return_const(Ok(vec![Role::default()])); + .return_const(Ok(vec![Role::get_role()])); } Arc::new(m) diff --git a/src/identity/application/services/get_roles_for_store_service.rs b/src/identity/application/services/get_roles_for_store_service.rs new file mode 100644 index 0000000..603cb8e --- /dev/null +++ b/src/identity/application/services/get_roles_for_store_service.rs @@ -0,0 +1,121 @@ +// SPDX-FileCopyrightText: 2024 Aravinth Manivannan +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +use std::sync::Arc; + +use derive_builder::Builder; +use mockall::predicate::*; +use mockall::*; + +use super::errors::*; +use crate::identity::{ + application::port::output::db::{get_roles_for_store::*, store_id_exists::*}, + domain::{role_aggregate::*, store_aggregate::*}, +}; + +#[automock] +#[async_trait::async_trait] +pub trait GetRolesForStoreUseCase: Send + Sync { + async fn get_roles_for_store(&self, store: &Store) -> IdentityResult>; +} + +pub type GetRolesForStoreServiceObj = Arc; + +#[derive(Clone, Builder)] +pub struct GetRolesForStoreService { + db_store_id_exists: StoreIDExistsDBPortObj, + db_get_roles_for_store: GetRolesForStoreDBPortObj, +} + +#[async_trait::async_trait] +impl GetRolesForStoreUseCase for GetRolesForStoreService { + async fn get_roles_for_store(&self, store: &Store) -> IdentityResult> { + if !self + .db_store_id_exists + .store_id_exists(store.store_id()) + .await? + { + return Err(IdentityError::StoreNotFound); + } + + Ok(self + .db_get_roles_for_store + .get_roles_for_store(*store.store_id()) + .await?) + } +} + +#[cfg(test)] +pub mod tests { + use super::*; + + use crate::tests::bdd::*; + use crate::utils::uuid::tests::*; + + pub fn mock_get_roles_for_store_service( + times: Option, + store: &Store, + ) -> GetRolesForStoreServiceObj { + let mut m = MockGetRolesForStoreUseCase::new(); + + let res = vec![Role::default()]; + + if let Some(times) = times { + m.expect_get_roles_for_store() + .times(times) + .return_const(Ok(res)); + } else { + m.expect_get_roles_for_store().return_const(Ok(res)); + } + + Arc::new(m) + } + + #[actix_rt::test] + // with mock that returns Vec.len() = 1 + async fn test_service() { + let store = Store::default(); + + let s = GetRolesForStoreServiceBuilder::default() + .db_store_id_exists(mock_store_id_exists_db_port_true(IS_CALLED_ONLY_ONCE)) + .db_get_roles_for_store(mock_get_roles_for_store_db_port(IS_CALLED_ONLY_ONCE)) + .build() + .unwrap(); + + let roles = s.get_roles_for_store(&store).await.unwrap(); + assert_eq!(roles.len(), 1); + assert_eq!(roles.first().unwrap().to_owned(), Role::get_role()); + } + + #[actix_rt::test] + // with mock that returns empty Vec + async fn test_service_empty_res() { + let store = Store::default(); + + { + let s = GetRolesForStoreServiceBuilder::default() + .db_store_id_exists(mock_store_id_exists_db_port_true(IS_CALLED_ONLY_ONCE)) + .db_get_roles_for_store(mock_get_roles_for_store_db_port_empty(IS_CALLED_ONLY_ONCE)) + .build() + .unwrap(); + + let roles = s.get_roles_for_store(&store).await.unwrap(); + assert!(roles.is_empty()); + } + } + + #[actix_rt::test] + async fn test_service_store_id_no_exist() { + let store = Store::default(); + let s = GetRolesForStoreServiceBuilder::default() + .db_store_id_exists(mock_store_id_exists_db_port_false(IS_CALLED_ONLY_ONCE)) + .db_get_roles_for_store(mock_get_roles_for_store_db_port_empty(IS_NEVER_CALLED)) + .build() + .unwrap(); + assert_eq!( + s.get_roles_for_store(&store).await.err(), + Some(IdentityError::StoreNotFound) + ); + } +} diff --git a/src/identity/application/services/mod.rs b/src/identity/application/services/mod.rs index 8e597d9..7d30306 100644 --- a/src/identity/application/services/mod.rs +++ b/src/identity/application/services/mod.rs @@ -32,6 +32,7 @@ pub mod update_password; //pub mod owner_remove_employee_from_role_service; pub mod add_store_service; +pub mod get_roles_for_store_service; pub mod update_store_service; use add_store_service::*; @@ -80,6 +81,7 @@ use crate::utils::{ uuid::*, }; use delete_user::command::*; +use get_roles_for_store_service::*; use login::command::*; use mark_user_verified::command::*; use owner_manage_store_employee_service::*; @@ -94,9 +96,9 @@ use crate::identity::application::port::output::{ create_login_otp::*, create_verification_otp::*, create_verification_secret::*, delete_login_otp::*, delete_verification_otp::*, delete_verification_secret::*, email_exists::*, emp_id_exists::*, get_emp_id_from_phone_number::*, get_login_otp::*, - get_verification_otp::*, get_verification_secret::*, phone_exists::*, role_id_exists::*, - role_name_exists_for_store::*, store_id_exists::*, store_name_exists::*, user_id_exists::*, - verification_secret_exists::*, + get_roles_for_store::*, get_verification_otp::*, get_verification_secret::*, + phone_exists::*, role_id_exists::*, role_name_exists_for_store::*, store_id_exists::*, + store_name_exists::*, user_id_exists::*, verification_secret_exists::*, }, mailer::account_validation_link::*, phone::{account_login_otp::*, account_validation_otp::*}, @@ -145,6 +147,7 @@ pub trait IdentityServicesInterface: Send + Sync { fn update_password(&self) -> UpdatePasswordServiceObj; fn owner_manage_employee(&self) -> OwnerManageStoreEmployeesServiceObj; fn add_role_to_store(&self) -> AddRoleToStoreServiceObj; + fn get_roles_for_store(&self) -> GetRolesForStoreServiceObj; // employee // fn employee_accept_invite_service(&self) -> EmployeeAcceptInviteServiceObj; @@ -174,6 +177,7 @@ pub struct IdentityServices { update_password: UpdatePasswordServiceObj, owner_manage_store_employee: OwnerManageStoreEmployeesServiceObj, add_role_to_store: AddRoleToStoreServiceObj, + get_roles_for_store: GetRolesForStoreServiceObj, // employee_accept_invite_service: EmployeeAcceptInviteServiceObj, employee_exit_organization_service: EmployeeExitOrganizationServiceObj, @@ -220,6 +224,9 @@ impl IdentityServicesInterface for IdentityServices { fn add_role_to_store(&self) -> AddRoleToStoreServiceObj { self.add_role_to_store.clone() } + fn get_roles_for_store(&self) -> GetRolesForStoreServiceObj { + self.get_roles_for_store.clone() + } // employee // fn employee_accept_invite_service(&self) -> EmployeeAcceptInviteServiceObj { @@ -273,6 +280,7 @@ impl IdentityServices { out_db_verification_secret_exists: VerificationSecretExistsOutDBPortObj, out_db_role_id_exists: RoleIDExistsDBPortObj, out_db_role_name_exists_for_store: RoleNameExistsForStoreDBPortObj, + out_db_get_roles_for_store: GetRolesForStoreDBPortObj, out_mailer_account_validating_link: AccountValidationLinkOutMailerPortObj, @@ -347,6 +355,14 @@ impl IdentityServices { .unwrap(), ); + let get_roles_for_store: GetRolesForStoreServiceObj = Arc::new( + GetRolesForStoreServiceBuilder::default() + .db_store_id_exists(out_db_store_id_exists.clone()) + .db_get_roles_for_store(out_db_get_roles_for_store.clone()) + .build() + .unwrap(), + ); + // let employee_accept_invite_service: EmployeeAcceptInviteServiceObj = Arc::new( // EmployeeAcceptInviteServiceBuilder::default() // .db_get_invite_adapter(unimplemented!()) @@ -451,6 +467,7 @@ impl IdentityServices { update_password, owner_manage_store_employee, add_role_to_store, + get_roles_for_store, // employee_accept_invite_service, employee_exit_organization_service, @@ -499,6 +516,7 @@ mod tests { mock_verification_secret_exists_db_port(IS_NEVER_CALLED, false), mock_role_id_exists_db_port_true(IS_NEVER_CALLED), mock_role_name_exists_for_store_db_port_true(IS_NEVER_CALLED), + mock_get_roles_for_store_db_port(IS_NEVER_CALLED), mock_account_validation_link_mailer_port(IS_NEVER_CALLED), mock_account_validation_otp_phone_port(IS_NEVER_CALLED), mock_account_login_otp_phone_port(IS_NEVER_CALLED), diff --git a/src/identity/domain/aggregate.rs b/src/identity/domain/aggregate.rs index 4cf2624..0246073 100644 --- a/src/identity/domain/aggregate.rs +++ b/src/identity/domain/aggregate.rs @@ -235,13 +235,26 @@ mod tests { use super::*; use crate::identity::{ application::services::{ - add_role_to_store_service::AddRoleToStoreService, delete_user::{command::DeleteUserCommand, service::DeleteUserService}, events::IdentityEvent, login::{command::LoginCommand, events::LoginEvent, service::LoginService}, owner_manage_store_employee_service::*, register_user::{ + add_role_to_store_service::AddRoleToStoreService, + delete_user::{command::DeleteUserCommand, service::DeleteUserService}, + events::IdentityEvent, + login::{command::LoginCommand, events::LoginEvent, service::LoginService}, + owner_manage_store_employee_service::*, + register_user::{ command::RegisterUserCommand, events::UserRegisteredEvent, service::RegisterUserService, - }, IdentityCommand, MockIdentityServicesInterface + }, + IdentityCommand, MockIdentityServicesInterface, }, domain::{ - add_role_command::AddRoleCommand, employee_removed_from_role::EmployeeRemovedFromRoleEvent, owner_add_employee_to_store_command::*, owner_added_employee_to_store_event::*, owner_remove_employee_from_store_command::OwnerRemoveEmployeeFromStoreCommand, owner_removed_employee_from_store_event::OwnerRemovedEmployeeFromStoreEvent, remove_employee_from_role_command::RemoveEmployeeFromRoleCommand, role_added_event::RoleAddedEvent, role_set_to_employee_event::RoleSetToEmployeeEvent, set_role_to_employee_command::SetRoleToEmployeeCommand + add_role_command::AddRoleCommand, + employee_removed_from_role::EmployeeRemovedFromRoleEvent, + owner_add_employee_to_store_command::*, owner_added_employee_to_store_event::*, + owner_remove_employee_from_store_command::OwnerRemoveEmployeeFromStoreCommand, + owner_removed_employee_from_store_event::OwnerRemovedEmployeeFromStoreEvent, + remove_employee_from_role_command::RemoveEmployeeFromRoleCommand, + role_added_event::RoleAddedEvent, role_set_to_employee_event::RoleSetToEmployeeEvent, + set_role_to_employee_command::SetRoleToEmployeeCommand, }, }; use crate::tests::bdd::*; @@ -531,12 +544,10 @@ mod tests { services .expect_add_role_to_store() .times(IS_CALLED_ONLY_ONCE.unwrap()) - .return_const( - AddRoleToStoreService::mock_service( - IS_CALLED_ONLY_ONCE, - cmd.clone(), - ), - ); + .return_const(AddRoleToStoreService::mock_service( + IS_CALLED_ONLY_ONCE, + cmd.clone(), + )); UserTestFramework::with(Arc::new(services)) .given_no_previous_events() diff --git a/src/identity/domain/role_aggregate.rs b/src/identity/domain/role_aggregate.rs index d0772b0..5bd3257 100644 --- a/src/identity/domain/role_aggregate.rs +++ b/src/identity/domain/role_aggregate.rs @@ -80,10 +80,13 @@ mod tests { use cqrs_es::test::TestFramework; - use crate::identity::domain::{ - add_role_command::*, - // accept_invite_command::AcceptInviteCommand, - role_added_event::*, + use crate::{ + identity::domain::{ + add_role_command::*, + // accept_invite_command::AcceptInviteCommand, + role_added_event::*, + }, + utils::uuid::tests::UUID, }; use add_role_to_store_service::*; @@ -92,6 +95,17 @@ mod tests { type RoleTestFramework = TestFramework; + impl Role { + pub fn get_role() -> Self { + Role { + name: "test_role_should_never_exist_in_prod".to_string(), + store_id: UUID, + role_id: UUID, + deleted: false, + } + } + } + #[test] fn test_role_aggregate_add_role() { let cmd = AddRoleCommand::get_cmd();