@tomei/sso
Version:
Tomei SSO Package
506 lines (469 loc) • 19.1 kB
text/typescript
import { ClassError, ObjectBase } from '@tomei/general';
import { IUserReportingHierarchyAttr } from '../../interfaces/user-reporting-hierarchy.interface';
import { UserReportingHierarchyRepository } from './user-reporting-hierarchy.repository';
import { User } from '../login-user/user';
import { ApplicationConfig } from '@tomei/config';
import { ActionEnum, Activity } from '@tomei/activity-history';
import { Op } from 'sequelize';
export class UserReportingHierarchy
extends ObjectBase
implements IUserReportingHierarchyAttr
{
ObjectId: string;
ObjectName: string;
ObjectType = 'UserReportingHierarchy';
TableName = 'sso_UserReportingHierarchy';
ReportingUserId: number;
UserId: number;
Rank: number;
Status: string;
private _CreatedById: number;
private _CreatedAt: Date;
private _UpdatedById: number;
private _UpdatedAt: Date;
private static _Repo = new UserReportingHierarchyRepository();
get UserReportingHierarchyId(): number {
return parseInt(this.ObjectId);
}
set UserReportingHierarchyId(value: number) {
this.ObjectId = value.toString();
}
get CreatedById(): number {
return this._CreatedById;
}
get CreatedAt(): Date {
return this._CreatedAt;
}
get UpdatedById(): number {
return this._UpdatedById;
}
get UpdatedAt(): Date {
return this._UpdatedAt;
}
private constructor(params?: IUserReportingHierarchyAttr) {
super();
if (params) {
this.ObjectId = params.UserReportingHierarchyId.toString();
this.ReportingUserId = params.ReportingUserId;
this.UserId = params.UserId;
this.Rank = params.Rank;
this.Status = params.Status;
this._CreatedById = params.CreatedById;
this._CreatedAt = params.CreatedAt;
this._UpdatedById = params.UpdatedById;
this._UpdatedAt = params.UpdatedAt;
}
}
public static async init(
userReportingHierarchyId?: number,
dbTransaction?: any,
): Promise<UserReportingHierarchy> {
try {
if (userReportingHierarchyId) {
const data = await UserReportingHierarchy._Repo.findByPk(
userReportingHierarchyId.toString(),
dbTransaction,
);
if (!data) {
throw new ClassError(
'UserReportingHierarchy',
'UserReportingHierarchyErrMsg01',
'UserReportingHierarchy not found',
'init',
400,
);
}
return new UserReportingHierarchy(data.get({ plain: true }));
}
return new UserReportingHierarchy();
} catch (error) {
throw error;
}
}
async createUserReportingHierarchy(
loginUser: User, //The user performing the operation(typically the logged -in user).
dbTransaction: any, //Database transaction object to ensure the operation is atomic.
reportingUserId: number, //The ID of the user who will do the reporting.
userId: number, //The Id of the user who need to be reported to.
rank: number, //The rank to be assigned to the user.
status: 'Active' | 'Inactive', //The initial status of relationship.
): Promise<UserReportingHierarchy> {
// Returns a ReportingUserHierarchy instance representing the newly created record.
try {
//Creates a new User Reporting Hierarchy entry in the sso_UserReportingHierarchy table.
// Privilege Checking
// Call the loginUser.checkPrivileges() method by passing:
// SystemCode: Retrieve from app config.
// PrivilegeCode: "GROUP_REPORTING_USER_CREATE".
const systemCode =
ApplicationConfig.getComponentConfigValue('system-code');
const isPrivileged = await loginUser.checkPrivileges(
systemCode,
'USER_REPORTING_HIERARCHY_CREATE',
);
if (!isPrivileged) {
throw new ClassError(
'UserReportingHierarchy',
'UserReportingHierarchyErrMsg02',
'User does not have the required privileges',
'createUserReportingHierarchy',
403,
);
}
// Validate Input Parameters
// Ensure userId exists in the sso_User table by calling the User.init() method.
await User.init(dbTransaction, userId);
await User.init(dbTransaction, reportingUserId);
// Query the sso_UserReportingHierarchy table to see if the relationship is already defined for the user.
let userReportingHierarchy = await UserReportingHierarchy._Repo.findOne({
where: {
ReportingUserId: reportingUserId,
UserId: userId,
},
transaction: dbTransaction,
});
// If the record already exists, throw an error.
if (userReportingHierarchy) {
throw new ClassError(
'UserReportingHierarchy',
'UserReportingHierarchyErrMsg03',
'Relationship already exists',
'createUserReportingHierarchy',
400,
);
}
//Query the sso_UserReportingHierarchy table to see if the rank already exists for the reporting user.
//If the rank already exists, throw an error indicating the rank is already exist.
userReportingHierarchy = await UserReportingHierarchy._Repo.findOne({
where: {
ReportingUserId: reportingUserId,
Rank: rank,
},
transaction: dbTransaction,
});
if (userReportingHierarchy) {
throw new ClassError(
'UserReportingHierarchy',
'UserReportingHierarchyErrMsg04',
'Rank already exists',
'createUserReportingHierarchy',
400,
);
}
//Check if one rank before the new rank is not already assigned to the user, if not throw an error
if (rank > 1) {
const userReportingHierarchyBefore =
await UserReportingHierarchy._Repo.findOne({
where: {
ReportingUserId: reportingUserId,
Rank: rank - 1,
},
transaction: dbTransaction,
});
if (!userReportingHierarchyBefore) {
throw new ClassError(
'UserReportingHierarchy',
'UserReportingHierarchyErrMsg05',
'Rank before the new rank is not yet assigned to the user',
'createUserReportingHierarchy',
400,
);
}
}
// Create ReportingUserHierarchy Entry
// If validation and privilege checks pass, insert a new record in the sso_UserReportingHierarchy table
this.ReportingUserId = reportingUserId;
this.UserId = userId;
this.Rank = rank;
this.Status = status;
this._CreatedById = loginUser.UserId;
this._CreatedAt = new Date();
this._UpdatedAt = new Date();
this._UpdatedById = loginUser.UserId;
const entityValueAfter: any = {
ReportingUserId: reportingUserId,
UserId: userId,
Rank: rank,
Status: status,
CreatedById: loginUser.UserId,
CreatedAt: this._CreatedAt,
UpdatedById: loginUser.UserId,
UpdatedAt: this._UpdatedAt,
};
userReportingHierarchy = await UserReportingHierarchy._Repo.create(
entityValueAfter,
{
transaction: dbTransaction,
},
);
entityValueAfter.UserReportingHierarchyId =
userReportingHierarchy.UserReportingHierarchyId;
// Record Create Activity
// Instantiate a new activity from the Activity class, and set:\
// ActivityId: activity.createId()
// Action: ActionEnum.Create
// Description: Create User Reporting Hierarchy
// EntityType: ReportingUserHierarchy
// EntityId: newReportingUserHierarchy.ReportingUserHierarchyId
// EntityValueBefore: Stringified empty object({})
// EntityValueAfter: EntityValueAfter(stringified representation of the newly created entity)
const activity = new Activity();
activity.ActivityId = activity.createId();
activity.Action = ActionEnum.CREATE;
activity.Description = 'Create User Reporting Hierarchy';
activity.EntityType = 'UserReportingHierarchy';
activity.EntityId =
userReportingHierarchy.UserReportingHierarchyId.toString();
activity.EntityValueBefore = JSON.stringify({});
activity.EntityValueAfter = JSON.stringify(entityValueAfter);
// Call the activity create() method by passing:
// dbTransaction
// userId: loginUser.UserId
await activity.create(loginUser.ObjectId, dbTransaction);
// Return the Created ReportingUserHierarchy
// Return the newly created ReportingUserHierarchy instance
return this;
} catch (error) {
throw error;
}
}
async updateUserReportingHierarchy(
loginUser: User, //The user performing the operation(typically the logged -in user).
dbTransaction: any, //Database transaction object to ensure the operation is atomic.
reportingUserId: number, //The ID of the user who will do the reporting.
userId: number, //The ID of the user who need to be reported to.
rank: number, //The rank to be assigned to the user.
status: 'Active' | 'Inactive', //The initial status of the user.
): Promise<UserReportingHierarchy> {
// Returns a ReportingUserHierarchy instance representing the updated record.
try {
//Update a User Reporting Hierarchy entry in the sso_UserReportingHierarchy table.
// Validate Input Parameters
// Ensure userId exists in the sso_User table by calling the User.init() method.
await User.init(dbTransaction, userId);
await User.init(dbTransaction, reportingUserId);
// Privilege Checking
// Call the loginUser.checkPrivileges() method by passing:
// SystemCode: Retrieve from app config.
// PrivilegeCode: "GROUP_REPORTING_USER_UPDATE".
const systemCode =
ApplicationConfig.getComponentConfigValue('system-code');
const isPrivileged = await loginUser.checkPrivileges(
systemCode,
'USER_REPORTING_HIERARCHY_UPDATE',
);
if (!isPrivileged) {
throw new ClassError(
'UserReportingHierarchy',
'UserReportingHierarchyErrMsg02',
'User does not have the required privileges',
'updateUserReportingHierarchy',
403,
);
}
// Query the sso_UserReportingHierarchy table to see if the userId already exists.
const userReportingHierarchy = await UserReportingHierarchy._Repo.findOne(
{
where: {
ReportingUserId: reportingUserId,
UserId: userId,
UserReportingHierarchyId: {
[Op.ne]: this.UserReportingHierarchyId,
},
},
transaction: dbTransaction,
},
);
// If the user already exists, throw an error indicating the reporting user is already part of reporting hierarchy.
if (userReportingHierarchy) {
throw new ClassError(
'UserReportingHierarchy',
'UserReportingHierarchyErrMsg03',
'Relationship already exists',
'updateUserReportingHierarchy',
);
}
//Query the sso_UserReportingHierarchy table to see if the rank already exists in the specified groupCode.
//If the rank already exists, throw an error indicating the rank is already in part of reporting hierarchy.
const userReportingRank = await UserReportingHierarchy._Repo.findOne({
where: {
ReportingUserId: reportingUserId,
Rank: rank,
UserReportingHierarchyId: {
[Op.ne]: this.UserReportingHierarchyId,
},
},
transaction: dbTransaction,
});
if (userReportingRank) {
throw new ClassError(
'UserReportingHierarchy',
'UserReportingHierarchyErrMsg04',
'Rank already exists',
'updateUserReportingHierarchy',
);
}
//Check if rank before the new rank is not already assigned to the user
if (rank > 1) {
const userReportingRankBefore =
await UserReportingHierarchy._Repo.findOne({
where: {
ReportingUserId: reportingUserId,
Rank: rank - 1,
UserReportingHierarchyId: {
[Op.ne]: this.UserReportingHierarchyId,
},
},
transaction: dbTransaction,
});
if (!userReportingRankBefore) {
throw new ClassError(
'UserReportingHierarchy',
'UserReportingHierarchyErrMsg05',
'Rank before the new rank is not yet assigned to the user',
'updateUserReportingHierarchy',
);
}
}
// UPDATE ReportingUserHierarchy Entry
// If validation and privilege checks pass, insert a new record in the sso_UserReportingHierarchy table.
const entityValueBefore: any = {
UserReportingHierarchyId: this.UserReportingHierarchyId,
ReportingUserId: this.ReportingUserId,
UserId: this.UserId,
Rank: this.Rank,
Status: this.Status,
CreatedById: this._CreatedById,
CreatedAt: this._CreatedAt,
UpdatedById: this._UpdatedById,
UpdatedAt: this._UpdatedAt,
};
this.ReportingUserId = reportingUserId;
this.UserId = userId;
this.Rank = rank;
this.Status = status;
this._CreatedById = this.CreatedById;
this._CreatedAt = this.CreatedAt;
this._UpdatedAt = new Date();
this._UpdatedById = loginUser.UserId;
const entityValueAfter: any = {
ReportingUserId: reportingUserId,
UserId: userId,
Rank: rank,
Status: status,
CreatedById: this.CreatedById,
CreatedAt: this._CreatedAt,
UpdatedById: loginUser.UserId,
UpdatedAt: this._UpdatedAt,
};
await UserReportingHierarchy._Repo.update(entityValueAfter, {
where: {
UserReportingHierarchyId: this.UserReportingHierarchyId,
},
transaction: dbTransaction,
});
// Record Update Activity
// Instantiate a new activity from the Activity class, and set:\
// ActivityId: activity.createId()
// Action: ActionEnum.Update
// Description: Update User Reporting Hierarchy
// EntityType: ReportingUserHierarchy
// EntityId: newReportingUserHierarchy.ReportingUserHierarchyId
// EntityValueBefore: Stringified empty object({})
// EntityValueAfter: EntityValueAfter(stringified representation of the newly created entity)
const activity = new Activity();
activity.ActivityId = activity.createId();
activity.Action = ActionEnum.UPDATE;
activity.Description = 'Update User Reporting Hierarchy';
activity.EntityType = 'UserReportingHierarchy';
activity.EntityId = this.UserReportingHierarchyId.toString();
activity.EntityValueBefore = JSON.stringify(entityValueBefore);
activity.EntityValueAfter = JSON.stringify(entityValueAfter);
// Call the activity create() method by passing:
// dbTransaction
// userId: loginUser.UserId
await activity.create(loginUser.ObjectId, dbTransaction);
// Return the Updated ReportingUserHierarchy
// Return the updated ReportingUserHierarchy instance, including all the relevant details like ReportingUserHierarchyId, groupCode, userId, rank, status, and timestamps for CreatedAt.
return this;
} catch (error) {
throw error;
}
}
public static async removeUserReportingHierarchy(
loginUser: User, //The user performing the operation, used for privilege checking and logging.
dbTransaction: any, // The database transaction object to ensure the operation's atomicity.
userReportingHierarchyId: number, //The ID of the UserReportingHierarchy to be removed.
): Promise<void> {
// This method removes a UserReportingHierarchy record from the database.
try {
// Part 1: Privilege Checking
// Call loginUser.checkPrivileges() method by passing:
// SystemCode: Retrieve from app config.
// PrivilegeCode: "USER_REPORTING_HIERARCHY_REMOVE".
const systemCode =
ApplicationConfig.getComponentConfigValue('system-code');
const isPrivileged = await loginUser.checkPrivileges(
systemCode,
'USER_REPORTING_HIERARCHY_REMOVE',
);
if (!isPrivileged) {
throw new ClassError(
'UserReportingHierarchy',
'UserReportingHierarchyErrMsg06',
'Insufficient privileges to remove reporting hierarchy',
'removeUserReportingHierarchy',
403,
);
}
// Part 2: Find User
// Call UserReportingHierarchy.init(dbTransaction, UserReportingHierarchyId) to check if the user exists.
const userReportingHierarchy = await UserReportingHierarchy.init(
userReportingHierarchyId,
dbTransaction,
);
// Part 3: Remove User
// Call UserReportingHierarchy._Repo.destroy({ where: { UserReportingHierarchyId: UserReportingHierarchyId }, transaction: dbTransaction }) to remove the user from the database.
await UserReportingHierarchy._Repo.destroy(
userReportingHierarchyId,
dbTransaction,
);
// Part 4: Record Create Activity
// Initialise EntityValueBefore variable and set it to the UserReportingHierarchy instance before destruction.
const entityValueBefore = {
UserReportingHierarchyId:
userReportingHierarchy.UserReportingHierarchyId,
ReportingUserId: userReportingHierarchy.ReportingUserId,
UserId: userReportingHierarchy.UserId,
Rank: userReportingHierarchy.Rank,
Status: userReportingHierarchy.Status,
CreatedById: userReportingHierarchy.CreatedById,
CreatedAt: userReportingHierarchy.CreatedAt,
UpdatedById: userReportingHierarchy.UpdatedById,
UpdatedAt: userReportingHierarchy.UpdatedAt,
};
// Instantiate a new activity from the Activity class, and set:
const activity = new Activity();
// ActivityId: activity.createId()
// Action: ActionEnum.Delete
// Description: Remove User Reporting Hierarchy
// EntityType: UserReportingHierarchy
// EntityId: userReportingHierarchyId
// EntityValueBefore: Stringified representation of the UserReportingHierarchy instance before destroy
// EntityValueAfter: Stringified empty object ({})
activity.ActivityId = activity.createId();
activity.Action = ActionEnum.DELETE;
activity.Description = 'Remove User Reporting Hierarchy';
activity.EntityType = 'UserReportingHierarchy';
activity.EntityId = userReportingHierarchy.toString();
activity.EntityValueBefore = JSON.stringify(entityValueBefore);
activity.EntityValueAfter = JSON.stringify({});
// Call the activity.create() method by passing:
// dbTransaction
// userId: loginUser.UserId
await activity.create(loginUser.ObjectId, dbTransaction);
} catch (error) {
throw error;
}
}
}