Revert "fix: sync and script keycloak"
All checks were successful
Build & Deploy on Dev / build (push) Successful in 2m11s
All checks were successful
Build & Deploy on Dev / build (push) Successful in 2m11s
This reverts commit d667ad9173.
This commit is contained in:
parent
d667ad9173
commit
c5c19b6d5e
12 changed files with 33 additions and 2444 deletions
|
|
@ -1,254 +0,0 @@
|
|||
import {
|
||||
Controller,
|
||||
Post,
|
||||
Get,
|
||||
Route,
|
||||
Security,
|
||||
Tags,
|
||||
Path,
|
||||
Request,
|
||||
Response,
|
||||
Query,
|
||||
Body,
|
||||
} from "tsoa";
|
||||
import { KeycloakAttributeService } from "../services/KeycloakAttributeService";
|
||||
import HttpSuccess from "../interfaces/http-success";
|
||||
import HttpStatus from "../interfaces/http-status";
|
||||
import HttpError from "../interfaces/http-error";
|
||||
import { RequestWithUser } from "../middlewares/user";
|
||||
|
||||
@Route("api/v1/org/keycloak-sync")
|
||||
@Tags("Keycloak Sync")
|
||||
@Security("bearerAuth")
|
||||
@Response(
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
"เกิดข้อผิดพลาด ไม่สามารถดำเนินการได้ กรุณาลองใหม่ในภายหลัง",
|
||||
)
|
||||
export class KeycloakSyncController extends Controller {
|
||||
private keycloakAttributeService = new KeycloakAttributeService();
|
||||
|
||||
/**
|
||||
* Sync attributes for the current logged-in user
|
||||
*
|
||||
* @summary Sync profileId and rootDnaId to Keycloak for current user
|
||||
*/
|
||||
@Post("sync-me")
|
||||
async syncCurrentUser(@Request() request: RequestWithUser) {
|
||||
const keycloakUserId = request.user.sub;
|
||||
|
||||
if (!keycloakUserId) {
|
||||
throw new HttpError(HttpStatus.UNAUTHORIZED, "ไม่พบ Keycloak user ID");
|
||||
}
|
||||
|
||||
// Get attributes from database before sync
|
||||
const dbAttrs = await this.keycloakAttributeService.getUserProfileAttributes(keycloakUserId);
|
||||
|
||||
const success = await this.keycloakAttributeService.syncUserAttributes(keycloakUserId);
|
||||
|
||||
if (!success) {
|
||||
throw new HttpError(
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
"ไม่สามารถ sync ข้อมูลไปยัง Keycloak ได้ กรุณาติดต่อผู้ดูแลระบบ",
|
||||
);
|
||||
}
|
||||
|
||||
// Verify sync by fetching attributes from Keycloak after update
|
||||
const kcAttrsAfter =
|
||||
await this.keycloakAttributeService.getCurrentKeycloakAttributes(keycloakUserId);
|
||||
|
||||
return new HttpSuccess({
|
||||
message: "Sync ข้อมูลสำเร็จ",
|
||||
syncedToKeycloak: !!kcAttrsAfter?.profileId,
|
||||
databaseAttributes: dbAttrs,
|
||||
keycloakAttributesAfter: kcAttrsAfter,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current attributes of the logged-in user
|
||||
*
|
||||
* @summary Get current profileId and rootDnaId from Keycloak
|
||||
*/
|
||||
// @Get("my-attributes")
|
||||
async getMyAttributes(@Request() request: RequestWithUser) {
|
||||
const keycloakUserId = request.user.sub;
|
||||
|
||||
if (!keycloakUserId) {
|
||||
throw new HttpError(HttpStatus.UNAUTHORIZED, "ไม่พบ Keycloak user ID");
|
||||
}
|
||||
|
||||
const keycloakAttributes =
|
||||
await this.keycloakAttributeService.getCurrentKeycloakAttributes(keycloakUserId);
|
||||
const dbAttributes =
|
||||
await this.keycloakAttributeService.getUserProfileAttributes(keycloakUserId);
|
||||
|
||||
return new HttpSuccess({
|
||||
keycloakAttributes,
|
||||
databaseAttributes: dbAttributes,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync attributes for a specific profile (Admin only)
|
||||
*
|
||||
* @summary Sync profileId and rootDnaId to Keycloak by profile ID (ADMIN)
|
||||
*
|
||||
* @param {string} profileId Profile ID
|
||||
* @param {string} profileType Profile type (PROFILE or PROFILE_EMPLOYEE)
|
||||
*/
|
||||
@Post("sync-profile/:profileId")
|
||||
async syncByProfileId(
|
||||
@Path() profileId: string,
|
||||
@Query() profileType: "PROFILE" | "PROFILE_EMPLOYEE" = "PROFILE",
|
||||
) {
|
||||
if (!["PROFILE", "PROFILE_EMPLOYEE"].includes(profileType)) {
|
||||
throw new HttpError(
|
||||
HttpStatus.BAD_REQUEST,
|
||||
"profileType ต้องเป็น PROFILE หรือ PROFILE_EMPLOYEE เท่านั้น",
|
||||
);
|
||||
}
|
||||
|
||||
const success = await this.keycloakAttributeService.syncOnOrganizationChange(
|
||||
profileId,
|
||||
profileType,
|
||||
);
|
||||
|
||||
if (!success) {
|
||||
throw new HttpError(
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
"ไม่สามารถ sync ข้อมูลไปยัง Keycloak ได้ หรือไม่พบข้อมูล profile",
|
||||
);
|
||||
}
|
||||
|
||||
return new HttpSuccess({ message: "Sync ข้อมูลสำเร็จ" });
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch sync attributes for multiple profiles (Admin only)
|
||||
*
|
||||
* @summary Batch sync profileId and rootDnaId to Keycloak for multiple profiles (ADMIN)
|
||||
*
|
||||
* @param {request} request Request body containing profileIds array and profileType
|
||||
*/
|
||||
// @Post("sync-profiles-batch")
|
||||
async syncByProfileIds(
|
||||
@Body() request: { profileIds: string[]; profileType: "PROFILE" | "PROFILE_EMPLOYEE" },
|
||||
) {
|
||||
const { profileIds, profileType } = request;
|
||||
|
||||
// Validate profileIds
|
||||
if (!profileIds || profileIds.length === 0) {
|
||||
throw new HttpError(HttpStatus.BAD_REQUEST, "profileIds ต้องไม่ว่างเปล่า");
|
||||
}
|
||||
|
||||
// Validate profileType
|
||||
if (!["PROFILE", "PROFILE_EMPLOYEE"].includes(profileType)) {
|
||||
throw new HttpError(
|
||||
HttpStatus.BAD_REQUEST,
|
||||
"profileType ต้องเป็น PROFILE หรือ PROFILE_EMPLOYEE เท่านั้น",
|
||||
);
|
||||
}
|
||||
|
||||
const result = {
|
||||
total: profileIds.length,
|
||||
success: 0,
|
||||
failed: 0,
|
||||
details: [] as Array<{ profileId: string; status: "success" | "failed"; error?: string }>,
|
||||
};
|
||||
|
||||
// Process each profileId
|
||||
for (const profileId of profileIds) {
|
||||
try {
|
||||
const success = await this.keycloakAttributeService.syncOnOrganizationChange(
|
||||
profileId,
|
||||
profileType,
|
||||
);
|
||||
|
||||
if (success) {
|
||||
result.success++;
|
||||
result.details.push({ profileId, status: "success" });
|
||||
} else {
|
||||
result.failed++;
|
||||
result.details.push({
|
||||
profileId,
|
||||
status: "failed",
|
||||
error: "Sync returned false - ไม่พบข้อมูล profile หรือ Keycloak user ID",
|
||||
});
|
||||
}
|
||||
} catch (error: any) {
|
||||
result.failed++;
|
||||
result.details.push({ profileId, status: "failed", error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
return new HttpSuccess({
|
||||
message: "Batch sync เสร็จสิ้น",
|
||||
...result,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch sync all users (Admin only)
|
||||
*
|
||||
* @summary Batch sync all users to Keycloak without limit (ADMIN)
|
||||
*
|
||||
* @description Syncs profileId and orgRootDnaId to Keycloak for all users
|
||||
* that have a keycloak ID. Uses parallel processing for better performance.
|
||||
*/
|
||||
// @Post("sync-all")
|
||||
async syncAll() {
|
||||
const result = await this.keycloakAttributeService.batchSyncUsers();
|
||||
|
||||
return new HttpSuccess({
|
||||
message: "Batch sync เสร็จสิ้น",
|
||||
total: result.total,
|
||||
success: result.success,
|
||||
failed: result.failed,
|
||||
details: result.details,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure Keycloak users exist for all profiles (Admin only)
|
||||
*
|
||||
* @summary Create or verify Keycloak users for all profiles in Profile and ProfileEmployee tables (ADMIN)
|
||||
*
|
||||
* @description
|
||||
* This endpoint will:
|
||||
* - Create new Keycloak users for profiles without a keycloak ID
|
||||
* - Create new Keycloak users for profiles where the stored keycloak ID doesn't exist in Keycloak
|
||||
* - Verify existing Keycloak users
|
||||
* - Skip profiles without a citizenId
|
||||
*/
|
||||
// @Post("ensure-users")
|
||||
async ensureAllUsers() {
|
||||
const result = await this.keycloakAttributeService.batchEnsureKeycloakUsers();
|
||||
return new HttpSuccess({
|
||||
message: "Batch ensure Keycloak users เสร็จสิ้น",
|
||||
...result,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear orphaned Keycloak users (Admin only)
|
||||
*
|
||||
* @summary Delete Keycloak users that are not in the database (ADMIN)
|
||||
*
|
||||
* @description
|
||||
* This endpoint will:
|
||||
* - Find users in Keycloak that are not referenced in Profile or ProfileEmployee tables
|
||||
* - Delete those orphaned users from Keycloak
|
||||
* - Skip protected users (super_admin, admin_issue)
|
||||
*
|
||||
* @param {request} request Request body containing skipUsernames array
|
||||
*/
|
||||
// @Post("clear-orphaned-users")
|
||||
async clearOrphanedUsers(@Body() request?: { skipUsernames?: string[] }) {
|
||||
const skipUsernames = request?.skipUsernames || ["super_admin", "admin_issue"];
|
||||
const result = await this.keycloakAttributeService.clearOrphanedKeycloakUsers(skipUsernames);
|
||||
return new HttpSuccess({
|
||||
message: "Clear orphaned Keycloak users เสร็จสิ้น",
|
||||
...result,
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue