From c313da8d5cb729dba3fff70ebd8ef86cc5926df1 Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Thu, 7 May 2026 15:07:30 +0700 Subject: [PATCH] fix --- src/controllers/PermissionController.ts | 396 +++++++++++++++++++----- 1 file changed, 324 insertions(+), 72 deletions(-) diff --git a/src/controllers/PermissionController.ts b/src/controllers/PermissionController.ts index feb8d7a3..1116396c 100644 --- a/src/controllers/PermissionController.ts +++ b/src/controllers/PermissionController.ts @@ -289,7 +289,15 @@ export class PermissionController extends Controller { } } - let reply = await getAsync("menu_" + profile.id); + // Query ตำแหน่งรักษาการ + const actingData = await actingPositionService.getActingPositionsWithPrivilege( + profile.id, + orgRevision?.id + ); + + // ใช้ cache key แบบเดียวกับ getPermission + const cacheKey = `menu_${profile.id}_${actingData.isAct ? 'acting' : 'normal'}`; + let reply = await getAsync(cacheKey); if (reply != null) { reply = JSON.parse(reply); } else { @@ -325,10 +333,47 @@ export class PermissionController extends Controller { if (!authRole) { throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลสิทธิ์"); } - const roleAttrData = await this.authRoleAttrRepo.find({ + + // ดึง roleAttrData ของ user ปกติ + let roleAttrData = await this.authRoleAttrRepo.find({ select: ["authSysId", "parentNode"], where: { authRoleId: authRole.id, attrIsList: true }, }); + + // ถ้ามี acting positions ให้รวมสิทธิ์ + if (actingData.isAct && actingData.posMasterActs.length > 0) { + // ดึง authRoleId ของทุกตำแหน่งรักษาการ + const actingAuthRoleIds = await this.posMasterActRepo + .createQueryBuilder("posMasterAct") + .leftJoin("posMasterAct.posMaster", "posMaster") + .select("posMaster.authRoleId", "authRoleId") + .leftJoin("posMasterAct.posMasterChild", "posMasterChild") + .leftJoin("posMasterChild.current_holder", "profile") + .where("profile.id = :profileId", { profileId: profile.id }) + .andWhere("posMaster.orgRevisionId = :orgRevisionId", { orgRevisionId: orgRevision?.id }) + .getRawMany(); + + // ดึง AuthRoleAttr ทั้งหมดของ acting roles (เฉพาะที่มี attrIsList: true) + const actingRoleIds = actingAuthRoleIds.map(x => x.authRoleId).filter(id => id != null); + const actingRoleAttrs = await this.authRoleAttrRepo.find({ + select: ["authSysId", "parentNode"], + where: { authRoleId: In(actingRoleIds) as any, attrIsList: true }, + }); + + // รวม authSysId และ parentNode จาก acting เข้ากับ base + // สำหรับระบบที่มีในทั้งสอง ให้ใช้ค่าของ acting (parentNode) + for (const actingAttr of actingRoleAttrs) { + const existingIndex = roleAttrData.findIndex(x => x.authSysId === actingAttr.authSysId); + if (existingIndex >= 0) { + // ระบบนี้มีใน base ด้วย -> ใช้ parentNode ของ acting + roleAttrData[existingIndex].parentNode = actingAttr.parentNode; + } else { + // ระบบนี้มีเฉพาะใน acting -> เพิ่มเข้าไป + roleAttrData.push(actingAttr); + } + } + } + const parentNode = roleAttrData.map((x) => x.parentNode); const authSysId = roleAttrData.map((x) => x.authSysId); const sysId = parentNode.concat(authSysId); @@ -369,7 +414,7 @@ export class PermissionController extends Controller { }; }); - redisClient.setex("menu_" + profile.id, 86400, JSON.stringify(reply)); + redisClient.setex(cacheKey, 86400, JSON.stringify(reply)); } return new HttpSuccess(reply); @@ -824,17 +869,26 @@ export class PermissionController extends Controller { } } - let reply = await getAsync("role_" + profile.id); + // Query ตำแหน่งรักษาการ + const orgRevision = await this.orgRevisionRepository.findOne({ + select: ["id"], + where: { + orgRevisionIsDraft: false, + orgRevisionIsCurrent: true, + }, + }); + + const actingData = await actingPositionService.getActingPositionsWithPrivilege( + profile.id, + orgRevision?.id + ); + + // ใช้ cache key แบบเดียวกับ getPermission() + const cacheKey = `role_${profile.id}_${actingData.isAct ? 'acting' : 'normal'}`; + let reply = await getAsync(cacheKey); if (reply != null) { reply = JSON.parse(reply); } else { - const orgRevision = await this.orgRevisionRepository.findOne({ - select: ["id"], - where: { - orgRevisionIsDraft: false, - orgRevisionIsCurrent: true, - }, - }); let posMaster: any = await this.posMasterRepository.findOne({ select: ["authRoleId"], where: { @@ -878,11 +932,129 @@ export class PermissionController extends Controller { where: { authRoleId: getDetail.id }, }); - reply = { - ...getDetail, - roles: roleAttrData, - }; - redisClient.setex("role_" + profile.id, 86400, JSON.stringify(reply)); + // ถ้ามี acting positions ให้รวมสิทธิ์ + if (actingData.isAct && actingData.posMasterActs.length > 0) { + // ดึง authRoleId ของทุกตำแหน่งรักษาการ + const actingAuthRoleIds = await this.posMasterActRepo + .createQueryBuilder("posMasterAct") + .leftJoin("posMasterAct.posMaster", "posMaster") + .select("posMaster.authRoleId", "authRoleId") + .leftJoin("posMasterAct.posMasterChild", "posMasterChild") + .leftJoin("posMasterChild.current_holder", "profile") + .where("profile.id = :profileId", { profileId: profile.id }) + .andWhere("posMaster.orgRevisionId = :orgRevisionId", { orgRevisionId: orgRevision?.id }) + .getRawMany(); + + // ดึง AuthRoleAttr ทั้งหมดของ acting roles + const actingRoleIds = actingAuthRoleIds.map(x => x.authRoleId).filter(id => id != null); + const actingRoleAttrs = await this.authRoleAttrRepo.find({ + select: [ + "authSysId", + "parentNode", + "attrOwnership", + "attrIsCreate", + "attrIsList", + "attrIsGet", + "attrIsUpdate", + "attrIsDelete", + "attrPrivilege", + ], + where: { authRoleId: In(actingRoleIds) as any }, + }); + + // ลำดับความสำคัญของ privilege (มากไปน้อย) + const privilegePriority: Record = { + "OWNER": 7, + "PARENT": 6, + "ROOT": 5, + "BROTHER": 4, + "CHILD": 3, + "NORMAL": 2, + "SPECIFIC": 1, + "null": 0, + }; + + // ฟังก์ชันเปรียบเทียบ privilege + const getHigherPrivilege = (priv1: string | null, priv2: string | null): string | null => { + const p1 = priv1 ?? "null"; + const p2 = priv2 ?? "null"; + const priority1 = privilegePriority[p1] ?? 0; + const priority2 = privilegePriority[p2] ?? 0; + return priority1 >= priority2 ? priv1 : priv2; + }; + + // ฟังก์ชันเปรียบเทียบ ownership (OWNER > STAFF > null) + const getHigherOwnership = (own1: string | null, own2: string | null): string | null => { + if (own1 === "OWNER" || own2 === "OWNER") return "OWNER"; + if (own1 === "STAFF" || own2 === "STAFF") return "STAFF"; + return null; + }; + + // สร้าง map ของ authSysId -> สิทธิ์ที่ดีที่สุดจาก acting + const actingPermissionMap = new Map(); + + for (const attr of actingRoleAttrs) { + const key = attr.authSysId; + if (!actingPermissionMap.has(key)) { + actingPermissionMap.set(key, attr); + } else { + const existing = actingPermissionMap.get(key); + actingPermissionMap.set(key, { + ...attr, + attrIsCreate: existing.attrIsCreate || attr.attrIsCreate, + attrIsList: existing.attrIsList || attr.attrIsList, + attrIsGet: existing.attrIsGet || attr.attrIsGet, + attrIsUpdate: existing.attrIsUpdate || attr.attrIsUpdate, + attrIsDelete: existing.attrIsDelete || attr.attrIsDelete, + attrPrivilege: getHigherPrivilege(attr.attrPrivilege, existing.attrPrivilege), + parentNode: attr.parentNode, + attrOwnership: getHigherOwnership(attr.attrOwnership, existing.attrOwnership), + }); + } + } + + // รวมกับสิทธิ์พื้นฐานของ User + const mergedRoleAttrs = roleAttrData.map((baseAttr) => { + const actingAttr = actingPermissionMap.get(baseAttr.authSysId); + if (actingAttr) { + return { + ...baseAttr, + parentNode: actingAttr.parentNode, + attrOwnership: actingAttr.attrOwnership, + attrIsCreate: actingAttr.attrIsCreate, + attrIsList: actingAttr.attrIsList, + attrIsGet: actingAttr.attrIsGet, + attrIsUpdate: actingAttr.attrIsUpdate, + attrIsDelete: actingAttr.attrIsDelete, + attrPrivilege: actingAttr.attrPrivilege, + _isActing: true, + }; + } + return baseAttr; + }); + + // เพิ่มระบบที่มีเฉพาะใน acting roles + for (const [authSysId, actingAttr] of actingPermissionMap) { + if (!roleAttrData.find(a => a.authSysId === authSysId)) { + mergedRoleAttrs.push({ + ...actingAttr, + _isActing: true, + }); + } + } + + reply = { + ...getDetail, + roles: mergedRoleAttrs, + }; + } else { + reply = { + ...getDetail, + roles: roleAttrData, + }; + } + + redisClient.setex(cacheKey, 86400, JSON.stringify(reply)); } return reply; } @@ -932,77 +1104,157 @@ export class PermissionController extends Controller { } } - let reply = await getAsync("posMaster_" + profile.id); + // Query ตำแหน่งรักษาการ + const orgRevision = await this.orgRevisionRepository.findOne({ + select: ["id"], + where: { + orgRevisionIsDraft: false, + orgRevisionIsCurrent: true, + }, + }); + + const actingData = await actingPositionService.getActingPositionsWithPrivilege( + profile.id, + orgRevision?.id + ); + + // ใช้ cache key แบบใหม่ + const cacheKey = `posMaster_${profile.id}_${actingData.isAct ? 'acting' : 'normal'}`; + let reply = await getAsync(cacheKey); if (reply != null) { reply = JSON.parse(reply); } else { let privilege = await this.Permission(request, system, action); - const orgRevision = await this.orgRevisionRepository.findOne({ - select: ["id"], - where: { - orgRevisionIsDraft: false, - orgRevisionIsCurrent: true, - }, - }); - if (profileType == "OFFICER") { - const posMaster = await this.posMasterRepository.findOne({ - where: { - current_holderId: profile.id, - orgRevisionId: orgRevision?.id, - }, - }); - if (!posMaster) { + + // ถ้ากำลังรักษาการ ให้ดึง org จาก acting position + if (actingData.isAct) { + // ดึงข้อมูล permission เพื่อเช็คว่าระบบนี้มาจาก acting หรือไม่ + const permData: any = await this.getPermissionFunc(request); + const role = permData.roles.find((r: any) => r.authSysId === system); + + if (role && role._isActing) { + // ระบบนี้มาจาก acting position ดึง org จาก acting + const actingOrgData = await this.getActingOrgScope(profile.id, orgRevision?.id, system, profileType); reply = { - orgRootId: null, - orgChild1Id: null, - orgChild2Id: null, - orgChild3Id: null, - orgChild4Id: null, + orgRootId: actingOrgData.orgRootId, + orgChild1Id: actingOrgData.orgChild1Id, + orgChild2Id: actingOrgData.orgChild2Id, + orgChild3Id: actingOrgData.orgChild3Id, + orgChild4Id: actingOrgData.orgChild4Id, privilege: privilege, }; } else { - reply = { - orgRootId: posMaster.orgRootId, - orgChild1Id: posMaster.orgChild1Id, - orgChild2Id: posMaster.orgChild2Id, - orgChild3Id: posMaster.orgChild3Id, - orgChild4Id: posMaster.orgChild4Id, - privilege: privilege, - }; + // ระบบนี้มาจากตำแหน่งปกติ ใช้ org ปกติ + reply = await this.getBaseOrgScope(profile.id, orgRevision?.id, profileType, privilege); } - redisClient.setex("posMaster_" + profile.id, 86400, JSON.stringify(reply)); } else { - const posMaster = await this.posMasterEmpRepository.findOne({ - where: { - current_holderId: profile.id, - orgRevisionId: orgRevision?.id, - }, - }); - if (!posMaster) { - reply = { - orgRootId: null, - orgChild1Id: null, - orgChild2Id: null, - orgChild3Id: null, - orgChild4Id: null, - privilege: privilege, - }; - } else { - reply = { - orgRootId: posMaster.orgRootId, - orgChild1Id: posMaster.orgChild1Id, - orgChild2Id: posMaster.orgChild2Id, - orgChild3Id: posMaster.orgChild3Id, - orgChild4Id: posMaster.orgChild4Id, - privilege: privilege, - }; - } - redisClient.setex("posMaster_" + profile.id, 86400, JSON.stringify(reply)); + // ไม่มี acting ใช้ org ปกติ + reply = await this.getBaseOrgScope(profile.id, orgRevision?.id, profileType, privilege); } + + redisClient.setex(cacheKey, 86400, JSON.stringify(reply)); } return reply; } + // Helper method: ดึง org scope จากตำแหน่งปกติ + private async getBaseOrgScope(profileId: string, orgRevisionId: string | undefined, profileType: string, privilege: any) { + if (profileType == "OFFICER") { + const posMaster = await this.posMasterRepository.findOne({ + where: { + current_holderId: profileId, + orgRevisionId: orgRevisionId, + }, + }); + if (!posMaster) { + return { + orgRootId: null, + orgChild1Id: null, + orgChild2Id: null, + orgChild3Id: null, + orgChild4Id: null, + privilege: privilege, + }; + } else { + return { + orgRootId: posMaster.orgRootId, + orgChild1Id: posMaster.orgChild1Id, + orgChild2Id: posMaster.orgChild2Id, + orgChild3Id: posMaster.orgChild3Id, + orgChild4Id: posMaster.orgChild4Id, + privilege: privilege, + }; + } + } else { + const posMaster = await this.posMasterEmpRepository.findOne({ + where: { + current_holderId: profileId, + orgRevisionId: orgRevisionId, + }, + }); + if (!posMaster) { + return { + orgRootId: null, + orgChild1Id: null, + orgChild2Id: null, + orgChild3Id: null, + orgChild4Id: null, + privilege: privilege, + }; + } else { + return { + orgRootId: posMaster.orgRootId, + orgChild1Id: posMaster.orgChild1Id, + orgChild2Id: posMaster.orgChild2Id, + orgChild3Id: posMaster.orgChild3Id, + orgChild4Id: posMaster.orgChild4Id, + privilege: privilege, + }; + } + } + } + + // Helper method: ดึง org scope จาก acting position ที่มีสิทธิ์ในระบบนั้น + private async getActingOrgScope(profileId: string, orgRevisionId: string | undefined, system: string, profileType: string) { + const repo = profileType === "OFFICER" ? this.posMasterRepository : this.posMasterEmpRepository; + + const actingOrgData = await this.posMasterActRepo + .createQueryBuilder("posMasterAct") + .leftJoin("posMasterAct.posMaster", "posMaster") + .select([ + "posMaster.orgRootId", + "posMaster.orgChild1Id", + "posMaster.orgChild2Id", + "posMaster.orgChild3Id", + "posMaster.orgChild4Id", + ]) + .leftJoin("posMasterAct.posMasterChild", "posMasterChild") + .leftJoin("posMasterChild.current_holder", "profile") + .where("profile.id = :profileId", { profileId }) + .andWhere("posMaster.orgRevisionId = :orgRevisionId", { orgRevisionId }) + .orderBy("posMasterAct.posMasterOrder", "ASC") + .getRawOne(); + + if (!actingOrgData) { + // ไม่พบ acting position คืนค่า null + return { + orgRootId: null, + orgChild1Id: null, + orgChild2Id: null, + orgChild3Id: null, + orgChild4Id: null, + }; + } + + return { + orgRootId: actingOrgData.orgRootId, + orgChild1Id: actingOrgData.orgChild1Id, + orgChild2Id: actingOrgData.orgChild2Id, + orgChild3Id: actingOrgData.orgChild3Id, + orgChild4Id: actingOrgData.orgChild4Id, + }; + } + public async PermissionOrg(req: RequestWithUser, system: string, action: string) { let x: any = await this.listAuthSysOrgFunc(req, system, action); let privilege = x.privilege;