1
import type { LogicalFilterAND, LogicalFilterOR, Permission } from '@directus/types';
2
import { flatten, intersection, isEqual, merge, omit } from 'lodash-es';
4
export function mergePermissions(strategy: 'and' | 'or', ...permissions: Permission[][]): Permission[] {
5
const allPermissions = flatten(permissions);
7
const mergedPermissions = allPermissions
8
.reduce((acc, val) => {
9
const key = `${val.collection}__${val.action}__${val.role || '$PUBLIC'}`;
10
const current = acc.get(key);
11
acc.set(key, current ? mergePermission(strategy, current, val) : val);
16
return Array.from(mergedPermissions);
19
export function mergePermission(
20
strategy: 'and' | 'or',
21
currentPerm: Permission,
23
): Omit<Permission, 'id' | 'system'> {
24
const logicalKey = `_${strategy}` as keyof LogicalFilterOR | keyof LogicalFilterAND;
26
let permissions = currentPerm.permissions;
27
let validation = currentPerm.validation;
28
let fields = currentPerm.fields;
29
let presets = currentPerm.presets;
31
if (newPerm.permissions) {
32
if (currentPerm.permissions && Object.keys(currentPerm.permissions)[0] === logicalKey) {
35
...(currentPerm.permissions as LogicalFilterOR & LogicalFilterAND)[logicalKey],
38
} as LogicalFilterAND | LogicalFilterOR;
39
} else if (currentPerm.permissions) {
41
if (strategy === 'or' && (isEqual(currentPerm.permissions, {}) || isEqual(newPerm.permissions, {}))) {
45
[logicalKey]: [currentPerm.permissions, newPerm.permissions],
46
} as LogicalFilterAND | LogicalFilterOR;
50
[logicalKey]: [newPerm.permissions],
51
} as LogicalFilterAND | LogicalFilterOR;
55
if (newPerm.validation) {
56
if (currentPerm.validation && Object.keys(currentPerm.validation)[0] === logicalKey) {
59
...(currentPerm.validation as LogicalFilterOR & LogicalFilterAND)[logicalKey],
62
} as LogicalFilterAND | LogicalFilterOR;
63
} else if (currentPerm.validation) {
65
if (strategy === 'or' && (isEqual(currentPerm.validation, {}) || isEqual(newPerm.validation, {}))) {
69
[logicalKey]: [currentPerm.validation, newPerm.validation],
70
} as LogicalFilterAND | LogicalFilterOR;
74
[logicalKey]: [newPerm.validation],
75
} as LogicalFilterAND | LogicalFilterOR;
80
if (Array.isArray(currentPerm.fields) && strategy === 'or') {
81
fields = [...new Set([...currentPerm.fields, ...newPerm.fields])];
82
} else if (Array.isArray(currentPerm.fields) && strategy === 'and') {
83
fields = intersection(currentPerm.fields, newPerm.fields);
85
fields = newPerm.fields;
88
if (fields.includes('*')) fields = ['*'];
91
if (newPerm.presets) {
92
presets = merge({}, presets, newPerm.presets);