UNPKG

@tomei/sso

Version:
457 lines (416 loc) 13.9 kB
import { ClassError, HashTable, ObjectBase } from '@tomei/general'; import { SystemRepository } from './system.repository'; import { ISystemAttr } from '../../interfaces/system.interface'; import { LoginUser } from '../login-user/login-user'; import { ApplicationConfig, ComponentConfig } from '@tomei/config'; import { ActionEnum, Activity } from '@tomei/activity-history'; import { ISystemSearchAttr } from '../../interfaces/system-search-attr.interface'; import { Op } from 'sequelize'; import { v4 as uuidv4 } from 'uuid'; export class System extends ObjectBase { ObjectId: string; ObjectName: string; TableName = 'sso_System'; ObjectType = 'System'; private static _htSystem: HashTable; SystemCode: string; Name: string; Description: string; AccessURL: string; GooglePlayURL: string; AppleStoreURL: string; APIKey: string; APISecret: string; Status: string; private _CreatedById: number; private _CreatedAt: Date; private _UpdatedById: number; private _UpdatedAt: Date; private static _Repo = new SystemRepository(); 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(systemAttr?: ISystemAttr) { super(); if (systemAttr) { this.SystemCode = systemAttr.SystemCode; this.Name = systemAttr.Name; this.Description = systemAttr?.Description; this.AccessURL = systemAttr?.AccessURL; this.GooglePlayURL = systemAttr?.GooglePlayURL; this.AppleStoreURL = systemAttr?.AppleStoreURL; this.APIKey = systemAttr?.APIKey; this.APISecret = systemAttr?.APISecret; this.Status = systemAttr?.Status; this._CreatedById = systemAttr.CreatedById; this._CreatedAt = systemAttr.CreatedAt; this._UpdatedById = systemAttr.UpdatedById; this._UpdatedAt = systemAttr.UpdatedAt; } } public static async init(dbTransaction: any, SystemCode?: string) { try { if (SystemCode) { const system = await System._Repo.findByPk(SystemCode, { transaction: dbTransaction, }); if (system) { return new System(system); } else { throw new ClassError('System', 'SystemErrMsg00', 'System Not Found'); } } return new System(); } catch (error) { throw new ClassError( 'System', 'SystemErrMsg01', 'Failed To Initialize System', ); } } public async createSystem( loginUser: LoginUser, dbTransaction: any, ): Promise<void> { try { //Creates a new system in the database. //Part 1: Check Privilege //Call loginUser.checkPrivilege() method to check if the user has the privilege to create a system. const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'System - Create', ); if (!isPrivileged) { throw new Error('You do not have permission to list UserGroup.'); } //Part 2: Validate Input Params //If this._SystemCode is missing, throw ClassError if (!this.SystemCode) { throw new ClassError( 'System', 'SystemErrMsg02', 'SystemCode must have value.', ); } //If this._Name missing, throw ClassError if (!this.Name) { throw new ClassError( 'System', 'SystemErrMsg03', 'Name must have value.', ); } //If this._Description missing, throw ClassError if (!this.Description) { throw new ClassError( 'System', 'SystemErrMsg04', 'Description must have value.', ); } //Part 3: Prepare to Insert Data //Set private properties this._CreatedById = loginUser.UserId; this._CreatedAt = new Date(); this._UpdatedById = loginUser.UserId; this._UpdatedAt = new Date(); //Call System._Repo create method await System._Repo.create( { SystemCode: this.SystemCode, Name: this.Name, Description: this.Description, AccessURL: this.AccessURL, GooglePlayURL: this.GooglePlayURL, AppleStoreURL: this.AppleStoreURL, APIKey: this.APIKey, APISecret: this.APISecret, Status: this.Status, CreatedById: this._CreatedById, CreatedAt: this._CreatedAt, UpdatedById: this._UpdatedById, UpdatedAt: this._UpdatedAt, }, { transaction: dbTransaction, }, ); //Part 4: Record Create System Activity //Initialise EntityValueAfter variable and set to this class. const entityValueAfter = { SystemCode: this.SystemCode, Name: this.Name, Description: this.Description, AccessURL: this.AccessURL, GooglePlayURL: this.GooglePlayURL, AppleStoreURL: this.AppleStoreURL, APIKey: this.APIKey, APISecret: this.APISecret, Status: this.Status, }; //Instantiate new activity from Activity class, call createId() method, then set the properties. const activity = new Activity(); activity.ActivityId = activity.createId(); activity.Action = ActionEnum.CREATE; activity.Description = 'Add System'; activity.EntityType = 'System'; activity.EntityId = this.SystemCode; activity.EntityValueBefore = JSON.stringify({}); activity.EntityValueAfter = JSON.stringify(entityValueAfter); } catch (error) { throw error; } } protected static async checkDuplicateSystemCode( dbTransaction: any, systemCode: string, ): Promise<void> { //This method will make sure there is no duplicate system code. try { //Call System._Repo findOne() method by passing Params.SystemCode and dbTransaction, if SystemCode already exists, throw ClassError. const system = await System._Repo.findOne({ where: { SystemCode: systemCode, }, transaction: dbTransaction, }); if (system) { throw new ClassError( 'System', 'SystemErrMsg05', 'System Code already exists.', ); } } catch (error) { throw error; } } public async setSystemCode( dbTransaction: any, systemCode: string, ): Promise<void> { //Custom setter method for SystemCode try { //Call checkDuplicateSystemCode() method to make sure there is no duplicate system code. await System.checkDuplicateSystemCode(dbTransaction, systemCode); //Set this._SystemCode to Params.SystemCode this.SystemCode = systemCode; } catch (error) { throw error; } } public static async findAll( dbTransaction: any, loginUser: LoginUser, page?: number, rows?: number, search?: ISystemSearchAttr, ): Promise<{ count: number; systems: System[] }> { //This method list all system records based on filter. try { //Part 1: Retrieve listing const queryObj: any = {}; const whereObj: any = {}; if (search) { Object.entries(search).forEach(([key, value]) => { if (value) { queryObj[key] = { [Op.substring]: value, }; } }); } if (page && rows) { whereObj.offset = (page - 1) * rows; whereObj.limit = rows; } //Call System._Repo findAll() method by passing queryObj and whereObj const result = await System._Repo.findAllWithPagination({ distinct: true, where: queryObj, ...whereObj, order: [['CreatedAt', 'DESC']], transaction: dbTransaction, }); //Return result const systems = result.rows.map((system) => new System(system)); return { count: result.count, systems }; } catch (error) { throw error; } } public static async renewApiKeyAndSecret( loginUser: LoginUser, dbTransaction: any, systemCode: string, ) { try { //Part 1: Privilege Checking //Call loginUser.checkPrivilege() method to check if the user has the privilege to renew API Key and Secret. const sc = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges(sc, 'SYSTEM_UPDATE'); if (!isPrivileged) { throw new ClassError( 'System', 'SystemErrMsg06', 'You do not have permission to renew API Key and Secret.', ); } //Part 2: Validation //Instantiate existing System const system = await System.init(dbTransaction, systemCode); //Check if system.AccessURL got value. If not, throw new ClassError if (!system.AccessURL) { throw new ClassError( 'System', 'SystemErrMsg07', 'AccessURL is required for callback', ); } //Check if system.Status is "Active". If not, throw new ClassError if (system.Status !== 'Active') { throw new ClassError( 'System', 'SystemErrMsg08', 'Cannot do this operation on inactive system.', ); } //Set EntityValueBefore to system instance. const entityValueBefore = { SystemCode: system.SystemCode, Name: system.Name, Description: system.Description, AccessURL: system.AccessURL, GooglePlayURL: system.GooglePlayURL, AppleStoreURL: system.AppleStoreURL, APIKey: system.APIKey, APISecret: system.APISecret, Status: system.Status, }; //Part 3: Generate API key and secret //Use https://www.npmjs.com/package/uuid package to generate both the api key and api secret. const apiKey = uuidv4(); const apiSecret = uuidv4(); //Update the system instance with new API key and secret. system.APIKey = apiKey; system.APISecret = apiSecret; system._UpdatedById = loginUser.UserId; system._UpdatedAt = new Date(); //Call System._Repo update() method to update the system record. await System._Repo.update( { APIKey: apiKey, APISecret: apiSecret, UpdatedById: system._UpdatedById, UpdatedAt: system._UpdatedAt, }, { where: { SystemCode: systemCode, }, transaction: dbTransaction, }, ); //Part 4: Record Renew API Key and Secret Activity //Set EntityValueAfter to system instance. const entityValueAfter = { SystemCode: system.SystemCode, Name: system.Name, Description: system.Description, AccessURL: system.AccessURL, GooglePlayURL: system.GooglePlayURL, AppleStoreURL: system.AppleStoreURL, APIKey: system.APIKey, APISecret: system.APISecret, Status: system.Status, }; //Instantiate new activity from Activity class, call createId() method, then set the properties. const activity = new Activity(); activity.ActivityId = activity.createId(); activity.Action = ActionEnum.UPDATE; activity.Description = 'Renew API key and secret for a system'; activity.EntityType = 'System'; activity.EntityId = system.SystemCode; activity.EntityValueBefore = JSON.stringify(entityValueBefore); activity.EntityValueAfter = JSON.stringify(entityValueAfter); await activity.create(loginUser.ObjectId, dbTransaction); //Return the updated system instance. return system; } catch (error) { throw error; } } public static async loadSystem(dbTransaction): Promise<string> { try { // Part 1: Retrieve System Info // Load sso component config.loadComponentConfig Call Config. by passing: // filepath: '/component-config/sso-config.json' ComponentConfig.loadComponentConfig('./component-config/sso-config.json'); const config: { name: string; code: string; description: string; userId: string; } = ComponentConfig.getComponentConfigValue('@tomei/sso', 'system'); // Make sure all required fields are provided in the config file. if ( !config.name || !config.code || !config.description || !config.userId ) { throw new Error('Missing required fields in the config file.'); } // Retrieve existing System. Call System._Repo findByPk method by passing: // SystemCode: system.code // dbTransaction const system = await System._Repo.findByPk(config.code, { transaction: dbTransaction, }); // If system already exists, skip all steps below and return "System loaded." if (system) { return 'System loaded.'; } //if system not exists. Call System._Repo create method by passing: // SystemCode: system.code, // Name: system.name // Description: system.description, // Status: 'Active', // CreatedById: system.userId // CreatedAt: current date & time // UpdatedById: system.userId // UpdatedAt: current date & time await System._Repo.create( { SystemCode: config.code, Name: config.name, Description: config.description, Status: 'Active', CreatedById: config.userId, CreatedAt: new Date(), UpdatedById: config.userId, UpdatedAt: new Date(), }, { transaction: dbTransaction, }, ); // Return "System loaded." return 'System loaded.'; } catch (error) { throw error; } } }