import { getObjectEntries, isDefined, isEmpty } from "prostgles-types"; import type { TableHandler } from "../DboBuilder/TableHandler/TableHandler"; import { type ParsedTableRule, type PermissionScope } from "./PublishParser"; export const applyScopeToTableRules = ( tableName: string, tableHandler: Partial, tableRules: ParsedTableRule | undefined, scope: PermissionScope | undefined, ): ParsedTableRule | undefined => { if (!tableRules) return; if (!scope || scope.allowSql) return tableRules; const tableScope = scope.tables?.[tableName]; if (!tableScope) return; const validatedTableRules = tableHandler.getValidatedRules?.(tableRules); if (!validatedTableRules) { throw "INTERNAL ERROR: getValidatedRules is missing for " + tableName; } /** Make sure the scope does not allow things outside the validatedTableRules */ const result = fromEntries( getObjectEntries(tableScope) .map(([ruleName, ruleScope]) => { if (!ruleScope) return undefined; const rule = tableRules[ruleName]; const validatedRule = validatedTableRules[ruleName]; if (!validatedRule || !rule) { throw `Invalid scope: ${tableName}.${ruleName}. The publish does not allow this command.`; } if (ruleScope === true || isEmpty(ruleScope)) { return [ruleName, rule] as const; } const scopeFields = "fields" in ruleScope ? ruleScope.fields : undefined; const scopeFieldList = scopeFields && tableHandler.parseFieldFilter!(scopeFields); const scopeForcedFilter = "forcedFilter" in ruleScope ? ruleScope.forcedFilter : undefined; if (scopeFieldList) { if (!scopeFieldList.length) { throw `Invalid scope: ${tableName}.${ruleName}. At least one field must be selected.`; } const validatedRuleFields = "fields" in validatedRule ? validatedRule.fields : undefined; for (const field of scopeFieldList) { if (!validatedRuleFields?.includes(field)) { throw `Invalid scope: ${tableName}.${ruleName}. The field "${field}" is not allowed to be selected according to the publish rules.`; } } } const ruleForcedFilter = "forcedFilter" in validatedRule ? validatedRule.forcedFilter : undefined; const combinedForcedFilter = scopeForcedFilter && ruleForcedFilter ? { $and: [scopeForcedFilter, ruleForcedFilter] } : scopeForcedFilter || ruleForcedFilter; return [ ruleName, { ...rule, ...(scopeFieldList && { fields: fromEntries(scopeFieldList.map((field) => [field, 1] as const)), }), ...(scopeForcedFilter && { forcedFilter: combinedForcedFilter }), }, ] as const; }) .filter(isDefined), ) as ParsedTableRule; return result; }; export const fromEntries = ( entries: readonly (readonly [K, V])[], ): Record => { return Object.fromEntries(entries) as Record; };