Basic rest implementation for connecting user to sales-person

This commit is contained in:
Simon Goller 2024-05-09 14:16:47 +02:00
parent e3ec694876
commit bf94ec33de
10 changed files with 181 additions and 1 deletions

View file

@ -26,6 +26,7 @@ pub trait PermissionDao {
async fn create_user(&self, user: &UserEntity, process: &str) -> Result<(), DaoError>;
async fn all_users(&self) -> Result<Arc<[UserEntity]>, DaoError>;
async fn find_user(&self, username: &str) -> Result<Option<UserEntity>, DaoError>;
async fn delete_user(&self, username: &str) -> Result<(), DaoError>;
async fn create_role(&self, role: &RoleEntity, process: &str) -> Result<(), DaoError>;

View file

@ -20,6 +20,10 @@ pub struct SalesPersonEntity {
pub trait SalesPersonDao {
async fn all(&self) -> Result<Arc<[SalesPersonEntity]>, DaoError>;
async fn find_by_id(&self, id: Uuid) -> Result<Option<SalesPersonEntity>, DaoError>;
async fn find_by_user(&self, user_id: &str) -> Result<Option<SalesPersonEntity>, 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<Option<Arc<str>>, 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>;
}

View file

@ -91,6 +91,18 @@ impl dao::PermissionDao for PermissionDaoImpl {
.map_db_error()?;
Ok(())
}
async fn find_user(&self, username: &str) -> Result<Option<dao::UserEntity>, 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();

View file

@ -72,6 +72,21 @@ impl SalesPersonDao for SalesPersonDaoImpl {
.map(SalesPersonEntity::try_from)
.transpose()?)
}
async fn find_by_user(&self, user_id: &str) -> Result<Option<SalesPersonEntity>, 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<Option<Arc<str>>, 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()))
}
}

View file

@ -10,3 +10,15 @@ CREATE TABLE sales_person (
update_process TEXT NOT NULL,
update_version blob(16) NOT NULL
);
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)
)

View file

@ -55,6 +55,9 @@ pub fn generate_route<RestState: RestStateDef>() -> Router<RestState> {
.route("/", post(create_sales_person::<RestState>))
.route("/:id", put(update_sales_person::<RestState>))
.route("/:id", delete(delete_sales_person::<RestState>))
.route("/:id/user", get(get_sales_person_user::<RestState>))
.route("/:id/user", post(set_sales_person_user::<RestState>))
.route("/:id/user", delete(delete_sales_person_user::<RestState>))
}
pub async fn get_all_sales_persons<RestState: RestStateDef>(
@ -158,3 +161,56 @@ pub async fn delete_sales_person<RestState: RestStateDef>(
.await,
)
}
pub async fn get_sales_person_user<RestState: RestStateDef>(
rest_state: State<RestState>,
Path(sales_person_id): Path<Uuid>,
) -> 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<RestState: RestStateDef>(
rest_state: State<RestState>,
Path(sales_person_id): Path<Uuid>,
Json(user): Json<Arc<str>>,
) -> 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<RestState: RestStateDef>(
rest_state: State<RestState>,
Path(sales_person_id): Path<Uuid>,
) -> 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,
)
}

View file

@ -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<bool, ServiceError>;
async fn delete_user(&self, user: &str, context: Self::Context) -> Result<(), ServiceError>;
async fn get_all_users(&self, context: Self::Context) -> Result<Arc<[User]>, ServiceError>;

View file

@ -56,4 +56,15 @@ pub trait SalesPersonService {
context: Self::Context,
) -> Result<SalesPerson, ServiceError>;
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<Option<Arc<str>>, ServiceError>;
async fn set_user(
&self,
sales_person_id: Uuid,
user_id: Option<Arc<str>>,
context: Self::Context,
) -> Result<(), ServiceError>;
}

View file

@ -1,6 +1,7 @@
use std::sync::Arc;
use async_trait::async_trait;
use service::ServiceError;
pub struct PermissionServiceImpl<PermissionDao, UserService>
where
@ -75,6 +76,11 @@ where
Ok(())
}
async fn user_exists(&self, user: &str, context: Self::Context) -> Result<bool, ServiceError> {
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,

View file

@ -188,4 +188,36 @@ where
.await?;
Ok(())
}
async fn get_assigned_user(
&self,
sales_person_id: Uuid,
context: Self::Context,
) -> Result<Option<Arc<str>>, 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<Arc<str>>,
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(())
}
}