All files / components/collections rulesHelpers.ts

100% Statements 14/14
100% Branches 2/2
100% Functions 12/12
100% Lines 12/12

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91                                              5x                                               63x                             46x             22x       115x 11x         115x 103x         23x 115x 115x 1x    
/**
 * Helpers for collection access-rule draft comparison and status display.
 * Semantics match authorization middleware:
 * - null → locked (403 for non-superadmin)
 * - "" → public (unauthenticated allowed)
 * - non-empty → custom expression (auth required)
 */
 
import type { CollectionRule } from '@/services/collections.service';
 
export type RuleOperationKey =
  | 'list_rule'
  | 'view_rule'
  | 'create_rule'
  | 'update_rule'
  | 'delete_rule';
 
export type FieldPermissionKey =
  | 'list_fields'
  | 'view_fields'
  | 'create_fields'
  | 'update_fields';
 
export const RULE_OPERATIONS: { key: RuleOperationKey; label: string }[] = [
  { key: 'list_rule', label: 'List' },
  { key: 'view_rule', label: 'View' },
  { key: 'create_rule', label: 'Create' },
  { key: 'update_rule', label: 'Update' },
  { key: 'delete_rule', label: 'Delete' },
];
 
/** Snapshot of rule fields used for dirty comparison and saves. */
export interface RulesSnapshot {
  list_rule: string | null;
  view_rule: string | null;
  create_rule: string | null;
  update_rule: string | null;
  delete_rule: string | null;
  list_fields: string;
  view_fields: string;
  create_fields: string;
  update_fields: string;
}
 
export function toRulesSnapshot(
  rules: Pick<CollectionRule, keyof RulesSnapshot>,
): RulesSnapshot {
  return {
    list_rule: rules.list_rule,
    view_rule: rules.view_rule,
    create_rule: rules.create_rule,
    update_rule: rules.update_rule,
    delete_rule: rules.delete_rule,
    list_fields: rules.list_fields,
    view_fields: rules.view_fields,
    create_fields: rules.create_fields,
    update_fields: rules.update_fields,
  };
}
 
/** Stable string for dirty comparison. */
export function normalizeRulesForCompare(rules: RulesSnapshot): string {
  return JSON.stringify(toRulesSnapshot(rules));
}
 
export function isRulesDirty(
  draft: RulesSnapshot,
  baseline: RulesSnapshot,
): boolean {
  return normalizeRulesForCompare(draft) !== normalizeRulesForCompare(baseline);
}
 
export function getPublicOperations(rules: RulesSnapshot): string[] {
  return RULE_OPERATIONS.filter(({ key }) => rules[key] === '').map(
    ({ label }) => label,
  );
}
 
export function getLockedOperations(rules: RulesSnapshot): string[] {
  return RULE_OPERATIONS.filter(({ key }) => rules[key] === null).map(
    ({ label }) => label,
  );
}
 
export function getCustomOperations(rules: RulesSnapshot): string[] {
  return RULE_OPERATIONS.filter(({ key }) => {
    const v = rules[key];
    return v !== null && v !== '';
  }).map(({ label }) => label);
}