From 9f5f1af6e2ce96660c091279f7ba8de7890f2442 Mon Sep 17 00:00:00 2001 From: Bright Date: Wed, 22 Jan 2025 17:42:23 +0700 Subject: [PATCH] fix issue #896 --- src/controllers/CommandController.ts | 162 +++++++++++++-------------- src/controllers/UserController.ts | 19 ++++ src/keycloak/index.ts | 24 +++- 3 files changed, 123 insertions(+), 82 deletions(-) diff --git a/src/controllers/CommandController.ts b/src/controllers/CommandController.ts index 2c42c54b..32cc5881 100644 --- a/src/controllers/CommandController.ts +++ b/src/controllers/CommandController.ts @@ -53,7 +53,7 @@ import { PosMasterAct } from "../entities/PosMasterAct"; import { sendToQueue } from "../services/rabbitmq"; import { PosLevel } from "../entities/PosLevel"; import { PosType } from "../entities/PosType"; -import { addUserRoles, createUser, getRoles, deleteUser, enableStatus } from "../keycloak"; +import { addUserRoles, createUser, getRoles, deleteUser, enableStatus, getUserByUsername, getRoleMappings } from "../keycloak"; import { ProfileEducation, CreateProfileEducation } from "../entities/ProfileEducation"; import { ProfileEducationHistory } from "../entities/ProfileEducationHistory"; import { CreateProfileCertificate, ProfileCertificate } from "../entities/ProfileCertificate"; @@ -2564,47 +2564,37 @@ export class CommandController extends Controller { //คำสั่งบรรจุกลับเข้ารับราชการ หรือ ผู้ออกไปรับราชการทหารกลับเข้ารับราชการ solutionเดิม ให้ enable user เปลี่ยนเป็นสร้าง user ใหม่เลยเพราะยังไงตอนถูกพักก็ถูกลบ user if (returnWork && item.isGovernment) { let userKeycloakId; - userKeycloakId = await createUser(profile.citizenId, profile.citizenId, { - firstName: profile.firstName, - lastName: profile.lastName, - }); - // กรณี Keycloak ไม่ถูกลบ ให้ลบซ้ำอีกรอบแล้วสร้างใหม่ และหากยังไม่สามารถลบได้ให้แสดง Error - if ( - profile.keycloak != null && - userKeycloakId && - userKeycloakId.errorMessage === "User exists with same username" - ) { - const delUserKeycloak = await deleteUser(profile.keycloak); - if (delUserKeycloak) { - userKeycloakId = await createUser(profile.citizenId, profile.citizenId, { - firstName: profile.firstName, - lastName: profile.lastName, - }); - } else { - throw new HttpError( - HttpStatus.BAD_REQUEST, - "พบข้อผิดพลาด ไม่สามารถจัดการผู้ใช้งานได้", + const checkUser = await getUserByUsername(profile.citizenId) + //ถ้ายังไม่มี user keycloak ให้สร้างใหม่ + if (checkUser.length == 0) { + userKeycloakId = await createUser(profile.citizenId, profile.citizenId, { + firstName: profile.firstName, + lastName: profile.lastName, + }); + const list = await getRoles(); + let result = false; + if (Array.isArray(list) && userKeycloakId) { + result = await addUserRoles( + userKeycloakId, + list + .filter((v) => v.name === "USER") + .map((x) => ({ + id: x.id, + name: x.name, + })), ); } + profile.roleKeycloaks = result && roleKeycloak ? [roleKeycloak] : []; + profile.keycloak = userKeycloakId && typeof userKeycloakId === "string" ? userKeycloakId : "";; } - const list = await getRoles(); - let result = false; - if (Array.isArray(list) && userKeycloakId) { - result = await addUserRoles( - userKeycloakId, - list - .filter((v) => v.name === "USER") - .map((x) => ({ - id: x.id, - name: x.name, - })), - ); + //ถ้ามีอยู่แล้วให้ใช้อันเดิม + else { + // const _roleKeycloaks = await getRoleMappings(checkUser[0].id); + profile.keycloak = checkUser[0].id; } profile.amount = item.amount ?? _null; profile.amountSpecial = item.amountSpecial ?? _null; profile.isActive = true; - profile.keycloak = typeof userKeycloakId === "string" ? userKeycloakId : ""; - profile.roleKeycloaks = result && roleKeycloak ? [roleKeycloak] : []; } await this.profileRepository.save(profile); }), @@ -3929,26 +3919,32 @@ export class CommandController extends Controller { item.bodyProfile.birthDate == null ? _null : calculateRetireLaw(item.bodyProfile.birthDate); - const userKeycloakId = await createUser(profile.citizenId, profile.citizenId, { - firstName: profile.firstName, - lastName: profile.lastName, - }); - // if (typeof userKeycloakId !== "string") { - // throw new Error(userKeycloakId.errorMessage); - // } - const list = await getRoles(); - if (!Array.isArray(list)) - throw new Error("Failed. Cannot get role(s) data from the server."); - const result = await addUserRoles( - userKeycloakId, - list - .filter((v) => v.name === "USER") - .map((x) => ({ - id: x.id, - name: x.name, - })), - ); - // if (!result) throw new Error("Failed. Cannot set user's role."); + + const checkUser = await getUserByUsername(profile.citizenId) + if(checkUser.length == 0) { + const userKeycloakId = await createUser(profile.citizenId, profile.citizenId, { + firstName: profile.firstName, + lastName: profile.lastName, + }); + const list = await getRoles(); + if (!Array.isArray(list)) + throw new Error("Failed. Cannot get role(s) data from the server."); + const result = await addUserRoles( + userKeycloakId, + list + .filter((v) => v.name === "USER") + .map((x) => ({ + id: x.id, + name: x.name, + })), + ); + profile.roleKeycloaks = result && roleKeycloak ? [roleKeycloak] : []; + profile.keycloak = userKeycloakId && typeof userKeycloakId === "string" ? userKeycloakId : ""; + } + else { + profile.keycloak = checkUser[0].id; + } + let registrationProvinceId = await this.provinceRepo.findOneBy({ id: profile.registrationProvinceId, }); @@ -3980,8 +3976,6 @@ export class CommandController extends Controller { id: profile.currentSubDistrictId, }); profile.currentSubDistrictId = currentSubDistrictId ? currentSubDistrictId.id : null_; - profile.keycloak = typeof userKeycloakId === "string" ? userKeycloakId : ""; - profile.roleKeycloaks = result && roleKeycloak ? [roleKeycloak] : []; profile.email = item.bodyProfile.email; profile.dateStart = item.bodyProfile.dateStart; profile.amount = item.bodyProfile.amount ?? null; @@ -4317,30 +4311,36 @@ export class CommandController extends Controller { if (positionNew != null) { // Create Keycloak - const userKeycloakId = await createUser(profile.citizenId, profile.citizenId, { - firstName: profile.firstName, - lastName: profile.lastName, - // email: profile.email, - }); - // if (typeof userKeycloakId !== "string") { - // throw new Error(userKeycloakId.errorMessage); - // } - const list = await getRoles(); - if (!Array.isArray(list)) - throw new Error("Failed. Cannot get role(s) data from the server."); - const result = await addUserRoles( - userKeycloakId, - list - .filter((v) => v.name === "USER") - .map((x) => ({ - id: x.id, - name: x.name, - })), - ); - // if (!result) throw new Error("Failed. Cannot set user's role."); - profile.keycloak = typeof userKeycloakId == "string" ? userKeycloakId : ""; - profile.roleKeycloaks = result && roleKeycloak ? [roleKeycloak] : []; - // End Create Keycloak + const checkUser = await getUserByUsername(profile.citizenId) + if(checkUser.length == 0) { + const userKeycloakId = await createUser(profile.citizenId, profile.citizenId, { + firstName: profile.firstName, + lastName: profile.lastName, + // email: profile.email, + }); + // if (typeof userKeycloakId !== "string") { + // throw new Error(userKeycloakId.errorMessage); + // } + const list = await getRoles(); + if (!Array.isArray(list)) + throw new Error("Failed. Cannot get role(s) data from the server."); + const result = await addUserRoles( + userKeycloakId, + list + .filter((v) => v.name === "USER") + .map((x) => ({ + id: x.id, + name: x.name, + })), + ); + // if (!result) throw new Error("Failed. Cannot set user's role."); + profile.keycloak = userKeycloakId && typeof userKeycloakId == "string" ? userKeycloakId : ""; + profile.roleKeycloaks = result && roleKeycloak ? [roleKeycloak] : []; + // End Create Keycloak + } + else { + profile.keycloak = checkUser[0].id; + } positionNew.positionIsSelected = true; profile.posLevelId = positionNew.posLevelId; diff --git a/src/controllers/UserController.ts b/src/controllers/UserController.ts index 0a3dd02d..15394982 100644 --- a/src/controllers/UserController.ts +++ b/src/controllers/UserController.ts @@ -30,6 +30,7 @@ import { getRoleMappings, getUserCount, enableStatus, + getUserByUsername } from "../keycloak"; import { AppDataSource } from "../database/data-source"; import { Profile } from "../entities/Profile"; @@ -693,6 +694,24 @@ export class KeycloakController extends Controller { return profile.roleKeycloaks; } + @Get("user/username/{citizenId}") + async getUserByUsername(@Path("citizenId") citizenId: string) { + const userData = await getUserByUsername(citizenId); + if (!userData || userData.length == 0) { + throw new Error("User not found"); + } + const rolesData = await getRoleMappings(userData[0].id); + if (!rolesData) { + throw new Error("Role mappings not found"); + } + const userDataWithRoles = { + ...userData, + roles: rolesData, + }; + + return userDataWithRoles + } + @Put("user/{userId}/enableStatus/{status}") //#log? async changeEnableStatus(@Path() userId: string, @Path() status: boolean) { const profile = await this.profileRepo.findOne({ diff --git a/src/keycloak/index.ts b/src/keycloak/index.ts index 16081ee3..23d4426c 100644 --- a/src/keycloak/index.ts +++ b/src/keycloak/index.ts @@ -114,6 +114,28 @@ export async function getUser(userId: string) { return await res.json(); } +/** + * Get keycloak user by Username (citizenId) + * + * Client must have permission to manage realm's user + * + * @returns user if success, false otherwise. + */ +export async function getUserByUsername(citizenId: string) { + const res = await fetch(`${KC_URL}/admin/realms/${KC_REALMS}/users?username=${citizenId}`, { + // prettier-ignore + headers: { + "authorization": `Bearer ${await getToken()}`, + "content-type": `application/json`, + }, + }).catch((e) => console.log("Keycloak Error: ", e)); + if (!res) return false; + if (!res.ok) { + return Boolean(console.error("Keycloak Error Response: ", await res.json())); + } + return await res.json(); +} + /** * Get keycloak user list * @@ -476,7 +498,7 @@ export async function getUserRoles(userId: string) { */ export async function addUserRoles(userId: string, roles: { id: string; name: string }[]) { const res = await fetch( - `${KC_URL}/admin/realms/${KC_REALMS}/users/${userId}/role-mappings/realm`, + `${KC_URL}/admin/realms/${KC_REALMS}/users/${userId}`, { // prettier-ignore headers: {