Add REST endpoint for slot
This commit is contained in:
parent
82e89baeeb
commit
8f378472ea
28 changed files with 1925 additions and 28 deletions
199
service_impl/src/slot.rs
Normal file
199
service_impl/src/slot.rs
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use service::{slot::Slot, ServiceError, ValidationFailureItem};
|
||||
use tokio::join;
|
||||
use uuid::Uuid;
|
||||
|
||||
const SLOT_SERVICE_PROCESS: &str = "slot-service";
|
||||
|
||||
pub struct SlotServiceImpl<SlotDao, PermissionService, ClockService, UuidService>
|
||||
where
|
||||
SlotDao: dao::slot::SlotDao + Send + Sync,
|
||||
PermissionService: service::permission::PermissionService + Send + Sync,
|
||||
ClockService: service::clock::ClockService + Send + Sync,
|
||||
UuidService: service::uuid_service::UuidService + Send + Sync,
|
||||
{
|
||||
pub slot_dao: Arc<SlotDao>,
|
||||
pub permission_service: Arc<PermissionService>,
|
||||
pub clock_service: Arc<ClockService>,
|
||||
pub uuid_service: Arc<UuidService>,
|
||||
}
|
||||
impl<SlotDao, PermissionService, ClockService, UuidService>
|
||||
SlotServiceImpl<SlotDao, PermissionService, ClockService, UuidService>
|
||||
where
|
||||
SlotDao: dao::slot::SlotDao + Send + Sync,
|
||||
PermissionService: service::permission::PermissionService + Send + Sync,
|
||||
ClockService: service::clock::ClockService + Send + Sync,
|
||||
UuidService: service::uuid_service::UuidService + Send + Sync,
|
||||
{
|
||||
pub fn new(
|
||||
slot_dao: Arc<SlotDao>,
|
||||
permission_service: Arc<PermissionService>,
|
||||
clock_service: Arc<ClockService>,
|
||||
uuid_service: Arc<UuidService>,
|
||||
) -> Self {
|
||||
Self {
|
||||
slot_dao,
|
||||
permission_service,
|
||||
clock_service,
|
||||
uuid_service,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test_overlapping_slots(slot_1: &Slot, slot_2: &Slot) -> bool {
|
||||
slot_1.day_of_week == slot_2.day_of_week
|
||||
&& (slot_2.from < slot_1.from && slot_1.from < slot_2.to
|
||||
|| slot_1.from < slot_2.from && slot_2.from < slot_1.to
|
||||
|| slot_1.from == slot_2.from && slot_1.to == slot_2.to)
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<SlotDao, PermissionService, ClockService, UuidService> service::slot::SlotService
|
||||
for SlotServiceImpl<SlotDao, PermissionService, ClockService, UuidService>
|
||||
where
|
||||
SlotDao: dao::slot::SlotDao + Send + Sync,
|
||||
PermissionService: service::permission::PermissionService + Send + Sync,
|
||||
ClockService: service::clock::ClockService + Send + Sync,
|
||||
UuidService: service::uuid_service::UuidService + Send + Sync,
|
||||
{
|
||||
async fn get_slots(&self) -> Result<Arc<[Slot]>, ServiceError> {
|
||||
let (hr_permission, sales_permission) = join!(
|
||||
self.permission_service.check_permission("hr"),
|
||||
self.permission_service.check_permission("sales"),
|
||||
);
|
||||
hr_permission.or(sales_permission)?;
|
||||
|
||||
Ok(self
|
||||
.slot_dao
|
||||
.get_slots()
|
||||
.await?
|
||||
.iter()
|
||||
.map(Slot::from)
|
||||
.collect())
|
||||
}
|
||||
async fn get_slot(&self, id: &Uuid) -> Result<Slot, ServiceError> {
|
||||
let (hr_permission, sales_permission) = join!(
|
||||
self.permission_service.check_permission("hr"),
|
||||
self.permission_service.check_permission("sales"),
|
||||
);
|
||||
hr_permission.or(sales_permission)?;
|
||||
|
||||
let slot_entity = self.slot_dao.get_slot(id).await?;
|
||||
let slot = slot_entity
|
||||
.as_ref()
|
||||
.map(Slot::from)
|
||||
.ok_or_else(move || ServiceError::EntityNotFound(*id))?;
|
||||
Ok(slot)
|
||||
}
|
||||
async fn create_slot(&self, slot: &Slot) -> Result<Slot, ServiceError> {
|
||||
self.permission_service.check_permission("hr").await?;
|
||||
|
||||
if slot.id != Uuid::nil() {
|
||||
return Err(ServiceError::IdSetOnCreate);
|
||||
}
|
||||
if slot.version != Uuid::nil() {
|
||||
return Err(ServiceError::VersionSetOnCreate);
|
||||
}
|
||||
if slot.from > slot.to {
|
||||
return Err(ServiceError::TimeOrderWrong(slot.from, slot.to));
|
||||
}
|
||||
if slot.valid_to.is_some() && slot.valid_to.unwrap() < slot.valid_from {
|
||||
return Err(ServiceError::DateOrderWrong(
|
||||
slot.valid_from,
|
||||
slot.valid_to.unwrap(),
|
||||
));
|
||||
}
|
||||
|
||||
if self
|
||||
.get_slots()
|
||||
.await?
|
||||
.iter()
|
||||
.any(|s| test_overlapping_slots(slot, s))
|
||||
{
|
||||
return Err(ServiceError::OverlappingTimeRange);
|
||||
}
|
||||
|
||||
let slot = Slot {
|
||||
id: self.uuid_service.new_uuid("slot-id"),
|
||||
version: self.uuid_service.new_uuid("slot-version"),
|
||||
..slot.clone()
|
||||
};
|
||||
self.slot_dao
|
||||
.create_slot(&(&slot).into(), SLOT_SERVICE_PROCESS)
|
||||
.await?;
|
||||
Ok(slot)
|
||||
}
|
||||
|
||||
async fn delete_slot(&self, id: &Uuid) -> Result<(), ServiceError> {
|
||||
self.permission_service.check_permission("hr").await?;
|
||||
let mut slot = self
|
||||
.slot_dao
|
||||
.get_slot(id)
|
||||
.await?
|
||||
.ok_or(ServiceError::EntityNotFound(*id))?;
|
||||
slot.deleted = Some(self.clock_service.date_time_now());
|
||||
self.slot_dao
|
||||
.update_slot(&slot, SLOT_SERVICE_PROCESS)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
async fn update_slot(&self, slot: &Slot) -> Result<(), ServiceError> {
|
||||
self.permission_service.check_permission("hr").await?;
|
||||
let persisted_slot = self
|
||||
.slot_dao
|
||||
.get_slot(&slot.id)
|
||||
.await?
|
||||
.ok_or(ServiceError::EntityNotFound(slot.id))?;
|
||||
if persisted_slot.version != slot.version {
|
||||
return Err(ServiceError::EntityConflicts(
|
||||
slot.id,
|
||||
persisted_slot.version,
|
||||
slot.version,
|
||||
));
|
||||
}
|
||||
if slot.valid_to.is_some() && slot.valid_to.unwrap() < slot.valid_from {
|
||||
return Err(ServiceError::DateOrderWrong(
|
||||
slot.valid_from,
|
||||
slot.valid_to.unwrap(),
|
||||
));
|
||||
}
|
||||
|
||||
let mut validation = Vec::new();
|
||||
if persisted_slot.day_of_week != slot.day_of_week.into() {
|
||||
validation.push(ValidationFailureItem::ModificationNotAllowed(
|
||||
"day_of_week".into(),
|
||||
));
|
||||
}
|
||||
if persisted_slot.from != slot.from {
|
||||
validation.push(ValidationFailureItem::ModificationNotAllowed("from".into()));
|
||||
}
|
||||
if persisted_slot.to != slot.to {
|
||||
validation.push(ValidationFailureItem::ModificationNotAllowed("to".into()));
|
||||
}
|
||||
if persisted_slot.valid_from != slot.valid_from {
|
||||
validation.push(ValidationFailureItem::ModificationNotAllowed(
|
||||
"valid_from".into(),
|
||||
));
|
||||
}
|
||||
if persisted_slot.valid_to.is_some() && persisted_slot.valid_to != slot.valid_to {
|
||||
validation.push(ValidationFailureItem::ModificationNotAllowed(
|
||||
"valid_to".into(),
|
||||
));
|
||||
}
|
||||
|
||||
if !validation.is_empty() {
|
||||
return Err(ServiceError::ValidationError(validation.into()));
|
||||
}
|
||||
|
||||
let slot = Slot {
|
||||
version: self.uuid_service.new_uuid("slot-version"),
|
||||
..slot.clone()
|
||||
};
|
||||
self.slot_dao
|
||||
.update_slot(&(&slot).into(), SLOT_SERVICE_PROCESS)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue