@tomei/sso
Version:
Tomei SSO Package
663 lines (614 loc) • 25.1 kB
text/typescript
import { ClassError, ObjectBase } from '@tomei/general';
import { IUserPrivilegeAttr } from '../../interfaces/user-privilege.interface';
import { UserPrivilegeRepository } from './user-privilege.repository';
import { User as UserClass } from '../login-user/user';
import { ApplicationConfig } from '@tomei/config';
import SystemPrivilegeModel from '../../models/system-privilege.entity';
import SystemModel from '../../models/system.entity';
import { UserGroupRepository } from '../user-group/user-group.repository';
import GroupModel from '../../models/group.entity';
import User from '../../models/user.entity';
import { GroupPrivilegeRepository } from '../group-privilege/group-privilege.repository';
import { User as UserLogin } from '../login-user/user';
import { SystemPrivilegeRepository } from '../system-privilege/system-privilege.repository';
import { Op } from 'sequelize';
import { ActionEnum, Activity } from '@tomei/activity-history';
import { UserGroup } from 'components/user-group';
export class UserPrivilege extends ObjectBase {
TableName = 'sso_UserPrivilege';
ObjectType = 'UserPrivilege';
ObjectName: string;
ObjectId: string;
UserPrivilegeId: number;
UserId: number;
SystemPrivilegeId: string;
Status: string;
private _CreatedById: number;
private _UpdatedById: number;
private _CreatedAt: Date;
private _UpdatedAt: Date;
get CreatedById(): number {
return this._CreatedById;
}
get UpdatedById(): number {
return this._UpdatedById;
}
get CreatedAt(): Date {
return this._CreatedAt;
}
get UpdatedAt(): Date {
return this._UpdatedAt;
}
private static _Repository = new UserPrivilegeRepository();
private static _UserGroupRepository = new UserGroupRepository();
private static _GroupPrivilegeRepository = new GroupPrivilegeRepository();
private static _SystemPrivilegeRepository = new SystemPrivilegeRepository();
private constructor(userPrivilegeAttr?: IUserPrivilegeAttr) {
super();
if (userPrivilegeAttr) {
this.UserPrivilegeId = userPrivilegeAttr.UserPrivilegeId;
this.UserId = userPrivilegeAttr.UserId;
this.SystemPrivilegeId = userPrivilegeAttr.SystemPrivilegeId;
this.Status = userPrivilegeAttr.Status;
this._CreatedById = userPrivilegeAttr.CreatedById;
this._UpdatedById = userPrivilegeAttr.UpdatedById;
this._CreatedAt = userPrivilegeAttr.CreatedAt;
this._UpdatedAt = userPrivilegeAttr.UpdatedAt;
}
}
public static async init(dbTransaction?: any, UserPrivilegeId?: number) {
try {
let userPrivilege = new UserPrivilege();
if (UserPrivilegeId) {
const userPrivilegeAttr = await this._Repository.findOne({
where: { UserPrivilegeId },
transaction: dbTransaction,
});
if (userPrivilegeAttr) {
userPrivilege = new UserPrivilege(userPrivilegeAttr);
} else {
throw new ClassError(
'UserPrivilege',
'UserPrivilegeErrMsg00',
'UserPrivilege not found',
);
}
}
return userPrivilege;
} catch (error) {
throw error;
}
}
public static async findAll(
loginUser: UserClass, //The currently logged-in user initiating the request.
dbTransaction: any, //The active database transaction to ensure consistency during the query.
whereOption: {
//An object containing filter criteria, specifically:
UserId: number; //The ID of the user whose system access records are to be retrieved.
SystemCode?: string;
},
pagination: {
//An object containing pagination parameters:
page: number; //The current page number to retrieve.
limit: number; //The number of records to retrieve per page.
},
): Promise<{
records: {
UserPrivilegeId: number;
SystemPrivilegeId: string;
PrivilegeCode: string;
SystemName: string;
Status: string;
CreatedBy: string;
CreatedAt: Date;
UpdatedBy: string;
UpdatedAt: Date;
}[];
pagination: {
currentPage: number;
pageSize: number;
totalRecords: number;
};
}> {
try {
// Privilege Checking:
// Call loginUser.checkPrivileges() method by passing:
// SystemCode: Retrieve from app config.
// PrivilegeCode: 'USER_PRIVILEGE_LIST'.
const systemCode =
ApplicationConfig.getComponentConfigValue('system-code');
const privilegeCode = 'USER_PRIVILEGE_LIST';
const isPrivileged = await loginUser.checkPrivileges(
systemCode,
privilegeCode,
);
if (!isPrivileged) {
throw new ClassError(
'UserPrivilege',
'UserPrivilegeErrMsg01',
'You do not have permission to access this resource.',
);
}
const options: any = {
distinct: true,
where: {
UserId: whereOption.UserId,
},
offset: (pagination.page - 1) * pagination.limit,
limit: pagination.limit,
transaction: dbTransaction,
include: [
{
model: SystemPrivilegeModel,
attributes: ['PrivilegeCode'],
include: [
{
model: SystemModel,
attributes: ['Name'],
},
],
},
{
model: User,
as: 'CreatedByUser',
attributes: ['FullName'],
},
{
model: User,
as: 'UpdatedByUser',
attributes: ['FullName'],
},
],
};
const { count, rows } =
await this._Repository.findAllWithPagination(options);
return {
records: rows.map((record) => {
return {
UserPrivilegeId: record.UserPrivilegeId,
SystemPrivilegeId: record.SystemPrivilegeId,
PrivilegeCode: record.Privilege.PrivilegeCode,
SystemName: record.Privilege.System.Name,
Status: record.Status,
CreatedBy: record.CreatedByUser.FullName,
CreatedAt: record.CreatedAt,
UpdatedBy: record.UpdatedByUser.FullName,
UpdatedAt: record.UpdatedAt,
};
}),
pagination: {
currentPage: pagination.page,
pageSize: pagination.limit,
totalRecords: count,
},
};
} catch (error) {
throw error;
}
}
public static async findAllInheritedPrivileges(
UserId: number, //The ID of the user for whom privileges are being retrieved.
loginUser: UserClass, //The currently logged-in user initiating the request.
dbTransaction: any, //The active database transaction to ensure consistency during the query.
) {
try {
// Part 1: Privilege Checking
// Call loginUser.checkPrivileges() to ensure the user has permission to retrieve system access information.
// SystemCode: Retrieve from app config.
// PrivilegeCode: 'USER_PRIVILEGE_LIST'.
// If the privilege check fails, throw an error with a 403 Forbidden status.
const systemCode =
ApplicationConfig.getComponentConfigValue('system-code');
const privilegeCode = 'USER_PRIVILEGE_LIST';
const isPrivileged = await loginUser.checkPrivileges(
systemCode,
privilegeCode,
);
if (!isPrivileged) {
throw new ClassError(
'UserPrivilege',
'UserPrivilegeErrMsg01',
'You do not have permission to access this resource.',
);
}
// Part 2: Retrieve User Groups
// Query the sso_UserGroup table to find all active groups the user belongs to.
// Join with the sso_Group table to retrieve the GroupCode, GroupName, and InheritGroupPrivilegeYNfields.
// Ensure that the value of InheritGroupPrivilegeYN is explicitly 'Y' or 'N' for each group.
// If InheritGroupPrivilegeYN is not set, default it to 'N'.
// Return only active groups (based on Status field).
// The query should return the following fields for each group:
// - GroupCode
// - GroupName
// - InheritPrivilegeYN
const userGroups = await UserPrivilege._UserGroupRepository.findAll({
where: {
UserId,
},
include: [
{
model: GroupModel,
attributes: ['GroupCode', 'Name', 'InheritParentPrivilegeYN'],
},
],
transaction: dbTransaction,
});
const listOfGroups = userGroups.map((groups) => {
let inheritPrivilegeYN = groups.InheritGroupPrivilegeYN;
if (inheritPrivilegeYN !== 'Y') {
inheritPrivilegeYN = 'N';
}
return {
UserGroupId: groups.UserGroupId,
GroupCode: groups.GroupCode,
GroupName: groups.Group.Name,
InheritPrivilegeYN: inheritPrivilegeYN,
Status: groups.Status,
};
});
// Part 3: Retrieve System Privilege for Groups with Inheritance
// For each group where InheritGroupPrivilegeYN = 'Y', query the sso_GroupPrivilege table to retrieve system privilege details.
// Join with the sso_SystemPrivilege table to fetch system details (PrivilegeCode).
// Ensure only active group privilege (Status = 'Active') are included.
// For each privilege, retrieve the following fields:
// - GroupPrivilegeId (from sso_GroupPrivilege.GroupPrivilegeId)
// - SystemPrivilegeId (from sso_GroupPrivilege.SystemPrivilegeId)
// - PrivilegeCode (from sso_SystemPrivilege.SystemCode)
// - Status (from sso_GroupPrivilege.Status)
// - CreatedAt (from sso_GroupPrivilege.CreatedAt)
// - UpdatedAt (from sso_GroupPrivilege.UpdatedAt)
const userGroupPrivilege = [];
for (let i = 0; i < listOfGroups.length; i++) {
const group = await listOfGroups[i];
const data = {
UserGroupId: group.UserGroupId,
GroupCode: group.GroupCode,
GroupName: group.GroupName,
InheritPrivilegeYN: group.InheritPrivilegeYN,
systems: [],
};
// Part 4: Handling Non-Inherited Groups
// For groups where InheritGroupSPrivilegeYN = 'N', return the group details without group privilege records.
// Set the Privileges field to an empty array or null to indicate no inherited privilege for those groups.
if (group.InheritPrivilegeYN === 'Y') {
if (group.Status === 'Active') {
const options: any = {
where: {
GroupCode: group.GroupCode,
Status: 'Active',
},
transaction: dbTransaction,
include: [
{
model: SystemPrivilegeModel,
attributes: ['PrivilegeCode'],
include: [
{
model: SystemModel,
attributes: ['Name'],
},
],
},
{
model: User,
as: 'CreatedByUser',
attributes: ['FullName'],
},
{
model: User,
as: 'UpdatedByUser',
attributes: ['FullName'],
},
],
};
const systemPrivilege =
await this._GroupPrivilegeRepository.findAll(options);
const privilegeDetails = systemPrivilege.map((record) => {
return {
GroupPrivilegeId: record.GroupPrivilegeId,
SystemPrivilegeId: record.SystemPrivilegeId,
PrivilegeCode: record.Privilege.PrivilegeCode,
Status: record.Status,
CreatedBy: record.CreatedByUser.FullName,
CreatedAt: record.CreatedAt,
UpdatedBy: record.UpdatedByUser.FullName,
UpdatedAt: record.UpdatedAt,
};
});
data.systems = privilegeDetails;
}
}
userGroupPrivilege.push(data);
}
return userGroupPrivilege;
} catch (error) {
throw error;
}
}
public static async assignPrivileges(
loginUser: UserLogin, //The currently logged-in user initiating the request.
dbTransaction: any, //The active database transaction to ensure consistency during the query.
UserId: string, //The user ID for whom system access is being created.
SystemPrivilegeId: string, //The system code for which access is being granted.
Status: string, //The status of access ('Active' or 'Inactive').
) {
try {
// Part 1: Privilege Check
// Call the LoginUser.checkPrivileges() method to validate if the loginUser has the privilege to create system privilege:
// SystemCode: retrieve from the application configuration.
// PrivilegeCode: set to "USER_PRIVILEGE_CREATE".
// If the user does not have the required privilege, throw an appropriate error.
const systemCode =
ApplicationConfig.getComponentConfigValue('system-code');
const privilegeCode = 'USER_PRIVILEGE_CREATE';
const isPrivileged = await loginUser.checkPrivileges(
systemCode,
privilegeCode,
);
if (!isPrivileged) {
throw new ClassError(
'UserSystemPrivilege',
'UserSystemPrivilegeErrMsg01',
'You do not have permission to access this resource.',
);
}
// Part 2: Validation
// Use UserPrivilege._SystemPrivilegeRepo.findOne method to check if the privileges exist:
// Pass the following parameters:
// - SystemPrivilegeId
// - dbTransaction
// If the record is not found, throw an error indicating that privileges don't exist.
// Use the UserPrivilege.findAll() method to check if the privileges has been assigned to the user:
// Pass the following parameters:
// - loginUser
// - dbTransaction
// - whereOption: set to UserId = UserId and SystemPrivilegeId = SystemPrivilegeId.
// If a record is found, throw an error indicating that access for this user and system already exists.
const isExist = await UserPrivilege._SystemPrivilegeRepository.findAll({
where: { SystemPrivilegeId: SystemPrivilegeId },
transaction: dbTransaction,
});
if (isExist?.length < 1) {
throw new ClassError(
'UserSystemPrivilege',
'UserSystemPrivilegeErrMsg02',
"system privileges don't exist",
);
}
const isUserAlreadyAssign = await UserPrivilege._Repository.findAll({
where: {
[Op.and]: [
{ UserId: UserId },
{ SystemPrivilegeId: SystemPrivilegeId },
],
},
transaction: dbTransaction,
});
if (isUserAlreadyAssign?.length > 0) {
throw new ClassError(
'UserSystemPrivilege',
'UserSystemPrivilegeErrMsg03',
'User already have access to this privilege',
);
}
// Part 3: Insert User Privilege Record
// After successful validation, create a new instance of UserPrivilege with the following fields:
// - UserPrivilegeId: set to the result of createId
// - SystemPrivilegeId: set to payload.SystemPrivilegeId
// - Status: set to payload.Status
// - CreatedBy: set to LoginUser.UserId
// - CreatedAt: set to the current timestamps
// - UpdatedBy: set to LoginUser.UserId
// - UpdatedAt: set to the current timestamps
// Save the new UserPrivilege instance in the database within the dbTransaction.
const newUserPrivilege = new UserPrivilege();
newUserPrivilege.UserId = parseInt(UserId);
newUserPrivilege.SystemPrivilegeId = SystemPrivilegeId;
newUserPrivilege.Status = Status;
newUserPrivilege._CreatedById = loginUser.UserId;
newUserPrivilege._CreatedAt = new Date();
newUserPrivilege._UpdatedById = loginUser.UserId;
newUserPrivilege._UpdatedAt = new Date();
const payload = {
UserId: newUserPrivilege.UserId,
SystemPrivilegeId: newUserPrivilege.SystemPrivilegeId,
Status: newUserPrivilege.Status,
CreatedById: newUserPrivilege.CreatedById,
CreatedAt: newUserPrivilege.CreatedAt,
UpdatedById: newUserPrivilege.UpdatedById,
UpdatedAt: newUserPrivilege.UpdatedAt,
};
const userPrivilege = await UserPrivilege._Repository.create(payload, {
transaction: dbTransaction,
});
// Part 4: Record Activity History
// Initialize an empty object ({}) as EntityValueBefore.
// Set EntityValueAfter to the stringified version of the newly created UserPrivilege instance.
// Create a new activity log entry:
// - ActivityId: auto-generated by calling activity.createId().
// - Action: set to ActionEnum.Create.
// - Description: set to "Create User Privilege".
// - EntityType: set to UserPrivilege.
// - EntityId: set to the newly created UserPrivilege.UserPrivilegeId.
// - EntityValueBefore: set to {} (empty).
// - EntityValueAfter: set to the stringified version of the new record.
// Call the activity.create() method, passing:
// - dbTransaction
// - userId: set to loginUser.UserId.
const entityValueBefore = {};
//Instantiate new activity
const activity = new Activity();
activity.ActivityId = activity.createId();
activity.Action = ActionEnum.CREATE;
activity.Description = 'Create User Privilege';
activity.EntityType = 'UserPrivilege';
activity.EntityId = userPrivilege.UserPrivilegeId?.toString();
activity.EntityValueBefore = JSON.stringify(entityValueBefore);
activity.EntityValueAfter = JSON.stringify(payload);
//Call Activity.create method
await activity.create(loginUser.ObjectId, dbTransaction);
// Part 5: Return Newly Created Record
// Return the newly created UserPrivilege instance with all relevant fields, including UserPrivilegeId, SystemPrivilegeId, Status, CreatedAt, and CreatedById.
newUserPrivilege.UserPrivilegeId = userPrivilege.UserPrivilegeId;
return newUserPrivilege;
} catch (error) {
throw error;
}
}
public async update(
loginUser: UserLogin, //The user object representing the currently logged-in user.
dbTransaction: any, //The database transaction instance for managing the transaction scope.
Status: string, //The new access status (Active/Inactive) for the user privilege
) {
try {
// Part 1: Update User Privilege
// Call the UserPrivilege._Repo.update() method to perform the update operation, passing:
// - Status: The new status.
// - UpdatedById: loginUser.UserId (to indicate who updated the record).
// - UpdatedAt: Set to the current date and time.
// - dbTransaction: The database transaction instance.
const entityValueBefore = {
UserPrivilegeId: this.UserPrivilegeId,
UserId: this.UserId,
SystemPrivilegeId: this.SystemPrivilegeId,
Status: this.Status,
CreatedById: this.CreatedById,
CreatedAt: this.CreatedAt,
UpdatedById: this.UpdatedById,
UpdatedAt: this.UpdatedAt,
};
await UserPrivilege._Repository.update(
{
Status: Status,
UpdatedById: loginUser.UserId,
UpdatedAt: new Date(),
},
{
where: {
UserPrivilegeId: this.UserPrivilegeId,
},
transaction: dbTransaction,
},
);
const entityValueAfter = {
UserPrivilegeId: this.UserPrivilegeId,
UserId: this.UserId,
SystemPrivilegeId: this.SystemPrivilegeId,
Status: Status,
CreatedById: this.CreatedById,
CreatedAt: this.CreatedAt,
UpdatedById: loginUser.UserId,
UpdatedAt: new Date(),
};
// Part 2: Record Activity History
// Initialize a variable entityValueBefore to store the current state of the user privilege record before the update.
// Create an instance of the Activity class and set the following properties:
// - ActivityId: Call activity.createId().
// - Action: Set to ActionEnum.Update.
// - Description: Set to Update User Privilege.
// - EntityType: Set to UserPrivilege.
// - EntityId: Use the ID of the updated user privilege record.
// - EntityValueBefore: Stringify entityValueBefore to capture the state before the update.
// - EntityValueAfter: Stringify the updated user privilege record to capture the new state after the update.
// Call the activity create method with the following parameters:
// - dbTransaction
// - userId: loginUser.UserId
const activity = new Activity();
activity.ActivityId = activity.createId();
activity.Action = ActionEnum.UPDATE;
activity.Description = 'Update User Privilege';
activity.EntityType = 'UserPrivilege';
activity.EntityId = this.SystemPrivilegeId + '';
activity.EntityValueBefore = JSON.stringify(entityValueBefore);
activity.EntityValueAfter = JSON.stringify(entityValueAfter);
await activity.create(loginUser.ObjectId, dbTransaction);
// Part 3: Return Updated Record
// Retrieve the updated user system access record from the database or return the updated instance as needed.
return entityValueAfter;
} catch (error) {
throw error;
}
}
public static async remove(
loginUser: UserLogin, //The currently logged-in user initiating the request.
dbTransaction: any, //The active database transaction to ensure consistency during the query.
UserPrivilegeId: number, //The unique identifier of the record to be deleted.
) {
try {
// Part 1: Privilege Checking
// Call loginUser.checkPrivileges() method by passing:
// - SystemCode: Retrieve from app config.
// - PrivilegeCode: 'USER_PRIVILEGE_REMOVE'.
// If the user does not have the required privileges, throw an appropriate exception.
const systemCode =
ApplicationConfig.getComponentConfigValue('system-code');
const privilegeCode = 'USER_PRIVILEGE_REMOVE';
const isPrivileged = await loginUser.checkPrivileges(
systemCode,
privilegeCode,
);
if (!isPrivileged) {
throw new ClassError(
'UserSystemPrivilege',
'UserSystemPrivilegeErrMsg01',
'You do not have permission to access this resource.',
);
}
// Part 2: Retrieve Record
// Use the UserPrivilege._Repo.findById(UserPrivilegeId) method to retrieve the record.
// If the record does not exist, throw an exception indicating the record was not found.
const userPrivilege = await UserPrivilege._Repository.findOne({
where: {
UserPrivilegeId: UserPrivilegeId,
},
transaction: dbTransaction,
});
if (!userPrivilege) {
throw new ClassError(
'UserSystemPrivilege',
'UserSystemPrivilegeErrMsg01',
'User Privilege not Found',
);
}
// Part 3: Delete Record
// Call the UserPrivilege._Repo.delete() method, passing:
// - UserPrivilegeId
// - dbTransaction to permanently delete the record from the database.
await UserPrivilege._Repository.delete(UserPrivilegeId, dbTransaction);
const entityValueBefore = {
UserId: userPrivilege.UserId,
SystemPrivilegeId: userPrivilege.SystemPrivilegeId,
Status: userPrivilege.Status,
CreatedById: userPrivilege.CreatedById,
CreatedAt: userPrivilege.CreatedAt,
UpdatedById: userPrivilege.UpdatedById,
UpdatedAt: userPrivilege.UpdatedAt,
};
// Part 4: Record Activity History
// Instantiate a new activity from the Activity class, and set:
// - ActivityId: activity.createId()
// - Action: ActionEnum.Delete
// - Description: Delete User Privilege
// - EntityType: UserPrivilege
// - EntityId: UserPrivilegeId
// - EntityValueBefore: Stringified representation of the record before deletion.
// - EntityValueAfter: null.
// Call the activity.create() method by passing:
// - dbTransaction
// - userId: loginUser.UserId.
//Instantiate new activity
const activity = new Activity();
activity.ActivityId = activity.createId();
activity.Action = ActionEnum.DELETE;
activity.Description = 'Delete User Privilege';
activity.EntityType = 'UserPrivilege';
activity.EntityId = UserPrivilegeId?.toString();
activity.EntityValueBefore = JSON.stringify(entityValueBefore);
activity.EntityValueAfter = JSON.stringify({});
//Call Activity.create method
await activity.create(loginUser.ObjectId, dbTransaction);
} catch (error) {
throw error;
}
}
}