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.
This commit is contained in:
MythEclipse
2025-09-26 15:05:45 +07:00
parent b80662188f
commit 96debc210a
35 changed files with 564 additions and 431 deletions
Generated
+5 -1
View File
@@ -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",
+1
View File
@@ -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"
@@ -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;
@@ -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;
@@ -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<UsersSchema> = None;
+3
View File
@@ -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
-9
View File
@@ -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<T: Serialize> {
pub meta: Option<MetaResponseDto>,
}
pub type SurrealWsClient = Surreal<Any>;
pub type SurrealMemClient = Surreal<Db>;
#[derive(Clone)]
pub struct AppState {
pub surrealdb_ws: SurrealWsClient,
pub surrealdb_mem: SurrealMemClient,
}
#[derive(Debug, serde::Deserialize)]
pub struct CountResult {
+4
View File
@@ -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::*;
+295
View File
@@ -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<PermissionsEnum> {
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<String>,
pub updated_at: Option<String>,
}
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<Thing>,
pub name: Option<String>,
pub created_at: Option<String>,
pub updated_at: Option<String>,
}
+116
View File
@@ -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<Vec<Option<PermissionsQueryDto>>>,
pub is_deleted: bool,
pub created_at: Option<String>,
pub updated_at: Option<String>,
}
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<PermissionsItemDto>,
pub created_at: Option<String>,
pub updated_at: Option<String>,
}
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<String>,
pub email: String,
pub avatar: Option<String>,
pub phone_number: String,
pub phone_for_verification: Option<String>,
pub is_active: bool,
pub is_deleted: bool,
pub gender: Option<String>,
pub birthdate: Option<String>,
pub domicile: Option<String>,
pub bio: Option<String>,
pub last_education: Option<String>,
pub linkedin_url: Option<String>,
pub github_url: Option<String>,
pub cv_url: Option<String>,
pub portfolio_url: Option<String>,
pub website_url: Option<String>,
pub twitter_url: Option<String>,
pub location: Option<String>,
pub skills: Option<Vec<String>>,
pub experience: Option<Vec<ExperienceDto>>,
pub education: Option<Vec<EducationDto>>,
pub career_status: Option<String>,
pub password: String,
pub role: RolesDetailQueryDto,
pub created_at: String,
pub updated_at: String,
pub mentor_id: Option<Thing>,
}
impl UsersDetailQueryDto {
pub fn from(self) -> Self {
self
}
}
+8 -8
View File
@@ -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},
+6 -3
View File
@@ -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()
+1
View File
@@ -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 }
+35 -24
View File
@@ -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<UserCacheSchema> = self
.state
.surrealdb_mem
.db
.delete::<Option<UserCacheSchema>>((table.clone(), user_id.clone()))
.await?;
info!(query = %format!("CREATE {}:{}", table, user_id), "Executing SurrealDB query");
let record: Option<UserCacheSchema> = self
.state
.surrealdb_mem
.db
.create((table, user_id))
.content(user_cache)
.await?;
@@ -61,8 +61,7 @@ impl<'a> AuthRepository<'a> {
) -> Result<UsersDetailQueryDto> {
info!(query = %format!("SELECT FROM {} WHERE id = '{}'", ResourceEnum::UsersCache.to_string(), email), "Executing SurrealDB query");
let user_cache: Option<UserCacheSchema> = 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<String> {
info!(query = %format!("DELETE FROM {} WHERE id = '{}'", ResourceEnum::UsersCache.to_string(), email), "Executing SurrealDB query");
let record: Option<UsersDetailQueryDto> = 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<AuthOtpSchema> = self.state.surrealdb_mem.select(key).await?;
let result: Option<AuthOtpSchema> = 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::<Option<AuthOtpSchema>>(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<AuthOtpSchema> = 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<String> {
info!(query = %format!("DELETE FROM {} WHERE id = '{}'", ResourceEnum::OtpCache.to_string(), email), "Executing SurrealDB query");
let record: Option<AuthOtpSchema> = 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<UsersDetailQueryDto, anyhow::Error> {
let repo = AuthRepository { db: self.db.clone() };
repo.query_get_stored_user(email).await.map_err(|e| anyhow::anyhow!(e))
}
}
+5 -5
View File
@@ -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,
@@ -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 {}: {}",
@@ -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,
@@ -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<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
pub struct PermissionsItemDto {
pub id: String,
pub name: String,
pub created_at: Option<String>,
pub updated_at: Option<String>,
}
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<Thing>,
pub name: Option<String>,
pub created_at: Option<String>,
pub updated_at: Option<String>,
}
@@ -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<PermissionsEnum> {
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;
@@ -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,
};
@@ -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 {
+1 -1
View File
@@ -1,4 +1,4 @@
use crate::{PermissionsItemDto, PermissionsQueryDto};
use imphnen_entities::{PermissionsItemDto, PermissionsQueryDto};
use serde::{Deserialize, Serialize};
use surrealdb::sql::Thing;
use utoipa::ToSchema;
+1 -58
View File
@@ -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<String>,
pub email: String,
pub avatar: Option<String>,
pub phone_number: String,
pub phone_for_verification: Option<String>,
pub is_active: bool,
pub is_deleted: bool,
pub gender: Option<String>,
pub birthdate: Option<String>,
pub domicile: Option<String>,
pub bio: Option<String>,
pub last_education: Option<String>,
pub linkedin_url: Option<String>,
pub github_url: Option<String>,
pub cv_url: Option<String>,
pub portfolio_url: Option<String>,
pub website_url: Option<String>,
pub twitter_url: Option<String>,
pub location: Option<String>,
pub skills: Option<Vec<String>>,
pub experience: Option<Vec<ExperienceDto>>,
pub education: Option<Vec<EducationDto>>,
pub career_status: Option<String>,
pub password: String,
pub role: RolesDetailQueryDto,
pub created_at: String,
pub updated_at: String,
pub mentor_id: Option<Thing>,
}
impl UsersDetailQueryDto {
pub fn from(self) -> Self {
self
}
}
impl From<&UsersDetailItemDto> for UsersDetailQueryDto {
fn from(dto: &UsersDetailItemDto) -> Self {
+2 -1
View File
@@ -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,
};
+2 -1
View File
@@ -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};
+15 -1
View File
@@ -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<imphnen_entities::UsersDetailQueryDto, anyhow::Error> {
let repo = crate::UsersRepository::new(state);
repo.query_user_by_id(thing_id).await.map_err(|e| anyhow::anyhow!(e))
}
}
+1
View File
@@ -24,3 +24,4 @@ sha2.workspace = true
hmac.workspace = true
hex.workspace = true
urlencoding.workspace = true
async-trait.workspace = true
+1 -2
View File
@@ -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;
+11 -1
View File
@@ -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<dyn UserLookupService>,
pub auth_repository: Arc<dyn AuthRepositoryTrait>,
}
+22
View File
@@ -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<UsersDetailQueryDto, anyhow::Error>;
}
#[async_trait]
pub trait AuthRepositoryTrait: Send + Sync {
async fn query_get_stored_user(
&self,
email: String,
) -> Result<UsersDetailQueryDto, anyhow::Error>;
}
+4 -2
View File
@@ -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<any::Any>;
pub type SurrealMemClient = Surreal<Db>;
pub mod resource;
pub use resource::*;
-1
View File
@@ -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
@@ -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<UsersDetailQueryDto> = 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<Option<UsersDetailQueryDto>, _> = mem_db.update(("users", &user_id)).content(user.clone()).await;
@@ -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(
+6 -3
View File
@@ -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() {