Re_Backend/src/services/form16Permission.service.ts

90 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Form 16 permission service API-driven access based on admin configuration.
* Reads submissionViewerEmails and twentySixAsViewerEmails from FORM16_ADMIN_CONFIG.
* No hardcoded emails or roles; all driven by stored config.
*/
import { sequelize } from '../config/database';
import { QueryTypes } from 'sequelize';
import { getDealerCodeForUser } from './form16.service';
const FORM16_CONFIG_KEY = 'FORM16_ADMIN_CONFIG';
export interface Form16ViewerConfig {
submissionViewerEmails: string[];
twentySixAsViewerEmails: string[];
}
const emptyConfig: Form16ViewerConfig = {
submissionViewerEmails: [],
twentySixAsViewerEmails: [],
};
/** Normalize email for comparison (lowercase, trim). */
function normalizeEmail(email: string): string {
return (email || '').trim().toLowerCase();
}
/**
* Load Form 16 viewer config from admin_configurations (API-driven).
* Returns empty arrays if no config or parse error (empty = allow all).
*/
export async function getForm16ViewerConfig(): Promise<Form16ViewerConfig> {
try {
const result = await sequelize.query<{ config_value: string }>(
`SELECT config_value FROM admin_configurations WHERE config_key = :configKey LIMIT 1`,
{ replacements: { configKey: FORM16_CONFIG_KEY }, type: QueryTypes.SELECT }
);
if (!result?.length || !result[0].config_value) {
return emptyConfig;
}
const parsed = JSON.parse(result[0].config_value);
const submission = Array.isArray(parsed.submissionViewerEmails)
? parsed.submissionViewerEmails.map((e: unknown) => normalizeEmail(String(e ?? ''))).filter(Boolean)
: [];
const twentySixAs = Array.isArray(parsed.twentySixAsViewerEmails)
? parsed.twentySixAsViewerEmails.map((e: unknown) => normalizeEmail(String(e ?? ''))).filter(Boolean)
: [];
return { submissionViewerEmails: submission, twentySixAsViewerEmails: twentySixAs };
} catch {
return emptyConfig;
}
}
/**
* Check if user can view Form 16 submission data (Credit Notes, Non-submitted Dealers, etc.).
* - Admin: always allowed (full access to everything).
* - Dealers: always allowed (they see their own submissions).
* - RE users: allowed if submissionViewerEmails is empty, or user email is in submissionViewerEmails,
* or user email is in twentySixAsViewerEmails (26AS access implies submission access so sidebar shows both).
*/
export async function canViewForm16Submission(
userEmail: string,
userId: string,
role?: string
): Promise<boolean> {
if (role === 'ADMIN') return true;
const isDealer = (await getDealerCodeForUser(userId)) !== null;
if (isDealer) return true;
const config = await getForm16ViewerConfig();
const email = normalizeEmail(userEmail);
if (!email) return false;
if (config.submissionViewerEmails.length === 0 && config.twentySixAsViewerEmails.length === 0) return true;
if (config.submissionViewerEmails.includes(email)) return true;
if (config.twentySixAsViewerEmails.includes(email)) return true;
return false;
}
/**
* Check if user can view 26AS page and 26AS data.
* - Admin: always allowed (full access to everything).
* - Otherwise: allowed if twentySixAsViewerEmails is empty, or user email is in the list.
*/
export async function canView26As(userEmail: string, role?: string): Promise<boolean> {
if (role === 'ADMIN') return true;
const config = await getForm16ViewerConfig();
const email = normalizeEmail(userEmail);
if (config.twentySixAsViewerEmails.length === 0) return true;
return config.twentySixAsViewerEmails.includes(email);
}