From 96debc210af782a7cc634517240f7a4c11493842 Mon Sep 17 00:00:00 2001 From: MythEclipse Date: Fri, 26 Sep 2025 15:05:45 +0700 Subject: [PATCH] Refactor permissions and user DTOs to use imphnen_entities module - Updated permissions_repository.rs to import PermissionsItemDto from imphnen_entities. - Modified permissions_schema.rs to import PermissionsItemDto and PermissionsQueryDto from imphnen_entities. - Changed roles_dto.rs to import PermissionsItemDto and PermissionsQueryDto from imphnen_entities. - Updated users_dto.rs to import ExperienceDto, EducationDto, UsersDetailQueryDto, RolesDetailQueryDto, and RolesDetailItemDto from imphnen_entities, and removed redundant struct definitions. - Refactored users_repository.rs to import UsersDetailQueryDto from imphnen_entities. - Updated users_schema.rs to import UsersDetailQueryDto, ExperienceDto, and EducationDto from imphnen_entities. - Modified users_service.rs to use UsersDetailQueryDto from imphnen_entities and added UserLookupService implementation. - Updated Cargo.toml in imphnen-libs to include async-trait as a workspace dependency. - Refactored axum module to remove redundant imports and streamline code. - Updated lib.rs to include AppState struct with user_lookup_service and auth_repository fields. - Refactored surrealdb module to define SurrealWsClient and SurrealMemClient types. - Removed imphnen-iam dependency from middleware's Cargo.toml. - Updated auth_middleware to use UsersDetailQueryDto from imphnen_entities and refactored user retrieval logic. - Refactored permissions_middleware to use PermissionsEnum from imphnen_entities and updated user retrieval logic. - Updated mock_test.rs to create AppState with user_lookup_service and auth_repository. - Added permissions.rs and users.rs to imphnen_entities with necessary DTOs and enums. - Created services.rs in imphnen-libs to define UserLookupService and AuthRepositoryTrait traits. --- Cargo.lock | 6 +- Cargo.toml | 1 + .../landing/testimonials/testimonials_dto.rs | 2 +- .../src/v1/mentors/mentors_controller.rs | 3 +- .../src/v1/mentors/mentors_service.rs | 5 +- imphnen-entities/Cargo.toml | 3 + imphnen-entities/src/common_dto.rs | 9 - imphnen-entities/src/lib.rs | 4 + imphnen-entities/src/permissions.rs | 295 ++++++++++++++++++ imphnen-entities/src/users.rs | 116 +++++++ imphnen-gateway/src/docs.rs | 16 +- imphnen-gateway/src/lib.rs | 9 +- imphnen-iam/Cargo.toml | 1 + imphnen-iam/src/v1/auth/auth_repository.rs | 59 ++-- imphnen-iam/src/v1/auth/auth_service.rs | 10 +- .../v1/auth/google/google_oauth_service.rs | 4 +- .../v1/permissions/permissions_controller.rs | 3 +- .../src/v1/permissions/permissions_dto.rs | 28 -- .../src/v1/permissions/permissions_enum.rs | 266 +--------------- .../v1/permissions/permissions_repository.rs | 3 +- .../src/v1/permissions/permissions_schema.rs | 2 +- imphnen-iam/src/v1/roles/roles_dto.rs | 2 +- imphnen-iam/src/v1/users/users_dto.rs | 59 +--- imphnen-iam/src/v1/users/users_repository.rs | 3 +- imphnen-iam/src/v1/users/users_schema.rs | 3 +- imphnen-iam/src/v1/users/users_service.rs | 16 +- imphnen-libs/Cargo.toml | 1 + imphnen-libs/src/axum/mod.rs | 3 +- imphnen-libs/src/lib.rs | 12 +- imphnen-libs/src/services.rs | 22 ++ imphnen-libs/src/surrealdb/mod.rs | 6 +- imphnen-middleware/Cargo.toml | 1 - imphnen-middleware/src/auth_middleware/mod.rs | 8 +- .../src/permissions_middleware/mod.rs | 5 +- tests/src/mock_test.rs | 9 +- 35 files changed, 564 insertions(+), 431 deletions(-) create mode 100644 imphnen-entities/src/permissions.rs create mode 100644 imphnen-entities/src/users.rs create mode 100644 imphnen-libs/src/services.rs diff --git a/Cargo.lock b/Cargo.lock index 609a9aa..fe60e07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2122,9 +2122,12 @@ dependencies = [ "anyhow", "axum", "serde", + "strum 0.27.2", + "strum_macros 0.27.2", "surrealdb", "thiserror 2.0.14", "utoipa", + "uuid", ] [[package]] @@ -2189,6 +2192,7 @@ name = "imphnen-iam" version = "0.1.0" dependencies = [ "anyhow", + "async-trait", "axum", "axum-extra", "axum-test", @@ -2227,6 +2231,7 @@ version = "0.1.0" dependencies = [ "anyhow", "argon2", + "async-trait", "axum", "base64 0.22.1", "chrono", @@ -2258,7 +2263,6 @@ dependencies = [ "chrono", "futures", "imphnen-entities", - "imphnen-iam", "imphnen-libs", "imphnen-utils", "lazy_static", diff --git a/Cargo.toml b/Cargo.toml index c54a218..733e387 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ members = [ [workspace.dependencies] +async-trait = "0.1.83" oauth2 = "5.0.0" reqwest = { version = "0.12.23", features = ["json"] } serde_json = "1.0.142" diff --git a/imphnen-cms/src/v1/landing/testimonials/testimonials_dto.rs b/imphnen-cms/src/v1/landing/testimonials/testimonials_dto.rs index 1c4557c..7acdf88 100644 --- a/imphnen-cms/src/v1/landing/testimonials/testimonials_dto.rs +++ b/imphnen-cms/src/v1/landing/testimonials/testimonials_dto.rs @@ -1,4 +1,4 @@ -use imphnen_iam::users::UsersSchema; +use imphnen_iam::v1::users::UsersSchema; use serde::{Deserialize, Serialize}; use surrealdb::sql::Thing; use utoipa::ToSchema; diff --git a/imphnen-dimentorin/src/v1/mentors/mentors_controller.rs b/imphnen-dimentorin/src/v1/mentors/mentors_controller.rs index 1fdbe45..2623ea7 100644 --- a/imphnen-dimentorin/src/v1/mentors/mentors_controller.rs +++ b/imphnen-dimentorin/src/v1/mentors/mentors_controller.rs @@ -8,7 +8,8 @@ use ::axum::{ http::HeaderMap, response::{IntoResponse, Response}, }; -use imphnen_entities::*; +use imphnen_entities::MetaRequestDto; +use imphnen_libs::AppState; use imphnen_iam::{PermissionsEnum, permissions_guard}; use imphnen_utils::extract_email; use serde_json::json; diff --git a/imphnen-dimentorin/src/v1/mentors/mentors_service.rs b/imphnen-dimentorin/src/v1/mentors/mentors_service.rs index dd7362a..c553275 100644 --- a/imphnen-dimentorin/src/v1/mentors/mentors_service.rs +++ b/imphnen-dimentorin/src/v1/mentors/mentors_service.rs @@ -6,8 +6,9 @@ use crate::v1::mentors::{ use axum::http::StatusCode; use axum::response::Response; use imphnen_entities::{ - AppState, MetaRequestDto, ResponseListSuccessDto, ResponseSuccessDto, + MetaRequestDto, ResponseListSuccessDto, ResponseSuccessDto, }; +use imphnen_libs::AppState; use imphnen_iam::{ AuthRepository, RolesEnum, RolesRepository, UsersRepository, UsersSchema, }; @@ -33,7 +34,7 @@ impl MentorsService { let user_repo = UsersRepository::new(state); let mentor_repo = MentorsRepository::new(state); let role_repo = RolesRepository::new(state); - let auth_repo = AuthRepository::new(state); + let auth_repo = AuthRepository::new(state.surrealdb_mem.clone()); let user_email = &dto.email; let mut _user_to_update: Option = None; diff --git a/imphnen-entities/Cargo.toml b/imphnen-entities/Cargo.toml index cb4c0af..55bd9a2 100644 --- a/imphnen-entities/Cargo.toml +++ b/imphnen-entities/Cargo.toml @@ -10,3 +10,6 @@ utoipa.workspace = true surrealdb.workspace = true anyhow.workspace = true thiserror.workspace = true +uuid.workspace = true +strum.workspace = true +strum_macros.workspace = true diff --git a/imphnen-entities/src/common_dto.rs b/imphnen-entities/src/common_dto.rs index 32e89e6..27ecdf5 100644 --- a/imphnen-entities/src/common_dto.rs +++ b/imphnen-entities/src/common_dto.rs @@ -1,5 +1,4 @@ use serde::{Deserialize, Serialize}; -use surrealdb::{Surreal, engine::any::Any, engine::local::Db}; use utoipa::{IntoParams, ToSchema}; #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] @@ -51,14 +50,6 @@ pub struct ResponseListSuccessDto { pub meta: Option, } -pub type SurrealWsClient = Surreal; -pub type SurrealMemClient = Surreal; - -#[derive(Clone)] -pub struct AppState { - pub surrealdb_ws: SurrealWsClient, - pub surrealdb_mem: SurrealMemClient, -} #[derive(Debug, serde::Deserialize)] pub struct CountResult { diff --git a/imphnen-entities/src/lib.rs b/imphnen-entities/src/lib.rs index 3e78fd6..63a456a 100644 --- a/imphnen-entities/src/lib.rs +++ b/imphnen-entities/src/lib.rs @@ -1,4 +1,8 @@ pub mod common_dto; pub mod error_dto; +pub mod users; +pub mod permissions; pub use common_dto::*; pub use error_dto::*; +pub use users::*; +pub use permissions::*; diff --git a/imphnen-entities/src/permissions.rs b/imphnen-entities/src/permissions.rs new file mode 100644 index 0000000..fbfe3b3 --- /dev/null +++ b/imphnen-entities/src/permissions.rs @@ -0,0 +1,295 @@ +use std::fmt; +use uuid::Uuid; +use strum_macros::EnumIter; +use serde::{Deserialize, Serialize}; +use surrealdb::sql::Thing; +use utoipa::ToSchema; + +#[derive(Debug, Clone, PartialEq, Eq, EnumIter)] +pub enum PermissionsEnum { + // User permissions + ReadListUsers, + ReadDetailUsers, + CreateUsers, + DeleteUsers, + UpdateUsers, + ActivateUsers, + + // Role permissions + ReadListRoles, + ReadDetailRoles, + CreateRoles, + DeleteRoles, + UpdateRoles, + + // Permission permissions + ReadListPermissions, + ReadDetailPermissions, + CreatePermissions, + DeletePermissions, + UpdatePermissions, + + // Team permissions + ReadListTeams, + ReadDetailTeams, + + // Administrator permissions + ManageAllUsers, + ManageAllRoles, + ManageAllPermissions, + ManageAllTeams, + ViewAllSensitiveData, + AccessAdminDashboard, + Administrator, + + // Gacha permissions + CreateGachaClaims, + ReadDetailGachaClaims, + ReadListGachaItems, + ReadDetailGachaItems, + CreateGachaItems, + DeleteGachaItems, + UpdateGachaItems, + ReadDetailGachaRolls, + CreateGachaRolls, + ExecuteGachaRolls, + DeleteGachaRolls, + + // Mentor permissions + ReadListMentors, + ReadDetailMentors, + RegisterMentors, + ReadOwnMentorProfile, + UpdateOwnMentorProfile, + ReadOwnMentorStatus, + UpdateMentors, + VerifyMentors, + DeleteMentors, +} + +impl fmt::Display for PermissionsEnum { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let permission_str = match self { + // User permissions + PermissionsEnum::ReadListUsers => "Read List Users", + PermissionsEnum::ReadDetailUsers => "Read Detail Users", + PermissionsEnum::CreateUsers => "Create Users", + PermissionsEnum::DeleteUsers => "Delete Users", + PermissionsEnum::UpdateUsers => "Update Users", + PermissionsEnum::ActivateUsers => "Activate Users", + + // Role permissions + PermissionsEnum::ReadListRoles => "Read List Roles", + PermissionsEnum::ReadDetailRoles => "Read Detail Roles", + PermissionsEnum::CreateRoles => "Create Roles", + PermissionsEnum::DeleteRoles => "Delete Roles", + PermissionsEnum::UpdateRoles => "Update Roles", + + // Permission permissions + PermissionsEnum::ReadListPermissions => "Read List Permissions", + PermissionsEnum::ReadDetailPermissions => "Read Detail Permissions", + PermissionsEnum::CreatePermissions => "Create Permissions", + PermissionsEnum::DeletePermissions => "Delete Permissions", + PermissionsEnum::UpdatePermissions => "Update Permissions", + + // Team permissions + PermissionsEnum::ReadListTeams => "Read List Teams", + PermissionsEnum::ReadDetailTeams => "Read Detail Teams", + + // Gacha permissions + PermissionsEnum::CreateGachaClaims => "Create Gacha Claims", + PermissionsEnum::ReadDetailGachaClaims => "Read Detail Gacha Claims", + PermissionsEnum::ReadListGachaItems => "Read List Gacha Items", + PermissionsEnum::ReadDetailGachaItems => "Read Detail Gacha Items", + PermissionsEnum::CreateGachaItems => "Create Gacha Items", + PermissionsEnum::DeleteGachaItems => "Delete Gacha Items", + PermissionsEnum::UpdateGachaItems => "Update Gacha Items", + PermissionsEnum::ReadDetailGachaRolls => "Read Detail Gacha Rolls", + PermissionsEnum::CreateGachaRolls => "Create Gacha Rolls", + PermissionsEnum::ExecuteGachaRolls => "Execute Gacha Rolls", + PermissionsEnum::DeleteGachaRolls => "Delete Gacha Rolls", + + // Mentor permissions + PermissionsEnum::ReadListMentors => "Read List Mentors", + PermissionsEnum::ReadDetailMentors => "Read Detail Mentors", + PermissionsEnum::RegisterMentors => "Register Mentors", + PermissionsEnum::ReadOwnMentorProfile => "Read Own Mentor Profile", + PermissionsEnum::UpdateOwnMentorProfile => "Update Own Mentor Profile", + PermissionsEnum::ReadOwnMentorStatus => "Read Own Mentor Status", + PermissionsEnum::UpdateMentors => "Update Mentors", + PermissionsEnum::VerifyMentors => "Verify Mentors", + PermissionsEnum::DeleteMentors => "Delete Mentors", + + // Administrator permissions + PermissionsEnum::ManageAllUsers => "Manage All Users", + PermissionsEnum::ManageAllRoles => "Manage All Roles", + PermissionsEnum::ManageAllPermissions => "Manage All Permissions", + PermissionsEnum::ManageAllTeams => "Manage All Teams", + PermissionsEnum::ViewAllSensitiveData => "View All Sensitive Data", + PermissionsEnum::AccessAdminDashboard => "Access Admin Dashboard", + PermissionsEnum::Administrator => "Administrator", + }; + write!(f, "{permission_str}") + } +} + +impl PermissionsEnum { + pub fn id(&self) -> String { + match self { + // User permissions + PermissionsEnum::ReadListUsers => "7c15e31d-36e2-49f9-97db-138c03fb0cf6".to_string(), + PermissionsEnum::ReadDetailUsers => "319ee593-ff0a-4f29-bbaf-9feb3174a3a6".to_string(), + PermissionsEnum::CreateUsers => "023e2dfe-93c3-4008-94a8-b5dff403f73b".to_string(), + PermissionsEnum::DeleteUsers => "96df0689-2ae9-4894-bf00-837c19415e5c".to_string(), + PermissionsEnum::UpdateUsers => "98b3dc4c-0124-461f-afcd-166637c5e6e8".to_string(), + PermissionsEnum::ActivateUsers => "4da8b434-89f9-4d91-85ae-eebd63cdbeda".to_string(), + + // Role permissions + PermissionsEnum::ReadListRoles => "9164ca6e-c7e3-4238-a15f-f36ab9577e7e".to_string(), + PermissionsEnum::ReadDetailRoles => "73888d18-b3e9-4f62-95a5-ba2c0d69fccb".to_string(), + PermissionsEnum::CreateRoles => "319ee593-ff0a-4f29-bbaf-9feb3174a3a2".to_string(), + PermissionsEnum::DeleteRoles => "35b0d992-65c8-4b62-b030-e6e0320e4048".to_string(), + PermissionsEnum::UpdateRoles => "a00d5608-4c48-4542-845c-dfe004687022".to_string(), + + // Permission permissions + PermissionsEnum::ReadListPermissions => "8195eeb8-e64f-4172-aa57-596492c84a72".to_string(), + PermissionsEnum::ReadDetailPermissions => "dad435cf-042c-41bd-a946-cea61ed2ffbc".to_string(), + PermissionsEnum::CreatePermissions => "0269ed71-0ae0-4c43-ad29-e3d861d8f9a0".to_string(), + PermissionsEnum::DeletePermissions => "b2dc3928-86ba-4c59-a03d-0b57d5183ebc".to_string(), + PermissionsEnum::UpdatePermissions => "299cb4d5-6556-4cc9-b6c1-32e6d31e0f9b".to_string(), + + // Team permissions + PermissionsEnum::ReadListTeams => "e1f23456-7890-1234-5678-90abcdef1234".to_string(), + PermissionsEnum::ReadDetailTeams => "f2345678-8901-2345-6789-01bcdef23456".to_string(), + + // Gacha permissions + PermissionsEnum::CreateGachaClaims => "f41d53ce-4f88-4bb6-b9b4-5e3a8c38d962".to_string(), + PermissionsEnum::ReadDetailGachaClaims => "c1c3d6c2-19fb-4b70-b58c-c19f2e8cfc79".to_string(), + PermissionsEnum::ReadListGachaItems => "fa6eb842-0a61-40c2-9c24-b226ad975037".to_string(), + PermissionsEnum::ReadDetailGachaItems => "9c7857d7-b5ae-4688-923d-ef5572e9bc8b".to_string(), + PermissionsEnum::CreateGachaItems => "cf063be1-4d71-489e-b9fb-1c08c65f396c".to_string(), + PermissionsEnum::DeleteGachaItems => "46f8c6cf-ea0c-4c90-860c-69e2e65f7eb1".to_string(), + PermissionsEnum::UpdateGachaItems => "2d0cf4ae-56ae-4714-a12e-655cfc3d9eb2".to_string(), + PermissionsEnum::ReadDetailGachaRolls => "53d6483a-04cd-4667-8792-2d0cc8e2d343".to_string(), + PermissionsEnum::CreateGachaRolls => "18e36c63-fcb7-4877-b911-c5aa611e878f".to_string(), + PermissionsEnum::ExecuteGachaRolls => "14c6a1cd-5c63-4643-89b5-b1a5f9920cc0".to_string(), + PermissionsEnum::DeleteGachaRolls => "12345678-ABCD-EFAB-CDEF-0123456789AB".to_string(), + + // Mentor permissions + PermissionsEnum::ReadListMentors => "a1b2c3d4-5e6f-7890-abcd-ef1234567890".to_string(), + PermissionsEnum::ReadDetailMentors => "b2c3d4e5-6f78-9012-bcde-f23456789012".to_string(), + PermissionsEnum::RegisterMentors => "c3d4e5f6-7890-1234-cdef-345678901234".to_string(), + PermissionsEnum::ReadOwnMentorProfile => "d4e5f6a7-8901-2345-def0-456789012345".to_string(), + PermissionsEnum::UpdateOwnMentorProfile => "e5f6a7b8-9012-3456-ef01-567890123456".to_string(), + PermissionsEnum::ReadOwnMentorStatus => "f6a7b8c9-0123-4567-f012-678901234567".to_string(), + PermissionsEnum::UpdateMentors => "a7b8c9d0-1234-5678-0123-789012345678".to_string(), + PermissionsEnum::VerifyMentors => "b8c9d0e1-2345-6789-1234-890123456789".to_string(), + PermissionsEnum::DeleteMentors => "c9d0e1f2-3456-7890-2345-901234567890".to_string(), + + // Administrator permissions + PermissionsEnum::ManageAllUsers => "d0e1f2a3-4567-8901-2345-0123456789ab".to_string(), + PermissionsEnum::ManageAllRoles => "e1f2a3b4-5678-9012-3456-1234567890ab".to_string(), + PermissionsEnum::ManageAllPermissions => "f2a3b4c5-6789-0123-4567-2345678901ab".to_string(), + PermissionsEnum::ManageAllTeams => "a3b4c5d6-7890-1234-5678-3456789012ab".to_string(), + PermissionsEnum::ViewAllSensitiveData => "b4c5d6e7-8901-2345-6789-4567890123ab".to_string(), + PermissionsEnum::AccessAdminDashboard => "c5d6e7f8-9012-3456-7890-5678901234ab".to_string(), + PermissionsEnum::Administrator => "d6e7f8a9-0123-4567-8901-6789012345ab".to_string(), + } + } + + /// Generate a new unique ID for a permission + pub fn generate_id() -> String { + Uuid::new_v4().to_string() + } + + /// Get all permissions as a vector + pub fn all() -> Vec { + vec![ + // User permissions + PermissionsEnum::ReadListUsers, + PermissionsEnum::ReadDetailUsers, + PermissionsEnum::CreateUsers, + PermissionsEnum::DeleteUsers, + PermissionsEnum::UpdateUsers, + PermissionsEnum::ActivateUsers, + + // Role permissions + PermissionsEnum::ReadListRoles, + PermissionsEnum::ReadDetailRoles, + PermissionsEnum::CreateRoles, + PermissionsEnum::DeleteRoles, + PermissionsEnum::UpdateRoles, + + // Permission permissions + PermissionsEnum::ReadListPermissions, + PermissionsEnum::ReadDetailPermissions, + PermissionsEnum::CreatePermissions, + PermissionsEnum::DeletePermissions, + PermissionsEnum::UpdatePermissions, + + // Team permissions + PermissionsEnum::ReadListTeams, + PermissionsEnum::ReadDetailTeams, + + // Gacha permissions + PermissionsEnum::CreateGachaClaims, + PermissionsEnum::ReadDetailGachaClaims, + PermissionsEnum::ReadListGachaItems, + PermissionsEnum::ReadDetailGachaItems, + PermissionsEnum::CreateGachaItems, + PermissionsEnum::DeleteGachaItems, + PermissionsEnum::UpdateGachaItems, + PermissionsEnum::ReadDetailGachaRolls, + PermissionsEnum::CreateGachaRolls, + PermissionsEnum::ExecuteGachaRolls, + PermissionsEnum::DeleteGachaRolls, + + // Mentor permissions + PermissionsEnum::ReadListMentors, + PermissionsEnum::ReadDetailMentors, + PermissionsEnum::RegisterMentors, + PermissionsEnum::ReadOwnMentorProfile, + PermissionsEnum::UpdateOwnMentorProfile, + PermissionsEnum::ReadOwnMentorStatus, + PermissionsEnum::UpdateMentors, + PermissionsEnum::VerifyMentors, + PermissionsEnum::DeleteMentors, + + // Administrator permissions + PermissionsEnum::ManageAllUsers, + PermissionsEnum::ManageAllRoles, + PermissionsEnum::ManageAllPermissions, + PermissionsEnum::ManageAllTeams, + PermissionsEnum::ViewAllSensitiveData, + PermissionsEnum::AccessAdminDashboard, + PermissionsEnum::Administrator, + ] + } +} + +#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] +pub struct PermissionsItemDto { + pub id: String, + pub name: String, + pub created_at: Option, + pub updated_at: Option, +} + +impl PermissionsItemDto { + pub fn from(dto: &PermissionsQueryDto) -> Self { + Self { + id: dto.id.as_ref().map(|id| id.id.to_raw()).unwrap_or_default(), + name: dto.name.clone().unwrap_or_default(), + created_at: dto.created_at.clone(), + updated_at: dto.updated_at.clone(), + } + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PermissionsQueryDto { + pub id: Option, + pub name: Option, + pub created_at: Option, + pub updated_at: Option, +} \ No newline at end of file diff --git a/imphnen-entities/src/users.rs b/imphnen-entities/src/users.rs new file mode 100644 index 0000000..1ff5b2e --- /dev/null +++ b/imphnen-entities/src/users.rs @@ -0,0 +1,116 @@ +use serde::{Deserialize, Serialize}; +use surrealdb::sql::Thing; +use utoipa::ToSchema; +use crate::permissions::{PermissionsQueryDto, PermissionsItemDto}; + +#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] +pub struct ExperienceDto { + pub id: String, + pub company: String, + pub position: String, + pub duration: String, + pub period: String, +} + +#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] +pub struct EducationDto { + pub id: String, + pub institution: String, + pub degree: String, + pub field: String, + pub period: String, +} + + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct RolesDetailQueryDto { + pub id: Thing, + pub name: String, + pub permissions: Option>>, + pub is_deleted: bool, + pub created_at: Option, + pub updated_at: Option, +} + +impl Default for RolesDetailQueryDto { + fn default() -> Self { + Self { + id: Thing::from(("".to_string(), surrealdb::sql::Id::Number(0))), + name: String::new(), + permissions: None, + is_deleted: false, + created_at: None, + updated_at: None, + } + } +} + +#[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Default)] +pub struct RolesDetailItemDto { + pub id: String, + pub name: String, + pub is_deleted: bool, + pub permissions: Vec, + pub created_at: Option, + pub updated_at: Option, +} + +impl RolesDetailItemDto { + pub fn from(dto: &RolesDetailQueryDto) -> Self { + Self { + id: dto.id.id.to_raw(), + name: dto.name.clone(), + is_deleted: dto.is_deleted, + permissions: dto + .permissions + .as_ref() + .unwrap_or(&vec![]) + .iter() + .filter_map(|p| p.as_ref()) + .map(PermissionsItemDto::from) + .collect(), + created_at: dto.created_at.clone(), + updated_at: dto.updated_at.clone(), + } + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct UsersDetailQueryDto { + pub id: Thing, + pub fullname: String, + pub legal_name: Option, + pub email: String, + pub avatar: Option, + pub phone_number: String, + pub phone_for_verification: Option, + pub is_active: bool, + pub is_deleted: bool, + pub gender: Option, + pub birthdate: Option, + pub domicile: Option, + pub bio: Option, + pub last_education: Option, + pub linkedin_url: Option, + pub github_url: Option, + pub cv_url: Option, + pub portfolio_url: Option, + pub website_url: Option, + pub twitter_url: Option, + pub location: Option, + pub skills: Option>, + pub experience: Option>, + pub education: Option>, + pub career_status: Option, + pub password: String, + pub role: RolesDetailQueryDto, + pub created_at: String, + pub updated_at: String, + pub mentor_id: Option, +} + +impl UsersDetailQueryDto { + pub fn from(self) -> Self { + self + } +} \ No newline at end of file diff --git a/imphnen-gateway/src/docs.rs b/imphnen-gateway/src/docs.rs index b3d738a..5d02670 100644 --- a/imphnen-gateway/src/docs.rs +++ b/imphnen-gateway/src/docs.rs @@ -20,19 +20,19 @@ use imphnen_gacha::{ GachaClaimItemDto, GachaClaimRequestDto, GachaItemDto, GachaItemRequestDto, GachaRollItemDto, GachaRollRequestDto, gacha_claims, gacha_items, gacha_rolls, }; +use imphnen_entities::{PermissionsItemDto, RolesDetailItemDto}; use imphnen_iam::{ AuthLoginRequestDto, AuthLoginResponsetDto, AuthNewPasswordRequestDto, AuthRefreshTokenRequestDto, AuthResendOtpRequestDto, AuthVerifyEmailRequestDto, - MessageResponseDto, MetaRequestDto, MetaResponseDto, PermissionsItemDto, - PermissionsRequestDto, ResponseListSuccessDto, ResponseSuccessDto, - RolesDetailItemDto, RolesListItemDto, RolesRequestCreateDto, + MessageResponseDto, MetaRequestDto, MetaResponseDto, PermissionsRequestDto, + ResponseListSuccessDto, ResponseSuccessDto, RolesListItemDto, RolesRequestCreateDto, RolesRequestUpdateDto, TokenDto, UsersCreateRequestDto, UsersDetailItemDto, - UsersListItemDto, UsersUpdateRequestDto, auth, permissions, roles, users, - TeamsCreateRequestDto, TeamsUpdateRequestDto, TeamInviteRequestDto, - TeamAcceptInvitationRequestDto, TeamsDetailItemDto, TeamsListItemDto, - TeamMemberDto, TeamInvitationDto, TeamsSearchQueryDto, teams, + UsersListItemDto, UsersUpdateRequestDto, TeamsCreateRequestDto, TeamsUpdateRequestDto, + TeamInviteRequestDto, TeamAcceptInvitationRequestDto, TeamsDetailItemDto, + TeamsListItemDto, TeamMemberDto, TeamInvitationDto, TeamsSearchQueryDto, }; -use imphnen_iam::users::users_controller::FileUploadSchema; +use imphnen_iam::v1::{auth, permissions, roles, users, teams}; +use imphnen_iam::v1::users::users_controller::FileUploadSchema; use utoipa::{ Modify, OpenApi, openapi::security::{Http, HttpAuthScheme, SecurityScheme}, diff --git a/imphnen-gateway/src/lib.rs b/imphnen-gateway/src/lib.rs index 825aba7..0bc8dd4 100644 --- a/imphnen-gateway/src/lib.rs +++ b/imphnen-gateway/src/lib.rs @@ -6,10 +6,11 @@ use imphnen_cms::{ testimonials_public_routes, }; use imphnen_dimentorin::dimentorin_router; -use imphnen_entities::{AppState, SurrealMemClient, SurrealWsClient}; +use imphnen_libs::{AppState, SurrealMemClient, SurrealWsClient}; use imphnen_gacha::gacha_router; -use imphnen_iam::{iam_protected_routes, iam_public_routes}; +use imphnen_iam::{iam_protected_routes, iam_public_routes, v1::users::users_service::UsersService, v1::auth::auth_repository::AuthRepoImpl}; use imphnen_middleware::{auth_middleware, cors_middleware}; +use std::sync::Arc; use utoipa_swagger_ui::SwaggerUi; pub mod docs; @@ -21,7 +22,9 @@ pub async fn gateway_service( ) -> Router { let state = AppState { surrealdb_ws, - surrealdb_mem, + surrealdb_mem: surrealdb_mem.clone(), + user_lookup_service: Arc::new(UsersService), + auth_repository: Arc::new(AuthRepoImpl { db: surrealdb_mem }), }; let public_routes = Router::new() diff --git a/imphnen-iam/Cargo.toml b/imphnen-iam/Cargo.toml index 6d8212e..6ffc41f 100644 --- a/imphnen-iam/Cargo.toml +++ b/imphnen-iam/Cargo.toml @@ -8,6 +8,7 @@ imphnen-libs.workspace = true imphnen-utils.workspace = true imphnen-entities.workspace = true +async-trait.workspace = true axum.workspace = true serde.workspace = true serde_json = { workspace = true } diff --git a/imphnen-iam/src/v1/auth/auth_repository.rs b/imphnen-iam/src/v1/auth/auth_repository.rs index d0b7a93..492550a 100644 --- a/imphnen-iam/src/v1/auth/auth_repository.rs +++ b/imphnen-iam/src/v1/auth/auth_repository.rs @@ -1,22 +1,24 @@ use super::AuthOtpSchema; use super::UserCacheSchema; -use crate::{ - AppState, PermissionsQueryDto, ResourceEnum, RolesDetailQueryDto, - UsersDetailQueryDto, -}; +use imphnen_entities::{PermissionsQueryDto, RolesDetailQueryDto, UsersDetailQueryDto}; +use crate::ResourceEnum; use anyhow::{Result, anyhow, bail}; use chrono::{Duration, Utc}; use surrealdb::sql::Thing; use tracing::instrument; use tracing::info; +use async_trait::async_trait; +use imphnen_libs::AuthRepositoryTrait; +use imphnen_libs::SurrealMemClient; -pub struct AuthRepository<'a> { - pub state: &'a AppState, + +pub struct AuthRepository { + pub db: SurrealMemClient, } -impl<'a> AuthRepository<'a> { - pub fn new(state: &'a AppState) -> Self { - Self { state } +impl AuthRepository { + pub fn new(db: SurrealMemClient) -> Self { + Self { db } } #[instrument(skip(self, user), err)] @@ -35,15 +37,13 @@ impl<'a> AuthRepository<'a> { info!(query = %format!("DELETE FROM {} WHERE id = '{}'", table, user_id), "Executing SurrealDB query"); let _record: Option = self - .state - .surrealdb_mem + .db .delete::>((table.clone(), user_id.clone())) .await?; info!(query = %format!("CREATE {}:{}", table, user_id), "Executing SurrealDB query"); let record: Option = self - .state - .surrealdb_mem + .db .create((table, user_id)) .content(user_cache) .await?; @@ -61,8 +61,7 @@ impl<'a> AuthRepository<'a> { ) -> Result { info!(query = %format!("SELECT FROM {} WHERE id = '{}'", ResourceEnum::UsersCache.to_string(), email), "Executing SurrealDB query"); let user_cache: Option = self - .state - .surrealdb_mem + .db .select((ResourceEnum::UsersCache.to_string(), email.clone())) .await?; @@ -132,8 +131,7 @@ impl<'a> AuthRepository<'a> { pub async fn query_delete_stored_user(&self, email: String) -> Result { info!(query = %format!("DELETE FROM {} WHERE id = '{}'", ResourceEnum::UsersCache.to_string(), email), "Executing SurrealDB query"); let record: Option = self - .state - .surrealdb_mem + .db .delete((ResourceEnum::UsersCache.to_string(), email)) .await?; match record { @@ -147,14 +145,13 @@ impl<'a> AuthRepository<'a> { let table = ResourceEnum::OtpCache.to_string(); let key = (table.as_str(), email.as_str()); info!(query = %format!("SELECT FROM {} WHERE id = '{}'", table, email), "Executing SurrealDB query"); - let result: Option = self.state.surrealdb_mem.select(key).await?; + let result: Option = self.db.select(key).await?; match result { Some(data) => match Utc::now() > data.expires_at { true => { info!(query = %format!("DELETE FROM {} WHERE id = '{}'", table, email), "Executing SurrealDB query"); let _ = self - .state - .surrealdb_mem + .db .delete::>(key) .await?; Err(anyhow!("OTP expired")) @@ -171,8 +168,7 @@ impl<'a> AuthRepository<'a> { let table: String = ResourceEnum::OtpCache.to_string(); info!(query = %format!("CREATE {}:{}", table, email), "Executing SurrealDB query"); let record: Option = self - .state - .surrealdb_mem + .db .create((table.as_str(), email.as_str())) .content(AuthOtpSchema { otp, expires_at }) .await?; @@ -186,8 +182,7 @@ impl<'a> AuthRepository<'a> { pub async fn query_delete_stored_otp(&self, email: String) -> Result { info!(query = %format!("DELETE FROM {} WHERE id = '{}'", ResourceEnum::OtpCache.to_string(), email), "Executing SurrealDB query"); let record: Option = self - .state - .surrealdb_mem + .db .delete((ResourceEnum::OtpCache.to_string(), email)) .await?; match record { @@ -196,3 +191,19 @@ impl<'a> AuthRepository<'a> { } } } + +pub struct AuthRepoImpl { + pub db: SurrealMemClient, +} + +#[async_trait] +impl AuthRepositoryTrait for AuthRepoImpl { + async fn query_get_stored_user( + &self, + email: String, + ) -> Result { + let repo = AuthRepository { db: self.db.clone() }; + repo.query_get_stored_user(email).await.map_err(|e| anyhow::anyhow!(e)) + } +} + diff --git a/imphnen-iam/src/v1/auth/auth_service.rs b/imphnen-iam/src/v1/auth/auth_service.rs index bd78add..b188e12 100644 --- a/imphnen-iam/src/v1/auth/auth_service.rs +++ b/imphnen-iam/src/v1/auth/auth_service.rs @@ -71,7 +71,7 @@ impl AuthServiceTrait for AuthService { } let user_repo = UsersRepository::new(&state); - let auth_repo = AuthRepository::new(&state); + let auth_repo = AuthRepository::new(state.surrealdb_mem.clone()); let email = &payload.email; let password = &payload.password; @@ -169,7 +169,7 @@ impl AuthServiceTrait for AuthService { } let user_repo = UsersRepository::new(&state); - let auth_repo = AuthRepository::new(&state); + let auth_repo = AuthRepository::new(state.surrealdb_mem.clone()); match user_repo.query_user_by_email(payload.email.clone()).await { Ok(user) => { @@ -269,7 +269,7 @@ impl AuthServiceTrait for AuthService { return common_response(status, &message); } let user_repo = UsersRepository::new(&state); - let auth_repo = AuthRepository::new(&state); + let auth_repo = AuthRepository::new(state.surrealdb_mem.clone()); let role_repo = RolesRepository::new(&state); let role = match role_repo .query_role_by_name(RolesEnum::User.to_string()) @@ -378,7 +378,7 @@ impl AuthServiceTrait for AuthService { { return common_response(StatusCode::BAD_REQUEST, "User not found"); } - let auth_repo = AuthRepository::new(&state); + let auth_repo = AuthRepository::new(state.surrealdb_mem.clone()); let _ = auth_repo.query_get_stored_otp(payload.email.clone()).await; let otp = generate_otp::OtpManager::generate_otp(); let message = format!("Your OTP code is {otp}"); @@ -501,7 +501,7 @@ impl AuthServiceTrait for AuthService { return common_response(status, &message); } let user_repo = UsersRepository::new(&state); - let auth_repo = AuthRepository::new(&state); + let auth_repo = AuthRepository::new(state.surrealdb_mem.clone()); let email = payload.email.clone(); let user = match user_repo.query_user_by_email(email.clone()).await { Ok(user) => user, diff --git a/imphnen-iam/src/v1/auth/google/google_oauth_service.rs b/imphnen-iam/src/v1/auth/google/google_oauth_service.rs index 3abd334..93cbfc5 100644 --- a/imphnen-iam/src/v1/auth/google/google_oauth_service.rs +++ b/imphnen-iam/src/v1/auth/google/google_oauth_service.rs @@ -356,8 +356,8 @@ let refresh_token = encode_refresh_token(user.email.clone(), user.id.clone()) }; // Cache the user in auth repository for subsequent requests - let auth_repo = crate::v1::auth::AuthRepository::new(&app_state); - let user_query_dto: crate::v1::users::users_dto::UsersDetailQueryDto = (&user).into(); + let auth_repo = crate::v1::auth::AuthRepository::new(app_state.surrealdb_mem.clone()); + let user_query_dto: imphnen_entities::UsersDetailQueryDto = (&user).into(); if let Err(err_store) = auth_repo.query_store_user(user_query_dto).await { error!( "Failed to store user cache for {}: {}", diff --git a/imphnen-iam/src/v1/permissions/permissions_controller.rs b/imphnen-iam/src/v1/permissions/permissions_controller.rs index adb32ed..4575bf5 100644 --- a/imphnen-iam/src/v1/permissions/permissions_controller.rs +++ b/imphnen-iam/src/v1/permissions/permissions_controller.rs @@ -8,12 +8,13 @@ use crate::{ AppState, MessageResponseDto, MetaRequestDto, ResponseListSuccessDto, ResponseSuccessDto, v1::{ - permissions_dto::{PermissionsItemDto, PermissionsRequestDto, PermissionsUpdateRequestDto}, + permissions_dto::{PermissionsRequestDto, PermissionsUpdateRequestDto}, permissions_service::PermissionsService, }, }; use super::{PermissionsEnum, permissions_guard}; +use imphnen_entities::PermissionsItemDto; #[utoipa::path( get, diff --git a/imphnen-iam/src/v1/permissions/permissions_dto.rs b/imphnen-iam/src/v1/permissions/permissions_dto.rs index 21ad42f..748e7c6 100644 --- a/imphnen-iam/src/v1/permissions/permissions_dto.rs +++ b/imphnen-iam/src/v1/permissions/permissions_dto.rs @@ -1,5 +1,4 @@ use serde::{Deserialize, Serialize}; -use surrealdb::sql::Thing; use utoipa::ToSchema; use validator::Validate; @@ -15,30 +14,3 @@ pub struct PermissionsUpdateRequestDto { #[serde(skip_serializing_if = "Option::is_none")] pub name: Option, } - -#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] -pub struct PermissionsItemDto { - pub id: String, - pub name: String, - pub created_at: Option, - pub updated_at: Option, -} - -impl PermissionsItemDto { - pub fn from(dto: &PermissionsQueryDto) -> Self { - Self { - id: dto.id.as_ref().map(|id| id.id.to_raw()).unwrap_or_default(), - name: dto.name.clone().unwrap_or_default(), - created_at: dto.created_at.clone(), - updated_at: dto.updated_at.clone(), - } - } -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PermissionsQueryDto { - pub id: Option, - pub name: Option, - pub created_at: Option, - pub updated_at: Option, -} diff --git a/imphnen-iam/src/v1/permissions/permissions_enum.rs b/imphnen-iam/src/v1/permissions/permissions_enum.rs index 80ccf73..0384c52 100644 --- a/imphnen-iam/src/v1/permissions/permissions_enum.rs +++ b/imphnen-iam/src/v1/permissions/permissions_enum.rs @@ -1,265 +1 @@ -use std::fmt; -use uuid::Uuid; -use strum_macros::EnumIter; - -#[derive(Debug, Clone, PartialEq, Eq, EnumIter)] -pub enum PermissionsEnum { - // User permissions - ReadListUsers, - ReadDetailUsers, - CreateUsers, - DeleteUsers, - UpdateUsers, - ActivateUsers, - - // Role permissions - ReadListRoles, - ReadDetailRoles, - CreateRoles, - DeleteRoles, - UpdateRoles, - - // Permission permissions - ReadListPermissions, - ReadDetailPermissions, - CreatePermissions, - DeletePermissions, - UpdatePermissions, - - // Team permissions - ReadListTeams, - ReadDetailTeams, - - // Administrator permissions - ManageAllUsers, - ManageAllRoles, - ManageAllPermissions, - ManageAllTeams, - ViewAllSensitiveData, - AccessAdminDashboard, - Administrator, - - // Gacha permissions - CreateGachaClaims, - ReadDetailGachaClaims, - ReadListGachaItems, - ReadDetailGachaItems, - CreateGachaItems, - DeleteGachaItems, - UpdateGachaItems, - ReadDetailGachaRolls, - CreateGachaRolls, - ExecuteGachaRolls, - DeleteGachaRolls, - - // Mentor permissions - ReadListMentors, - ReadDetailMentors, - RegisterMentors, - ReadOwnMentorProfile, - UpdateOwnMentorProfile, - ReadOwnMentorStatus, - UpdateMentors, - VerifyMentors, - DeleteMentors, -} - -impl fmt::Display for PermissionsEnum { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let permission_str = match self { - // User permissions - PermissionsEnum::ReadListUsers => "Read List Users", - PermissionsEnum::ReadDetailUsers => "Read Detail Users", - PermissionsEnum::CreateUsers => "Create Users", - PermissionsEnum::DeleteUsers => "Delete Users", - PermissionsEnum::UpdateUsers => "Update Users", - PermissionsEnum::ActivateUsers => "Activate Users", - - // Role permissions - PermissionsEnum::ReadListRoles => "Read List Roles", - PermissionsEnum::ReadDetailRoles => "Read Detail Roles", - PermissionsEnum::CreateRoles => "Create Roles", - PermissionsEnum::DeleteRoles => "Delete Roles", - PermissionsEnum::UpdateRoles => "Update Roles", - - // Permission permissions - PermissionsEnum::ReadListPermissions => "Read List Permissions", - PermissionsEnum::ReadDetailPermissions => "Read Detail Permissions", - PermissionsEnum::CreatePermissions => "Create Permissions", - PermissionsEnum::DeletePermissions => "Delete Permissions", - PermissionsEnum::UpdatePermissions => "Update Permissions", - - // Team permissions - PermissionsEnum::ReadListTeams => "Read List Teams", - PermissionsEnum::ReadDetailTeams => "Read Detail Teams", - - // Gacha permissions - PermissionsEnum::CreateGachaClaims => "Create Gacha Claims", - PermissionsEnum::ReadDetailGachaClaims => "Read Detail Gacha Claims", - PermissionsEnum::ReadListGachaItems => "Read List Gacha Items", - PermissionsEnum::ReadDetailGachaItems => "Read Detail Gacha Items", - PermissionsEnum::CreateGachaItems => "Create Gacha Items", - PermissionsEnum::DeleteGachaItems => "Delete Gacha Items", - PermissionsEnum::UpdateGachaItems => "Update Gacha Items", - PermissionsEnum::ReadDetailGachaRolls => "Read Detail Gacha Rolls", - PermissionsEnum::CreateGachaRolls => "Create Gacha Rolls", - PermissionsEnum::ExecuteGachaRolls => "Execute Gacha Rolls", - PermissionsEnum::DeleteGachaRolls => "Delete Gacha Rolls", - - // Mentor permissions - PermissionsEnum::ReadListMentors => "Read List Mentors", - PermissionsEnum::ReadDetailMentors => "Read Detail Mentors", - PermissionsEnum::RegisterMentors => "Register Mentors", - PermissionsEnum::ReadOwnMentorProfile => "Read Own Mentor Profile", - PermissionsEnum::UpdateOwnMentorProfile => "Update Own Mentor Profile", - PermissionsEnum::ReadOwnMentorStatus => "Read Own Mentor Status", - PermissionsEnum::UpdateMentors => "Update Mentors", - PermissionsEnum::VerifyMentors => "Verify Mentors", - PermissionsEnum::DeleteMentors => "Delete Mentors", - - // Administrator permissions - PermissionsEnum::ManageAllUsers => "Manage All Users", - PermissionsEnum::ManageAllRoles => "Manage All Roles", - PermissionsEnum::ManageAllPermissions => "Manage All Permissions", - PermissionsEnum::ManageAllTeams => "Manage All Teams", - PermissionsEnum::ViewAllSensitiveData => "View All Sensitive Data", - PermissionsEnum::AccessAdminDashboard => "Access Admin Dashboard", - PermissionsEnum::Administrator => "Administrator", - }; - write!(f, "{permission_str}") - } -} - -impl PermissionsEnum { - pub fn id(&self) -> String { - match self { - // User permissions - PermissionsEnum::ReadListUsers => "7c15e31d-36e2-49f9-97db-138c03fb0cf6".to_string(), - PermissionsEnum::ReadDetailUsers => "319ee593-ff0a-4f29-bbaf-9feb3174a3a6".to_string(), - PermissionsEnum::CreateUsers => "023e2dfe-93c3-4008-94a8-b5dff403f73b".to_string(), - PermissionsEnum::DeleteUsers => "96df0689-2ae9-4894-bf00-837c19415e5c".to_string(), - PermissionsEnum::UpdateUsers => "98b3dc4c-0124-461f-afcd-166637c5e6e8".to_string(), - PermissionsEnum::ActivateUsers => "4da8b434-89f9-4d91-85ae-eebd63cdbeda".to_string(), - - // Role permissions - PermissionsEnum::ReadListRoles => "9164ca6e-c7e3-4238-a15f-f36ab9577e7e".to_string(), - PermissionsEnum::ReadDetailRoles => "73888d18-b3e9-4f62-95a5-ba2c0d69fccb".to_string(), - PermissionsEnum::CreateRoles => "319ee593-ff0a-4f29-bbaf-9feb3174a3a2".to_string(), - PermissionsEnum::DeleteRoles => "35b0d992-65c8-4b62-b030-e6e0320e4048".to_string(), - PermissionsEnum::UpdateRoles => "a00d5608-4c48-4542-845c-dfe004687022".to_string(), - - // Permission permissions - PermissionsEnum::ReadListPermissions => "8195eeb8-e64f-4172-aa57-596492c84a72".to_string(), - PermissionsEnum::ReadDetailPermissions => "dad435cf-042c-41bd-a946-cea61ed2ffbc".to_string(), - PermissionsEnum::CreatePermissions => "0269ed71-0ae0-4c43-ad29-e3d861d8f9a0".to_string(), - PermissionsEnum::DeletePermissions => "b2dc3928-86ba-4c59-a03d-0b57d5183ebc".to_string(), - PermissionsEnum::UpdatePermissions => "299cb4d5-6556-4cc9-b6c1-32e6d31e0f9b".to_string(), - - // Team permissions - PermissionsEnum::ReadListTeams => "e1f23456-7890-1234-5678-90abcdef1234".to_string(), - PermissionsEnum::ReadDetailTeams => "f2345678-8901-2345-6789-01bcdef23456".to_string(), - - // Gacha permissions - PermissionsEnum::CreateGachaClaims => "f41d53ce-4f88-4bb6-b9b4-5e3a8c38d962".to_string(), - PermissionsEnum::ReadDetailGachaClaims => "c1c3d6c2-19fb-4b70-b58c-c19f2e8cfc79".to_string(), - PermissionsEnum::ReadListGachaItems => "fa6eb842-0a61-40c2-9c24-b226ad975037".to_string(), - PermissionsEnum::ReadDetailGachaItems => "9c7857d7-b5ae-4688-923d-ef5572e9bc8b".to_string(), - PermissionsEnum::CreateGachaItems => "cf063be1-4d71-489e-b9fb-1c08c65f396c".to_string(), - PermissionsEnum::DeleteGachaItems => "46f8c6cf-ea0c-4c90-860c-69e2e65f7eb1".to_string(), - PermissionsEnum::UpdateGachaItems => "2d0cf4ae-56ae-4714-a12e-655cfc3d9eb2".to_string(), - PermissionsEnum::ReadDetailGachaRolls => "53d6483a-04cd-4667-8792-2d0cc8e2d343".to_string(), - PermissionsEnum::CreateGachaRolls => "18e36c63-fcb7-4877-b911-c5aa611e878f".to_string(), - PermissionsEnum::ExecuteGachaRolls => "14c6a1cd-5c63-4643-89b5-b1a5f9920cc0".to_string(), - PermissionsEnum::DeleteGachaRolls => "12345678-ABCD-EFAB-CDEF-0123456789AB".to_string(), - - // Mentor permissions - PermissionsEnum::ReadListMentors => "a1b2c3d4-5e6f-7890-abcd-ef1234567890".to_string(), - PermissionsEnum::ReadDetailMentors => "b2c3d4e5-6f78-9012-bcde-f23456789012".to_string(), - PermissionsEnum::RegisterMentors => "c3d4e5f6-7890-1234-cdef-345678901234".to_string(), - PermissionsEnum::ReadOwnMentorProfile => "d4e5f6a7-8901-2345-def0-456789012345".to_string(), - PermissionsEnum::UpdateOwnMentorProfile => "e5f6a7b8-9012-3456-ef01-567890123456".to_string(), - PermissionsEnum::ReadOwnMentorStatus => "f6a7b8c9-0123-4567-f012-678901234567".to_string(), - PermissionsEnum::UpdateMentors => "a7b8c9d0-1234-5678-0123-789012345678".to_string(), - PermissionsEnum::VerifyMentors => "b8c9d0e1-2345-6789-1234-890123456789".to_string(), - PermissionsEnum::DeleteMentors => "c9d0e1f2-3456-7890-2345-901234567890".to_string(), - - // Administrator permissions - PermissionsEnum::ManageAllUsers => "d0e1f2a3-4567-8901-2345-0123456789ab".to_string(), - PermissionsEnum::ManageAllRoles => "e1f2a3b4-5678-9012-3456-1234567890ab".to_string(), - PermissionsEnum::ManageAllPermissions => "f2a3b4c5-6789-0123-4567-2345678901ab".to_string(), - PermissionsEnum::ManageAllTeams => "a3b4c5d6-7890-1234-5678-3456789012ab".to_string(), - PermissionsEnum::ViewAllSensitiveData => "b4c5d6e7-8901-2345-6789-4567890123ab".to_string(), - PermissionsEnum::AccessAdminDashboard => "c5d6e7f8-9012-3456-7890-5678901234ab".to_string(), - PermissionsEnum::Administrator => "administrator-permission-id-123456789".to_string(), - } - } - - /// Generate a new unique ID for a permission - pub fn generate_id() -> String { - Uuid::new_v4().to_string() - } - - /// Get all permissions as a vector - pub fn all() -> Vec { - vec![ - // User permissions - PermissionsEnum::ReadListUsers, - PermissionsEnum::ReadDetailUsers, - PermissionsEnum::CreateUsers, - PermissionsEnum::DeleteUsers, - PermissionsEnum::UpdateUsers, - PermissionsEnum::ActivateUsers, - - // Role permissions - PermissionsEnum::ReadListRoles, - PermissionsEnum::ReadDetailRoles, - PermissionsEnum::CreateRoles, - PermissionsEnum::DeleteRoles, - PermissionsEnum::UpdateRoles, - - // Permission permissions - PermissionsEnum::ReadListPermissions, - PermissionsEnum::ReadDetailPermissions, - PermissionsEnum::CreatePermissions, - PermissionsEnum::DeletePermissions, - PermissionsEnum::UpdatePermissions, - - // Team permissions - PermissionsEnum::ReadListTeams, - PermissionsEnum::ReadDetailTeams, - - // Gacha permissions - PermissionsEnum::CreateGachaClaims, - PermissionsEnum::ReadDetailGachaClaims, - PermissionsEnum::ReadListGachaItems, - PermissionsEnum::ReadDetailGachaItems, - PermissionsEnum::CreateGachaItems, - PermissionsEnum::DeleteGachaItems, - PermissionsEnum::UpdateGachaItems, - PermissionsEnum::ReadDetailGachaRolls, - PermissionsEnum::CreateGachaRolls, - PermissionsEnum::ExecuteGachaRolls, - PermissionsEnum::DeleteGachaRolls, - - // Mentor permissions - PermissionsEnum::ReadListMentors, - PermissionsEnum::ReadDetailMentors, - PermissionsEnum::RegisterMentors, - PermissionsEnum::ReadOwnMentorProfile, - PermissionsEnum::UpdateOwnMentorProfile, - PermissionsEnum::ReadOwnMentorStatus, - PermissionsEnum::UpdateMentors, - PermissionsEnum::VerifyMentors, - PermissionsEnum::DeleteMentors, - - // Administrator permissions - PermissionsEnum::ManageAllUsers, - PermissionsEnum::ManageAllRoles, - PermissionsEnum::ManageAllPermissions, - PermissionsEnum::ManageAllTeams, - PermissionsEnum::ViewAllSensitiveData, - PermissionsEnum::AccessAdminDashboard, - PermissionsEnum::Administrator, - ] - } -} +pub use imphnen_entities::PermissionsEnum; diff --git a/imphnen-iam/src/v1/permissions/permissions_repository.rs b/imphnen-iam/src/v1/permissions/permissions_repository.rs index 634e02a..352cadb 100644 --- a/imphnen-iam/src/v1/permissions/permissions_repository.rs +++ b/imphnen-iam/src/v1/permissions/permissions_repository.rs @@ -1,4 +1,5 @@ -use super::{PermissionsItemDto, PermissionsSchema}; +use imphnen_entities::PermissionsItemDto; +use super::PermissionsSchema; use crate::{ AppState, MetaRequestDto, ResourceEnum, ResponseListSuccessDto, get_id, make_thing, }; diff --git a/imphnen-iam/src/v1/permissions/permissions_schema.rs b/imphnen-iam/src/v1/permissions/permissions_schema.rs index b63f858..e51db1a 100644 --- a/imphnen-iam/src/v1/permissions/permissions_schema.rs +++ b/imphnen-iam/src/v1/permissions/permissions_schema.rs @@ -3,7 +3,7 @@ use imphnen_utils::make_thing_from_enum; use serde::{Deserialize, Serialize}; use surrealdb::{Uuid, sql::Thing}; -use super::{PermissionsItemDto, PermissionsQueryDto}; +use imphnen_entities::{PermissionsItemDto, PermissionsQueryDto}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct PermissionsSchema { diff --git a/imphnen-iam/src/v1/roles/roles_dto.rs b/imphnen-iam/src/v1/roles/roles_dto.rs index e516c3f..870c288 100644 --- a/imphnen-iam/src/v1/roles/roles_dto.rs +++ b/imphnen-iam/src/v1/roles/roles_dto.rs @@ -1,4 +1,4 @@ -use crate::{PermissionsItemDto, PermissionsQueryDto}; +use imphnen_entities::{PermissionsItemDto, PermissionsQueryDto}; use serde::{Deserialize, Serialize}; use surrealdb::sql::Thing; use utoipa::ToSchema; diff --git a/imphnen-iam/src/v1/users/users_dto.rs b/imphnen-iam/src/v1/users/users_dto.rs index fd06006..5636640 100644 --- a/imphnen-iam/src/v1/users/users_dto.rs +++ b/imphnen-iam/src/v1/users/users_dto.rs @@ -1,4 +1,4 @@ -use crate::{RolesDetailItemDto, RolesDetailQueryDto}; +use imphnen_entities::{ExperienceDto, EducationDto, UsersDetailQueryDto, RolesDetailQueryDto, RolesDetailItemDto}; use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; use surrealdb::sql::Thing; @@ -11,24 +11,6 @@ lazy_static! { regex::Regex::new(r"^[A-Za-z\d@$!%*?&]{8,}$").unwrap(); } -#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] -pub struct ExperienceDto { - pub id: String, - pub company: String, - pub position: String, - pub duration: String, - pub period: String, -} - -#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] -pub struct EducationDto { - pub id: String, - pub institution: String, - pub degree: String, - pub field: String, - pub period: String, -} - #[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] pub struct UsersActiveInactiveRequestDto { pub is_active: bool, @@ -288,45 +270,6 @@ impl UsersListQueryDto { } } -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct UsersDetailQueryDto { - pub id: Thing, - pub fullname: String, - pub legal_name: Option, - pub email: String, - pub avatar: Option, - pub phone_number: String, - pub phone_for_verification: Option, - pub is_active: bool, - pub is_deleted: bool, - pub gender: Option, - pub birthdate: Option, - pub domicile: Option, - pub bio: Option, - pub last_education: Option, - pub linkedin_url: Option, - pub github_url: Option, - pub cv_url: Option, - pub portfolio_url: Option, - pub website_url: Option, - pub twitter_url: Option, - pub location: Option, - pub skills: Option>, - pub experience: Option>, - pub education: Option>, - pub career_status: Option, - pub password: String, - pub role: RolesDetailQueryDto, - pub created_at: String, - pub updated_at: String, - pub mentor_id: Option, -} - -impl UsersDetailQueryDto { - pub fn from(self) -> Self { - self - } -} impl From<&UsersDetailItemDto> for UsersDetailQueryDto { fn from(dto: &UsersDetailItemDto) -> Self { diff --git a/imphnen-iam/src/v1/users/users_repository.rs b/imphnen-iam/src/v1/users/users_repository.rs index bdeb3c6..566c606 100644 --- a/imphnen-iam/src/v1/users/users_repository.rs +++ b/imphnen-iam/src/v1/users/users_repository.rs @@ -1,4 +1,5 @@ -use super::{UsersDetailQueryDto, UsersListItemDto, UsersListQueryDto, UsersSchema}; +use imphnen_entities::UsersDetailQueryDto; +use super::{UsersListItemDto, UsersListQueryDto, UsersSchema}; use crate::{ AppState, MetaRequestDto, ResourceEnum, ResponseListSuccessDto, get_id, make_thing, }; diff --git a/imphnen-iam/src/v1/users/users_schema.rs b/imphnen-iam/src/v1/users/users_schema.rs index fdaa4ef..da4308c 100644 --- a/imphnen-iam/src/v1/users/users_schema.rs +++ b/imphnen-iam/src/v1/users/users_schema.rs @@ -1,4 +1,5 @@ -use super::{UsersCreateRequestDto, UsersDetailQueryDto, UsersUpdateRequestDto, ExperienceDto, EducationDto}; +use imphnen_entities::{UsersDetailQueryDto, ExperienceDto, EducationDto}; +use super::{UsersCreateRequestDto, UsersUpdateRequestDto}; use imphnen_libs::{ResourceEnum, hash_password}; use imphnen_utils::extract_id; use imphnen_utils::{get_iso_date, make_thing_from_enum}; diff --git a/imphnen-iam/src/v1/users/users_service.rs b/imphnen-iam/src/v1/users/users_service.rs index bf71435..586df76 100644 --- a/imphnen-iam/src/v1/users/users_service.rs +++ b/imphnen-iam/src/v1/users/users_service.rs @@ -1,8 +1,8 @@ use super::{ UsersActiveInactiveRequestDto, UsersCreateRequestDto, UsersSetNewPasswordRequestDto, UsersUpdateRequestDto, - users_dto::UsersDetailQueryDto, // Add this line }; +use imphnen_entities::UsersDetailQueryDto; use crate::{ AppState, MetaRequestDto, ResponseListSuccessDto, UsersRepository, UsersSchema, }; @@ -22,6 +22,8 @@ use tracing::info; use tracing::error; use crate::v1::users::users_dto::{UsersDetailItemDto as UserDto, UsersCreateRequestDto as CreateUserDto}; use serde_json::json; +use async_trait::async_trait; +use imphnen_libs::UserLookupService; pub trait UsersServiceTrait: Send + Sync + 'static { @@ -610,4 +612,16 @@ pub trait UsersServiceTrait: Send + Sync + 'static { } }) } +} + +#[async_trait] +impl UserLookupService for UsersService { + async fn get_user_by_id_internal( + &self, + thing_id: &surrealdb::sql::Thing, + state: &imphnen_libs::AppState, + ) -> Result { + let repo = crate::UsersRepository::new(state); + repo.query_user_by_id(thing_id).await.map_err(|e| anyhow::anyhow!(e)) + } } \ No newline at end of file diff --git a/imphnen-libs/Cargo.toml b/imphnen-libs/Cargo.toml index 03130db..9ac3c5b 100644 --- a/imphnen-libs/Cargo.toml +++ b/imphnen-libs/Cargo.toml @@ -24,3 +24,4 @@ sha2.workspace = true hmac.workspace = true hex.workspace = true urlencoding.workspace = true +async-trait.workspace = true diff --git a/imphnen-libs/src/axum/mod.rs b/imphnen-libs/src/axum/mod.rs index 8713a6b..700e971 100644 --- a/imphnen-libs/src/axum/mod.rs +++ b/imphnen-libs/src/axum/mod.rs @@ -1,6 +1,5 @@ -use crate::{surrealdb_init_mem, surrealdb_init_ws}; +use crate::{surrealdb_init_mem, surrealdb_init_ws, SurrealMemClient, SurrealWsClient}; use axum::{Router, serve}; -use imphnen_entities::{SurrealMemClient, SurrealWsClient}; use std::{future::Future, net::SocketAddr}; use tokio::net::TcpListener; use crate::enviroment::ENV; diff --git a/imphnen-libs/src/lib.rs b/imphnen-libs/src/lib.rs index 50d0efe..30b70be 100644 --- a/imphnen-libs/src/lib.rs +++ b/imphnen-libs/src/lib.rs @@ -1,4 +1,4 @@ -use imphnen_entities::*; +use std::sync::Arc; pub mod argon; pub mod axum; @@ -6,6 +6,7 @@ pub mod enviroment; pub mod jsonwebtoken; pub mod lettre; pub mod minio; +pub mod services; pub mod surrealdb; pub use argon::*; @@ -15,4 +16,13 @@ pub use imphnen_entities::*; pub use jsonwebtoken::*; pub use lettre::*; pub use minio::*; +pub use services::*; pub use surrealdb::*; + +#[derive(Clone)] +pub struct AppState { + pub surrealdb_ws: SurrealWsClient, + pub surrealdb_mem: SurrealMemClient, + pub user_lookup_service: Arc, + pub auth_repository: Arc, +} diff --git a/imphnen-libs/src/services.rs b/imphnen-libs/src/services.rs new file mode 100644 index 0000000..c12bf72 --- /dev/null +++ b/imphnen-libs/src/services.rs @@ -0,0 +1,22 @@ +use async_trait::async_trait; +use imphnen_entities::UsersDetailQueryDto; +use crate::AppState; +use std::result::Result; +use surrealdb::sql::Thing; + +#[async_trait] +pub trait UserLookupService: Send + Sync { + async fn get_user_by_id_internal( + &self, + thing_id: &Thing, + state: &AppState, + ) -> Result; +} + +#[async_trait] +pub trait AuthRepositoryTrait: Send + Sync { + async fn query_get_stored_user( + &self, + email: String, + ) -> Result; +} \ No newline at end of file diff --git a/imphnen-libs/src/surrealdb/mod.rs b/imphnen-libs/src/surrealdb/mod.rs index e1e2b92..21b3782 100644 --- a/imphnen-libs/src/surrealdb/mod.rs +++ b/imphnen-libs/src/surrealdb/mod.rs @@ -1,10 +1,12 @@ use crate::enviroment::ENV; -use crate::SurrealMemClient; use surrealdb::engine::any; -use surrealdb::engine::local::Mem; +use surrealdb::engine::local::{Db, Mem}; use surrealdb::opt::auth::Root; use surrealdb::{Result, Surreal}; +pub type SurrealWsClient = Surreal; +pub type SurrealMemClient = Surreal; + pub mod resource; pub use resource::*; diff --git a/imphnen-middleware/Cargo.toml b/imphnen-middleware/Cargo.toml index b194f42..1753b85 100644 --- a/imphnen-middleware/Cargo.toml +++ b/imphnen-middleware/Cargo.toml @@ -4,7 +4,6 @@ version = "0.1.0" edition = "2024" [dependencies] -imphnen-iam.workspace = true imphnen-libs.workspace = true imphnen-utils.workspace = true imphnen-entities.workspace = true diff --git a/imphnen-middleware/src/auth_middleware/mod.rs b/imphnen-middleware/src/auth_middleware/mod.rs index 2233562..55c9648 100644 --- a/imphnen-middleware/src/auth_middleware/mod.rs +++ b/imphnen-middleware/src/auth_middleware/mod.rs @@ -3,11 +3,10 @@ use axum::{ response::Response, }; use imphnen_libs::{AppState, jsonwebtoken::decode_access_token}; -use imphnen_iam::v1::users::users_dto::UsersDetailQueryDto; +use imphnen_entities::UsersDetailQueryDto; use imphnen_utils::common_response; use axum_extra::headers::{authorization::Bearer, Authorization, HeaderMapExt}; use std::convert::Infallible; -use imphnen_iam::v1::users::{users_service::{UsersService, UsersServiceTrait}}; use imphnen_libs::ResourceEnum; use imphnen_utils::make_thing; @@ -45,7 +44,7 @@ pub async fn auth_middleware( let mut user_data: Option = None; if let Ok(opt_user) = mem_db.select(("users", &user_id)).await { if let Some(user) = opt_user { - let user: imphnen_iam::v1::users::users_dto::UsersDetailQueryDto = user; + let user: UsersDetailQueryDto = user; if !user.is_deleted && !user.role.is_deleted { user_data = Some(user); } @@ -56,8 +55,7 @@ pub async fn auth_middleware( let user_data = match user_data { Some(user) => user, None => { - let repo = UsersService {}; - match repo.get_user_by_id_internal(&thing_id, &state).await { + match state.user_lookup_service.get_user_by_id_internal(&thing_id, &state).await { Ok(user) => { // Optionally: insert into mem for future requests let _: Result, _> = mem_db.update(("users", &user_id)).content(user.clone()).await; diff --git a/imphnen-middleware/src/permissions_middleware/mod.rs b/imphnen-middleware/src/permissions_middleware/mod.rs index 2426415..d21327f 100644 --- a/imphnen-middleware/src/permissions_middleware/mod.rs +++ b/imphnen-middleware/src/permissions_middleware/mod.rs @@ -3,7 +3,7 @@ use axum::{ http::{Request, Response, StatusCode}, }; use futures::future::BoxFuture; -use imphnen_iam::{AuthRepository, PermissionsEnum}; +use imphnen_entities::PermissionsEnum; use imphnen_libs::AppState; use imphnen_utils::{common_response, extract_email, extract_email_async}; use std::task::{Context, Poll}; @@ -77,8 +77,7 @@ where } }; - let auth_repo = AuthRepository::new(&app_state); - let user = match auth_repo.query_get_stored_user(email).await { + let user = match app_state.auth_repository.query_get_stored_user(email).await { Ok(user) => user, Err(_) => { return Ok(common_response( diff --git a/tests/src/mock_test.rs b/tests/src/mock_test.rs index b95db27..711a3ba 100644 --- a/tests/src/mock_test.rs +++ b/tests/src/mock_test.rs @@ -1,7 +1,8 @@ // Restore only the necessary imports to fix unresolved function errors use crate::{get_iso_date, hash_password}; -use imphnen_entities::AppState; -use imphnen_iam::{PermissionsEnum, UsersSchema}; +use imphnen_libs::AppState; +use imphnen_iam::{PermissionsEnum, UsersSchema, v1::users::users_service::UsersService, v1::auth::auth_repository::AuthRepoImpl}; +use std::sync::Arc; use serde::{Deserialize, Serialize}; use strum::IntoEnumIterator; use surrealdb::engine::{any, local}; @@ -50,7 +51,9 @@ pub async fn create_mock_app_state() -> AppState { AppState { surrealdb_ws: db_ws, - surrealdb_mem: db_mem, + surrealdb_mem: db_mem.clone(), + user_lookup_service: Arc::new(UsersService), + auth_repository: Arc::new(AuthRepoImpl { db: db_mem.clone() }), } } pub async fn cleanup_db() {