221 lines
7.1 KiB
Rust
221 lines
7.1 KiB
Rust
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
|
|
//
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
use derive_builder::Builder;
|
|
use mockall::predicate::*;
|
|
use mockall::*;
|
|
|
|
use super::errors::*;
|
|
use super::*;
|
|
use crate::identity::application::port::output::{
|
|
db::{create_verification_otp::*, emp_id_exists::*, phone_exists::*},
|
|
phone::account_validation_otp::*,
|
|
};
|
|
use crate::identity::domain::{
|
|
employee_aggregate::*, employee_register_command::*, employee_registered_event::*,
|
|
};
|
|
use crate::utils::random_number::*;
|
|
|
|
pub const OTP_LEN: u32 = 6;
|
|
|
|
#[derive(Builder)]
|
|
pub struct EmployeeRegisterUserService {
|
|
db_phone_exists_adapter: PhoneNumberExistsOutDBPortObj,
|
|
db_emp_id_exists_adapter: EmpIDExistsOutDBPortObj,
|
|
db_create_verification_otp_adapter: CreateVerificationOTPOutDBPortObj,
|
|
phone_account_validation_otp_adapter: AccountValidationOTPOutPhonePortObj,
|
|
random_number_adapter: GenerateRandomNumberInterfaceObj,
|
|
}
|
|
|
|
pub type EmployeeRegisterServiceObj = std::sync::Arc<dyn EmployeeRegisterUserUseCase>;
|
|
|
|
#[automock]
|
|
#[async_trait::async_trait]
|
|
pub trait EmployeeRegisterUserUseCase: Send + Sync {
|
|
async fn register_employee(
|
|
&self,
|
|
cmd: EmployeeRegisterCommand,
|
|
) -> IdentityResult<EmployeeRegisteredEvent>;
|
|
}
|
|
|
|
#[async_trait::async_trait]
|
|
impl EmployeeRegisterUserUseCase for EmployeeRegisterUserService {
|
|
async fn register_employee(
|
|
&self,
|
|
cmd: EmployeeRegisterCommand,
|
|
) -> IdentityResult<EmployeeRegisteredEvent> {
|
|
if self
|
|
.db_phone_exists_adapter
|
|
.phone_exists(cmd.phone_number())
|
|
.await
|
|
.unwrap()
|
|
{
|
|
return Err(IdentityError::DuplicatePhoneNumber);
|
|
}
|
|
|
|
if self
|
|
.db_emp_id_exists_adapter
|
|
.emp_id_exists(cmd.emp_id())
|
|
.await
|
|
.unwrap()
|
|
{
|
|
return Err(IdentityError::DuplicateEmployeeID);
|
|
}
|
|
|
|
let otp = self.random_number_adapter.get_random(OTP_LEN);
|
|
|
|
self.db_create_verification_otp_adapter
|
|
.create_verification_otp(
|
|
CreateOTPMsgBuilder::default()
|
|
.otp(otp.clone())
|
|
.emp_id(*cmd.emp_id())
|
|
.build()
|
|
.unwrap(),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
self.phone_account_validation_otp_adapter
|
|
.account_validation_otp(cmd.phone_number(), otp)
|
|
.await?;
|
|
|
|
let e = EmployeeBuilder::default()
|
|
.first_name(cmd.first_name().clone())
|
|
.last_name(cmd.last_name().clone())
|
|
.emp_id(*cmd.emp_id())
|
|
.phone_number(cmd.phone_number().clone())
|
|
.phone_verified(false)
|
|
.deleted(false)
|
|
.build()
|
|
.unwrap();
|
|
|
|
Ok(EmployeeRegisteredEventBuilder::default()
|
|
.employee(e)
|
|
.build()
|
|
.unwrap())
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
pub mod tests {
|
|
use super::*;
|
|
|
|
use crate::tests::bdd::*;
|
|
use crate::utils::random_number::tests::*;
|
|
use crate::utils::uuid::tests::*;
|
|
|
|
impl EmployeeRegisterUserService {
|
|
pub fn mock(
|
|
times: Option<usize>,
|
|
cmd: EmployeeRegisterCommand,
|
|
) -> EmployeeRegisterServiceObj {
|
|
let res = EmployeeRegisteredEventBuilder::default()
|
|
.employee(
|
|
EmployeeBuilder::default()
|
|
.first_name(cmd.first_name().clone())
|
|
.last_name(cmd.last_name().clone())
|
|
.emp_id(*cmd.emp_id())
|
|
.phone_number(cmd.phone_number().clone())
|
|
.phone_verified(false)
|
|
.deleted(false)
|
|
.build()
|
|
.unwrap(),
|
|
)
|
|
.build()
|
|
.unwrap();
|
|
|
|
let mut m = MockEmployeeRegisterUserUseCase::default();
|
|
|
|
if let Some(times) = times {
|
|
m.expect_register_employee()
|
|
.times(times)
|
|
.returning(move |_| Ok(res.clone()));
|
|
} else {
|
|
m.expect_register_employee()
|
|
.returning(move |_| Ok(res.clone()));
|
|
}
|
|
|
|
std::sync::Arc::new(m)
|
|
}
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
async fn test_service() {
|
|
let username = "realaravinth";
|
|
let phone_number = PhoneNumber::default();
|
|
|
|
let cmd = EmployeeRegisterCommandBuilder::default()
|
|
.first_name(username.into())
|
|
.last_name(username.into())
|
|
.phone_number(phone_number)
|
|
.emp_id(UUID)
|
|
.build()
|
|
.unwrap();
|
|
|
|
let s = EmployeeRegisterUserServiceBuilder::default()
|
|
.db_emp_id_exists_adapter(mock_emp_id_exists_db_port(
|
|
IS_CALLED_ONLY_ONCE,
|
|
RETURNS_FALSE,
|
|
))
|
|
.db_create_verification_otp_adapter(mock_create_verification_otp_db_port(
|
|
IS_CALLED_ONLY_ONCE,
|
|
))
|
|
.db_phone_exists_adapter(mock_phone_exists_db_port(
|
|
IS_CALLED_ONLY_ONCE,
|
|
RETURNS_FALSE,
|
|
))
|
|
.random_number_adapter(mock_generate_random_number(
|
|
IS_CALLED_ONLY_ONCE,
|
|
RETURNS_RANDOM_NUMBER.into(),
|
|
))
|
|
.phone_account_validation_otp_adapter(mock_account_validation_otp_phone_port(
|
|
IS_CALLED_ONLY_ONCE,
|
|
))
|
|
.build()
|
|
.unwrap();
|
|
|
|
let res = s.register_employee(cmd.clone()).await.unwrap();
|
|
let emp = res.employee();
|
|
assert_eq!(emp.first_name(), cmd.first_name());
|
|
assert_eq!(emp.last_name(), cmd.last_name());
|
|
assert_eq!(emp.emp_id(), &UUID);
|
|
assert_eq!(emp.phone_number(), cmd.phone_number());
|
|
assert!(!emp.deleted());
|
|
assert!(!emp.phone_verified());
|
|
}
|
|
#[actix_rt::test]
|
|
async fn test_service_phone_exists() {
|
|
let username = "realaravinth";
|
|
let phone_number = PhoneNumber::default();
|
|
|
|
let cmd = EmployeeRegisterCommandBuilder::default()
|
|
.first_name(username.into())
|
|
.last_name(username.into())
|
|
.phone_number(phone_number)
|
|
.emp_id(UUID)
|
|
.build()
|
|
.unwrap();
|
|
|
|
let s = EmployeeRegisterUserServiceBuilder::default()
|
|
.db_emp_id_exists_adapter(mock_emp_id_exists_db_port(IGNORE_CALL_COUNT, RETURNS_FALSE))
|
|
.db_create_verification_otp_adapter(mock_create_verification_otp_db_port(
|
|
IS_NEVER_CALLED,
|
|
))
|
|
.db_phone_exists_adapter(mock_phone_exists_db_port(IS_CALLED_ONLY_ONCE, RETURNS_TRUE))
|
|
.random_number_adapter(mock_generate_random_number(
|
|
IS_NEVER_CALLED,
|
|
RETURNS_RANDOM_NUMBER.into(),
|
|
))
|
|
.phone_account_validation_otp_adapter(mock_account_validation_otp_phone_port(
|
|
IS_NEVER_CALLED,
|
|
))
|
|
.build()
|
|
.unwrap();
|
|
|
|
assert_eq!(
|
|
s.register_employee(cmd.clone()).await.err(),
|
|
Some(IdentityError::DuplicatePhoneNumber)
|
|
);
|
|
}
|
|
}
|