From b071bc2d924977c84d0f10965e14d7b20f989f7f Mon Sep 17 00:00:00 2001 From: waruneeauy Date: Thu, 21 May 2026 11:44:28 +0700 Subject: [PATCH] api service add filter by dnaId of Profile --- src/controllers/ApiWebServiceController.ts | 106 +++++++++++++++++++++ src/middlewares/authWebService.ts | 18 +++- src/middlewares/user.ts | 6 ++ 3 files changed, 129 insertions(+), 1 deletion(-) diff --git a/src/controllers/ApiWebServiceController.ts b/src/controllers/ApiWebServiceController.ts index 8a1e87be..7c09fe95 100644 --- a/src/controllers/ApiWebServiceController.ts +++ b/src/controllers/ApiWebServiceController.ts @@ -20,6 +20,7 @@ export class ApiWebServiceController extends Controller { private apiNameRepository = AppDataSource.getRepository(ApiName); private orgRevisionRepository = AppDataSource.getRepository(OrgRevision); private apiHistoryRepository = AppDataSource.getRepository(ApiHistory); + private currentRevisionId: string = ""; // การแทนที่ฟิลด์ ID ด้วยฟิลด์ Name สำหรับ Profile entity private readonly PROFILE_FIELD_REPLACEMENTS: Record< @@ -68,6 +69,82 @@ export class ApiWebServiceController extends Controller { }, }; + /** + * build posMaster permission condition + * @summary สร้างเงื่อนไขการกรองข้อมูลตามสิทธิ์การเข้าถึง + */ + private buildPosMasterPermissionCondition( + accessType: string | undefined, + dnaIds: { + dnaRootId?: string | null; + dnaChild1Id?: string | null; + dnaChild2Id?: string | null; + dnaChild3Id?: string | null; + dnaChild4Id?: string | null; + }, + ): string { + // ALL - no filtering + if (accessType === "ALL") { + return "1=1"; + } + + // No access type specified but has DNA IDs - default to NORMAL behavior + const conditions: string[] = []; + + if (accessType === "ROOT" && dnaIds.dnaRootId) { + // All organizations under this root + conditions.push( + `posMaster.orgRootId IN (SELECT id FROM orgRoot WHERE orgRevisionId = "${this.currentRevisionId}" AND ancestorDNA LIKE "${dnaIds.dnaRootId}%")`, + ); + } else if (accessType === "CHILD" || accessType === "NORMAL") { + // Build conditions based on which DNA level is specified + if (dnaIds.dnaChild4Id) { + conditions.push( + `posMaster.orgChild4Id IN (SELECT id FROM orgChild4 WHERE orgRevisionId = "${this.currentRevisionId}" AND ancestorDNA = "${dnaIds.dnaChild4Id}")`, + ); + } else if (dnaIds.dnaChild3Id) { + conditions.push( + `posMaster.orgChild3Id IN (SELECT id FROM orgChild3 WHERE orgRevisionId = "${this.currentRevisionId}" AND ancestorDNA = "${dnaIds.dnaChild3Id}")`, + ); + // For CHILD type, include all descendants + if (accessType === "CHILD") { + conditions.push( + `(posMaster.orgChild3Id IN (SELECT id FROM orgChild3 WHERE orgRevisionId = "${this.currentRevisionId}" AND ancestorDNA LIKE "${dnaIds.dnaChild3Id}%") OR posMaster.orgChild4Id IS NOT NULL)`, + ); + } + } else if (dnaIds.dnaChild2Id) { + conditions.push( + `posMaster.orgChild2Id IN (SELECT id FROM orgChild2 WHERE orgRevisionId = "${this.currentRevisionId}" AND ancestorDNA = "${dnaIds.dnaChild2Id}")`, + ); + if (accessType === "CHILD") { + conditions.push( + `(posMaster.orgChild2Id IN (SELECT id FROM orgChild2 WHERE orgRevisionId = "${this.currentRevisionId}" AND ancestorDNA LIKE "${dnaIds.dnaChild2Id}%") OR posMaster.orgChild3Id IS NOT NULL)`, + ); + } + } else if (dnaIds.dnaChild1Id) { + conditions.push( + `posMaster.orgChild1Id IN (SELECT id FROM orgChild1 WHERE orgRevisionId = "${this.currentRevisionId}" AND ancestorDNA = "${dnaIds.dnaChild1Id}")`, + ); + if (accessType === "CHILD") { + conditions.push( + `(posMaster.orgChild1Id IN (SELECT id FROM orgChild1 WHERE orgRevisionId = "${this.currentRevisionId}" AND ancestorDNA LIKE "${dnaIds.dnaChild1Id}%") OR posMaster.orgChild2Id IS NOT NULL)`, + ); + } + } else if (dnaIds.dnaRootId) { + conditions.push( + `posMaster.orgRootId IN (SELECT id FROM orgRoot WHERE orgRevisionId = "${this.currentRevisionId}" AND ancestorDNA = "${dnaIds.dnaRootId}")`, + ); + if (accessType === "CHILD") { + conditions.push( + `(posMaster.orgRootId IN (SELECT id FROM orgRoot WHERE orgRevisionId = "${this.currentRevisionId}" AND ancestorDNA LIKE "${dnaIds.dnaRootId}%") OR posMaster.orgChild1Id IS NOT NULL)`, + ); + } + } + } + + return conditions.length > 0 ? `(${conditions.join(" OR ")})` : "1=1"; + } + /** * list fields by systems * @summary รายการ fields ตาม systems @@ -125,6 +202,29 @@ export class ApiWebServiceController extends Controller { condition = `PosMaster.orgRevisionId = "${revision?.id}"`; } + let posMasterCondition: string = ""; + + // Special handling for Profile system with permission filtering + if (system == "registry") { + // Get current revision + const revision = await this.orgRevisionRepository.findOne({ + select: ["id"], + where: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false }, + }); + + // Store for use in permission building + this.currentRevisionId = revision?.id || ""; + + // Build permission condition + posMasterCondition = this.buildPosMasterPermissionCondition(request.user.accessType, { + dnaRootId: request.user.dnaRootId, + dnaChild1Id: request.user.dnaChild1Id, + dnaChild2Id: request.user.dnaChild2Id, + dnaChild3Id: request.user.dnaChild3Id, + dnaChild4Id: request.user.dnaChild4Id, + }); + } + const repo = AppDataSource.getRepository(tbMain); const metadata = repo.metadata; @@ -178,6 +278,11 @@ export class ApiWebServiceController extends Controller { }); } + // join กับ posMaster สำหรับ Profile เพื่อกรองตามสิทธิ์การเข้าถึง + if (tbMain === "Profile" && posMasterCondition !== "1=1") { + queryBuilder.leftJoin("Profile.current_holders", "posMaster"); + } + // // เพิ่ม Main.id เพราะจะใช้ pk ในการแมบและนับจำนวน // if (!propertyKey.includes(`${Main}.id`)) { // propertyKey.push(`${Main}.id`); @@ -196,6 +301,7 @@ export class ApiWebServiceController extends Controller { const [items, total] = await queryBuilder .select(propertyKey) .where(condition) + .andWhere(posMasterCondition) .orderBy(propertyKey[0], "ASC") .skip(offset) .take(pageSize) diff --git a/src/middlewares/authWebService.ts b/src/middlewares/authWebService.ts index fa50b3fe..1f17b9cf 100644 --- a/src/middlewares/authWebService.ts +++ b/src/middlewares/authWebService.ts @@ -17,7 +17,17 @@ export async function handleWebServiceAuth(request: express.Request) { // ตรวจสอบ API Key กับฐานข้อมูล const apiKeyData = await AppDataSource.getRepository(ApiKey).findOne({ - select: { id: true, name: true, keyApi: true }, + select: { + id: true, + name: true, + keyApi: true, + accessType: true, + dnaRootId: true, + dnaChild1Id: true, + dnaChild2Id: true, + dnaChild3Id: true, + dnaChild4Id: true, + }, where: { keyApi: apiKey }, relations: ["apiNames"], }); @@ -40,6 +50,12 @@ export async function handleWebServiceAuth(request: express.Request) { name: apiKeyData.name, type: "web-service", accessApi: apiKeyData.apiNames.map((x) => x.id) ?? [], + accessType: apiKeyData.accessType, + dnaRootId: apiKeyData.dnaRootId, + dnaChild1Id: apiKeyData.dnaChild1Id, + dnaChild2Id: apiKeyData.dnaChild2Id, + dnaChild3Id: apiKeyData.dnaChild3Id, + dnaChild4Id: apiKeyData.dnaChild4Id, }; } diff --git a/src/middlewares/user.ts b/src/middlewares/user.ts index 75c84d01..09e32ef9 100644 --- a/src/middlewares/user.ts +++ b/src/middlewares/user.ts @@ -25,5 +25,11 @@ export type RequestWithUserWebService = Request & { id: string; name: string; accessApi: string[]; + accessType?: string; + dnaRootId?: string | null; + dnaChild1Id?: string | null; + dnaChild2Id?: string | null; + dnaChild3Id?: string | null; + dnaChild4Id?: string | null; }; };