@tomei/live-price
Version:
Tomei live-price Package
263 lines (239 loc) • 7.86 kB
text/typescript
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}`);
}
}
}