2025-02-21 11:29:43 +08:00

87 lines
2.6 KiB
TypeScript

/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import _ from 'lodash';
export function mergeRole(roles) {
const result: Record<string, any> = {
roles: [],
strategy: {},
actions: null,
snippets: [],
resources: null,
};
for (const role of roles) {
const jsonRole = role.toJSON();
result.roles = mergeRoleNames(result.roles, jsonRole.role);
result.strategy = mergeRoleStrategy(result.strategy, jsonRole.strategy);
result.actions = mergeRoleActions(result.actions, jsonRole.actions);
result.snippets = mergeRoleSnippets(result.snippets, jsonRole.snippets);
result.resources = mergeRoleResources(result.resources, [...role.resources.keys()]);
}
return result;
}
function mergeRoleNames(sourceRoleNames, newRoleName) {
return newRoleName ? sourceRoleNames.concat(newRoleName) : sourceRoleNames;
}
function mergeRoleStrategy(sourceStrategy, newStrategy) {
if (!newStrategy) {
return sourceStrategy;
}
const actions = sourceStrategy.actions.concat(newStrategy.actions);
return {
...sourceStrategy,
actions: [...new Set(actions)],
};
}
function mergeRoleActions(sourceActions, newActions = {}) {
// {} 为最大权限,两者合并取最大权限
const isObjectEmpty = (value) => {
return _.isObject(value) && Object.keys(value).length === 0;
};
if (isObjectEmpty(sourceActions) || isObjectEmpty(newActions)) {
return {};
}
// 不同参数的合并策略不一样,先简单处理
return _.merge(sourceActions, newActions);
}
function mergeRoleSnippets(sourceSnippets, newSnippets = []) {
const allSnippets = Array.from(new Set([...sourceSnippets, ...newSnippets]));
return allSnippets
.map((snippet) => {
const isExclusion = snippet.startsWith('!');
const newSnippet = isExclusion ? snippet.slice(1) : snippet;
// 如果同时出现包含和排除,选择包含,如 ['!a', 'a'] 最后选择 ['a']
if (isExclusion && allSnippets.includes(newSnippet)) {
return undefined;
}
return newSnippet;
})
.filter((x) => Boolean(x));
}
function mergeRoleResources(sourceResources, newResources) {
if (sourceResources === null) {
return newResources;
}
const isEmptyArray = (value) => {
return _.isArray(value) && value.length === 0;
};
if (isEmptyArray(sourceResources) || isEmptyArray(newResources)) {
return [];
}
return [...new Set(sourceResources.concat(newResources))];
}