UNPKG

@tomei/sso

Version:
765 lines (725 loc) 26.9 kB
import { ClassError, ObjectBase } from '@tomei/general'; import { UserGroupRepository } from './user-group.repository'; import { IUserGroupAttr } from '../../interfaces/user-group.interface'; import { LoginUser, User } from '../../components/login-user'; import { Group } from '../../components/group'; import { ApplicationConfig } from '@tomei/config'; import { ActionEnum, Activity } from '@tomei/activity-history'; import GroupSystemAccessModel from '../../models/group-system-access.entity'; import GroupModel from '../../models/group.entity'; import SystemModel from '../../models/system.entity'; import UserModel from '../../models/user.entity'; import { Transaction } from 'sequelize'; export class UserGroup extends ObjectBase { ObjectType = 'UserGroup'; TableName = 'sso_UserGroup'; ObjectName: string; ObjectId: string; UserGroupId: number; UserId: number; GroupCode: string; InheritGroupPrivilegeYN = 'Y'; InheritGroupSystemAccessYN = 'Y'; Status: string; private _CreatedAt: Date; private _UpdatedAt: Date; private _CreatedById: number; private _UpdatedById: number; protected static _Repository = new UserGroupRepository(); get CreatedAt() { return this._CreatedAt; } get UpdatedAt() { return this._UpdatedAt; } get CreatedById() { return this._CreatedById; } get UpdatedById() { return this._UpdatedById; } private constructor(userGroupAttr?: IUserGroupAttr) { super(); if (userGroupAttr) { this.UserGroupId = userGroupAttr.UserGroupId; this.UserId = userGroupAttr.UserId; this.GroupCode = userGroupAttr.GroupCode; this.Status = userGroupAttr.Status; this.InheritGroupPrivilegeYN = userGroupAttr.InheritGroupPrivilegeYN; this.InheritGroupSystemAccessYN = userGroupAttr.InheritGroupSystemAccessYN; this._CreatedById = userGroupAttr.CreatedById; this._CreatedAt = userGroupAttr.CreatedAt; this._UpdatedById = userGroupAttr.UpdatedById; this._UpdatedAt = userGroupAttr.UpdatedAt; } } static async init(dbTransaction: any, UserGroupId?: number) { try { const userGroup = new UserGroup(); if (UserGroupId) { const userGroupAttr = await this._Repository.findOne({ where: { UserGroupId }, transaction: dbTransaction, }); if (userGroupAttr) { userGroup.UserGroupId = userGroupAttr.UserGroupId; userGroup.UserId = userGroupAttr.UserId; userGroup.GroupCode = userGroupAttr.GroupCode; userGroup.Status = userGroupAttr.Status; userGroup.InheritGroupPrivilegeYN = userGroupAttr.InheritGroupPrivilegeYN; userGroup.InheritGroupSystemAccessYN = userGroupAttr.InheritGroupSystemAccessYN; userGroup._CreatedById = userGroupAttr.CreatedById; userGroup._CreatedAt = userGroupAttr.CreatedAt; userGroup._UpdatedById = userGroupAttr.UpdatedById; userGroup._UpdatedAt = userGroupAttr.UpdatedAt; } else { throw new ClassError( 'UserGroup', 'UserGroupErrMsg00', 'UserGroup Not Found', ); } } return userGroup; } catch (error) { throw error; } } async create( loginUser: LoginUser, dbTransaction: any, group: Group, user: User, ) { //This method will create a user group record. try { // Part 1: Privilege Checking // Call loginUser.checkPrivileges() by passing: // SystemCode: "<get_from_app_config>" // PrivilegeCode: "USER_GROUP_CREATE" const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'USER_GROUP_CREATE', ); // If user does not have privilege to update user, throw a ClassError if (!isPrivileged) { throw new ClassError( 'UserGroup', 'UserGroupErrMsg0X', 'User does not have privilege to create user group.', ); } // Part 2: Validation // Make sure group.GroupCode exists, if not throw new ClassError by passing: // Classname: "UserGroup" // MethodName: "create" // MessageCode: "UserGroupErrMsg02" // Message: "GroupCode is required." if (!group.GroupCode) { throw new ClassError( 'UserGroup', 'UserGroupErrMsg02', 'GroupCode is required.', ); } // Make sure user.UserId exists, if not throw new ClassError by passing: // Classname: "UserGroup" // MethodName: "create" // MessageCode: "UserGroupErrMsg03" // Message: "UserId is required." if (!user.UserId) { throw new ClassError( 'UserGroup', 'UserGroupErrMsg03', 'UserId is required.', ); } // Call UserGroup.findOne static method by passing: // loginUser // dbTransaction // GroupCode: group.GroupCode // UserId: user.UserId const userGroup = await UserGroup.findOne( dbTransaction, loginUser, group.GroupCode, user.UserId, ); if (userGroup) { return userGroup; } // Part 3: Create // Set below attributes: // UserGroupId: this.createId() // UserId: Params.user.UserId // GroupCode: Params.group.GroupCode // Status: "Active" // CreatedById: loginUser.ObjectId // CreatedAt: current timestamp // UpdatedById: loginUser.ObjectId // UpdatedAt: current timestamp this.UserId = user.UserId; this.GroupCode = group.GroupCode; this.Status = 'Active'; this._CreatedById = loginUser.UserId; this._CreatedAt = new Date(); this._UpdatedById = loginUser.UserId; this._UpdatedAt = new Date(); // Call UserGroup._Repo create() method by passing: // populate this instance attributes // dbTransaction const userData = await UserGroup._Repository.create( { UserId: this.UserId, GroupCode: this.GroupCode, Status: this.Status, CreatedById: this._CreatedById, CreatedAt: this._CreatedAt, UpdatedById: this._UpdatedById, UpdatedAt: this._UpdatedAt, InheritGroupPrivilegeYN: this.InheritGroupPrivilegeYN, InheritGroupSystemAccessYN: this.InheritGroupSystemAccessYN, }, { transaction: dbTransaction, }, ); this.UserGroupId = userData.UserGroupId; // Part 4: Record Create UserGroup Activity // Initialise EntityValueAfter variable and set to this instance const EntityValueAfter = { UserGroupId: this.UserGroupId, UserId: this.UserId, GroupCode: this.GroupCode, Status: this.Status, CreatedById: this._CreatedById, CreatedAt: this._CreatedAt, UpdatedById: this._UpdatedById, UpdatedAt: this._UpdatedAt, InheritGroupPrivilegeYN: this.InheritGroupPrivilegeYN, InheritGroupSystemAccessYN: this.InheritGroupSystemAccessYN, }; // Instantiate new activity from Activity class, call createId() method, then set: // Action: ActionEnum.Create // Description: Assign user to group. // EntityType: "UserGroup" // EntityId: this.UserGroupId // EntityValueBefore: <stringify of empty object> // EntityValueAfter: EntityValueAfter const activity = new Activity(); activity.ActivityId = activity.createId(); activity.Action = ActionEnum.CREATE; activity.Description = 'Assign user to group.'; activity.EntityType = 'UserGroup'; activity.EntityId = this.UserGroupId.toString(); activity.EntityValueBefore = JSON.stringify({}); activity.EntityValueAfter = JSON.stringify(EntityValueAfter); // Call new activity create method by passing: // dbTransaction // userId: loginUser.ObjectId // return this instance await activity.create(loginUser.ObjectId, dbTransaction); return this; } catch (error) { throw error; } } public static async findOne( dbTransaction: any, loginUser: LoginUser, GroupCode: string, UserId: number, ): Promise<UserGroup> { try { // Part 1: Privilege Checking // Call loginUser.checkPrivileges() by passing: // SystemCode: "<get_from_app_config>" // PrivilegeCode: "USER_GROUP_VIEW" const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'USER_GROUP_VIEW', ); // If user does not have privilege to view user group, throw a ClassError if (!isPrivileged) { throw new ClassError( 'UserGroup', 'UserGroupErrMsg0X', 'User does not have privilege to view user group.', ); } // Part 2: Retrieve Record // Call UserGroup._Repo findOne method by passing: // where: // [Op.AND]: // UserId: Params.UserId // GroupCode: Params.GroupCode // dbTransaction const userGroupAttr = await UserGroup._Repository.findOne({ where: { UserId, GroupCode, }, transaction: dbTransaction, }); // If record exists, instantiate UserGroup by calling the private constructor and passing the attributes. Then, returns the instance if (userGroupAttr) { return new UserGroup(userGroupAttr.get({ plain: true })); } // If record not exists, return null. return null; } catch (error) { throw error; } } public static async getUser( dbTransaction: any, loginUser: LoginUser, GroupCode: string, ) { try { // Part 1: Privilege Checking // Call loginUser.checkPrivileges() by passing: // SystemCode: "<get_from_app_config>" // PrivilegeCode: "USER_GROUP_VIEW" const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'USER_GROUP_VIEW', ); // If user does not have privilege to view user group, throw a ClassError if (!isPrivileged) { throw new ClassError( 'UserGroup', 'UserGroupErrMsg0X', 'User does not have privilege to view user group.', ); } // Part 2: Retrieve Record // Call UserGroup._Repo findAll method by passing: // where: // GroupCode: Params.GroupCode // dbTransaction const userGroup = await UserGroup._Repository.findAll({ where: { GroupCode, }, include: [ { model: UserModel, as: 'User', attributes: ['UserId', 'FullName', 'Email'], }, ], transaction: dbTransaction, }); // If record exists, instantiate UserGroup by calling the private constructor and passing the attributes. Then, returns the instance return userGroup; // If record not exists, return null. return null; } catch (error) { throw error; } } static async findAllInheritedSystemAccesses( UserId: number, loginUser: User, dbTransaction: any, ): Promise< { UserGroupId: number; GroupCode: string; GroupName: string; InheritGroupSystemAccessYN: string; CreatedAt: Date; UpdatedAt: Date; Systems: { SystemCode: string; SystemName: string; AccessStatus: string; CreatedAt: Date; UpdatedAt: Date; }[]; }[] > { 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_SYSTEM_ACCESS_LIST'. // If the privilege check fails, throw an error with a 403 Forbidden status. const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'USER_SYSTEM_ACCESS_LIST', ); if (!isPrivileged) { throw new ClassError( 'UserGroup', 'UserGroupErrMsg0X', 'User does not have privilege to view user system access.', 'findAllInheritedSystemAccesses', 403, ); } // 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 InheritGroupSystemAccessYNfields. // Ensure that the value of InheritGroupSystemAccessYN is explicitly 'Y' or 'N' for each group. // If InheritGroupSystemAccessYN 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 // InheritGroupSystemAccessYN const userGroups = await UserGroup._Repository.findAll({ where: { UserId, Status: 'Active', }, include: [ { model: GroupModel, required: true, where: { Status: 'Active', }, include: [ { model: GroupSystemAccessModel, where: { Status: 'Active', }, include: [ { model: SystemModel, }, ], }, ], }, ], transaction: dbTransaction, }); const result: { UserGroupId: number; GroupCode: string; GroupName: string; InheritGroupSystemAccessYN: string; CreatedAt: Date; UpdatedAt: Date; Systems: { SystemCode: string; SystemName: string; AccessStatus: string; CreatedAt: Date; UpdatedAt: Date; }[]; }[] = []; for (const userGroup of userGroups) { // Part 3: Retrieve System Access for Groups with Inheritance // For each group where InheritGroupSystemAccessYN = 'Y', query the sso_GroupSystemAccess table to retrieve system access details. // Join with the sso_System table to fetch system details (SystemName, SystemCode). // Ensure only active system accesses (AccessStatus = 'Active') are included. // For each system access, retrieve the following fields: // SystemName (from sso_System.Name) // SystemCode (from sso_System.SystemCode) // AccessStatus (from sso_GroupSystemAccess.Status) // CreatedAt (from sso_GroupSystemAccess.CreatedAt) // UpdatedAt (from sso_GroupSystemAccess.UpdatedAt) // Part 4: Handling Non-Inherited Groups // For groups where InheritGroupSystemAccessYN = 'N', return the group details without system access records. // Set the Systems field to an empty array or null to indicate no inherited access for those groups. // Part 5: Grouping Results // Group the results by GroupCode and GroupName. // For each group, create an object with the following structure: // GroupCode: Code of the group. // GroupName: Name of the group. // InheritGroupSystemAccessYN: 'Y' or 'N', indicating whether the user inherits system access from the group. // Systems: An array of system access objects (for groups where InheritGroupSystemAccessYN = 'Y'), each including: // SystemName // SystemCode // AccessStatus // CreatedAt // UpdatedAt // For groups where InheritGroupSystemAccessYN = 'N', Systems will be an empty array. const groupData = { UserGroupId: userGroup.UserGroupId, GroupCode: userGroup.GroupCode, GroupName: userGroup.Group.Name, InheritGroupSystemAccessYN: userGroup.InheritGroupSystemAccessYN, CreatedAt: userGroup.CreatedAt, UpdatedAt: userGroup.UpdatedAt, Systems: [], }; if (userGroup.InheritGroupSystemAccessYN === 'Y') { groupData.Systems = userGroup.Group.GroupSystemAccesses.map( (groupSystemAccess) => { return { SystemCode: groupSystemAccess.System.SystemCode, SystemName: groupSystemAccess.System.Name, AccessStatus: groupSystemAccess.Status, CreatedAt: groupSystemAccess.CreatedAt, UpdatedAt: groupSystemAccess.UpdatedAt, }; }, ); } result.push(groupData); } // Part 6: Return Grouped Data // Return the array of grouped system accesses for the user's groups, including both inherited ('Y') and non-inherited ('N') system accesses. return result; } catch (error) { throw error; } } public async update( loginUser: LoginUser, dbTransaction: Transaction, UpdatedProperties: { InheritGroupPrivilegeYN?: string; InheritGroupSystemAccessYN?: string; }, ): Promise<UserGroup> { 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_GROUP_UPDATE'. const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'USER_GROUP_UPDATE', ); // If the privilege check fails, throw an error with a 403 Forbidden status. if (!isPrivileged) { throw new ClassError( 'UserGroup', 'UserGroupErrMsg0X', 'User does not have privilege to update user group.', 'update', 403, ); } // Part 2: Validation // Check to make sure that at least one of the UpdatedProperties is exist if not throw error. if ( !UpdatedProperties.InheritGroupPrivilegeYN && !UpdatedProperties.InheritGroupSystemAccessYN ) { throw new ClassError( 'UserGroup', 'UserGroupErrMsg04', 'At least one of the properties to update is required.', 'update', 400, ); } // Part 3: Update User Group // Call the UserGroup._Repo.update() method to perform the update operation, passing: // InheritGroupPrivilegeYN (if exist): updatedProperties.InheritGroupPrivilegeYN // InheritGroupSystemAccessYN (if exist): updatedProperties.InheritGroupSystemAccessYN // UpdatedById: loginUser.UserId (to indicate who updated the record). // UpdatedAt: Set to the current date and time. // dbTransaction: The database transaction instance. const entityValueBefore = { UserGroupId: this.UserGroupId, UserId: this.UserId, GroupCode: this.GroupCode, Status: this.Status, CreatedById: this._CreatedById, CreatedAt: this._CreatedAt, UpdatedById: this._UpdatedById, UpdatedAt: this._UpdatedAt, InheritGroupPrivilegeYN: this.InheritGroupPrivilegeYN, InheritGroupSystemAccessYN: this.InheritGroupSystemAccessYN, }; this._UpdatedById = loginUser.UserId; this._UpdatedAt = new Date(); if (UpdatedProperties.InheritGroupPrivilegeYN) { this.InheritGroupPrivilegeYN = UpdatedProperties.InheritGroupPrivilegeYN; } if (UpdatedProperties.InheritGroupSystemAccessYN) { this.InheritGroupSystemAccessYN = UpdatedProperties.InheritGroupSystemAccessYN; } await UserGroup._Repository.update( { InheritGroupPrivilegeYN: this.InheritGroupPrivilegeYN, InheritGroupSystemAccessYN: this.InheritGroupSystemAccessYN, UpdatedById: this._UpdatedById, UpdatedAt: this._UpdatedAt, }, { where: { UserGroupId: this.UserGroupId, }, transaction: dbTransaction, }, ); // Part 2: Record Activity History // Initialize a variable entityValueBefore to store the current state of the record before the update. const entityValueAfter = { UserGroupId: this.UserGroupId, UserId: this.UserId, GroupCode: this.GroupCode, Status: this.Status, CreatedById: this._CreatedById, CreatedAt: this._CreatedAt, UpdatedById: this._UpdatedById, UpdatedAt: this._UpdatedAt, InheritGroupPrivilegeYN: this.InheritGroupPrivilegeYN, InheritGroupSystemAccessYN: this.InheritGroupSystemAccessYN, }; // 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 Group. // EntityType: Set to UserGroup. // EntityId: Use the ID of the updated record. // EntityValueBefore: Stringify entityValueBefore to capture the state before the update. // EntityValueAfter: Stringify the updated record to capture the new state after the update. const activity = new Activity(); activity.ActivityId = activity.createId(); activity.Action = ActionEnum.UPDATE; activity.Description = 'Update User Group'; activity.EntityType = 'UserGroup'; activity.EntityId = this.UserGroupId.toString(); activity.EntityValueBefore = JSON.stringify(entityValueBefore); activity.EntityValueAfter = JSON.stringify(entityValueAfter); // Call the activity create a method with the following parameters: // dbTransaction // userId: loginUser.UserId // Part 3: Return Updated Record await activity.create(loginUser.ObjectId, dbTransaction); // Retrieve the updated user group record from the database or return the updated instance as needed. return this; } catch (error) { throw error; } } public static async isUserMemberOfGroup( dbTransaction: any, loginUser: LoginUser, UserId: number, GroupCode: string, ): Promise<boolean> { 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_GROUP_VIEW'. const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'USER_GROUP_VIEW', ); // If the privilege check fails, throw an error with a 403 Forbidden status. if (!isPrivileged) { throw new ClassError( 'UserGroup', 'UserGroupErrMsg0X', 'User does not have privilege to view user group.', 'isUserMemberOfGroup', 403, ); } // Part 2: Retrieve User Group // Query the sso_UserGroup table to find the user group record with the given UserId and GroupCode. // If the record exists, return true; otherwise, return false. const userGroup = await UserGroup.findOne( dbTransaction, loginUser, GroupCode, UserId, ); return !!userGroup; } catch (error) { throw error; } } public async delete( loginUser: LoginUser, dbTransaction: Transaction, ): Promise<void> { try { // Part 1: Privilege Checking // Call loginUser.checkPrivileges() to ensure the user has permission to delete user group records. // SystemCode: Retrieve from app config. // PrivilegeCode: 'USER_GROUP_DELETE'. const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'USER_GROUP_DELETE', ); // If the privilege check fails, throw an error with a 403 Forbidden status. if (!isPrivileged) { throw new ClassError( 'UserGroup', 'UserGroupErrMsg0X', 'User does not have privilege to delete user group.', 'delete', 403, ); } // Part 2: Delete User Group // Call the UserGroup._Repo.destroy() method to delete the user group record with the given UserGroupId. // Pass the dbTransaction parameter to ensure the operation is part of the current transaction. await UserGroup._Repository.delete({ where: { UserGroupId: this.UserGroupId, }, transaction: dbTransaction, }); // Part 3: Record Activity History // Initialize a variable entityValueBefore to store the current state of the record before the update. const entityValueBefore = { UserGroupId: this.UserGroupId, UserId: this.UserId, GroupCode: this.GroupCode, Status: this.Status, CreatedById: this._CreatedById, CreatedAt: this._CreatedAt, UpdatedById: this._UpdatedById, UpdatedAt: this._UpdatedAt, InheritGroupPrivilegeYN: this.InheritGroupPrivilegeYN, InheritGroupSystemAccessYN: this.InheritGroupSystemAccessYN, }; // Create an instance of the Activity class and set the following properties: // ActivityId: Call activity.createId(). // Action: Set to ActionEnum.Delete. // Description: Set to Delete User Group. // EntityType: Set to UserGroup. // EntityId: Use the ID of the deleted record. // EntityValueBefore: Stringify entityValueBefore to capture the state before the delete. // EntityValueAfter: Set to an empty string to indicate the record has been deleted. const activity = new Activity(); activity.ActivityId = activity.createId(); activity.Action = ActionEnum.DELETE; activity.Description = `Delete User Group ${this.UserGroupId}`; activity.EntityType = 'UserGroup'; activity.EntityId = this.UserGroupId.toString(); activity.EntityValueBefore = JSON.stringify(entityValueBefore); activity.EntityValueAfter = JSON.stringify({}); // Call the activity create method with the following parameters: // dbTransaction // userId: loginUser.UserId await activity.create(loginUser.ObjectId, dbTransaction); } catch (error) { throw error; } } }