@tomei/sso
Version:
Tomei SSO Package
1,710 lines (1,523 loc) • 68.5 kB
text/typescript
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