From a43ef8ec044e5afcacc83ee53796b72ad5eeb083 Mon Sep 17 00:00:00 2001 From: Maulana Sodiqin Date: Sat, 17 May 2025 02:08:59 +0700 Subject: [PATCH] chore: normalize code --- Cargo.lock | 46 +-- Cargo.toml | 22 +- .../Cargo.toml | 4 +- .../src/bin/api.rs | 2 +- .../src/bin/seed_permissions.rs | 2 +- .../src/bin/seed_roles.rs | 2 +- .../src/bin/seed_roles_permissions.rs | 28 +- .../src/bin/seed_users.rs | 2 +- .../src/main.rs | 2 +- imphnen-dimentorin-service/src/lib.rs | 14 - .../Cargo.toml | 6 +- .../src/lib.rs | 0 .../src/v1/analytics/.gitkeep | 0 .../src/v1/articles/.gitkeep | 0 .../src/v1/courses/.gitkeep | 0 .../src/v2/.gitkeep | 0 imphnen-entities/Cargo.toml | 4 +- .../Cargo.toml | 6 +- .../src/lib.rs | 0 .../v1/gacha_claim/gacha_claim_controller.rs | 0 .../src/v1/gacha_claim/gacha_claim_dto.rs | 0 .../v1/gacha_claim/gacha_claim_repository.rs | 0 .../src/v1/gacha_claim/gacha_claim_schema.rs | 0 .../src/v1/gacha_claim/gacha_claim_service.rs | 0 .../src/v1/gacha_claim/mod.rs | 0 .../v1/gacha_item/gacha_item_controller.rs | 0 .../src/v1/gacha_item/gacha_item_dto.rs | 0 .../v1/gacha_item/gacha_item_repository.rs | 0 .../src/v1/gacha_item/gacha_item_schema.rs | 0 .../src/v1/gacha_item/gacha_item_service.rs | 0 .../src/v1/gacha_item/mod.rs | 0 .../v1/gacha_roll/gacha_roll_controller.rs | 0 .../src/v1/gacha_roll/gacha_roll_dto.rs | 0 .../v1/gacha_roll/gacha_roll_repository.rs | 0 .../src/v1/gacha_roll/gacha_roll_schema.rs | 0 .../src/v1/gacha_roll/gacha_roll_service.rs | 0 .../src/v1/gacha_roll/mod.rs | 0 .../src/v1/mod.rs | 0 .../src/v2/.gitkeep | 0 imphnen-gateway-service/Cargo.toml | 26 -- .../Cargo.toml | 8 +- .../src/docs.rs | 4 +- .../src/lib.rs | 6 +- imphnen-iam-service/src/v1/roles/roles_dto.rs | 66 ---- .../src/v1/users/users_repository.rs | 317 ------------------ .../src/v1/users/users_schema.rs | 56 ---- .../Cargo.toml | 6 +- .../src/lib.rs | 4 +- .../src/v1/auth/auth_controller.rs | 0 .../src/v1/auth/auth_dto.rs | 0 .../src/v1/auth/auth_repository.rs | 0 .../src/v1/auth/auth_schema.rs | 0 .../src/v1/auth/auth_service.rs | 0 .../src/v1/auth/mod.rs | 0 .../src/v1/mod.rs | 0 .../src/v1/permissions/mod.rs | 0 .../v1/permissions/permissions_controller.rs | 0 .../src/v1/permissions/permissions_dto.rs | 2 +- .../src/v1/permissions/permissions_enum.rs | 0 .../src/v1/permissions/permissions_guard.rs | 0 .../v1/permissions/permissions_repository.rs | 0 .../src/v1/permissions/permissions_schema.rs | 0 .../src/v1/permissions/permissions_service.rs | 0 .../src/v1/roles/mod.rs | 0 .../src/v1/roles/roles_controller.rs | 0 imphnen-iam/src/v1/roles/roles_dto.rs | 40 +++ .../src/v1/roles/roles_enum.rs | 0 .../src/v1/roles/roles_repository.rs | 0 .../src/v1/roles/roles_schema.rs | 0 .../src/v1/roles/roles_service.rs | 0 .../src/v1/users/mod.rs | 0 .../src/v1/users/users_controller.rs | 0 .../src/v1/users/users_dto.rs | 54 ++- imphnen-iam/src/v1/users/users_repository.rs | 296 ++++++++++++++++ imphnen-iam/src/v1/users/users_schema.rs | 66 ++++ .../src/v1/users/users_service.rs | 0 .../src/v2/.gitkeep | 0 imphnen-libs/Cargo.toml | 8 +- .../Cargo.toml | 10 +- .../src/auth_middleware/mod.rs | 2 +- .../src/cors_middleware/mod.rs | 0 .../src/lib.rs | 0 .../src/payment_middleware/.gitkeep | 0 .../src/permissions_middleware/mod.rs | 2 +- imphnen-utils/Cargo.toml | 2 +- imphnen-utils/src/crud.rs | 8 + imphnen-utils/src/lib.rs | 4 + imphnen-utils/src/query_builder.rs | 137 ++++++++ imphnen-utils/src/query_list.rs | 76 ++--- tests/Cargo.toml | 2 +- .../auth/auth_controller_test.rs | 0 .../auth/auth_repository_test.rs | 0 tests/src/{iam_service => iam}/auth/mod.rs | 0 tests/src/{iam_service => iam}/mod.rs | 0 .../{iam_service => iam}/permissions/mod.rs | 0 .../permissions_controller_test.rs | 0 .../permissions_repository_test.rs | 0 tests/src/{iam_service => iam}/roles/mod.rs | 0 .../roles/roles_controller_test.rs | 0 .../roles/roles_repository_test.rs | 0 tests/src/{iam_service => iam}/users/mod.rs | 0 .../users/users_controller_test.rs | 0 .../users/users_repository_test.rs | 0 tests/src/lib.rs | 4 +- 104 files changed, 691 insertions(+), 655 deletions(-) rename {imphnen-core-service => imphnen-backend}/Cargo.toml (84%) rename {imphnen-core-service => imphnen-backend}/src/bin/api.rs (79%) rename {imphnen-core-service => imphnen-backend}/src/bin/seed_permissions.rs (98%) rename {imphnen-core-service => imphnen-backend}/src/bin/seed_roles.rs (96%) rename {imphnen-core-service => imphnen-backend}/src/bin/seed_roles_permissions.rs (55%) rename {imphnen-core-service => imphnen-backend}/src/bin/seed_users.rs (97%) rename {imphnen-core-service => imphnen-backend}/src/main.rs (79%) delete mode 100644 imphnen-dimentorin-service/src/lib.rs rename {imphnen-cms-service => imphnen-dimentorin}/Cargo.toml (90%) rename {imphnen-cms-service => imphnen-dimentorin}/src/lib.rs (100%) rename {imphnen-dimentorin-service => imphnen-dimentorin}/src/v1/analytics/.gitkeep (100%) rename {imphnen-dimentorin-service => imphnen-dimentorin}/src/v1/articles/.gitkeep (100%) rename {imphnen-dimentorin-service => imphnen-dimentorin}/src/v1/courses/.gitkeep (100%) rename {imphnen-dimentorin-service => imphnen-dimentorin}/src/v2/.gitkeep (100%) rename {imphnen-iam-service => imphnen-gacha}/Cargo.toml (90%) rename {imphnen-gacha-service => imphnen-gacha}/src/lib.rs (100%) rename {imphnen-gacha-service => imphnen-gacha}/src/v1/gacha_claim/gacha_claim_controller.rs (100%) rename {imphnen-gacha-service => imphnen-gacha}/src/v1/gacha_claim/gacha_claim_dto.rs (100%) rename {imphnen-gacha-service => imphnen-gacha}/src/v1/gacha_claim/gacha_claim_repository.rs (100%) rename {imphnen-gacha-service => imphnen-gacha}/src/v1/gacha_claim/gacha_claim_schema.rs (100%) rename {imphnen-gacha-service => imphnen-gacha}/src/v1/gacha_claim/gacha_claim_service.rs (100%) rename {imphnen-gacha-service => imphnen-gacha}/src/v1/gacha_claim/mod.rs (100%) rename {imphnen-gacha-service => imphnen-gacha}/src/v1/gacha_item/gacha_item_controller.rs (100%) rename {imphnen-gacha-service => imphnen-gacha}/src/v1/gacha_item/gacha_item_dto.rs (100%) rename {imphnen-gacha-service => imphnen-gacha}/src/v1/gacha_item/gacha_item_repository.rs (100%) rename {imphnen-gacha-service => imphnen-gacha}/src/v1/gacha_item/gacha_item_schema.rs (100%) rename {imphnen-gacha-service => imphnen-gacha}/src/v1/gacha_item/gacha_item_service.rs (100%) rename {imphnen-gacha-service => imphnen-gacha}/src/v1/gacha_item/mod.rs (100%) rename {imphnen-gacha-service => imphnen-gacha}/src/v1/gacha_roll/gacha_roll_controller.rs (100%) rename {imphnen-gacha-service => imphnen-gacha}/src/v1/gacha_roll/gacha_roll_dto.rs (100%) rename {imphnen-gacha-service => imphnen-gacha}/src/v1/gacha_roll/gacha_roll_repository.rs (100%) rename {imphnen-gacha-service => imphnen-gacha}/src/v1/gacha_roll/gacha_roll_schema.rs (100%) rename {imphnen-gacha-service => imphnen-gacha}/src/v1/gacha_roll/gacha_roll_service.rs (100%) rename {imphnen-gacha-service => imphnen-gacha}/src/v1/gacha_roll/mod.rs (100%) rename {imphnen-gacha-service => imphnen-gacha}/src/v1/mod.rs (100%) rename {imphnen-gacha-service => imphnen-gacha}/src/v2/.gitkeep (100%) delete mode 100644 imphnen-gateway-service/Cargo.toml rename {imphnen-dimentorin-service => imphnen-gateway}/Cargo.toml (75%) rename {imphnen-gateway-service => imphnen-gateway}/src/docs.rs (99%) rename {imphnen-gateway-service => imphnen-gateway}/src/lib.rs (84%) delete mode 100644 imphnen-iam-service/src/v1/roles/roles_dto.rs delete mode 100644 imphnen-iam-service/src/v1/users/users_repository.rs delete mode 100644 imphnen-iam-service/src/v1/users/users_schema.rs rename {imphnen-gacha-service => imphnen-iam}/Cargo.toml (90%) rename {imphnen-iam-service => imphnen-iam}/src/lib.rs (88%) rename {imphnen-iam-service => imphnen-iam}/src/v1/auth/auth_controller.rs (100%) rename {imphnen-iam-service => imphnen-iam}/src/v1/auth/auth_dto.rs (100%) rename {imphnen-iam-service => imphnen-iam}/src/v1/auth/auth_repository.rs (100%) rename {imphnen-iam-service => imphnen-iam}/src/v1/auth/auth_schema.rs (100%) rename {imphnen-iam-service => imphnen-iam}/src/v1/auth/auth_service.rs (100%) rename {imphnen-iam-service => imphnen-iam}/src/v1/auth/mod.rs (100%) rename {imphnen-iam-service => imphnen-iam}/src/v1/mod.rs (100%) rename {imphnen-iam-service => imphnen-iam}/src/v1/permissions/mod.rs (100%) rename {imphnen-iam-service => imphnen-iam}/src/v1/permissions/permissions_controller.rs (100%) rename {imphnen-iam-service => imphnen-iam}/src/v1/permissions/permissions_dto.rs (94%) rename {imphnen-iam-service => imphnen-iam}/src/v1/permissions/permissions_enum.rs (100%) rename {imphnen-iam-service => imphnen-iam}/src/v1/permissions/permissions_guard.rs (100%) rename {imphnen-iam-service => imphnen-iam}/src/v1/permissions/permissions_repository.rs (100%) rename {imphnen-iam-service => imphnen-iam}/src/v1/permissions/permissions_schema.rs (100%) rename {imphnen-iam-service => imphnen-iam}/src/v1/permissions/permissions_service.rs (100%) rename {imphnen-iam-service => imphnen-iam}/src/v1/roles/mod.rs (100%) rename {imphnen-iam-service => imphnen-iam}/src/v1/roles/roles_controller.rs (100%) create mode 100644 imphnen-iam/src/v1/roles/roles_dto.rs rename {imphnen-iam-service => imphnen-iam}/src/v1/roles/roles_enum.rs (100%) rename {imphnen-iam-service => imphnen-iam}/src/v1/roles/roles_repository.rs (100%) rename {imphnen-iam-service => imphnen-iam}/src/v1/roles/roles_schema.rs (100%) rename {imphnen-iam-service => imphnen-iam}/src/v1/roles/roles_service.rs (100%) rename {imphnen-iam-service => imphnen-iam}/src/v1/users/mod.rs (100%) rename {imphnen-iam-service => imphnen-iam}/src/v1/users/users_controller.rs (100%) rename {imphnen-iam-service => imphnen-iam}/src/v1/users/users_dto.rs (83%) create mode 100644 imphnen-iam/src/v1/users/users_repository.rs create mode 100644 imphnen-iam/src/v1/users/users_schema.rs rename {imphnen-iam-service => imphnen-iam}/src/v1/users/users_service.rs (100%) rename {imphnen-iam-service => imphnen-iam}/src/v2/.gitkeep (100%) rename {imphnen-middleware-service => imphnen-middleware}/Cargo.toml (81%) rename {imphnen-middleware-service => imphnen-middleware}/src/auth_middleware/mod.rs (94%) rename {imphnen-middleware-service => imphnen-middleware}/src/cors_middleware/mod.rs (100%) rename {imphnen-middleware-service => imphnen-middleware}/src/lib.rs (100%) rename {imphnen-middleware-service => imphnen-middleware}/src/payment_middleware/.gitkeep (100%) rename {imphnen-middleware-service => imphnen-middleware}/src/permissions_middleware/mod.rs (97%) create mode 100644 imphnen-utils/src/crud.rs create mode 100644 imphnen-utils/src/query_builder.rs rename tests/src/{iam_service => iam}/auth/auth_controller_test.rs (100%) rename tests/src/{iam_service => iam}/auth/auth_repository_test.rs (100%) rename tests/src/{iam_service => iam}/auth/mod.rs (100%) rename tests/src/{iam_service => iam}/mod.rs (100%) rename tests/src/{iam_service => iam}/permissions/mod.rs (100%) rename tests/src/{iam_service => iam}/permissions/permissions_controller_test.rs (100%) rename tests/src/{iam_service => iam}/permissions/permissions_repository_test.rs (100%) rename tests/src/{iam_service => iam}/roles/mod.rs (100%) rename tests/src/{iam_service => iam}/roles/roles_controller_test.rs (100%) rename tests/src/{iam_service => iam}/roles/roles_repository_test.rs (100%) rename tests/src/{iam_service => iam}/users/mod.rs (100%) rename tests/src/{iam_service => iam}/users/users_controller_test.rs (100%) rename tests/src/{iam_service => iam}/users/users_repository_test.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 53d06e7..48f9341 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1847,7 +1847,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" [[package]] -name = "imphnen-backend-service" +name = "imphnen-backend" version = "0.1.0" dependencies = [ "anyhow", @@ -1855,7 +1855,7 @@ dependencies = [ "axum-test", "chrono", "imphnen-entities", - "imphnen-gateway-service", + "imphnen-gateway", "imphnen-libs", "imphnen-utils", "lazy_static", @@ -1872,31 +1872,7 @@ dependencies = [ ] [[package]] -name = "imphnen-cms-service" -version = "0.1.0" -dependencies = [ - "anyhow", - "axum", - "axum-test", - "chrono", - "imphnen-entities", - "imphnen-libs", - "imphnen-utils", - "lazy_static", - "rand 0.9.0", - "regex", - "serde", - "serde_json", - "surrealdb", - "tokio", - "tower-http", - "utoipa", - "utoipa-swagger-ui", - "validator", -] - -[[package]] -name = "imphnen-dimentorin-service" +name = "imphnen-dimentorin" version = "0.1.0" dependencies = [ "anyhow", @@ -1931,7 +1907,7 @@ dependencies = [ ] [[package]] -name = "imphnen-gacha-service" +name = "imphnen-gacha" version = "0.1.0" dependencies = [ "anyhow", @@ -1955,7 +1931,7 @@ dependencies = [ ] [[package]] -name = "imphnen-gateway-service" +name = "imphnen-gateway" version = "0.1.0" dependencies = [ "anyhow", @@ -1963,9 +1939,9 @@ dependencies = [ "axum-test", "chrono", "imphnen-entities", - "imphnen-iam-service", + "imphnen-iam", "imphnen-libs", - "imphnen-middleware-service", + "imphnen-middleware", "imphnen-utils", "lazy_static", "rand 0.9.0", @@ -1981,7 +1957,7 @@ dependencies = [ ] [[package]] -name = "imphnen-iam-service" +name = "imphnen-iam" version = "0.1.0" dependencies = [ "anyhow", @@ -2020,7 +1996,7 @@ dependencies = [ ] [[package]] -name = "imphnen-middleware-service" +name = "imphnen-middleware" version = "0.1.0" dependencies = [ "anyhow", @@ -2029,7 +2005,7 @@ dependencies = [ "chrono", "futures", "imphnen-entities", - "imphnen-iam-service", + "imphnen-iam", "imphnen-libs", "imphnen-utils", "lazy_static", @@ -4317,7 +4293,7 @@ dependencies = [ "axum-test", "chrono", "imphnen-entities", - "imphnen-iam-service", + "imphnen-iam", "imphnen-libs", "imphnen-utils", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 012ea8e..58e6c7e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,18 +1,16 @@ [workspace] resolver = "2" members = [ -# "imphnen-*", - "imphnen-utils", - "imphnen-libs", - "imphnen-entities", - "imphnen-cms-service", - "imphnen-iam-service", - "imphnen-gacha-service", - "imphnen-gateway-service", - "imphnen-dimentorin-service", - "imphnen-middleware-service", - "imphnen-core-service", "tests", + "imphnen-iam", + "imphnen-libs", + "imphnen-utils", + "imphnen-gacha", + "imphnen-gateway", + "imphnen-backend", + "imphnen-entities", + "imphnen-dimentorin", + "imphnen-middleware", ] @@ -38,6 +36,8 @@ lazy_static = "1.4.0" regex = "1.11.1" axum-test = "17.2.0" fancy-regex = "0.14.0" +futures = "0.3.31" +tower = "0.5.2" [profile.release] lto = "fat" diff --git a/imphnen-core-service/Cargo.toml b/imphnen-backend/Cargo.toml similarity index 84% rename from imphnen-core-service/Cargo.toml rename to imphnen-backend/Cargo.toml index 7ec3bb8..0409d39 100644 --- a/imphnen-core-service/Cargo.toml +++ b/imphnen-backend/Cargo.toml @@ -1,13 +1,13 @@ [package] -name = "imphnen-backend-service" +name = "imphnen-backend" version = "0.1.0" edition = "2021" [dependencies] imphnen-libs = { version = "0.1.0", path = "../imphnen-libs" } imphnen-utils = { version = "0.1.0", path = "../imphnen-utils" } +imphnen-gateway = { version = "0.1.0", path = "../imphnen-gateway" } imphnen-entities = { version = "0.1.0", path = "../imphnen-entities" } -imphnen-gateway-service = { version = "0.1.0", path = "../imphnen-gateway-service" } axum.workspace = true serde.workspace = true serde_json.workspace = true diff --git a/imphnen-core-service/src/bin/api.rs b/imphnen-backend/src/bin/api.rs similarity index 79% rename from imphnen-core-service/src/bin/api.rs rename to imphnen-backend/src/bin/api.rs index 7d654e2..a261ef9 100644 --- a/imphnen-core-service/src/bin/api.rs +++ b/imphnen-backend/src/bin/api.rs @@ -1,4 +1,4 @@ -use imphnen_gateway_service::gateway_service; +use imphnen_gateway::gateway_service; use imphnen_libs::axum_init; #[tokio::main] diff --git a/imphnen-core-service/src/bin/seed_permissions.rs b/imphnen-backend/src/bin/seed_permissions.rs similarity index 98% rename from imphnen-core-service/src/bin/seed_permissions.rs rename to imphnen-backend/src/bin/seed_permissions.rs index 53e4660..3f878d8 100644 --- a/imphnen-core-service/src/bin/seed_permissions.rs +++ b/imphnen-backend/src/bin/seed_permissions.rs @@ -140,6 +140,6 @@ async fn main() -> Result<(), Box> { .await?; println!("✅ Inserted: {}", name); } - println!("✅ Semua permissions berhasil disimpan ke SurrealDB!"); + println!("✅ All Permissions seeded"); Ok(()) } diff --git a/imphnen-core-service/src/bin/seed_roles.rs b/imphnen-backend/src/bin/seed_roles.rs similarity index 96% rename from imphnen-core-service/src/bin/seed_roles.rs rename to imphnen-backend/src/bin/seed_roles.rs index b01af23..5ca1aec 100644 --- a/imphnen-core-service/src/bin/seed_roles.rs +++ b/imphnen-backend/src/bin/seed_roles.rs @@ -65,6 +65,6 @@ async fn main() -> Result<(), Box> { .await?; println!("✅ Inserted role: {}", name); } - println!("✅ Semua role berhasil disimpan ke SurrealDB!"); + println!("✅ All Roles seeded"); Ok(()) } diff --git a/imphnen-core-service/src/bin/seed_roles_permissions.rs b/imphnen-backend/src/bin/seed_roles_permissions.rs similarity index 55% rename from imphnen-core-service/src/bin/seed_roles_permissions.rs rename to imphnen-backend/src/bin/seed_roles_permissions.rs index 816962d..71466d5 100644 --- a/imphnen-core-service/src/bin/seed_roles_permissions.rs +++ b/imphnen-backend/src/bin/seed_roles_permissions.rs @@ -19,24 +19,24 @@ async fn main() -> Result<(), Box> { let role_permissions = vec![ ( - "50133429-f4b1-4249-9f97-7b86e6ee9d86", // Staf + "50133429-f4b1-4249-9f97-7b86e6ee9d86", vec![ - "7c15e31d-36e2-49f9-97db-138c03fb0cf6", // Read List Users - "319ee593-ff0a-4f29-bbaf-9feb3174a3a6", // Read Detail Users + "7c15e31d-36e2-49f9-97db-138c03fb0cf6", + "319ee593-ff0a-4f29-bbaf-9feb3174a3a6", ], ), ( - "f6b03f25-e416-4893-ac88-caaa690afb07", // Admin + "f6b03f25-e416-4893-ac88-caaa690afb07", vec![ - "023e2dfe-93c3-4008-94a8-b5dff403f73b", // Create Users - "96df0689-2ae9-4894-bf00-837c19415e5c", // Delete Users - "98b3dc4c-0124-461f-afcd-166637c5e6e8", // Update Users - "319ee593-ff0a-4f29-bbaf-9feb3174a3a6", // Read Detail Users - "7c15e31d-36e2-49f9-97db-138c03fb0cf6", // Read List Users - "9164ca6e-c7e3-4238-a15f-f36ab9577e7e", // Read List Roles - "319ee593-ff0a-4f29-bbaf-9feb3174a3a2", // Create Roles - "a00d5608-4c48-4542-845c-dfe004687022", // Update Roles - "35b0d992-65c8-4b62-b030-e6e0320e4048", // Delete Roles + "023e2dfe-93c3-4008-94a8-b5dff403f73b", + "96df0689-2ae9-4894-bf00-837c19415e5c", + "98b3dc4c-0124-461f-afcd-166637c5e6e8", + "319ee593-ff0a-4f29-bbaf-9feb3174a3a6", + "7c15e31d-36e2-49f9-97db-138c03fb0cf6", + "9164ca6e-c7e3-4238-a15f-f36ab9577e7e", + "319ee593-ff0a-4f29-bbaf-9feb3174a3a2", + "a00d5608-4c48-4542-845c-dfe004687022", + "35b0d992-65c8-4b62-b030-e6e0320e4048", ], ), ]; @@ -53,7 +53,7 @@ async fn main() -> Result<(), Box> { .await?; println!("✅ Updated permissions for role ID: {}", role_id); } - println!("✅ Semua roles telah diperbarui dengan permissions di SurrealDB!"); + println!("✅ All Roles permissions seeded"); Ok(()) } diff --git a/imphnen-core-service/src/bin/seed_users.rs b/imphnen-backend/src/bin/seed_users.rs similarity index 97% rename from imphnen-core-service/src/bin/seed_users.rs rename to imphnen-backend/src/bin/seed_users.rs index 7318d79..01426bc 100644 --- a/imphnen-core-service/src/bin/seed_users.rs +++ b/imphnen-backend/src/bin/seed_users.rs @@ -90,6 +90,6 @@ async fn main() -> Result<(), Box> { println!("✅ Inserted user: {} ({})", fullname, email); } - println!("✅ Semua users berhasil disimpan ke SurrealDB!"); + println!("✅ All Users seeded"); Ok(()) } diff --git a/imphnen-core-service/src/main.rs b/imphnen-backend/src/main.rs similarity index 79% rename from imphnen-core-service/src/main.rs rename to imphnen-backend/src/main.rs index 7d654e2..a261ef9 100644 --- a/imphnen-core-service/src/main.rs +++ b/imphnen-backend/src/main.rs @@ -1,4 +1,4 @@ -use imphnen_gateway_service::gateway_service; +use imphnen_gateway::gateway_service; use imphnen_libs::axum_init; #[tokio::main] diff --git a/imphnen-dimentorin-service/src/lib.rs b/imphnen-dimentorin-service/src/lib.rs deleted file mode 100644 index 1303f3d..0000000 --- a/imphnen-dimentorin-service/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -pub fn add(left: u64, right: u64) -> u64 { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} diff --git a/imphnen-cms-service/Cargo.toml b/imphnen-dimentorin/Cargo.toml similarity index 90% rename from imphnen-cms-service/Cargo.toml rename to imphnen-dimentorin/Cargo.toml index c2d0734..6b4bce3 100644 --- a/imphnen-cms-service/Cargo.toml +++ b/imphnen-dimentorin/Cargo.toml @@ -1,12 +1,12 @@ [package] -name = "imphnen-cms-service" +name = "imphnen-dimentorin" version = "0.1.0" edition = "2024" [dependencies] -imphnen-entities = { version = "0.1.0", path = "../imphnen-entities" } imphnen-libs = { version = "0.1.0", path = "../imphnen-libs" } imphnen-utils = { version = "0.1.0", path = "../imphnen-utils" } +imphnen-entities = { version = "0.1.0", path = "../imphnen-entities" } axum.workspace = true serde.workspace = true serde_json.workspace = true @@ -21,4 +21,4 @@ tokio.workspace = true chrono.workspace = true anyhow.workspace = true tower-http.workspace = true -utoipa-swagger-ui.workspace = true \ No newline at end of file +utoipa-swagger-ui.workspace = true diff --git a/imphnen-cms-service/src/lib.rs b/imphnen-dimentorin/src/lib.rs similarity index 100% rename from imphnen-cms-service/src/lib.rs rename to imphnen-dimentorin/src/lib.rs diff --git a/imphnen-dimentorin-service/src/v1/analytics/.gitkeep b/imphnen-dimentorin/src/v1/analytics/.gitkeep similarity index 100% rename from imphnen-dimentorin-service/src/v1/analytics/.gitkeep rename to imphnen-dimentorin/src/v1/analytics/.gitkeep diff --git a/imphnen-dimentorin-service/src/v1/articles/.gitkeep b/imphnen-dimentorin/src/v1/articles/.gitkeep similarity index 100% rename from imphnen-dimentorin-service/src/v1/articles/.gitkeep rename to imphnen-dimentorin/src/v1/articles/.gitkeep diff --git a/imphnen-dimentorin-service/src/v1/courses/.gitkeep b/imphnen-dimentorin/src/v1/courses/.gitkeep similarity index 100% rename from imphnen-dimentorin-service/src/v1/courses/.gitkeep rename to imphnen-dimentorin/src/v1/courses/.gitkeep diff --git a/imphnen-dimentorin-service/src/v2/.gitkeep b/imphnen-dimentorin/src/v2/.gitkeep similarity index 100% rename from imphnen-dimentorin-service/src/v2/.gitkeep rename to imphnen-dimentorin/src/v2/.gitkeep diff --git a/imphnen-entities/Cargo.toml b/imphnen-entities/Cargo.toml index bce60d5..6db179b 100644 --- a/imphnen-entities/Cargo.toml +++ b/imphnen-entities/Cargo.toml @@ -6,6 +6,6 @@ edition = "2024" [dependencies] axum.workspace = true serde.workspace = true -surrealdb = { workspace = true, features = ["kv-mem"] } -thiserror.workspace = true utoipa.workspace = true +surrealdb.workspace = true +thiserror.workspace = true diff --git a/imphnen-iam-service/Cargo.toml b/imphnen-gacha/Cargo.toml similarity index 90% rename from imphnen-iam-service/Cargo.toml rename to imphnen-gacha/Cargo.toml index 4edeaac..a4ea4e9 100644 --- a/imphnen-iam-service/Cargo.toml +++ b/imphnen-gacha/Cargo.toml @@ -1,12 +1,12 @@ [package] -name = "imphnen-iam-service" +name = "imphnen-gacha" version = "0.1.0" edition = "2024" [dependencies] -imphnen-entities = { version = "0.1.0", path = "../imphnen-entities" } imphnen-libs = { version = "0.1.0", path = "../imphnen-libs" } imphnen-utils = { version = "0.1.0", path = "../imphnen-utils" } +imphnen-entities = { version = "0.1.0", path = "../imphnen-entities" } axum.workspace = true serde.workspace = true serde_json.workspace = true @@ -21,4 +21,4 @@ tokio.workspace = true chrono.workspace = true anyhow.workspace = true tower-http.workspace = true -utoipa-swagger-ui.workspace = true \ No newline at end of file +utoipa-swagger-ui.workspace = true diff --git a/imphnen-gacha-service/src/lib.rs b/imphnen-gacha/src/lib.rs similarity index 100% rename from imphnen-gacha-service/src/lib.rs rename to imphnen-gacha/src/lib.rs diff --git a/imphnen-gacha-service/src/v1/gacha_claim/gacha_claim_controller.rs b/imphnen-gacha/src/v1/gacha_claim/gacha_claim_controller.rs similarity index 100% rename from imphnen-gacha-service/src/v1/gacha_claim/gacha_claim_controller.rs rename to imphnen-gacha/src/v1/gacha_claim/gacha_claim_controller.rs diff --git a/imphnen-gacha-service/src/v1/gacha_claim/gacha_claim_dto.rs b/imphnen-gacha/src/v1/gacha_claim/gacha_claim_dto.rs similarity index 100% rename from imphnen-gacha-service/src/v1/gacha_claim/gacha_claim_dto.rs rename to imphnen-gacha/src/v1/gacha_claim/gacha_claim_dto.rs diff --git a/imphnen-gacha-service/src/v1/gacha_claim/gacha_claim_repository.rs b/imphnen-gacha/src/v1/gacha_claim/gacha_claim_repository.rs similarity index 100% rename from imphnen-gacha-service/src/v1/gacha_claim/gacha_claim_repository.rs rename to imphnen-gacha/src/v1/gacha_claim/gacha_claim_repository.rs diff --git a/imphnen-gacha-service/src/v1/gacha_claim/gacha_claim_schema.rs b/imphnen-gacha/src/v1/gacha_claim/gacha_claim_schema.rs similarity index 100% rename from imphnen-gacha-service/src/v1/gacha_claim/gacha_claim_schema.rs rename to imphnen-gacha/src/v1/gacha_claim/gacha_claim_schema.rs diff --git a/imphnen-gacha-service/src/v1/gacha_claim/gacha_claim_service.rs b/imphnen-gacha/src/v1/gacha_claim/gacha_claim_service.rs similarity index 100% rename from imphnen-gacha-service/src/v1/gacha_claim/gacha_claim_service.rs rename to imphnen-gacha/src/v1/gacha_claim/gacha_claim_service.rs diff --git a/imphnen-gacha-service/src/v1/gacha_claim/mod.rs b/imphnen-gacha/src/v1/gacha_claim/mod.rs similarity index 100% rename from imphnen-gacha-service/src/v1/gacha_claim/mod.rs rename to imphnen-gacha/src/v1/gacha_claim/mod.rs diff --git a/imphnen-gacha-service/src/v1/gacha_item/gacha_item_controller.rs b/imphnen-gacha/src/v1/gacha_item/gacha_item_controller.rs similarity index 100% rename from imphnen-gacha-service/src/v1/gacha_item/gacha_item_controller.rs rename to imphnen-gacha/src/v1/gacha_item/gacha_item_controller.rs diff --git a/imphnen-gacha-service/src/v1/gacha_item/gacha_item_dto.rs b/imphnen-gacha/src/v1/gacha_item/gacha_item_dto.rs similarity index 100% rename from imphnen-gacha-service/src/v1/gacha_item/gacha_item_dto.rs rename to imphnen-gacha/src/v1/gacha_item/gacha_item_dto.rs diff --git a/imphnen-gacha-service/src/v1/gacha_item/gacha_item_repository.rs b/imphnen-gacha/src/v1/gacha_item/gacha_item_repository.rs similarity index 100% rename from imphnen-gacha-service/src/v1/gacha_item/gacha_item_repository.rs rename to imphnen-gacha/src/v1/gacha_item/gacha_item_repository.rs diff --git a/imphnen-gacha-service/src/v1/gacha_item/gacha_item_schema.rs b/imphnen-gacha/src/v1/gacha_item/gacha_item_schema.rs similarity index 100% rename from imphnen-gacha-service/src/v1/gacha_item/gacha_item_schema.rs rename to imphnen-gacha/src/v1/gacha_item/gacha_item_schema.rs diff --git a/imphnen-gacha-service/src/v1/gacha_item/gacha_item_service.rs b/imphnen-gacha/src/v1/gacha_item/gacha_item_service.rs similarity index 100% rename from imphnen-gacha-service/src/v1/gacha_item/gacha_item_service.rs rename to imphnen-gacha/src/v1/gacha_item/gacha_item_service.rs diff --git a/imphnen-gacha-service/src/v1/gacha_item/mod.rs b/imphnen-gacha/src/v1/gacha_item/mod.rs similarity index 100% rename from imphnen-gacha-service/src/v1/gacha_item/mod.rs rename to imphnen-gacha/src/v1/gacha_item/mod.rs diff --git a/imphnen-gacha-service/src/v1/gacha_roll/gacha_roll_controller.rs b/imphnen-gacha/src/v1/gacha_roll/gacha_roll_controller.rs similarity index 100% rename from imphnen-gacha-service/src/v1/gacha_roll/gacha_roll_controller.rs rename to imphnen-gacha/src/v1/gacha_roll/gacha_roll_controller.rs diff --git a/imphnen-gacha-service/src/v1/gacha_roll/gacha_roll_dto.rs b/imphnen-gacha/src/v1/gacha_roll/gacha_roll_dto.rs similarity index 100% rename from imphnen-gacha-service/src/v1/gacha_roll/gacha_roll_dto.rs rename to imphnen-gacha/src/v1/gacha_roll/gacha_roll_dto.rs diff --git a/imphnen-gacha-service/src/v1/gacha_roll/gacha_roll_repository.rs b/imphnen-gacha/src/v1/gacha_roll/gacha_roll_repository.rs similarity index 100% rename from imphnen-gacha-service/src/v1/gacha_roll/gacha_roll_repository.rs rename to imphnen-gacha/src/v1/gacha_roll/gacha_roll_repository.rs diff --git a/imphnen-gacha-service/src/v1/gacha_roll/gacha_roll_schema.rs b/imphnen-gacha/src/v1/gacha_roll/gacha_roll_schema.rs similarity index 100% rename from imphnen-gacha-service/src/v1/gacha_roll/gacha_roll_schema.rs rename to imphnen-gacha/src/v1/gacha_roll/gacha_roll_schema.rs diff --git a/imphnen-gacha-service/src/v1/gacha_roll/gacha_roll_service.rs b/imphnen-gacha/src/v1/gacha_roll/gacha_roll_service.rs similarity index 100% rename from imphnen-gacha-service/src/v1/gacha_roll/gacha_roll_service.rs rename to imphnen-gacha/src/v1/gacha_roll/gacha_roll_service.rs diff --git a/imphnen-gacha-service/src/v1/gacha_roll/mod.rs b/imphnen-gacha/src/v1/gacha_roll/mod.rs similarity index 100% rename from imphnen-gacha-service/src/v1/gacha_roll/mod.rs rename to imphnen-gacha/src/v1/gacha_roll/mod.rs diff --git a/imphnen-gacha-service/src/v1/mod.rs b/imphnen-gacha/src/v1/mod.rs similarity index 100% rename from imphnen-gacha-service/src/v1/mod.rs rename to imphnen-gacha/src/v1/mod.rs diff --git a/imphnen-gacha-service/src/v2/.gitkeep b/imphnen-gacha/src/v2/.gitkeep similarity index 100% rename from imphnen-gacha-service/src/v2/.gitkeep rename to imphnen-gacha/src/v2/.gitkeep diff --git a/imphnen-gateway-service/Cargo.toml b/imphnen-gateway-service/Cargo.toml deleted file mode 100644 index 512f618..0000000 --- a/imphnen-gateway-service/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "imphnen-gateway-service" -version = "0.1.0" -edition = "2024" - -[dependencies] -imphnen-iam-service = { version = "0.1.0", path = "../imphnen-iam-service" } -imphnen-middleware-service = { version = "0.1.0", path = "../imphnen-middleware-service" } -imphnen-entities = { version = "0.1.0", path = "../imphnen-entities" } -imphnen-libs = { version = "0.1.0", path = "../imphnen-libs" } -imphnen-utils = { version = "0.1.0", path = "../imphnen-utils" } -axum.workspace = true -serde.workspace = true -serde_json.workspace = true -utoipa.workspace = true -lazy_static.workspace = true -regex.workspace = true -validator.workspace = true -axum-test.workspace = true -surrealdb.workspace = true -rand.workspace = true -tokio.workspace = true -chrono.workspace = true -anyhow.workspace = true -tower-http.workspace = true -utoipa-swagger-ui.workspace = true \ No newline at end of file diff --git a/imphnen-dimentorin-service/Cargo.toml b/imphnen-gateway/Cargo.toml similarity index 75% rename from imphnen-dimentorin-service/Cargo.toml rename to imphnen-gateway/Cargo.toml index 5c87db5..ae0602c 100644 --- a/imphnen-dimentorin-service/Cargo.toml +++ b/imphnen-gateway/Cargo.toml @@ -1,12 +1,14 @@ [package] -name = "imphnen-dimentorin-service" +name = "imphnen-gateway" version = "0.1.0" edition = "2024" [dependencies] -imphnen-entities = { version = "0.1.0", path = "../imphnen-entities" } +imphnen-iam = { version = "0.1.0", path = "../imphnen-iam" } imphnen-libs = { version = "0.1.0", path = "../imphnen-libs" } imphnen-utils = { version = "0.1.0", path = "../imphnen-utils" } +imphnen-entities = { version = "0.1.0", path = "../imphnen-entities" } +imphnen-middleware = { version = "0.1.0", path = "../imphnen-middleware" } axum.workspace = true serde.workspace = true serde_json.workspace = true @@ -21,4 +23,4 @@ tokio.workspace = true chrono.workspace = true anyhow.workspace = true tower-http.workspace = true -utoipa-swagger-ui.workspace = true \ No newline at end of file +utoipa-swagger-ui.workspace = true diff --git a/imphnen-gateway-service/src/docs.rs b/imphnen-gateway/src/docs.rs similarity index 99% rename from imphnen-gateway-service/src/docs.rs rename to imphnen-gateway/src/docs.rs index 341601e..9f9ab3f 100644 --- a/imphnen-gateway-service/src/docs.rs +++ b/imphnen-gateway/src/docs.rs @@ -1,4 +1,4 @@ -use imphnen_iam_service::{ +use imphnen_iam::{ auth, permissions, roles, users, AuthLoginRequestDto, AuthLoginResponsetDto, AuthResendOtpRequestDto, AuthVerifyEmailRequestDto, AuthNewPasswordRequestDto, AuthRefreshTokenRequestDto, MessageResponseDto, MetaRequestDto, MetaResponseDto, PermissionsItemDto, PermissionsRequestDto, ResponseListSuccessDto, ResponseSuccessDto, RolesItemDto, RolesRequestCreateDto, RolesRequestUpdateDto, TokenDto, UsersCreateRequestDto, UsersDetailItemDto, UsersItemDto, UsersListItemDto, UsersUpdateRequestDto }; @@ -102,4 +102,4 @@ impl Modify for SecurityAddon { pub fn docs_router() -> utoipa::openapi::OpenApi { ApiDoc::openapi() -} \ No newline at end of file +} diff --git a/imphnen-gateway-service/src/lib.rs b/imphnen-gateway/src/lib.rs similarity index 84% rename from imphnen-gateway-service/src/lib.rs rename to imphnen-gateway/src/lib.rs index f08ddbb..98d3f74 100644 --- a/imphnen-gateway-service/src/lib.rs +++ b/imphnen-gateway/src/lib.rs @@ -2,12 +2,12 @@ use axum::{ Extension, Router, middleware::from_fn, response::Redirect, routing::get, }; use imphnen_entities::{AppState, SurrealMemClient, SurrealWsClient}; -use imphnen_iam_service::{iam_protected_routes, iam_public_routes}; +use imphnen_iam::{iam_protected_routes, iam_public_routes}; +use imphnen_middleware::{auth_middleware, cors_middleware}; +use utoipa_swagger_ui::SwaggerUi; pub mod docs; pub use docs::*; -use imphnen_middleware_service::{auth_middleware, cors_middleware}; -use utoipa_swagger_ui::SwaggerUi; pub async fn gateway_service( surrealdb_ws: SurrealWsClient, diff --git a/imphnen-iam-service/src/v1/roles/roles_dto.rs b/imphnen-iam-service/src/v1/roles/roles_dto.rs deleted file mode 100644 index b53af14..0000000 --- a/imphnen-iam-service/src/v1/roles/roles_dto.rs +++ /dev/null @@ -1,66 +0,0 @@ -use crate::{PermissionsItemDto, PermissionsItemDtoRaw}; -use serde::{Deserialize, Serialize}; -use surrealdb::sql::Thing; -use utoipa::ToSchema; -use validator::Validate; - -#[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)] -pub struct RolesRequestUpdateDto { - #[validate(length(min = 1, message = "Role name must not be empty"))] - pub name: Option, - pub permissions: Option>, -} - -#[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)] -pub struct RolesRequestCreateDto { - #[validate(length(min = 1, message = "Role name must not be empty"))] - pub name: String, - pub permissions: Vec, -} - -#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] -pub struct RolesItemListDto { - pub id: String, - pub name: String, - pub created_at: Option, - pub updated_at: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] -pub struct RolesItemDto { - pub id: String, - pub name: String, - pub permissions: Vec, - pub created_at: Option, - pub updated_at: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] -pub struct RolesItemByIdDto { - pub id: String, - pub name: String, - pub is_deleted: bool, - pub permissions: Vec, - pub created_at: Option, - pub updated_at: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct RolesItemByIdDtoRaw { - pub id: Thing, - pub name: String, - pub permissions: Vec, - pub is_deleted: bool, - pub created_at: Option, - pub updated_at: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct RolesItemDtoRaw { - pub id: Thing, - pub name: String, - pub permissions: Vec, - pub is_deleted: bool, - pub created_at: Option, - pub updated_at: Option, -} diff --git a/imphnen-iam-service/src/v1/users/users_repository.rs b/imphnen-iam-service/src/v1/users/users_repository.rs deleted file mode 100644 index 18d6705..0000000 --- a/imphnen-iam-service/src/v1/users/users_repository.rs +++ /dev/null @@ -1,317 +0,0 @@ -use super::{ - UsersActiveInactiveSchema, UsersItemDto, UsersItemDtoRaw, UsersListItemDto, - UsersListItemDtoRaw, UsersSchema, UsersSetNewPasswordSchema, -}; -use crate::{ - extract_id, get_id, make_thing, query_list_with_meta, AppState, MetaRequestDto, - PermissionsItemDto, PermissionsItemDtoRaw, ResourceEnum, ResponseListSuccessDto, - RolesItemDto, RolesItemDtoRaw, -}; -use anyhow::{anyhow, bail, Result}; - -pub struct UsersRepository<'a> { - state: &'a AppState, -} - -impl<'a> UsersRepository<'a> { - pub fn new(state: &'a AppState) -> Self { - Self { state } - } - - pub async fn query_user_list( - &self, - meta: MetaRequestDto, - ) -> Result>> { - let db = &self.state.surrealdb_ws; - let mut conditions = vec!["is_deleted = false".to_string()]; - if let Some(search) = meta.search.as_deref() { - if !search.is_empty() { - conditions.push("string::contains(fullname ?? '', $search)".to_string()); - } - } - if let (Some(filter_by), Some(_filter)) = - (meta.filter_by.as_ref(), meta.filter.as_ref()) - { - conditions.push(format!("{} = $filter", filter_by)); - } - let where_clause = if !conditions.is_empty() { - format!("WHERE {}", conditions.join(" AND ")) - } else { - String::new() - }; - let limit = meta.per_page.unwrap_or(10); - let page = meta.page.unwrap_or(1); - if page < 1 || limit < 1 { - return Err(anyhow!("Invalid pagination parameters")); - } - let start = (page - 1) * limit; - let select_query = format!( - " - SELECT - id, - role.name AS role, - fullname, - email, - avatar, - phone_number, - is_active, - gender, - birthdate, - created_at, - updated_at - FROM {} - {} - LIMIT {} START {} - FETCH role - ", - ResourceEnum::Users.to_string(), - where_clause, - limit, - start - ); - let raw_result = query_list_with_meta::( - db, - &ResourceEnum::Users.to_string(), - &meta, - vec![], - Some(select_query), - ) - .await?; - let transformed_data = raw_result - .data - .into_iter() - .map(|user| UsersListItemDto { - id: extract_id(&user.id), - fullname: user.fullname, - email: user.email, - avatar: user.avatar, - phone_number: user.phone_number, - is_active: user.is_active, - role: user.role.unwrap_or_else(|| "-".into()), - created_at: user.created_at, - updated_at: user.updated_at, - }) - .collect::>(); - Ok(ResponseListSuccessDto { - data: transformed_data, - meta: raw_result.meta, - }) - } - - pub async fn query_user_by_email(&self, email: String) -> Result { - let db = &self.state.surrealdb_ws; - let sql = format!( - "SELECT *, role AS role FROM {} WHERE email = $email AND is_deleted = false LIMIT 1 FETCH role, role.permissions", - ResourceEnum::Users.to_string() - ); - - let response: Option = db - .query(sql) - .bind(("email", email.clone())) - .await? - .take(0)?; - - match response { - Some(user) if !user.role.is_deleted => { - let permissions = user - .role - .permissions - .into_iter() - .map(|perm| PermissionsItemDtoRaw { - id: perm.id, - name: perm.name, - created_at: perm.created_at, - updated_at: perm.updated_at, - }) - .collect::>(); - Ok(UsersItemDtoRaw { - id: user.id, - fullname: user.fullname, - email: user.email, - avatar: user.avatar, - phone_number: user.phone_number, - is_active: user.is_active, - is_deleted: user.is_deleted, - gender: user.gender, - birthdate: user.birthdate, - password: user.password, - created_at: user.created_at, - updated_at: user.updated_at, - role: RolesItemDtoRaw { - id: user.role.id, - name: user.role.name, - permissions, - created_at: user.role.created_at, - updated_at: user.role.updated_at, - is_deleted: user.role.is_deleted, - }, - }) - } - _ => bail!("User not found"), - } - } - - pub async fn query_user_by_id(&self, id: String) -> Result { - let db = &self.state.surrealdb_ws; - - let query = format!( - "SELECT *, role AS role FROM app_users:⟨{}⟩ FETCH role, role.permissions", - id - ); - - let mut result = db.query(query).await?; - - let response: Option = result.take(0)?; - - match response { - Some(user) if !user.role.is_deleted => { - let permissions = user - .role - .permissions - .into_iter() - .map(|perm| PermissionsItemDto { - id: extract_id(&perm.id), - name: perm.name, - created_at: perm.created_at, - updated_at: perm.updated_at, - }) - .collect::>(); - - Ok(UsersItemDto { - id: extract_id(&user.id), - fullname: user.fullname, - email: user.email, - avatar: user.avatar, - phone_number: user.phone_number, - is_active: user.is_active, - is_deleted: user.is_deleted, - gender: user.gender, - birthdate: user.birthdate, - password: user.password, - role: RolesItemDto { - id: extract_id(&user.role.id), - name: user.role.name, - permissions, - created_at: user.role.created_at, - updated_at: user.role.updated_at, - }, - created_at: user.created_at, - updated_at: user.updated_at, - }) - } - _ => bail!("User not found"), - } - } - - pub async fn query_create_user(&self, data: UsersSchema) -> Result { - let db = &self.state.surrealdb_ws; - let record: Option = db - .create(ResourceEnum::Users.to_string()) - .content(data) - .await?; - match record { - Some(_) => Ok("Success create user".into()), - None => bail!("Failed to create user"), - } - } - - pub async fn query_update_user(&self, data: UsersSchema) -> Result { - let db = &self.state.surrealdb_ws; - let record_key = get_id(&data.id)?; - let existing = self.query_user_by_id(data.id.id.to_raw()).await?; - if existing.is_deleted { - bail!("User already deleted"); - } - let merged = UsersSchema { - password: existing.password, - created_at: existing.created_at, - role: make_thing("app_roles", &existing.role.id), - ..data.clone() - }; - let record: Option = db.update(record_key).merge(merged).await?; - match record { - Some(_) => Ok("Success update user".into()), - None => bail!("Failed to update user"), - } - } - - pub async fn query_active_inactive_user( - &self, - email: String, - data: UsersActiveInactiveSchema, - ) -> Result { - let db = &self.state.surrealdb_ws; - let user = self.query_user_by_email(email.clone()).await?; - if user.is_deleted { - bail!("User already deleted"); - } - let record_key = get_id(&user.id)?; - let record: Option = db - .update(record_key) - .merge(UsersActiveInactiveSchema { - is_active: data.is_active, - }) - .await?; - match record { - Some(_) => Ok("Success update user".into()), - None => bail!("Failed to update user"), - } - } - - pub async fn query_active_inactive_user_by_id( - &self, - id: String, - data: UsersActiveInactiveSchema, - ) -> Result { - let db = &self.state.surrealdb_ws; - let record: Option = db - .update((ResourceEnum::Users.to_string(), id)) - .merge(UsersActiveInactiveSchema { - is_active: data.is_active, - }) - .await?; - match record { - Some(_) => Ok("Success update user".into()), - None => bail!("Failed to update user"), - } - } - - pub async fn query_update_password_user( - &self, - email: String, - data: UsersSetNewPasswordSchema, - ) -> Result { - let db = &self.state.surrealdb_ws; - let user = self.query_user_by_email(email).await?; - let record: Option = db - .update((ResourceEnum::Users.to_string(), user.id.id.to_raw())) - .merge(UsersSetNewPasswordSchema { - password: data.password.clone(), - }) - .await?; - dbg!(record.clone()); - match record { - Some(_) => Ok("Success update password user".into()), - None => bail!("Failed to update password user"), - } - } - - pub async fn query_delete_user(&self, id: String) -> Result { - let db = &self.state.surrealdb_ws; - let user_id = make_thing(&ResourceEnum::Users.to_string(), &id); - let user = self.query_user_by_id(user_id.id.to_raw()).await?; - if user.is_deleted { - bail!("User already deleted"); - } - let id = make_thing(&ResourceEnum::Users.to_string(), &user.id); - let record_key = get_id(&id)?; - let record: Option = db - .update(record_key) - .merge(serde_json::json!({ "is_deleted": true })) - .await?; - match record { - Some(_) => Ok("Success delete user".into()), - None => bail!("Failed to delete user"), - } - } -} diff --git a/imphnen-iam-service/src/v1/users/users_schema.rs b/imphnen-iam-service/src/v1/users/users_schema.rs deleted file mode 100644 index bca7755..0000000 --- a/imphnen-iam-service/src/v1/users/users_schema.rs +++ /dev/null @@ -1,56 +0,0 @@ -use crate::{get_iso_date, make_thing, ResourceEnum}; -use serde::{Deserialize, Serialize}; -use surrealdb::{sql::Thing, Uuid}; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct UsersSchema { - pub id: Thing, - pub fullname: String, - pub email: String, - pub password: String, - pub avatar: Option, - pub phone_number: String, - pub is_active: bool, - pub is_deleted: bool, - pub gender: Option, - pub birthdate: Option, - pub role: Thing, - pub created_at: String, - pub updated_at: String, -} - -impl Default for UsersSchema { - fn default() -> Self { - UsersSchema { - id: make_thing( - &ResourceEnum::Users.to_string(), - &Uuid::new_v4().to_string(), - ), - fullname: String::new(), - email: String::new(), - password: String::new(), - avatar: None, - phone_number: String::new(), - is_active: false, - is_deleted: false, - gender: None, - birthdate: None, - role: make_thing( - &ResourceEnum::Roles.to_string(), - &Uuid::new_v4().to_string(), - ), - created_at: get_iso_date(), - updated_at: get_iso_date(), - } - } -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct UsersSetNewPasswordSchema { - pub password: String, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct UsersActiveInactiveSchema { - pub is_active: bool, -} diff --git a/imphnen-gacha-service/Cargo.toml b/imphnen-iam/Cargo.toml similarity index 90% rename from imphnen-gacha-service/Cargo.toml rename to imphnen-iam/Cargo.toml index 1122fba..6266523 100644 --- a/imphnen-gacha-service/Cargo.toml +++ b/imphnen-iam/Cargo.toml @@ -1,12 +1,12 @@ [package] -name = "imphnen-gacha-service" +name = "imphnen-iam" version = "0.1.0" edition = "2024" [dependencies] -imphnen-entities = { version = "0.1.0", path = "../imphnen-entities" } imphnen-libs = { version = "0.1.0", path = "../imphnen-libs" } imphnen-utils = { version = "0.1.0", path = "../imphnen-utils" } +imphnen-entities = { version = "0.1.0", path = "../imphnen-entities" } axum.workspace = true serde.workspace = true serde_json.workspace = true @@ -21,4 +21,4 @@ tokio.workspace = true chrono.workspace = true anyhow.workspace = true tower-http.workspace = true -utoipa-swagger-ui.workspace = true \ No newline at end of file +utoipa-swagger-ui.workspace = true diff --git a/imphnen-iam-service/src/lib.rs b/imphnen-iam/src/lib.rs similarity index 88% rename from imphnen-iam-service/src/lib.rs rename to imphnen-iam/src/lib.rs index 3e5bec5..3249e5f 100644 --- a/imphnen-iam-service/src/lib.rs +++ b/imphnen-iam/src/lib.rs @@ -7,6 +7,7 @@ pub mod v1; pub use imphnen_entities::*; pub use imphnen_libs::*; +pub use imphnen_utils::*; pub use v1::*; pub fn create_test_user( @@ -27,6 +28,7 @@ pub fn create_test_user( gender: None, birthdate: None, role: make_thing("app_roles", role_id), - ..Default::default() + created_at: get_iso_date(), + updated_at: get_iso_date(), } } diff --git a/imphnen-iam-service/src/v1/auth/auth_controller.rs b/imphnen-iam/src/v1/auth/auth_controller.rs similarity index 100% rename from imphnen-iam-service/src/v1/auth/auth_controller.rs rename to imphnen-iam/src/v1/auth/auth_controller.rs diff --git a/imphnen-iam-service/src/v1/auth/auth_dto.rs b/imphnen-iam/src/v1/auth/auth_dto.rs similarity index 100% rename from imphnen-iam-service/src/v1/auth/auth_dto.rs rename to imphnen-iam/src/v1/auth/auth_dto.rs diff --git a/imphnen-iam-service/src/v1/auth/auth_repository.rs b/imphnen-iam/src/v1/auth/auth_repository.rs similarity index 100% rename from imphnen-iam-service/src/v1/auth/auth_repository.rs rename to imphnen-iam/src/v1/auth/auth_repository.rs diff --git a/imphnen-iam-service/src/v1/auth/auth_schema.rs b/imphnen-iam/src/v1/auth/auth_schema.rs similarity index 100% rename from imphnen-iam-service/src/v1/auth/auth_schema.rs rename to imphnen-iam/src/v1/auth/auth_schema.rs diff --git a/imphnen-iam-service/src/v1/auth/auth_service.rs b/imphnen-iam/src/v1/auth/auth_service.rs similarity index 100% rename from imphnen-iam-service/src/v1/auth/auth_service.rs rename to imphnen-iam/src/v1/auth/auth_service.rs diff --git a/imphnen-iam-service/src/v1/auth/mod.rs b/imphnen-iam/src/v1/auth/mod.rs similarity index 100% rename from imphnen-iam-service/src/v1/auth/mod.rs rename to imphnen-iam/src/v1/auth/mod.rs diff --git a/imphnen-iam-service/src/v1/mod.rs b/imphnen-iam/src/v1/mod.rs similarity index 100% rename from imphnen-iam-service/src/v1/mod.rs rename to imphnen-iam/src/v1/mod.rs diff --git a/imphnen-iam-service/src/v1/permissions/mod.rs b/imphnen-iam/src/v1/permissions/mod.rs similarity index 100% rename from imphnen-iam-service/src/v1/permissions/mod.rs rename to imphnen-iam/src/v1/permissions/mod.rs diff --git a/imphnen-iam-service/src/v1/permissions/permissions_controller.rs b/imphnen-iam/src/v1/permissions/permissions_controller.rs similarity index 100% rename from imphnen-iam-service/src/v1/permissions/permissions_controller.rs rename to imphnen-iam/src/v1/permissions/permissions_controller.rs diff --git a/imphnen-iam-service/src/v1/permissions/permissions_dto.rs b/imphnen-iam/src/v1/permissions/permissions_dto.rs similarity index 94% rename from imphnen-iam-service/src/v1/permissions/permissions_dto.rs rename to imphnen-iam/src/v1/permissions/permissions_dto.rs index f0e7df6..c589e21 100644 --- a/imphnen-iam-service/src/v1/permissions/permissions_dto.rs +++ b/imphnen-iam/src/v1/permissions/permissions_dto.rs @@ -18,7 +18,7 @@ pub struct PermissionsItemDto { } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PermissionsItemDtoRaw { +pub struct PermissionsQueryDto { pub id: Thing, pub name: String, pub created_at: Option, diff --git a/imphnen-iam-service/src/v1/permissions/permissions_enum.rs b/imphnen-iam/src/v1/permissions/permissions_enum.rs similarity index 100% rename from imphnen-iam-service/src/v1/permissions/permissions_enum.rs rename to imphnen-iam/src/v1/permissions/permissions_enum.rs diff --git a/imphnen-iam-service/src/v1/permissions/permissions_guard.rs b/imphnen-iam/src/v1/permissions/permissions_guard.rs similarity index 100% rename from imphnen-iam-service/src/v1/permissions/permissions_guard.rs rename to imphnen-iam/src/v1/permissions/permissions_guard.rs diff --git a/imphnen-iam-service/src/v1/permissions/permissions_repository.rs b/imphnen-iam/src/v1/permissions/permissions_repository.rs similarity index 100% rename from imphnen-iam-service/src/v1/permissions/permissions_repository.rs rename to imphnen-iam/src/v1/permissions/permissions_repository.rs diff --git a/imphnen-iam-service/src/v1/permissions/permissions_schema.rs b/imphnen-iam/src/v1/permissions/permissions_schema.rs similarity index 100% rename from imphnen-iam-service/src/v1/permissions/permissions_schema.rs rename to imphnen-iam/src/v1/permissions/permissions_schema.rs diff --git a/imphnen-iam-service/src/v1/permissions/permissions_service.rs b/imphnen-iam/src/v1/permissions/permissions_service.rs similarity index 100% rename from imphnen-iam-service/src/v1/permissions/permissions_service.rs rename to imphnen-iam/src/v1/permissions/permissions_service.rs diff --git a/imphnen-iam-service/src/v1/roles/mod.rs b/imphnen-iam/src/v1/roles/mod.rs similarity index 100% rename from imphnen-iam-service/src/v1/roles/mod.rs rename to imphnen-iam/src/v1/roles/mod.rs diff --git a/imphnen-iam-service/src/v1/roles/roles_controller.rs b/imphnen-iam/src/v1/roles/roles_controller.rs similarity index 100% rename from imphnen-iam-service/src/v1/roles/roles_controller.rs rename to imphnen-iam/src/v1/roles/roles_controller.rs diff --git a/imphnen-iam/src/v1/roles/roles_dto.rs b/imphnen-iam/src/v1/roles/roles_dto.rs new file mode 100644 index 0000000..28dc98a --- /dev/null +++ b/imphnen-iam/src/v1/roles/roles_dto.rs @@ -0,0 +1,40 @@ +use crate::{PermissionsItemDto, PermissionsQueryDto}; +use serde::{Deserialize, Serialize}; +use surrealdb::sql::Thing; +use utoipa::ToSchema; +use validator::Validate; + +#[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)] +pub struct RolesRequestDto { + #[validate(length(min = 1, message = "Role name must not be empty"))] + pub name: String, + pub permissions: Option>, +} + +#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] +pub struct RolesListItemDto { + pub id: String, + pub name: String, + pub permissions_count: u64, + pub created_at: Option, + pub updated_at: Option, +} + +#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] +pub struct RolesDetailItemDto { + pub id: String, + pub name: String, + pub permissions: Vec, + pub created_at: Option, + pub updated_at: Option, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct RolesDetailQueryDto { + pub id: Thing, + pub name: String, + pub permissions: Vec, + pub is_deleted: bool, + pub created_at: Option, + pub updated_at: Option, +} diff --git a/imphnen-iam-service/src/v1/roles/roles_enum.rs b/imphnen-iam/src/v1/roles/roles_enum.rs similarity index 100% rename from imphnen-iam-service/src/v1/roles/roles_enum.rs rename to imphnen-iam/src/v1/roles/roles_enum.rs diff --git a/imphnen-iam-service/src/v1/roles/roles_repository.rs b/imphnen-iam/src/v1/roles/roles_repository.rs similarity index 100% rename from imphnen-iam-service/src/v1/roles/roles_repository.rs rename to imphnen-iam/src/v1/roles/roles_repository.rs diff --git a/imphnen-iam-service/src/v1/roles/roles_schema.rs b/imphnen-iam/src/v1/roles/roles_schema.rs similarity index 100% rename from imphnen-iam-service/src/v1/roles/roles_schema.rs rename to imphnen-iam/src/v1/roles/roles_schema.rs diff --git a/imphnen-iam-service/src/v1/roles/roles_service.rs b/imphnen-iam/src/v1/roles/roles_service.rs similarity index 100% rename from imphnen-iam-service/src/v1/roles/roles_service.rs rename to imphnen-iam/src/v1/roles/roles_service.rs diff --git a/imphnen-iam-service/src/v1/users/mod.rs b/imphnen-iam/src/v1/users/mod.rs similarity index 100% rename from imphnen-iam-service/src/v1/users/mod.rs rename to imphnen-iam/src/v1/users/mod.rs diff --git a/imphnen-iam-service/src/v1/users/users_controller.rs b/imphnen-iam/src/v1/users/users_controller.rs similarity index 100% rename from imphnen-iam-service/src/v1/users/users_controller.rs rename to imphnen-iam/src/v1/users/users_controller.rs diff --git a/imphnen-iam-service/src/v1/users/users_dto.rs b/imphnen-iam/src/v1/users/users_dto.rs similarity index 83% rename from imphnen-iam-service/src/v1/users/users_dto.rs rename to imphnen-iam/src/v1/users/users_dto.rs index e752f26..2c71866 100644 --- a/imphnen-iam-service/src/v1/users/users_dto.rs +++ b/imphnen-iam/src/v1/users/users_dto.rs @@ -1,3 +1,4 @@ +use crate::{RolesDetailQueryDto, RolesItemDto}; use lazy_static::lazy_static; use regex::Regex; use serde::{Deserialize, Serialize}; @@ -5,17 +6,10 @@ use surrealdb::sql::Thing; use utoipa::ToSchema; use validator::Validate; -use crate::{RolesItemDto, RolesItemDtoRaw}; - lazy_static! { static ref PASSWORD_REGEX: Regex = Regex::new(r"^[A-Za-z\d@$!%*?&]{8,}$").unwrap(); } -#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] -pub struct UsersActiveInactiveRequestDto { - pub is_active: bool, -} - #[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)] pub struct UsersCreateRequestDto { #[validate( @@ -23,6 +17,7 @@ pub struct UsersCreateRequestDto { email(message = "Email not valid") )] pub email: String, + #[validate(length( min = 8, message = "Password must have at least 8 characters" @@ -32,8 +27,10 @@ pub struct UsersCreateRequestDto { message = "Password must include uppercase, lowercase, number, and special character" ))] pub password: String, + #[validate(length(min = 2, message = "Fullname at least have 2 character"))] pub fullname: String, + #[validate(length( min = 10, message = "Phone number at least have 10 character" @@ -71,23 +68,6 @@ pub struct UsersUpdateRequestDto { pub role_id: String, } -#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] -pub struct UsersItemDto { - pub id: String, - pub role: RolesItemDto, - pub fullname: String, - pub email: String, - pub avatar: Option, - pub phone_number: String, - pub is_active: bool, - pub is_deleted: bool, - pub gender: Option, - pub birthdate: Option, - pub password: String, - pub created_at: String, - pub updated_at: String, -} - #[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] pub struct UsersDetailItemDto { pub id: String, @@ -99,6 +79,8 @@ pub struct UsersDetailItemDto { pub is_active: bool, pub gender: Option, pub birthdate: Option, + pub created_at: String, + pub updated_at: String, } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] @@ -115,9 +97,9 @@ pub struct UsersListItemDto { } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct UsersListItemDtoRaw { +pub struct UsersListQueryDto { pub id: Thing, - pub role: Option, + pub role: RolesDetailQueryDto, pub fullname: String, pub email: String, pub avatar: Option, @@ -127,8 +109,24 @@ pub struct UsersListItemDtoRaw { pub updated_at: String, } +impl UsersListQueryDto { + pub fn list_from(&self, role: String) -> UsersListItemDto { + UsersListItemDto { + id: self.id.id.to_raw(), + role, + fullname: self.fullname.clone(), + email: self.email.clone(), + avatar: self.avatar.clone(), + phone_number: self.phone_number.clone(), + is_active: self.is_active, + created_at: self.created_at.clone(), + updated_at: self.updated_at.clone(), + } + } +} + #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct UsersItemDtoRaw { +pub struct UsersDetailQueryDto { pub id: Thing, pub fullname: String, pub email: String, @@ -138,8 +136,8 @@ pub struct UsersItemDtoRaw { pub is_deleted: bool, pub gender: Option, pub birthdate: Option, - pub role: RolesItemDtoRaw, pub password: String, + pub role: RolesDetailQueryDto, pub created_at: String, pub updated_at: String, } diff --git a/imphnen-iam/src/v1/users/users_repository.rs b/imphnen-iam/src/v1/users/users_repository.rs new file mode 100644 index 0000000..68e87ad --- /dev/null +++ b/imphnen-iam/src/v1/users/users_repository.rs @@ -0,0 +1,296 @@ +use super::{UsersDetailQueryDto, UsersListItemDto, UsersListQueryDto, UsersSchema}; +use crate::{ + AppState, MetaRequestDto, PermissionsItemDto, PermissionsItemDtoRaw, ResourceEnum, + ResponseListSuccessDto, RolesDetailQueryDto, extract_id, get_id, make_thing, + query_list_with_meta, +}; +use anyhow::{Result, bail}; + +pub struct UsersRepository<'a> { + state: &'a AppState, +} + +pub fn build_user_by_field_query(field: &str) -> String { + format!( + r#" + SELECT *, role AS role + FROM {} + WHERE {} = $value AND is_deleted = false + LIMIT 1 + FETCH role, role.permissions + "#, + ResourceEnum::Users.to_string(), + field + ) +} + +impl<'a> UsersRepository<'a> { + pub fn new(state: &'a AppState) -> Self { + Self { state } + } + + pub async fn query_user_list( + &self, + meta: MetaRequestDto, + ) -> Result>> { + let db = &self.state.surrealdb_ws; + + let raw_result = query_list_with_meta::( + db, + &ResourceEnum::Users.to_string(), + &meta, + vec!["is_deleted = false".into()], + None, + "fullname", + Some(vec![ + "email", + "fullname", + "id", + "is_active", + "is_deleted", + "role", + "role.permissions", + ]), + ) + .await?; + + let data = raw_result + .data + .into_iter() + .map(|schema| { + let role = schema.clone().role.name; + schema.list_from(role) + }) + .collect::>(); + + Ok(ResponseListSuccessDto { + data, + meta: raw_result.meta, + }) + } + + pub async fn query_user_by_email( + &self, + email: String, + ) -> Result { + let db = &self.state.surrealdb_ws; + + let sql = build_user_by_field_query("email"); + + let user_opt: Option = db + .query(sql) + .bind(("email", email.clone())) + .await? + .take(0)?; + + let Some(user) = user_opt else { + bail!("User not found"); + }; + + if user.role.is_deleted { + bail!("User not found"); + } + + let permissions = user + .role + .permissions + .into_iter() + .map(|perm| PermissionsItemDtoRaw { + id: perm.id, + name: perm.name, + created_at: perm.created_at, + updated_at: perm.updated_at, + }) + .collect(); + + Ok(UsersDetailQueryDto { + id: user.id, + fullname: user.fullname, + email: user.email, + avatar: user.avatar, + phone_number: user.phone_number, + is_active: user.is_active, + is_deleted: user.is_deleted, + gender: user.gender, + birthdate: user.birthdate, + password: user.password, + created_at: user.created_at, + updated_at: user.updated_at, + role: RolesDetailQueryDto { + id: user.role.id, + name: user.role.name, + created_at: user.role.created_at, + updated_at: user.role.updated_at, + is_deleted: user.role.is_deleted, + permissions, + }, + }) + } + + pub async fn query_user_by_id(&self, id: String) -> Result { + let db = &self.state.surrealdb_ws; + + let sql = build_user_by_field_query(&make_thing("app_users", &id).to_raw()); + + let user_opt: Option = db + .query(sql) + .bind(("email", make_thing("app_users", &id).to_raw())) + .await? + .take(0)?; + + let Some(user) = user_opt else { + bail!("User not found"); + }; + + if user.role.is_deleted { + bail!("User not found"); + } + + let permissions = user + .role + .permissions + .into_iter() + .map(|perm| PermissionsItemDtoRaw { + id: perm.id, + name: perm.name, + created_at: perm.created_at, + updated_at: perm.updated_at, + }) + .collect(); + + Ok(UsersDetailQueryDto { + id: user.id, + fullname: user.fullname, + email: user.email, + avatar: user.avatar, + phone_number: user.phone_number, + is_active: user.is_active, + is_deleted: user.is_deleted, + gender: user.gender, + birthdate: user.birthdate, + password: user.password, + created_at: user.created_at, + updated_at: user.updated_at, + role: RolesDetailQueryDto { + id: user.role.id, + name: user.role.name, + created_at: user.role.created_at, + updated_at: user.role.updated_at, + is_deleted: user.role.is_deleted, + permissions, + }, + }) + } + + pub async fn query_create_user(&self, data: UsersSchema) -> Result { + let db = &self.state.surrealdb_ws; + let record: Option = db + .create(ResourceEnum::Users.to_string()) + .content(data) + .await?; + match record { + Some(_) => Ok("Success create user".into()), + None => bail!("Failed to create user"), + } + } + + pub async fn query_update_user(&self, data: UsersSchema) -> Result { + let db = &self.state.surrealdb_ws; + let record_key = get_id(&data.id)?; + let existing = self.query_user_by_id(data.id.id.to_raw()).await?; + if existing.is_deleted { + bail!("User already deleted"); + } + let merged = UsersSchema { + password: existing.password, + created_at: existing.created_at, + role: make_thing("app_roles", &existing.role.id), + ..data.clone() + }; + let record: Option = db.update(record_key).merge(merged).await?; + match record { + Some(_) => Ok("Success update user".into()), + None => bail!("Failed to update user"), + } + } + + pub async fn query_active_inactive_user( + &self, + email: String, + data: UsersActiveInactiveSchema, + ) -> Result { + let db = &self.state.surrealdb_ws; + let user = self.query_user_by_email(email.clone()).await?; + if user.is_deleted { + bail!("User already deleted"); + } + let record_key = get_id(&user.id)?; + let record: Option = db + .update(record_key) + .merge(UsersActiveInactiveSchema { + is_active: data.is_active, + }) + .await?; + match record { + Some(_) => Ok("Success update user".into()), + None => bail!("Failed to update user"), + } + } + + pub async fn query_active_inactive_user_by_id( + &self, + id: String, + data: UsersActiveInactiveSchema, + ) -> Result { + let db = &self.state.surrealdb_ws; + let record: Option = db + .update((ResourceEnum::Users.to_string(), id)) + .merge(UsersActiveInactiveSchema { + is_active: data.is_active, + }) + .await?; + match record { + Some(_) => Ok("Success update user".into()), + None => bail!("Failed to update user"), + } + } + + pub async fn query_update_password_user( + &self, + email: String, + data: UsersSetNewPasswordSchema, + ) -> Result { + let db = &self.state.surrealdb_ws; + let user = self.query_user_by_email(email).await?; + let record: Option = db + .update((ResourceEnum::Users.to_string(), user.id.id.to_raw())) + .merge(UsersSetNewPasswordSchema { + password: data.password.clone(), + }) + .await?; + dbg!(record.clone()); + match record { + Some(_) => Ok("Success update password user".into()), + None => bail!("Failed to update password user"), + } + } + + pub async fn query_delete_user(&self, id: String) -> Result { + let db = &self.state.surrealdb_ws; + let user_id = make_thing(&ResourceEnum::Users.to_string(), &id); + let user = self.query_user_by_id(user_id.id.to_raw()).await?; + if user.is_deleted { + bail!("User already deleted"); + } + let id = make_thing(&ResourceEnum::Users.to_string(), &user.id); + let record_key = get_id(&id)?; + let record: Option = db + .update(record_key) + .merge(serde_json::json!({ "is_deleted": true })) + .await?; + match record { + Some(_) => Ok("Success delete user".into()), + None => bail!("Failed to delete user"), + } + } +} diff --git a/imphnen-iam/src/v1/users/users_schema.rs b/imphnen-iam/src/v1/users/users_schema.rs new file mode 100644 index 0000000..10b09aa --- /dev/null +++ b/imphnen-iam/src/v1/users/users_schema.rs @@ -0,0 +1,66 @@ +use super::{UsersDetailItemDto, UsersListItemDto}; +use crate::RolesItemDto; +use imphnen_utils::Crud; +use serde::{Deserialize, Serialize}; +use surrealdb::sql::Thing; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct UsersSchema { + pub id: Thing, + pub fullname: String, + pub email: String, + pub password: String, + pub avatar: Option, + pub phone_number: String, + pub is_active: bool, + pub is_deleted: bool, + pub gender: Option, + pub birthdate: Option, + pub role: Thing, + pub created_at: String, + pub updated_at: String, +} + +impl Crud for UsersSchema { + fn list(&self, role: String) -> UsersListItemDto { + UsersListItemDto { + id: self.id.id.to_raw(), + role, + fullname: self.fullname.clone(), + email: self.email.clone(), + avatar: self.avatar.clone(), + phone_number: self.phone_number.clone(), + is_active: self.is_active, + created_at: self.created_at.clone(), + updated_at: self.updated_at.clone(), + } + } +} + +impl Crud for UsersSchema { + fn detail(&self, role: RolesItemDto) -> UsersDetailItemDto { + UsersDetailItemDto { + id: self.id.id.to_raw(), + role, + fullname: self.fullname.clone(), + email: self.email.clone(), + avatar: self.avatar.clone(), + phone_number: self.phone_number.clone(), + is_active: self.is_active, + gender: self.gender.clone(), + birthdate: self.birthdate.clone(), + created_at: self.created_at.clone(), + updated_at: self.updated_at.clone(), + } + } +} + +impl UsersSchema { + pub fn list_from(&self, role: String) -> UsersListItemDto { + self.list(role) + } + + pub fn detail_from(&self, role: RolesItemDto) -> UsersDetailItemDto { + self.detail(role) + } +} diff --git a/imphnen-iam-service/src/v1/users/users_service.rs b/imphnen-iam/src/v1/users/users_service.rs similarity index 100% rename from imphnen-iam-service/src/v1/users/users_service.rs rename to imphnen-iam/src/v1/users/users_service.rs diff --git a/imphnen-iam-service/src/v2/.gitkeep b/imphnen-iam/src/v2/.gitkeep similarity index 100% rename from imphnen-iam-service/src/v2/.gitkeep rename to imphnen-iam/src/v2/.gitkeep diff --git a/imphnen-libs/Cargo.toml b/imphnen-libs/Cargo.toml index da99949..6ff4cf7 100644 --- a/imphnen-libs/Cargo.toml +++ b/imphnen-libs/Cargo.toml @@ -5,11 +5,11 @@ edition = "2024" [dependencies] imphnen-entities = { path = "../imphnen-entities" } -argon2.workspace = true axum.workspace = true tokio.workspace = true -chrono.workspace = true -jsonwebtoken.workspace = true serde.workspace = true +argon2.workspace = true lettre.workspace = true -surrealdb = { workspace = true, features = ["kv-mem"] } \ No newline at end of file +chrono.workspace = true +surrealdb.workspace = true +jsonwebtoken.workspace = true diff --git a/imphnen-middleware-service/Cargo.toml b/imphnen-middleware/Cargo.toml similarity index 81% rename from imphnen-middleware-service/Cargo.toml rename to imphnen-middleware/Cargo.toml index 4463224..cafff4f 100644 --- a/imphnen-middleware-service/Cargo.toml +++ b/imphnen-middleware/Cargo.toml @@ -1,13 +1,13 @@ [package] -name = "imphnen-middleware-service" +name = "imphnen-middleware" version = "0.1.0" edition = "2024" [dependencies] -imphnen-iam-service = { version = "0.1.0", path = "../imphnen-iam-service" } -imphnen-entities = { version = "0.1.0", path = "../imphnen-entities" } +imphnen-iam = { version = "0.1.0", path = "../imphnen-iam" } imphnen-libs = { version = "0.1.0", path = "../imphnen-libs" } imphnen-utils = { version = "0.1.0", path = "../imphnen-utils" } +imphnen-entities = { version = "0.1.0", path = "../imphnen-entities" } axum.workspace = true serde.workspace = true serde_json.workspace = true @@ -22,6 +22,6 @@ tokio.workspace = true chrono.workspace = true anyhow.workspace = true tower-http.workspace = true +futures.workspace = true +tower.workspace = true utoipa-swagger-ui.workspace = true -futures = "0.3.31" -tower = "0.5.2" diff --git a/imphnen-middleware-service/src/auth_middleware/mod.rs b/imphnen-middleware/src/auth_middleware/mod.rs similarity index 94% rename from imphnen-middleware-service/src/auth_middleware/mod.rs rename to imphnen-middleware/src/auth_middleware/mod.rs index 6c3f625..d91068b 100644 --- a/imphnen-middleware-service/src/auth_middleware/mod.rs +++ b/imphnen-middleware/src/auth_middleware/mod.rs @@ -2,7 +2,7 @@ use axum::{ Extension, extract::Request, http::StatusCode, middleware::Next, response::Response, }; -use imphnen_iam_service::{UsersItemDtoRaw, UsersRepository}; +use imphnen_iam::{UsersItemDtoRaw, UsersRepository}; use imphnen_libs::AppState; use imphnen_utils::{common_response, extract_email}; use std::convert::Infallible; diff --git a/imphnen-middleware-service/src/cors_middleware/mod.rs b/imphnen-middleware/src/cors_middleware/mod.rs similarity index 100% rename from imphnen-middleware-service/src/cors_middleware/mod.rs rename to imphnen-middleware/src/cors_middleware/mod.rs diff --git a/imphnen-middleware-service/src/lib.rs b/imphnen-middleware/src/lib.rs similarity index 100% rename from imphnen-middleware-service/src/lib.rs rename to imphnen-middleware/src/lib.rs diff --git a/imphnen-middleware-service/src/payment_middleware/.gitkeep b/imphnen-middleware/src/payment_middleware/.gitkeep similarity index 100% rename from imphnen-middleware-service/src/payment_middleware/.gitkeep rename to imphnen-middleware/src/payment_middleware/.gitkeep diff --git a/imphnen-middleware-service/src/permissions_middleware/mod.rs b/imphnen-middleware/src/permissions_middleware/mod.rs similarity index 97% rename from imphnen-middleware-service/src/permissions_middleware/mod.rs rename to imphnen-middleware/src/permissions_middleware/mod.rs index 27d7641..066c756 100644 --- a/imphnen-middleware-service/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_service::{AuthRepository, PermissionsEnum}; +use imphnen_iam::{AuthRepository, PermissionsEnum}; use imphnen_libs::AppState; use imphnen_utils::{common_response, extract_email}; use std::task::{Context, Poll}; diff --git a/imphnen-utils/Cargo.toml b/imphnen-utils/Cargo.toml index 2296459..4823820 100644 --- a/imphnen-utils/Cargo.toml +++ b/imphnen-utils/Cargo.toml @@ -14,4 +14,4 @@ anyhow.workspace = true axum-test.workspace = true serde.workspace = true serde_json.workspace = true -validator.workspace = true \ No newline at end of file +validator.workspace = true diff --git a/imphnen-utils/src/crud.rs b/imphnen-utils/src/crud.rs new file mode 100644 index 0000000..d95669b --- /dev/null +++ b/imphnen-utils/src/crud.rs @@ -0,0 +1,8 @@ +pub trait Crud { + fn list(&self, _args: Args) -> T { + unimplemented!("list() is not implemented for this type") + } + fn detail(&self, _args: Args) -> T { + unimplemented!("detail() is not implemented for this type") + } +} diff --git a/imphnen-utils/src/lib.rs b/imphnen-utils/src/lib.rs index e21a316..08ddcb6 100644 --- a/imphnen-utils/src/lib.rs +++ b/imphnen-utils/src/lib.rs @@ -2,17 +2,20 @@ use imphnen_entities::*; use imphnen_libs::*; pub mod bind_filter; +pub mod crud; pub mod extract_email; pub mod generate_date; pub mod generate_otp; pub mod get_id; pub mod make_thing; pub mod mock_test; +pub mod query_builder; pub mod query_list; pub mod response_format; pub mod validator; pub use bind_filter::*; +pub use crud::*; pub use extract_email::*; pub use generate_date::*; pub use generate_otp::*; @@ -21,6 +24,7 @@ pub use imphnen_entities::*; pub use imphnen_libs::*; pub use make_thing::*; pub use mock_test::*; +pub use query_builder::*; pub use query_list::*; pub use response_format::*; pub use validator::*; diff --git a/imphnen-utils/src/query_builder.rs b/imphnen-utils/src/query_builder.rs new file mode 100644 index 0000000..33e1a3e --- /dev/null +++ b/imphnen-utils/src/query_builder.rs @@ -0,0 +1,137 @@ +use imphnen_libs::MetaRequestDto; + +pub struct ListQueryBuilder { + resource: String, + conditions: Vec, + limit: usize, + start: usize, + order_by: Option, + order: Option, + fetch: Vec, + select_fields: Vec, +} + +impl ListQueryBuilder { + pub fn from_meta( + resource: impl Into, + meta: &MetaRequestDto, + search_field: impl Into, + select_fields: Option>, + ) -> Self { + let mut builder = Self::new(resource) + .with_search(meta.search.as_deref(), &search_field.into()) + .with_filter(meta.filter_by.as_deref(), meta.filter.as_deref()) + .with_sorting(meta.sort_by.as_deref(), meta.order.as_deref()) + .with_pagination(meta.page, meta.per_page); + + if let Some(fields) = select_fields { + builder = builder.with_select_fields(fields); + } + builder + } + + pub fn new(resource: impl Into) -> Self { + Self { + resource: resource.into(), + conditions: vec!["is_deleted = false".into()], + limit: 10, + start: 0, + order_by: None, + order: None, + fetch: vec![], + select_fields: vec![], + } + } + + pub fn with_select_fields(mut self, fields: Vec<&str>) -> Self { + self.select_fields = fields.into_iter().map(String::from).collect(); + self + } + + pub fn with_search(mut self, search: Option<&str>, field: &str) -> Self { + if let Some(search) = search { + if !search.is_empty() { + self + .conditions + .push(format!("string::contains({} ?? '', $search)", field)); + } + } + self + } + + pub fn with_filter(mut self, field: Option<&str>, value: Option<&str>) -> Self { + if let (Some(f), Some(v)) = (field, value) { + if !v.is_empty() { + self.conditions.push(format!("{} = $filter", f)); + } + } + self + } + + pub fn with_pagination( + mut self, + page: Option, + per_page: Option, + ) -> Self { + let limit = per_page.unwrap_or(10).max(1); + let page = page.unwrap_or(1).max(1); + self.limit = limit as usize; + self.start = ((page - 1) * limit) as usize; + self + } + + pub fn with_sorting(mut self, sort_by: Option<&str>, order: Option<&str>) -> Self { + self.order_by = sort_by.map(|s| s.to_string()); + self.order = order.map(|o| o.to_uppercase()); + self + } + + pub fn with_fetch(mut self, fetch: impl Into) -> Self { + self.fetch.push(fetch.into()); + self + } + + pub fn build(self) -> String { + let where_clause = if !self.conditions.is_empty() { + format!("WHERE {}", self.conditions.join(" AND ")) + } else { + String::new() + }; + + let order_clause = if let Some(field) = self.order_by { + let ord = self.order.unwrap_or_else(|| "ASC".into()); + format!("ORDER BY {} {}", field, ord) + } else { + String::new() + }; + + let fetch_clause = if !self.fetch.is_empty() { + format!("FETCH {}", self.fetch.join(", ")) + } else { + String::new() + }; + + let select_clause = if self.select_fields.is_empty() { + "*".to_string() + } else { + self.select_fields.join(", ") + }; + + format!( + r#" + SELECT {} FROM {} + {} + {} + LIMIT {} START {} + {} + "#, + select_clause, + self.resource, + where_clause, + order_clause, + self.limit, + self.start, + fetch_clause + ) + } +} diff --git a/imphnen-utils/src/query_list.rs b/imphnen-utils/src/query_list.rs index c875694..bb27db8 100644 --- a/imphnen-utils/src/query_list.rs +++ b/imphnen-utils/src/query_list.rs @@ -1,8 +1,8 @@ -use super::bind_filter_value; +use super::{ListQueryBuilder, bind_filter_value}; use crate::{CountResult, MetaRequestDto, MetaResponseDto, ResponseListSuccessDto}; -use anyhow::{bail, Result}; -use serde::{de::DeserializeOwned, Serialize}; -use surrealdb::{engine::remote::ws::Client, Surreal}; +use anyhow::Result; +use serde::{Serialize, de::DeserializeOwned}; +use surrealdb::{Surreal, engine::remote::ws::Client}; pub async fn query_list_with_meta( db: &Surreal, @@ -10,75 +10,61 @@ pub async fn query_list_with_meta( meta: &MetaRequestDto, conditions: Vec, custom_select: Option, + search_field: &str, + select_fields: Option>, ) -> Result>> where T: DeserializeOwned + Serialize, { - let page = meta.page.unwrap_or(1); - let per_page = meta.per_page.unwrap_or(10); - if page < 1 || per_page < 1 { - bail!("Invalid pagination: page and per_page must be greater than 0"); - } + let page = meta.page.unwrap_or(1).max(1); + let per_page = meta.per_page.unwrap_or(10).max(1); let start = (page - 1) * per_page; + let sql = custom_select.unwrap_or_else(|| { - let mut s = format!("SELECT * FROM {}", table); - if !conditions.is_empty() { - s.push_str(" WHERE "); - s.push_str(&conditions.join(" AND ")); - } - if let Some(sort_by) = &meta.sort_by { - let order = match meta - .order - .clone() - .unwrap_or_default() - .to_uppercase() - .as_str() - { - "DESC" => "DESC", - _ => "ASC", - }; - s.push_str(&format!(" ORDER BY {} {}", sort_by, order)); - } - s.push_str(" LIMIT $per_page START $start"); - s + ListQueryBuilder::from_meta(table, meta, search_field, select_fields).build() }); + let mut query_exec = db.query(sql); if let Some(search) = &meta.search { if !search.is_empty() { query_exec = query_exec.bind(("search", search.clone())); } } - if let Some(filter_val) = meta.filter.clone() { - query_exec = bind_filter_value(query_exec, filter_val); + if let Some(filter_val) = &meta.filter { + query_exec = bind_filter_value(query_exec, filter_val.clone()); } query_exec = query_exec .bind(("per_page", per_page)) .bind(("start", start)); + let raw: Vec = query_exec.await?.take(0)?; - let mut count_sql = format!("SELECT count() FROM {}", table); - if !conditions.is_empty() { - count_sql.push_str(" WHERE "); - count_sql.push_str(&conditions.join(" AND ")); - } - let mut count_query = db.query(count_sql); + + let mut count_query = db.query(format!( + "SELECT count() FROM {} {}", + table, + if conditions.is_empty() { + String::new() + } else { + format!("WHERE {}", conditions.join(" AND ")) + } + )); if let Some(search) = &meta.search { if !search.is_empty() { count_query = count_query.bind(("search", search.clone())); } } - if let Some(filter_val) = meta.filter.clone() { - count_query = bind_filter_value(count_query, filter_val); + if let Some(filter_val) = &meta.filter { + count_query = bind_filter_value(count_query, filter_val.clone()); } let count_result: Vec = count_query.await?.take(0)?; let total = count_result.first().map(|c| c.count); - let meta = MetaResponseDto { - page: Some(page), - per_page: Some(per_page), - total, - }; Ok(ResponseListSuccessDto { data: raw, - meta: Some(meta), + meta: Some(MetaResponseDto { + page: Some(page), + per_page: Some(per_page), + total, + }), }) } diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 8898e4f..f858262 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -4,10 +4,10 @@ version = "0.1.0" edition = "2024" [dependencies] +imphnen-iam = { version = "0.1.0", path = "../imphnen-iam" } imphnen-libs = { version = "0.1.0", path = "../imphnen-libs" } imphnen-utils = { version = "0.1.0", path = "../imphnen-utils" } imphnen-entities = { version = "0.1.0", path = "../imphnen-entities" } -imphnen-iam-service = { version = "0.1.0", path = "../imphnen-iam-service" } axum.workspace = true axum-test.workspace = true chrono.workspace = true diff --git a/tests/src/iam_service/auth/auth_controller_test.rs b/tests/src/iam/auth/auth_controller_test.rs similarity index 100% rename from tests/src/iam_service/auth/auth_controller_test.rs rename to tests/src/iam/auth/auth_controller_test.rs diff --git a/tests/src/iam_service/auth/auth_repository_test.rs b/tests/src/iam/auth/auth_repository_test.rs similarity index 100% rename from tests/src/iam_service/auth/auth_repository_test.rs rename to tests/src/iam/auth/auth_repository_test.rs diff --git a/tests/src/iam_service/auth/mod.rs b/tests/src/iam/auth/mod.rs similarity index 100% rename from tests/src/iam_service/auth/mod.rs rename to tests/src/iam/auth/mod.rs diff --git a/tests/src/iam_service/mod.rs b/tests/src/iam/mod.rs similarity index 100% rename from tests/src/iam_service/mod.rs rename to tests/src/iam/mod.rs diff --git a/tests/src/iam_service/permissions/mod.rs b/tests/src/iam/permissions/mod.rs similarity index 100% rename from tests/src/iam_service/permissions/mod.rs rename to tests/src/iam/permissions/mod.rs diff --git a/tests/src/iam_service/permissions/permissions_controller_test.rs b/tests/src/iam/permissions/permissions_controller_test.rs similarity index 100% rename from tests/src/iam_service/permissions/permissions_controller_test.rs rename to tests/src/iam/permissions/permissions_controller_test.rs diff --git a/tests/src/iam_service/permissions/permissions_repository_test.rs b/tests/src/iam/permissions/permissions_repository_test.rs similarity index 100% rename from tests/src/iam_service/permissions/permissions_repository_test.rs rename to tests/src/iam/permissions/permissions_repository_test.rs diff --git a/tests/src/iam_service/roles/mod.rs b/tests/src/iam/roles/mod.rs similarity index 100% rename from tests/src/iam_service/roles/mod.rs rename to tests/src/iam/roles/mod.rs diff --git a/tests/src/iam_service/roles/roles_controller_test.rs b/tests/src/iam/roles/roles_controller_test.rs similarity index 100% rename from tests/src/iam_service/roles/roles_controller_test.rs rename to tests/src/iam/roles/roles_controller_test.rs diff --git a/tests/src/iam_service/roles/roles_repository_test.rs b/tests/src/iam/roles/roles_repository_test.rs similarity index 100% rename from tests/src/iam_service/roles/roles_repository_test.rs rename to tests/src/iam/roles/roles_repository_test.rs diff --git a/tests/src/iam_service/users/mod.rs b/tests/src/iam/users/mod.rs similarity index 100% rename from tests/src/iam_service/users/mod.rs rename to tests/src/iam/users/mod.rs diff --git a/tests/src/iam_service/users/users_controller_test.rs b/tests/src/iam/users/users_controller_test.rs similarity index 100% rename from tests/src/iam_service/users/users_controller_test.rs rename to tests/src/iam/users/users_controller_test.rs diff --git a/tests/src/iam_service/users/users_repository_test.rs b/tests/src/iam/users/users_repository_test.rs similarity index 100% rename from tests/src/iam_service/users/users_repository_test.rs rename to tests/src/iam/users/users_repository_test.rs diff --git a/tests/src/lib.rs b/tests/src/lib.rs index 0c46bb0..eded98f 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -1,6 +1,6 @@ pub use imphnen_entities::*; -pub use imphnen_iam_service::*; +pub use imphnen_iam::*; pub use imphnen_utils::*; #[cfg(test)] -pub mod iam_service; +pub mod iam;