UNPKG

@tomei/live-price

Version:

Tomei live-price Package

263 lines (239 loc) 7.86 kB
import { ClassError } from '@tomei/general'; import { PriceCompanyFeedAccessAttr } from '../../interfaces/price-company-feed-access-attr.interface'; import { NonSourceFeedName, PricingLogic } from '../../enum/feed.enum'; import { CompanyFeedAccessRepository } from './company-feed-access.repository'; import { createId, init } from '@paralleldrive/cuid2'; export class CompanyFeedAccess implements PriceCompanyFeedAccessAttr { CompanyAccessId?: string; CompanyCode: string; FeedName: string; Status: string; PricingLogic: PricingLogic; CreatedById: number; CreatedAt?: Date; UpdatedById: number; UpdatedAt?: Date; protected static _Repo = new CompanyFeedAccessRepository(); constructor(accessAttr?: PriceCompanyFeedAccessAttr) { if (accessAttr) { this.CompanyAccessId = accessAttr.CompanyAccessId; this.CompanyCode = accessAttr.CompanyCode; this.FeedName = accessAttr.FeedName; this.Status = accessAttr.Status; this.PricingLogic = accessAttr.PricingLogic; this.CreatedById = accessAttr.CreatedById; this.CreatedAt = accessAttr.CreatedAt; this.UpdatedById = accessAttr.UpdatedById; this.UpdatedAt = accessAttr.UpdatedAt; } } public static async init( dbTransaction: any, CompanyAccessId?: string, ): Promise<CompanyFeedAccess> { try { if (CompanyAccessId) { const access = await CompanyFeedAccess._Repo.findByPk( CompanyAccessId, dbTransaction, ); if (access) { return new CompanyFeedAccess(access as PriceCompanyFeedAccessAttr); } else { throw new ClassError( 'CompanyFeedAccess', 'CompanyFeedAccessErrMsg00', 'Company Feed Access Not Found', ); } } return new CompanyFeedAccess(); } catch (error) { throw new ClassError( 'CompanyFeedAccess', 'CompanyFeedAccessErrMsg01', error.message, ); } } public async save(dbTransaction: any) { try { const existingAccess = await CompanyFeedAccess._Repo.findOne({ where: { CompanyCode: this.CompanyCode, FeedName: this.FeedName, }, transaction: dbTransaction, }); const payload: PriceCompanyFeedAccessAttr = { CompanyCode: this.CompanyCode, FeedName: this.FeedName, Status: this.Status, PricingLogic: this.PricingLogic, CreatedById: this.CreatedById, UpdatedById: this.UpdatedById, }; if (existingAccess) { payload.CompanyAccessId = existingAccess.CompanyAccessId; const affectedRows = await CompanyFeedAccess._Repo.update(payload, { where: { CompanyAccessId: existingAccess.CompanyAccessId }, transaction: dbTransaction, }); if (affectedRows[0] === 0) { throw new Error('Failed to update company feed access'); } this.CompanyAccessId = existingAccess.CompanyAccessId; } else { payload.CompanyAccessId = createId(); const newAccess = await CompanyFeedAccess._Repo.create(payload, { transaction: dbTransaction, }); this.CompanyAccessId = newAccess.CompanyAccessId; this.CreatedAt = newAccess.CreatedAt; this.UpdatedAt = newAccess.UpdatedAt; } } catch (error) { throw new ClassError( 'CompanyFeedAccess', 'CompanyFeedAccessErrMsg02', error.message, ); } } public static async hasAccessToFeed( dbTransaction: any, feedName: NonSourceFeedName, companyCode: string, ): Promise<boolean> { try { // Check if there are any access rules for this feed const accessRules = await CompanyFeedAccess._Repo.findAll({ where: { FeedName: feedName, Status: 'Active', }, transaction: dbTransaction, }); // If no access rules exist for this feed, it's available to all companies if (accessRules.length === 0) { return true; } // Check if the company is in the allowed list const hasAccess = accessRules.some( (rule: any) => rule.CompanyCode === companyCode, ); return hasAccess; } catch (error) { // Fail open - allow access if there's an error return true; } } public static async getAccessibleFeeds( dbTransaction: any, companyCode: string, ): Promise<NonSourceFeedName[]> { try { // Get all active access rules for this company const accessRules = await CompanyFeedAccess._Repo.findAll({ where: { CompanyCode: companyCode, Status: 'Active', }, attributes: ['FeedName'], transaction: dbTransaction, }); // Return only the feed names that have explicit access rules return accessRules.map((rule: any) => rule.FeedName as NonSourceFeedName); } catch (error) { // Return empty array if there's an error (fail closed) return []; } } public static async validateFeedAccess( dbTransaction: any, feedName: NonSourceFeedName, companyCode: string, ): Promise<void> { const hasAccess = await CompanyFeedAccess.hasAccessToFeed( dbTransaction, feedName, companyCode, ); if (!hasAccess) { const allowedCompanies = await CompanyFeedAccess.getCompaniesWithAccessToFeed( dbTransaction, feedName, ); throw new Error( `Access denied: Company '${companyCode}' does not have access to feed '${feedName}'. ` + `This feed is restricted to: ${allowedCompanies.join(', ')}`, ); } } public static async getCompaniesWithAccessToFeed( dbTransaction: any, feedName: NonSourceFeedName, ): Promise<string[]> { try { const accessRules = await CompanyFeedAccess._Repo.findAll({ where: { FeedName: feedName, Status: 'Active', }, attributes: ['CompanyCode'], transaction: dbTransaction, }); return accessRules.map((rule: any) => rule.CompanyCode); } catch (error) { return []; } } public static async getAllFeedAccessConfiguration( dbTransaction: any, ): Promise<Record<string, string[]>> { try { const accessRules = await CompanyFeedAccess._Repo.findAll({ where: { Status: 'Active', }, attributes: ['FeedName', 'CompanyCode'], transaction: dbTransaction, }); const feedAccess: Record<string, string[]> = {}; for (const rule of accessRules) { if (!feedAccess[rule.FeedName]) { feedAccess[rule.FeedName] = []; } feedAccess[rule.FeedName].push(rule.CompanyCode); } return feedAccess; } catch (error) { return {}; } } public static async getPricingLogic( dbTransaction: any, feedName: NonSourceFeedName, companyCode: string, ): Promise<PricingLogic> { try { const accessRule = await CompanyFeedAccess._Repo.findOne({ where: { FeedName: feedName, CompanyCode: companyCode, Status: 'Active', }, transaction: dbTransaction, }); if (!accessRule) { throw new Error( `No pricing logic configuration found for company '${companyCode}' and feed '${feedName}'`, ); } return accessRule.PricingLogic; } catch (error) { throw new Error(`Failed to retrieve pricing logic: ${error.message}`); } } }