diff --git a/dao/src/permission.rs b/dao/src/permission.rs index f5189af..391a351 100644 --- a/dao/src/permission.rs +++ b/dao/src/permission.rs @@ -26,6 +26,7 @@ pub trait PermissionDao { async fn create_user(&self, user: &UserEntity, process: &str) -> Result<(), DaoError>; async fn all_users(&self) -> Result, DaoError>; + async fn find_user(&self, username: &str) -> Result, DaoError>; async fn delete_user(&self, username: &str) -> Result<(), DaoError>; async fn create_role(&self, role: &RoleEntity, process: &str) -> Result<(), DaoError>; diff --git a/dao/src/sales_person.rs b/dao/src/sales_person.rs index 1c2a505..c7dd821 100644 --- a/dao/src/sales_person.rs +++ b/dao/src/sales_person.rs @@ -20,6 +20,10 @@ pub struct SalesPersonEntity { pub trait SalesPersonDao { async fn all(&self) -> Result, DaoError>; async fn find_by_id(&self, id: Uuid) -> Result, DaoError>; + async fn find_by_user(&self, user_id: &str) -> Result, DaoError>; async fn create(&self, entity: &SalesPersonEntity, process: &str) -> Result<(), DaoError>; async fn update(&self, entity: &SalesPersonEntity, process: &str) -> Result<(), DaoError>; + async fn get_assigned_user(&self, sales_person_id: Uuid) -> Result>, DaoError>; + async fn assign_to_user(&self, sales_person_id: Uuid, user_id: &str, process: &str) -> Result<(), DaoError>; + async fn discard_assigned_user(&self, sales_person_id: Uuid) -> Result<(), DaoError>; } diff --git a/dao_impl/src/lib.rs b/dao_impl/src/lib.rs index 3919680..988bf4f 100644 --- a/dao_impl/src/lib.rs +++ b/dao_impl/src/lib.rs @@ -91,6 +91,18 @@ impl dao::PermissionDao for PermissionDaoImpl { .map_db_error()?; Ok(()) } + async fn find_user(&self, username: &str) -> Result, DaoError> { + let result = query!( + r"SELECT name FROM user WHERE name = ?", + username + ) + .fetch_optional(self.pool.as_ref()) + .await + .map_db_error()?; + Ok(result.map(|row| dao::UserEntity { + name: row.name.clone().into(), + })) + } async fn create_role(&self, role: &dao::RoleEntity, process: &str) -> Result<(), DaoError> { let name = role.name.as_ref(); diff --git a/dao_impl/src/sales_person.rs b/dao_impl/src/sales_person.rs index f230b03..df23339 100644 --- a/dao_impl/src/sales_person.rs +++ b/dao_impl/src/sales_person.rs @@ -72,6 +72,21 @@ impl SalesPersonDao for SalesPersonDaoImpl { .map(SalesPersonEntity::try_from) .transpose()?) } + + async fn find_by_user(&self, user_id: &str) -> Result, DaoError> { + Ok(query_as!( + SalesPersonDb, + "SELECT sp.id, sp.name, sp.inactive, sp.deleted, sp.update_version FROM sales_person sp JOIN sales_person_user spu ON sp.id = spu.sales_person_id WHERE spu.user_id = ?", + user_id + ) + .fetch_optional(self.pool.as_ref()) + .await + .map_db_error()? + .as_ref() + .map(SalesPersonEntity::try_from) + .transpose()?) + } + async fn create(&self, entity: &SalesPersonEntity, process: &str) -> Result<(), DaoError> { let id = entity.id.as_bytes().to_vec(); let version = entity.version.as_bytes().to_vec(); @@ -96,4 +111,34 @@ impl SalesPersonDao for SalesPersonDaoImpl { .map_db_error()?; Ok(()) } + + async fn assign_to_user(&self, sales_person_id: Uuid, user_id: &str, process: &str) -> Result<(), DaoError> { + let sales_person_id = sales_person_id.as_bytes().to_vec(); + query!("INSERT INTO sales_person_user (user_id, sales_person_id, update_process) VALUES (?, ?, ?)", user_id, sales_person_id, process) + .execute(self.pool.as_ref()) + .await + .map_db_error()?; + Ok(()) + } + + async fn discard_assigned_user(&self, sales_person_id: Uuid) -> Result<(), DaoError> { + let sales_person_id = sales_person_id.as_bytes().to_vec(); + query!("DELETE FROM sales_person_user WHERE sales_person_id = ?", sales_person_id) + .execute(self.pool.as_ref()) + .await + .map_db_error()?; + Ok(()) + } + + async fn get_assigned_user(&self, sales_person_id: Uuid) -> Result>, DaoError> { + let sales_person_id = sales_person_id.as_bytes().to_vec(); + Ok(query!( + "SELECT user_id FROM sales_person_user WHERE sales_person_id = ?", + sales_person_id + ) + .fetch_optional(self.pool.as_ref()) + .await + .map_db_error()? + .map(|result| result.user_id.into())) + } } diff --git a/migrations/20240506114107_add_sales_person.sql b/migrations/20240506114107_add_sales_person.sql index 342fd70..96520c2 100644 --- a/migrations/20240506114107_add_sales_person.sql +++ b/migrations/20240506114107_add_sales_person.sql @@ -9,4 +9,16 @@ CREATE TABLE sales_person ( update_timestamp TEXT, update_process TEXT NOT NULL, update_version blob(16) NOT NULL -); \ No newline at end of file +); + +CREATE TABLE sales_person_user ( + sales_person_id blob(16) NOT NULL, + user_id TEXT NOT NULL, + update_timestamp TEXT, + update_process TEXT NOT NULL, + PRIMARY KEY (sales_person_id, user_id), + UNIQUE(sales_person_id), + UNIQUE(user_id), + FOREIGN KEY (sales_person_id) REFERENCES sales_person(id) + FOREIGN KEY (user_id) REFERENCES user(name) +) \ No newline at end of file diff --git a/rest/src/sales_person.rs b/rest/src/sales_person.rs index 392c769..4561dab 100644 --- a/rest/src/sales_person.rs +++ b/rest/src/sales_person.rs @@ -55,6 +55,9 @@ pub fn generate_route() -> Router { .route("/", post(create_sales_person::)) .route("/:id", put(update_sales_person::)) .route("/:id", delete(delete_sales_person::)) + .route("/:id/user", get(get_sales_person_user::)) + .route("/:id/user", post(set_sales_person_user::)) + .route("/:id/user", delete(delete_sales_person_user::)) } pub async fn get_all_sales_persons( @@ -158,3 +161,56 @@ pub async fn delete_sales_person( .await, ) } + + +pub async fn get_sales_person_user( + rest_state: State, + Path(sales_person_id): Path, +) -> Response { + error_handler( + (async { + let user = rest_state + .sales_person_service() + .get_assigned_user(sales_person_id, ()) + .await?; + Ok(Response::builder() + .status(200) + .body(Body::new(serde_json::to_string(&user).unwrap())) + .unwrap()) + }) + .await, + ) +} + +pub async fn set_sales_person_user( + rest_state: State, + Path(sales_person_id): Path, + Json(user): Json>, +) -> Response { + error_handler( + (async { + rest_state + .sales_person_service() + .set_user(sales_person_id, user.into(), ()) + .await?; + Ok(Response::builder().status(204).body(Body::empty()).unwrap()) + }) + .await, + ) +} + +pub async fn delete_sales_person_user( + rest_state: State, + Path(sales_person_id): Path, +) -> Response { + error_handler( + (async { + rest_state + .sales_person_service() + .set_user(sales_person_id, None, ()) + .await?; + Ok(Response::builder().status(204).body(Body::empty()).unwrap()) + }) + .await, + ) +} \ No newline at end of file diff --git a/service/src/permission.rs b/service/src/permission.rs index 45476e1..eb8b939 100644 --- a/service/src/permission.rs +++ b/service/src/permission.rs @@ -53,6 +53,7 @@ pub trait PermissionService { ) -> Result<(), ServiceError>; async fn create_user(&self, user: &str, context: Self::Context) -> Result<(), ServiceError>; + async fn user_exists(&self, user: &str, context: Self::Context) -> Result; async fn delete_user(&self, user: &str, context: Self::Context) -> Result<(), ServiceError>; async fn get_all_users(&self, context: Self::Context) -> Result, ServiceError>; diff --git a/service/src/sales_person.rs b/service/src/sales_person.rs index b3ac790..a68c2ce 100644 --- a/service/src/sales_person.rs +++ b/service/src/sales_person.rs @@ -56,4 +56,15 @@ pub trait SalesPersonService { context: Self::Context, ) -> Result; async fn delete(&self, id: Uuid, context: Self::Context) -> Result<(), ServiceError>; + async fn get_assigned_user( + &self, + sales_person_id: Uuid, + context: Self::Context, + ) -> Result>, ServiceError>; + async fn set_user( + &self, + sales_person_id: Uuid, + user_id: Option>, + context: Self::Context, + ) -> Result<(), ServiceError>; } diff --git a/service_impl/src/permission.rs b/service_impl/src/permission.rs index ffa9561..e72eda2 100644 --- a/service_impl/src/permission.rs +++ b/service_impl/src/permission.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use async_trait::async_trait; +use service::ServiceError; pub struct PermissionServiceImpl where @@ -75,6 +76,11 @@ where Ok(()) } + async fn user_exists(&self, user: &str, context: Self::Context) -> Result { + self.check_permission("hr", context).await?; + Ok(self.permission_dao.find_user(user).await.map(|x| x.is_some())?) + } + async fn get_all_users( &self, context: Self::Context, diff --git a/service_impl/src/sales_person.rs b/service_impl/src/sales_person.rs index 4553556..e8a279f 100644 --- a/service_impl/src/sales_person.rs +++ b/service_impl/src/sales_person.rs @@ -188,4 +188,36 @@ where .await?; Ok(()) } + + async fn get_assigned_user( + &self, + sales_person_id: Uuid, + context: Self::Context, + ) -> Result>, ServiceError> { + self.permission_service + .check_permission("hr", context) + .await?; + Ok(self.sales_person_dao.get_assigned_user(sales_person_id).await?) + } + + async fn set_user( + &self, + sales_person_id: Uuid, + user_id: Option>, + context: Self::Context, + ) -> Result<(), ServiceError> { + self.permission_service + .check_permission("hr", context) + .await?; + self.sales_person_dao + .discard_assigned_user(sales_person_id) + .await?; + if let Some(user) = user_id { + self.sales_person_dao + .assign_to_user(sales_person_id, user.as_ref(), SALES_PERSON_SERVICE_PROCESS) + .await?; + + } + Ok(()) + } }