UNPKG

@tomei/sso

Version:
1,710 lines (1,523 loc) 68.5 kB
import { ClassError, ObjectBase, TreeNodeBase } from '@tomei/general'; import { GroupRepository } from './group.repository'; import { IGroupAttr } from '../../interfaces/group.interface'; import { GroupTypeEnum } from '../../enum'; import { LoginUser } from '../login-user/login-user'; import { IGroupSearchAttr } from '../../interfaces/group-search-attr.interface'; import { ApplicationConfig } from '@tomei/config'; import { Op, Transaction } from 'sequelize'; import { ActionEnum, Activity } from '@tomei/activity-history'; import { GroupSystemAccessRepository } from '../group-system-access/group-system-access.repository'; import SystemModel from '../../models/system.entity'; import { GroupSystemAccess } from '../group-system-access'; import { RedisService } from '../../redis-client/redis.service'; import SystemPrivilegeModel from '../../models/system-privilege.entity'; import { GroupPrivilegeRepository } from '../group-privilege/group-privilege.repository'; import { SystemPrivilege } from '../system-privilege/system-privilege'; import GroupPrivilegeModel from '../../models/group-privilege.entity'; import { GroupObjectPrivilegeRepository } from '../group-object-privilege/group-object-privilege.repository'; import { GroupObjectPrivilege } from '../group-object-privilege/group-object-privilege'; import { GroupPrivilege } from '../group-privilege/group-privilege'; import { User } from '../login-user/user'; import GroupReportingUserModel from '../../models/group-reporting-user.entity'; import GroupModel from '../../models/group.entity'; import UserModel from '../../models/user.entity'; import { UserGroup } from '../user-group/user-group'; export class Group extends TreeNodeBase<Group> { ObjectId: string; ObjectName: string; TableName: 'sso_Group'; ObjectType = 'Group'; Name: string; Description: string; Type: GroupTypeEnum; ParentGroupCode: string; InheritParentPrivilegeYN: string; InheritParentSystemAccessYN: string; Status: string; ParentGroup?: any; _Path: string = ''; isChildrenLoaded = false; isParentLoaded = false; private _CreatedById: number; private _CreatedAt: Date; private _UpdatedById: number; private _UpdatedAt: Date; private static _Repo = new GroupRepository(); private static _GroupSystemAccessRepo = new GroupSystemAccessRepository(); private static _GroupPrivilegeRepo = new GroupPrivilegeRepository(); private static _GroupObjectPrivilegeRepo = new GroupObjectPrivilegeRepository(); private static _RedisService: RedisService; get GroupCode(): string { return this.ObjectId; } set GroupCode(value: string) { this.ObjectId = value; } get CreatedById(): number { return this._CreatedById; } get CreatedAt(): Date { return this._CreatedAt; } get UpdatedById(): number { return this._UpdatedById; } get UpdatedAt(): Date { return this._UpdatedAt; } get Path(): string { return this._Path; } set Path(value: string) { this._Path = value; } private constructor(groupAttr?: IGroupAttr) { super(); if (groupAttr) { this.GroupCode = groupAttr.GroupCode; this.Name = groupAttr.Name; this.Description = groupAttr?.Description; this.Type = groupAttr?.Type; this.ParentGroupCode = groupAttr?.ParentGroupCode; this.InheritParentPrivilegeYN = groupAttr?.InheritParentPrivilegeYN; this.InheritParentSystemAccessYN = groupAttr?.InheritParentSystemAccessYN; this.Status = groupAttr?.Status; this._Path = groupAttr?.Path; this._CreatedById = groupAttr.CreatedById; this._CreatedAt = groupAttr.CreatedAt; this._UpdatedById = groupAttr.UpdatedById; this._UpdatedAt = groupAttr.UpdatedAt; } } public static async init(dbTransaction: any, GroupCode?: string) { try { Group._RedisService = await RedisService.init(); if (GroupCode) { const group = await Group._Repo.findByPk(GroupCode, { transaction: dbTransaction, }); if (group) { return new Group(group); } else { throw Error('Group not found'); } } return new Group(); } catch (error) { throw new ClassError( 'Group', 'GroupErrMsg01', 'Failed To Initialize Group', ); } } async loadChildren(dbTransaction?: any) { if (!this.GroupCode) { throw Error('GroupCode is missing.'); } const children = await Group._Repo.findAll({ where: { ParentGroupCode: this.GroupCode }, order: [['CreatedAt', 'ASC']], transaction: dbTransaction, }); this.children = children.map((child) => { return new Group(child.get({ plain: true })); }); this.isChildrenLoaded = true; } async loadParent(dbTransaction?: any) { if (!this.GroupCode) { throw Error('GroupCode are missing.'); } if (this.ParentGroupCode) { if (this.ParentGroupCode !== this.GroupCode) { const parent = await Group._Repo.findByPk(this.ParentGroupCode, { transaction: dbTransaction, }); this.parent = new Group(parent.get({ plain: true })); } } this.isParentLoaded = true; } async isLeaf(dbTransaction?: any): Promise<boolean> { if (!this.isChildrenLoaded) { await this.loadChildren(dbTransaction); } return this.children.length === 0; } async getPath(dbTransaction?: any): Promise<string> { if (!this.isParentLoaded) { await this.loadParent(dbTransaction); } if (this.parent) { this._Path = (await this.parent.getPath(dbTransaction)) + '/' + this.GroupCode; return this._Path; } this._Path = this.GroupCode; return this._Path; } protected async updatePath(dbTransaction?: any): Promise<void> { const path = await this.getPath(dbTransaction); this._Path = path; } async setParent(parent: Group, dbTransaction?: any): Promise<void> { this.parent = parent; await this.updatePath(dbTransaction); } async getPathDetail(dbTransaction?: any): Promise<Group[]> { const path = this._Path.split('/'); const groups: Group[] = []; for (let i = 0; i < path.length; i++) { const group = await Group.init(dbTransaction, path[i]); groups.push(group); } return groups; } public static async findAll( page: number, row: number, dbTransaction: any, loginUser: LoginUser, search?: IGroupSearchAttr, ) { //This method will list all group based on the query params. //Part 1: Privilege Checking const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'GROUP_LIST', ); if (!isPrivileged) { throw new ClassError( 'Group', 'GroupErrMsg04', 'User is not privileged to list group', ); } //Part 2: Retrieve listing const queryObj: any = {}; let options: any = { transaction: dbTransaction, }; if (page && row) { options = { ...options, limit: row, offset: row * (page - 1), order: [['CreatedAt', 'DESC']], distinct: true, }; } if (search) { Object.entries(search).forEach(([key, value]) => { queryObj[key] = { [Op.substring]: value, }; }); options = { ...options, where: queryObj, }; const result = await Group._Repo.findAllWithPagination(options); //Map the result to Group instance return { Count: result.count, Groups: result.rows.map( (group) => new Group(group.get({ plain: true })), ), }; } } public static async create( loginUser: LoginUser, dbTransaction: any, group: Group, ) { try { //Part 1: Privilege Checking const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'GROUP_CREATE', ); if (!isPrivileged) { throw new Error('You do not have permission to create group'); } //Part 2: Validation if (!group.GroupCode) { throw new ClassError( 'Group', 'GroupErrMsg02', 'Group Code is required', ); } if (!group.Name) { throw new ClassError( 'Group', 'GroupErrMsg02', 'Group Name is required', ); } if (!group.Type) { throw new ClassError( 'Group', 'GroupErrMsg02', 'Group Type is required', ); } //Check if group code is unique const existingGroupCode = await Group._Repo.findByPk(group.GroupCode, { transaction: dbTransaction, }); if (existingGroupCode) { throw new ClassError( 'Group', 'GroupErrMsg03', 'Duplicate GroupCode found.', ); } //Validate parent group code if passed. Call Group._Repo.findByPk if (group.ParentGroupCode) { const parentGroup = await Group._Repo.findByPk(group.ParentGroupCode, { transaction: dbTransaction, }); if (!parentGroup) { throw new ClassError( 'Group', 'GroupErrMsg04', 'ParentGroupCode is not found.', ); } //If Params.group.GroupCode = Params.group?.ParentGroupCode, throw new ClassError if (group.GroupCode === group.ParentGroupCode) { throw new ClassError( 'Group', 'GroupErrMsg05', 'GroupCode and ParentGroupCode cannot be the same.', ); } } //Part 3: Create Group //Initialise new Group instance and populate const newGroup = new Group(group); newGroup.ObjectId = group.GroupCode; newGroup.Name = group.Name; newGroup.Type = group.Type; newGroup.Description = group.Description; newGroup.ParentGroupCode = group.ParentGroupCode; newGroup.InheritParentPrivilegeYN = group.InheritParentPrivilegeYN; newGroup.InheritParentSystemAccessYN = group.InheritParentSystemAccessYN; newGroup.Status = 'Active'; newGroup._CreatedById = loginUser.UserId; newGroup._UpdatedById = loginUser.UserId; newGroup._Path = await newGroup.getPath(dbTransaction); //Call Group._Repo create method const entityGroupAfter = { GroupCode: newGroup.ObjectId, Name: newGroup.Name, Type: newGroup.Type, Description: newGroup.Description, ParentGroupCode: newGroup.ParentGroupCode, InheritParentPrivilegeYN: newGroup.InheritParentPrivilegeYN, InheritParentSystemAccessYN: newGroup.InheritParentSystemAccessYN, Path: newGroup._Path, Status: newGroup.Status, CreatedById: newGroup._CreatedById, UpdatedById: newGroup._UpdatedById, CreatedAt: newGroup._CreatedAt, UpdatedAt: newGroup._UpdatedAt, }; await Group._Repo.create(entityGroupAfter, { transaction: dbTransaction, }); //Part 4: Record Create Group Activity and return newGroup const entityValueBefore = {}; //Instantiate new activity const activity = new Activity(); activity.ActivityId = activity.createId(); activity.Action = ActionEnum.CREATE; activity.Description = 'Create Group'; activity.EntityType = 'Group'; activity.EntityId = newGroup.ObjectId; activity.EntityValueBefore = JSON.stringify(entityValueBefore); activity.EntityValueAfter = JSON.stringify(entityGroupAfter); //Call Activity.create method await activity.create(loginUser.ObjectId, dbTransaction); return newGroup; } catch (error) { throw error; } } protected static async checkDuplicateGroupCode( dbTransaction: any, GroupCode, ) { const isGroupCodeExist = await Group._Repo.findOne({ where: { GroupCode }, transaction: dbTransaction, }); if (isGroupCodeExist) { throw new ClassError( 'Group', 'GroupErrMsg07', 'GroupCode already exists.', ); } } private async updateChildrenPath(oldGroupCode: string, dbTransaction: any) { try { const isLeaf = await this.isLeaf(dbTransaction); if (isLeaf) { return; } const childrens = await Group._Repo.findAll({ where: { Path: { [Op.like]: `${oldGroupCode}/%`, }, }, transaction: dbTransaction, }); childrens.forEach(async (children) => { //Break the path into array with oldGroupCode/ as separator; const path = children.Path.split(`${oldGroupCode}/`); //Retrive the last element of the array const childPath = path[1]; //Combine the childPath with this.Path then save it to the children.Path await children.update( { Path: `${this._Path}/${childPath}` }, { transaction: dbTransaction }, ); }); } catch (error) { throw error; } } public async update( loginUser: LoginUser, dbTransaction: any, group: { GroupCode: string; NewGroupCode?: string; Name: string; Description: string; Type: GroupTypeEnum; ParentGroupCode: string; InheritParentPrivilegeYN: string; InheritParentSystemAccessYN: string; Status: string; }, ) { //Part 1: Privilege Checking const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'GROUP_UPDATE', ); if (!isPrivileged) { throw new ClassError( 'Group', 'GroupErrMsg06', 'You do not have the privilege to update Group', ); } try { if (group.NewGroupCode) { await Group.checkDuplicateGroupCode(dbTransaction, group.NewGroupCode); } const entityValueBefore = { GroupCode: this.GroupCode, Name: this.Name, Type: this.Type, Description: this.Description, ParentGroupCode: this.ParentGroupCode, InheritParentPrivilegeYN: this.InheritParentPrivilegeYN, InheritParentSystemAccessYN: this.InheritParentSystemAccessYN, Path: this.Path, Status: this.Status, CreatedById: this._CreatedById, UpdatedById: this._UpdatedById, CreatedAt: this._CreatedAt, UpdatedAt: this._UpdatedAt, }; let isPathChanged = false; const oldGroupCode = this.GroupCode; if (group.NewGroupCode) { this.GroupCode = group.NewGroupCode; isPathChanged = true; } //Check if ParentGroupCode is changed or added if ( (group.ParentGroupCode && this.ParentGroupCode !== group.ParentGroupCode) || (group.ParentGroupCode && !this.ParentGroupCode) ) { const parentGroup = await Group.init( dbTransaction, group.ParentGroupCode, ); if (!parentGroup) { throw new ClassError( 'Group', 'GroupErrMsg08', 'Parent Group Code not found', ); } await this.setParent(parentGroup); //Check if ParentGroupCode is removed isPathChanged = true; } else if (!group.ParentGroupCode && this.ParentGroupCode) { await this.setParent(null); isPathChanged = true; } if (isPathChanged) { await this.updateChildrenPath(oldGroupCode, dbTransaction); } this.Name = group?.Name || this.Name; this.Type = group?.Type || this.Type; this.Description = group?.Description || this.Description; this.ParentGroupCode = group?.ParentGroupCode || this.ParentGroupCode; this.InheritParentPrivilegeYN = group?.InheritParentPrivilegeYN || this.InheritParentPrivilegeYN; this.InheritParentSystemAccessYN = group?.InheritParentSystemAccessYN || this.InheritParentSystemAccessYN; this.Status = group?.Status || this.Status; this._UpdatedById = loginUser.UserId; this._UpdatedAt = new Date(); await Group._Repo.update( { GroupCode: this.GroupCode, Name: this.Name, Type: this.Type, Description: this.Description, ParentGroupCode: this.ParentGroupCode, InheritParentPrivilegeYN: this.InheritParentPrivilegeYN, InheritParentSystemAccessYN: this.InheritParentSystemAccessYN, Status: this.Status, Path: this._Path, UpdatedById: this._UpdatedById, UpdatedAt: this._UpdatedAt, }, { where: { GroupCode: group.GroupCode, }, transaction: dbTransaction, }, ); const entityValueAfter = { GroupCode: this.GroupCode, Name: this.Name, Type: this.Type, Description: this.Description, ParentGroupCode: this.ParentGroupCode, InheritParentPrivilegeYN: this.InheritParentPrivilegeYN, InheritParentSystemAccessYN: this.InheritParentSystemAccessYN, Status: this.Status, Path: this._Path, CreatedById: this._CreatedById, UpdatedById: this._UpdatedById, CreatedAt: this._CreatedAt, UpdatedAt: this._UpdatedAt, }; const activity = new Activity(); activity.ActivityId = activity.createId(); activity.Action = ActionEnum.UPDATE; activity.Description = `Update Group ${group.Type}`; activity.EntityType = 'Group'; activity.EntityId = group.GroupCode; activity.EntityValueBefore = JSON.stringify(entityValueBefore); activity.EntityValueAfter = JSON.stringify(entityValueAfter); await activity.create(loginUser.ObjectId, dbTransaction); return this; } catch (error) { throw error; } } public static async delete( loginUser: LoginUser, dbTransaction: any, GroupCode: string, ) { // Part 1: Privilege Checking const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'GROUP_DELETE', ); if (!isPrivileged) { throw new ClassError( 'Group', 'GroupErrMsg03', 'You do not have the privilege to delete groups records.', ); } try { const group = await Group.init(dbTransaction, GroupCode); if (group.Status === 'Active') { throw new ClassError( 'Group', 'GroupErrMsg03', 'Active Group cant be deleted', ); } const relatedGroup = await Group.findAll( 1, Number.MAX_SAFE_INTEGER, dbTransaction, loginUser, { ParentGroupCode: GroupCode, }, ); if (relatedGroup.Count > 0) { const listOfRelatedGroup = relatedGroup.Groups.map((group) => { return group.GroupCode; }); throw new ClassError( 'Group', 'GroupErrMsg03', `Group still has associated user group ${listOfRelatedGroup}`, ); } await Group._Repo.delete(GroupCode, dbTransaction); const EntityValueBefore = { GroupCode: group.GroupCode, Name: group.Name, Type: group.Type, Description: group.Description, ParentGroupCode: group.ParentGroupCode, InheritParentPrivilegeYN: group.InheritParentPrivilegeYN, InheritParentSystemAccessYN: group.InheritParentSystemAccessYN, Status: group.Status, CreatedById: group._CreatedById, UpdatedById: group._UpdatedById, CreatedAt: group._CreatedAt, UpdatedAt: group._UpdatedAt, }; const activity = new Activity(); activity.ActivityId = activity.createId(); activity.Action = ActionEnum.DELETE; activity.Description = 'Delete Group'; activity.EntityType = 'Group'; activity.EntityId = group.ObjectId; activity.EntityValueBefore = JSON.stringify(EntityValueBefore); activity.EntityValueAfter = JSON.stringify({}); await activity.create(loginUser.ObjectId, dbTransaction); return { Message: 'Group removed.' }; } catch (error) { throw error; } } public static async getSystemAccesses( loginUser: LoginUser, dbTransaction: any, GroupCode: string, Page: number, Rows: number, Search: { SystemCode?: string; Status?: string; }, ) { // Part 1: Privilege Checking const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'SYSTEM_ACCESS_VIEW', ); if (!isPrivileged) { throw new ClassError( 'Group', 'GroupErrMsg06', 'You do not have the privilege to view system access', ); } try { // Part 2: Validation await Group.init(dbTransaction, GroupCode); // Part 3: Retrieve System Access and returns const queryObj: any = { GroupCode: GroupCode }; if (Search) { Object.entries(Search).forEach(([key, value]) => { queryObj[key] = value; }); } let options: any = { where: queryObj, distinct: true, transaction: dbTransaction, }; if (Page && Rows) { options = { ...options, limit: Rows, offset: Rows * (Page - 1), order: [['CreatedAt', 'DESC']], }; } const systemAccess = await Group._GroupSystemAccessRepo.findAndCountAll(options); return systemAccess; } catch (error) { return error; } } public static async getSystemAccessRoles( loginUser: LoginUser, dbTransaction: any, SystemCode: string, Page: number, Rows: number, Search: { GroupCode?: string; Status?: string; }, ) { // Part 1: Privilege Checking const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'SYSTEM_ACCESS_VIEW', ); if (!isPrivileged) { throw new ClassError( 'Group', 'GroupErrMsg06', 'You do not have the privilege to view system access', ); } try { // Part 2: Retrieve System Access and returns const queryObj: any = { SystemCode: SystemCode }; if (Search) { Object.entries(Search).forEach(([key, value]) => { queryObj[key] = value; }); } let options: any = { where: queryObj, distinct: true, transaction: dbTransaction, }; if (Page && Rows) { options = { ...options, limit: Rows, offset: Rows * (Page - 1), order: [['CreatedAt', 'DESC']], include: { model: GroupModel, where: { Type: 'Role', }, }, }; } const systemAccess = await Group._GroupSystemAccessRepo.findAndCountAll(options); return systemAccess; } catch (error) { return error; } } private static async getInheritedSystemAccess( dbTransaction: any, group: Group, ): Promise<any[]> { const options: any = { where: { GroupCode: group.GroupCode, Status: 'Active', }, include: [ { model: SystemModel, }, ], transaction: dbTransaction, }; let systemAccess = await Group._GroupSystemAccessRepo.findAll(options); if (group.InheritParentSystemAccessYN === 'Y' && group.ParentGroupCode) { const parentGroup = await Group.init( dbTransaction, group.ParentGroupCode, ); const parentSystemAccesses = await this.getInheritedSystemAccess( dbTransaction, parentGroup, ); systemAccess = systemAccess.concat(parentSystemAccesses); } return systemAccess; } public static async isGroupCodeInHierarchy( dbTransaction: any, GroupCode: string, ListGroupCode: string[] = [], ): Promise<boolean> { ListGroupCode.push(GroupCode); const group = await Group._Repo.findOne({ where: { GroupCode }, transaction: dbTransaction, }); if (group?.ParentGroupCode) { const isGroupCodeExist = ListGroupCode.includes(group.ParentGroupCode); if (!isGroupCodeExist) { await this.isGroupCodeInHierarchy( dbTransaction, group.ParentGroupCode, ListGroupCode, ); } { return false; } } else { return true; } } public static async getParentSystemAccesses( loginUser: LoginUser, dbTransaction: any, GroupCode: string, ) { // Part 1: Privilege Checking const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'SYSTEM_ACCESS_VIEW', ); if (!isPrivileged) { throw new ClassError( 'Group', 'GroupErrMsg06', 'You do not have the privilege to view system access', ); } try { const group = await Group.init(dbTransaction, GroupCode); if (group.InheritParentSystemAccessYN !== 'Y' || !group.ParentGroupCode) { return []; } else { const parentGroup = await Group.init( dbTransaction, group.ParentGroupCode, ); const inheritSystemAccess = await Group.getInheritedSystemAccess( dbTransaction, parentGroup, ); return inheritSystemAccess; } } catch (error) { throw error; } } public static async addSystemAccesses( loginUser: LoginUser, dbTransaction: any, GroupCode: string, SystemCodes: string[], ) { // Part 1: Privilege Checking const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'SYSTEM_ACCESS_CREATE', ); if (!isPrivileged) { throw new ClassError( 'Group', 'GroupErrMsg07', 'You do not have the privilege to create system access', ); } try { if (SystemCodes.length > 0) { for (const element of SystemCodes) { const CurrentGroupSystemAccess = await Group.getSystemAccesses( loginUser, dbTransaction, GroupCode, 1, Number.MAX_SAFE_INTEGER, { SystemCode: element }, ); if (CurrentGroupSystemAccess?.count > 0) { throw new ClassError( 'Group', 'GroupErrMsg08', 'System access already exists', ); } const groupSystemAccess = await GroupSystemAccess.init(dbTransaction); groupSystemAccess.createId(); groupSystemAccess.GroupCode = GroupCode; groupSystemAccess.SystemCode = element; groupSystemAccess.Status = 'Active'; groupSystemAccess.CreatedById = +loginUser.ObjectId; groupSystemAccess.CreatedAt = new Date(); groupSystemAccess.UpdatedById = +loginUser.ObjectId; groupSystemAccess.UpdatedAt = new Date(); const EntityValueAfter = { GroupCode: groupSystemAccess.GroupCode, SystemCode: groupSystemAccess.SystemCode, Status: groupSystemAccess.Status, CreatedById: groupSystemAccess.CreatedById, CreatedAt: groupSystemAccess.CreatedAt, UpdatedById: groupSystemAccess.UpdatedById, UpdatedAt: groupSystemAccess.UpdatedAt, }; const systemAccess = await Group._GroupSystemAccessRepo.create( EntityValueAfter, { transaction: dbTransaction, }, ); const activity = new Activity(); activity.ActivityId = activity.createId(); activity.Action = ActionEnum.CREATE; activity.Description = 'Create Group System Access'; activity.EntityType = 'GroupSystemAccess'; activity.EntityId = systemAccess.GroupSystemAccessId?.toString(); activity.EntityValueBefore = JSON.stringify({}); activity.EntityValueAfter = JSON.stringify(EntityValueAfter); await activity.create(loginUser.ObjectId, dbTransaction); } return { Message: 'Successfully added.' }; } } catch (error) { throw error; } } public static async deleteSystemAccess( loginUser: LoginUser, dbTransaction: any, GroupCode: string, SystemCode: string, ) { // Part 1: Privilege Checking const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'SYSTEM_ACCESS_DELETE', ); if (!isPrivileged) { throw new ClassError( 'Group', 'GroupErrMsg08', 'You do not have the privilege to delete system access', ); } try { const currentGroupSystemAccess = await Group.getSystemAccesses( loginUser, dbTransaction, GroupCode, 1, Number.MAX_SAFE_INTEGER, { SystemCode: SystemCode }, ); if (currentGroupSystemAccess.count < 1) { throw new ClassError( 'Group', 'GroupErrMsg10', 'No associated system access found.', ); } await Group._GroupSystemAccessRepo.delete( GroupCode, SystemCode, dbTransaction, ); const EntityValueBefore = { GroupCode: currentGroupSystemAccess?.rows[0]?.GroupCode, SystemCode: currentGroupSystemAccess?.rows[0]?.SystemCode, Status: currentGroupSystemAccess?.rows[0]?.Status, CreatedById: currentGroupSystemAccess?.rows[0]?.CreatedById, CreatedAt: currentGroupSystemAccess?.rows[0]?.CreatedAt, UpdatedById: currentGroupSystemAccess?.rows[0]?.UpdatedById, UpdatedAt: currentGroupSystemAccess?.rows[0]?.UpdatedAt, }; const activity = new Activity(); activity.ActivityId = activity.createId(); activity.Action = ActionEnum.DELETE; activity.Description = 'Delete Group System Access'; activity.EntityType = 'GroupSystemAccess'; activity.EntityId = currentGroupSystemAccess?.rows[0]?.GroupSystemAccessId?.toString(); activity.EntityValueBefore = JSON.stringify(EntityValueBefore); activity.EntityValueAfter = JSON.stringify({}); await activity.create(loginUser.ObjectId, dbTransaction); return { Message: 'System access removed.', SystemCode: SystemCode }; } catch (error) { throw error; } } public static async getSystemPrivileges( loginUser: LoginUser, dbTransaction: any, GroupCode: string, search?: { SystemCode?: string; Status?: string; }, ) { try { //Part 1: Privilege Checking const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'GROUP_PRIVILEGE_VIEW', ); if (!isPrivileged) { throw new ClassError( 'Group', 'GroupErrMsg11', 'You do not have the privilege to view group privileges', ); } //Set group to instantiation of existing Group await Group.init(dbTransaction, GroupCode); //Part 3: Retrieve Group Own Privilege //Retrieve group data and it's privileged by calling Group._Repo.findAll let where: any = { GroupCode, }; let systemWhere: any = {}; if (search) { if (search.Status) { where = { ...where, Status: search.Status, }; } if (search.SystemCode) { systemWhere = { SystemCode: { [Op.substring]: search.SystemCode, }, }; } } const groupOwnPrivileges = await Group._GroupPrivilegeRepo.findAll({ where, include: [ { model: SystemPrivilegeModel, where: systemWhere, }, ], transaction: dbTransaction, }); //Create variable called privileges and Map the SystemPrivilege data retrieved from 3.1 into SystemPrivilege object and push it to the privileges variables const privileges: SystemPrivilege[] = []; for (const groupPrivilege of groupOwnPrivileges) { const systemPrivilege = await SystemPrivilege.init(dbTransaction); systemPrivilege.setAttributes( groupPrivilege.Privilege.get({ plain: true }), ); privileges.push(systemPrivilege); } return privileges; } catch (error) { throw error; } } public static async getSystemPrivilegeRoles( loginUser: LoginUser, dbTransaction: any, SystemCode: string, search?: { GroupCode?: string[]; Status?: string; }, ) { try { //Part 1: Privilege Checking const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'GROUP_PRIVILEGE_VIEW', ); if (!isPrivileged) { throw new ClassError( 'Group', 'GroupErrMsg11', 'You do not have the privilege to view group privileges', ); } //Part 2: Retrieve Roles Based on Privilege //Retrieve Roles based on privilege on a system let systemWhere: any = {}; if (SystemCode) { systemWhere = { SystemCode: { [Op.substring]: SystemCode, }, }; } const groupCodesPrivileges: { SystemPrivilegeId: string; GroupCodes: { Code: string; Name: string }[]; }[] = []; const allGroupCodePrivileges = await Group._GroupPrivilegeRepo.findAll({ include: [ { model: SystemPrivilegeModel, where: systemWhere, }, { model: GroupModel, where: { Type: 'Role', }, }, ], transaction: dbTransaction, }); // Use a Map to group by SystemPrivilegeId const privilegesMap = new Map<string, { Code: string; Name: string }[]>(); for (const groupCodePrivilege of allGroupCodePrivileges) { const { SystemPrivilegeId, GroupCode, Group } = groupCodePrivilege; // `Group` contains Name from GroupModel if (!privilegesMap.has(SystemPrivilegeId)) { // Initialize with an empty array if not already present privilegesMap.set(SystemPrivilegeId, []); } // Add the GroupCode and Name to the array if it exists and is not already present if (GroupCode && Group?.Name) { const groupCodes = privilegesMap.get(SystemPrivilegeId); const newGroupEntry = { Code: GroupCode, Name: Group.Name }; // Ensure no duplicates if ( groupCodes && !groupCodes.some( (g) => g.Code === GroupCode && g.Name === Group.Name, ) ) { groupCodes.push(newGroupEntry); } } } // Convert the Map to the desired array format privilegesMap.forEach((groupCodes, SystemPrivilegeId) => { groupCodesPrivileges.push({ SystemPrivilegeId, GroupCodes: groupCodes, }); }); const allPrivileges = await SystemPrivilegeModel.findAll({ where: systemWhere, transaction: dbTransaction, }); const groupPrivilegeRoles: { SystemPrivilegeId: string; PrivilegeCode: string; Description: string; GroupCodes: { Code: string; Name: string }[]; }[] = []; // Iterate through allPrivileges to check for matches in groupCodesPrivileges for (const privilege of allPrivileges) { const matchingGroupPrivilege = groupCodesPrivileges.find( (groupPrivilege) => groupPrivilege.SystemPrivilegeId === privilege.SystemPrivilegeId, ); if (matchingGroupPrivilege) { // If match is found, push to groupPrivilegeRoles with GroupCodes groupPrivilegeRoles.push({ SystemPrivilegeId: privilege.SystemPrivilegeId, PrivilegeCode: privilege.PrivilegeCode, Description: privilege.Description, GroupCodes: matchingGroupPrivilege.GroupCodes, }); } else { // If no match is found, push with an empty array of GroupCodes groupPrivilegeRoles.push({ SystemPrivilegeId: privilege.SystemPrivilegeId, PrivilegeCode: privilege.PrivilegeCode, Description: privilege.Description, GroupCodes: [], }); } } const filteredGroupPrivilegeRoles = groupPrivilegeRoles .map((role) => { if (search.GroupCode?.length) { // Filter GroupCodes to only include matching Codes const matchingGroupCodes = role.GroupCodes.filter((groupCode) => search.GroupCode.includes(groupCode.Code), ); // If there are no matching GroupCodes, exclude this role if (matchingGroupCodes.length === 0) { return null; } // Return the role with filtered GroupCodes return { ...role, GroupCodes: matchingGroupCodes, }; } // If search.GroupCode is not provided, include all data return role; }) .filter(Boolean); // Remove any null values return filteredGroupPrivilegeRoles; } catch (error) { throw error; } } public static async getInheritedSystemPrivileges( dbTransaction: any, GroupCode: string, search?: { SystemCode?: string; Status?: string; PrivilegeCode?: string; }, ): Promise<SystemPrivilege[]> { try { //Retrieve group data and it's privileges by calling Group._Repo.findAll const where: any = { GroupCode, }; let groupPrivilegeWhere: any = {}; let systemPrivilegeWhere: any = {}; if (search) { if (search.Status) { groupPrivilegeWhere = { Status: search.Status, }; } if (search.SystemCode) { systemPrivilegeWhere = { SystemCode: { [Op.substring]: search.SystemCode, }, }; } if (search.PrivilegeCode) { systemPrivilegeWhere = { ...systemPrivilegeWhere, PrivilegeCode: { [Op.substring]: search.PrivilegeCode, }, }; } } const group = await Group._Repo.findOne({ where: where, include: [ { model: GroupPrivilegeModel, where: groupPrivilegeWhere, separate: true, include: [ { model: SystemPrivilegeModel, where: systemPrivilegeWhere, }, ], }, ], transaction: dbTransaction, }); //Retrieve group object privileges by calling LoginUser._GroupObjectPrivilegeRepo.findAll const objectWhere: any = { GroupCode, }; const systemWhere: any = {}; if (search) { Object.entries(search).forEach(([key, value]) => { if (key === 'Status') { objectWhere[key] = { [Op.substring]: value, }; } else { systemWhere[key] = { [Op.substring]: value, }; } }); } const groupObjectPrivileges = await Group._GroupObjectPrivilegeRepo.findAll({ where: objectWhere, include: [ { model: SystemPrivilegeModel, where: systemWhere, }, ], transaction: dbTransaction, }); //Map to SystemPrivilege object let privileges: SystemPrivilege[] = []; for (const groupPrivilege of group.GroupPrivileges) { const systemPrivilege = await SystemPrivilege.init(dbTransaction); systemPrivilege.setAttributes( groupPrivilege.Privilege.get({ plain: true }), ); privileges.push(systemPrivilege); } for (const groupObjectPrivilege of groupObjectPrivileges) { const systemPrivilege = await SystemPrivilege.init(dbTransaction); systemPrivilege.setAttributes( groupObjectPrivilege.Privilege.get({ plain: true }), ); privileges.push(systemPrivilege); } //Part 2: Retrieve Privileges Inherited from Parent Group //if group data retrieved from 1.1 have InheritParentPrivilegeYN == "Y" and ParentGroupCode value is not empty. Call this method again if (group.InheritParentPrivilegeYN === 'Y' && group.ParentGroupCode) { const inheritedPrivileges = await Group.getInheritedSystemPrivileges( dbTransaction, group.ParentGroupCode, search, ); privileges = privileges.concat(inheritedPrivileges); } //format to make sure no duplicate const uniquePrivileges = Array.from( new Set(privileges.map((a) => a.SystemPrivilegeId)), ).map((SystemPrivilegeId) => { return privileges.find( (a) => a.SystemPrivilegeId === SystemPrivilegeId, ); }); return uniquePrivileges; } catch (error) { throw error; } } public static async getParentSystemPrivileges( loginUser: LoginUser, dbTransaction: any, GroupCode: string, search?: { SystemCode?: string; Status?: string; PrivilegeCode?: string; }, ): Promise<SystemPrivilege[]> { try { //Part 1: Privilege Checking const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'GROUP_PRIVILEGE_VIEW', ); if (!isPrivileged) { throw new ClassError( 'Group', 'GroupErrMsg11', 'You do not have the privilege to view group privileges', ); } //Part 2: Validation //Set group to instantiation of existing Group const group = await Group.init(dbTransaction, GroupCode); //Check if group.InheritParentPrivilegeYN == "Y" and ParentGroupCode value is not empty. if no then return an empty array if (group.InheritParentPrivilegeYN !== 'Y' || !group.ParentGroupCode) { return []; } //Part 3: Retrieve Group Own Privilege //Retrieve group data and it's privileged by calling Group.getIheritedSystemPrivileges const privileges = await Group.getInheritedSystemPrivileges( dbTransaction, group.ParentGroupCode, search, ); return privileges; } catch (error) { throw error; } } public static async assignGroupObjectPrivilege( loginUser: LoginUser, dbTransaction: any, GroupCode: string, GroupObjectPrivileges: GroupObjectPrivilege[], SystemCode: string, ): Promise<string> { try { //Part 1: Privilege Checking const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'GROUP_OBJECT_PRIVILEGE_ASSIGN', ); if (!isPrivileged) { throw new ClassError( 'Group', 'GroupErrMsg12', 'You do not have the privilege to assign group object privilege', ); } //Part 2: Validation //Initialise group with group init const group = await Group.init(dbTransaction, GroupCode); //Retrieve all group system access by calling Group.getSystemAccesses const groupSystemAccesses = await Group.getSystemAccesses( loginUser, dbTransaction, GroupCode, 1, Number.MAX_SAFE_INTEGER, {}, ); //If Group.InheritParentSystemAccess == "Y" and Group.ParentGroupCode exist, initialise parent group let parentGroupSystemAccesses: any = { rows: [], count: 0, }; if (group.InheritParentSystemAccessYN === 'Y' && group.ParentGroupCode) { //Retrieve all parent group system access by calling Group.getSystemAccesses parentGroupSystemAccesses = await Group.getSystemAccesses( loginUser, dbTransaction, group.ParentGroupCode, 1, Number.MAX_SAFE_INTEGER, undefined, ); } // For each Params.GroupObjectPrivileges. for (const groupObjectPrivilege of GroupObjectPrivileges) { //Initialise existing System privilege const systemPrivilege = await SystemPrivilege.init( dbTransaction, groupObjectPrivilege.SystemPrivilegeId, ); //Check whether the system codes used by that privilege is exist inside the group system access const combinedSystemAccesses = { ...groupSystemAccesses.rows, ...parentGroupSystemAccesses.rows, }; const systemAccess = combinedSystemAccesses.find( (systemAccess) => systemAccess.SystemCode === systemPrivilege.SystemCode, ); if (!systemAccess) { throw new ClassError( 'Group', 'GroupErrMsg13', 'Failed to assign privilege ' + groupObjectPrivilege.SystemPrivilegeId + ' due to non-existent system access.', ); } //Check whether the group object privilege already exist by using Group._GroupObjectPrivilegesRepo.findOne const groupObjectPrivilegeData = await Group._GroupObjectPrivilegeRepo.findOne({ where: { GroupCode, SystemPrivilegeId: groupObjectPrivilege.SystemPrivilegeId, ObjectId: groupObjectPrivilege.ObjectId, ObjectType: groupObjectPrivilege.ObjectType, }, transaction: dbTransaction, }); //If GroupObjectPrivilege record exist. Skip this loop and proceed to the next privilege code if (groupObjectPrivilegeData) { continue; } else { //Call GroupObjectPrivilege.create await GroupObjectPrivilege.create( loginUser, dbTransaction, groupObjectPrivilege, ); } } return 'Successfully added.'; } catch (error) { throw error; } } public static async getGroubObjectPrivileges( loginUser: LoginUser, dbTransaction: any, GroupCode: string, search?: { PrivilegeCode?: string; ObjectType?: string; ObjectId?: string; SystemCode?: string; }, ): Promise<SystemPrivilege[]> { try { // Part 1: Privilege Checking const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'GROUP_PRIVILEGE_VIEW', ); if (!isPrivileged) { throw new ClassError( 'Group', 'GroupErrMsg11', 'You do not have the privilege to view group privileges', ); } // Part 2: Validation // Set group to instantiation of existing Group await Group.init(dbTransaction, GroupCode); // Part 3: Retrieve Group Own Privilege // Retrieve group object privileges by calling LoginUser._GroupObjectPrivilegeRepo.findAll const where: any = { GroupCode, }; const systemWhere: any = {}; if (search) { Object.entries(search).forEach(([key, value]) => { if (key === 'SystemCode' || key === 'PrivilegeCode') { systemWhere[key] = { [Op.substring]: value, }; } else { where[key] = { [Op.substring]: value, }; } }); } const groupObjectPrivileges = await Group._GroupObjectPrivilegeRepo.findAll({ where, include: [ { model: SystemPrivilegeModel, where: systemWhere, }, ], transaction: dbTransaction, }); // Create variable called privileges and Map the SystemPrivilege data retrieved from 3.1 into SystemPrivilege object and push it to the privileges variables const privileges: SystemPrivilege[] = []; for (const groupObjectPrivilege of groupObjectPrivileges) { const systemPrivilege = await SystemPrivilege.init(dbTransaction); systemPrivilege.setAttributes( groupObjectPrivilege.Privilege.get({ plain: true }), ); privileges.push(systemPrivilege); } //Remove duplicate const uniquePrivileges = Array.from( new Set(privileges.map((a) => a.SystemPrivilegeId)), ).map((SystemPrivilegeId) => { return privileges.find( (a) => a.SystemPrivilegeId === SystemPrivilegeId, ); }); // Create the result based on the spec on return then returns it. retur