@nocobase/plugin-acl 2.0.0-alpha.61 → 2.0.0-alpha.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/externalVersion.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
module.exports = {
|
|
11
|
-
"@nocobase/client": "2.0.0-alpha.
|
|
11
|
+
"@nocobase/client": "2.0.0-alpha.62",
|
|
12
12
|
"antd": "5.24.2",
|
|
13
13
|
"react": "18.2.0",
|
|
14
14
|
"react-i18next": "11.18.6",
|
|
@@ -17,14 +17,14 @@ module.exports = {
|
|
|
17
17
|
"@formily/react": "2.3.7",
|
|
18
18
|
"@ant-design/icons": "5.6.1",
|
|
19
19
|
"lodash": "4.17.21",
|
|
20
|
-
"@nocobase/utils": "2.0.0-alpha.
|
|
21
|
-
"@nocobase/actions": "2.0.0-alpha.
|
|
22
|
-
"@nocobase/cache": "2.0.0-alpha.
|
|
23
|
-
"@nocobase/database": "2.0.0-alpha.
|
|
24
|
-
"@nocobase/server": "2.0.0-alpha.
|
|
25
|
-
"@nocobase/test": "2.0.0-alpha.
|
|
20
|
+
"@nocobase/utils": "2.0.0-alpha.62",
|
|
21
|
+
"@nocobase/actions": "2.0.0-alpha.62",
|
|
22
|
+
"@nocobase/cache": "2.0.0-alpha.62",
|
|
23
|
+
"@nocobase/database": "2.0.0-alpha.62",
|
|
24
|
+
"@nocobase/server": "2.0.0-alpha.62",
|
|
25
|
+
"@nocobase/test": "2.0.0-alpha.62",
|
|
26
26
|
"@formily/core": "2.3.7",
|
|
27
27
|
"@formily/antd-v5": "1.2.3",
|
|
28
28
|
"antd-style": "3.7.1",
|
|
29
|
-
"@nocobase/acl": "2.0.0-alpha.
|
|
29
|
+
"@nocobase/acl": "2.0.0-alpha.62"
|
|
30
30
|
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { Context, Next } from '@nocobase/actions';
|
|
10
|
+
export declare const checkChangesWithAssociation: (ctx: Context, next: Next) => Promise<any>;
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __create = Object.create;
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
13
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
15
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
16
|
+
var __export = (target, all) => {
|
|
17
|
+
for (var name in all)
|
|
18
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
19
|
+
};
|
|
20
|
+
var __copyProps = (to, from, except, desc) => {
|
|
21
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
22
|
+
for (let key of __getOwnPropNames(from))
|
|
23
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
24
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
25
|
+
}
|
|
26
|
+
return to;
|
|
27
|
+
};
|
|
28
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
29
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
30
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
31
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
32
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
33
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
34
|
+
mod
|
|
35
|
+
));
|
|
36
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
37
|
+
var check_change_with_association_exports = {};
|
|
38
|
+
__export(check_change_with_association_exports, {
|
|
39
|
+
checkChangesWithAssociation: () => checkChangesWithAssociation
|
|
40
|
+
});
|
|
41
|
+
module.exports = __toCommonJS(check_change_with_association_exports);
|
|
42
|
+
var import_acl = require("@nocobase/acl");
|
|
43
|
+
var import_lodash = __toESM(require("lodash"));
|
|
44
|
+
function normalizeAssociationValue(value, recordKey) {
|
|
45
|
+
if (!value) {
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
if (Array.isArray(value)) {
|
|
49
|
+
const result = value.map((v) => v[recordKey]).filter((v) => v !== null && v !== void 0);
|
|
50
|
+
return result.length > 0 ? result : void 0;
|
|
51
|
+
} else {
|
|
52
|
+
return value[recordKey];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async function resolveScopeFilter(ctx, target, params) {
|
|
56
|
+
if (!params) {
|
|
57
|
+
return {};
|
|
58
|
+
}
|
|
59
|
+
const filteredParams = ctx.acl.filterParams(ctx, target, params);
|
|
60
|
+
const parsedParams = await ctx.acl.parseJsonTemplate(filteredParams, ctx);
|
|
61
|
+
return parsedParams.filter || {};
|
|
62
|
+
}
|
|
63
|
+
async function collectAllowedRecordKeys(ctx, items, recordKey, updateParams, target) {
|
|
64
|
+
const repo = ctx.db.getRepository(target);
|
|
65
|
+
if (!repo) {
|
|
66
|
+
return void 0;
|
|
67
|
+
}
|
|
68
|
+
const keys = items.map((item) => import_lodash.default.isPlainObject(item) ? item[recordKey] : void 0).filter((key) => key !== void 0 && key !== null);
|
|
69
|
+
if (!keys.length) {
|
|
70
|
+
return void 0;
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
const scopedFilter = await resolveScopeFilter(ctx, target, updateParams == null ? void 0 : updateParams.params);
|
|
74
|
+
const records = await repo.find({
|
|
75
|
+
filter: {
|
|
76
|
+
...scopedFilter,
|
|
77
|
+
[`${recordKey}.$in`]: keys
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
const allowedKeys = /* @__PURE__ */ new Set();
|
|
81
|
+
for (const record of records) {
|
|
82
|
+
const key = typeof record.get === "function" ? record.get(recordKey) : record[recordKey];
|
|
83
|
+
if (key !== void 0 && key !== null) {
|
|
84
|
+
allowedKeys.add(key);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const missingKeys = new Set(keys.filter((key) => !allowedKeys.has(key)));
|
|
88
|
+
return { allowedKeys, missingKeys };
|
|
89
|
+
} catch (e) {
|
|
90
|
+
if (e instanceof import_acl.NoPermissionError) {
|
|
91
|
+
return {
|
|
92
|
+
allowedKeys: /* @__PURE__ */ new Set(),
|
|
93
|
+
missingKeys: new Set(keys)
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
throw e;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async function collectExistingRecordKeys(ctx, recordKey, target, keys) {
|
|
100
|
+
const repo = ctx.db.getRepository(target);
|
|
101
|
+
if (!repo) {
|
|
102
|
+
return /* @__PURE__ */ new Set();
|
|
103
|
+
}
|
|
104
|
+
const keyList = Array.from(keys);
|
|
105
|
+
if (!keyList.length) {
|
|
106
|
+
return /* @__PURE__ */ new Set();
|
|
107
|
+
}
|
|
108
|
+
const records = await repo.find({
|
|
109
|
+
filter: {
|
|
110
|
+
[`${recordKey}.$in`]: keyList
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
const existingKeys = /* @__PURE__ */ new Set();
|
|
114
|
+
for (const record of records) {
|
|
115
|
+
const key = typeof record.get === "function" ? record.get(recordKey) : record[recordKey];
|
|
116
|
+
if (key !== void 0 && key !== null) {
|
|
117
|
+
existingKeys.add(key);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return existingKeys;
|
|
121
|
+
}
|
|
122
|
+
async function recordExistsWithoutScope(ctx, target, recordKey, keyValue) {
|
|
123
|
+
const repo = ctx.db.getRepository(target);
|
|
124
|
+
if (!repo) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
const record = await repo.findOne({
|
|
128
|
+
filter: {
|
|
129
|
+
[recordKey]: keyValue
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
return Boolean(record);
|
|
133
|
+
}
|
|
134
|
+
async function processAssociationChild(ctx, value, recordKey, updateAssociationValues, createParams, updateParams, target, fieldPath, allowedRecordKeys, existingRecordKeys) {
|
|
135
|
+
const keyValue = value == null ? void 0 : value[recordKey];
|
|
136
|
+
const fallbackToCreate = async () => {
|
|
137
|
+
if (!createParams) {
|
|
138
|
+
return keyValue;
|
|
139
|
+
}
|
|
140
|
+
ctx.log.debug(`Association record missing, fallback to create`, {
|
|
141
|
+
fieldPath,
|
|
142
|
+
value,
|
|
143
|
+
target
|
|
144
|
+
});
|
|
145
|
+
return await processValues(ctx, value, updateAssociationValues, createParams.params, target, fieldPath, []);
|
|
146
|
+
};
|
|
147
|
+
const tryFallbackToCreate = async (reason, knownExists) => {
|
|
148
|
+
if (!createParams) {
|
|
149
|
+
return void 0;
|
|
150
|
+
}
|
|
151
|
+
const recordExists = typeof knownExists === "boolean" ? knownExists : await recordExistsWithoutScope(ctx, target, recordKey, keyValue);
|
|
152
|
+
if (!recordExists) {
|
|
153
|
+
ctx.log.debug(reason, {
|
|
154
|
+
fieldPath,
|
|
155
|
+
value,
|
|
156
|
+
createParams,
|
|
157
|
+
updateParams
|
|
158
|
+
});
|
|
159
|
+
return await fallbackToCreate();
|
|
160
|
+
}
|
|
161
|
+
return void 0;
|
|
162
|
+
};
|
|
163
|
+
if (keyValue !== void 0 && keyValue !== null) {
|
|
164
|
+
if (!updateParams) {
|
|
165
|
+
const created = await tryFallbackToCreate(`No permission to update association, try create not exist record`);
|
|
166
|
+
if (created !== void 0) {
|
|
167
|
+
return created;
|
|
168
|
+
}
|
|
169
|
+
ctx.log.debug(`No permission to update association`, { fieldPath, value, updateParams });
|
|
170
|
+
return keyValue;
|
|
171
|
+
} else {
|
|
172
|
+
const repo = ctx.db.getRepository(target);
|
|
173
|
+
if (!repo) {
|
|
174
|
+
return keyValue;
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
if (allowedRecordKeys) {
|
|
178
|
+
if (!allowedRecordKeys.has(keyValue)) {
|
|
179
|
+
const created = await tryFallbackToCreate(
|
|
180
|
+
`No permission to update association due to scope, try create not exist record`,
|
|
181
|
+
existingRecordKeys ? existingRecordKeys.has(keyValue) : void 0
|
|
182
|
+
);
|
|
183
|
+
if (created !== void 0) {
|
|
184
|
+
return created;
|
|
185
|
+
}
|
|
186
|
+
ctx.log.debug(`No permission to update association due to scope`, { fieldPath, value, updateParams });
|
|
187
|
+
return keyValue;
|
|
188
|
+
}
|
|
189
|
+
} else {
|
|
190
|
+
const filter = await resolveScopeFilter(ctx, target, updateParams.params);
|
|
191
|
+
const record = await repo.findOne({
|
|
192
|
+
filter: {
|
|
193
|
+
...filter,
|
|
194
|
+
[recordKey]: keyValue
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
if (!record) {
|
|
198
|
+
const created = await tryFallbackToCreate(
|
|
199
|
+
`No permission to update association due to scope, try create not exist record`
|
|
200
|
+
);
|
|
201
|
+
if (created !== void 0) {
|
|
202
|
+
return created;
|
|
203
|
+
}
|
|
204
|
+
ctx.log.debug(`No permission to update association due to scope`, { fieldPath, value, updateParams });
|
|
205
|
+
return keyValue;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return await processValues(ctx, value, updateAssociationValues, updateParams.params, target, fieldPath, []);
|
|
209
|
+
} catch (e) {
|
|
210
|
+
if (e instanceof import_acl.NoPermissionError) {
|
|
211
|
+
return keyValue;
|
|
212
|
+
}
|
|
213
|
+
throw e;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (createParams) {
|
|
218
|
+
return await processValues(ctx, value, updateAssociationValues, createParams.params, target, fieldPath, []);
|
|
219
|
+
}
|
|
220
|
+
ctx.log.debug(`No permission to create association`, { fieldPath, value, createParams });
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
async function processValues(ctx, values, updateAssociationValues, aclParams, collectionName, lastFieldPath = "", protectedKeys = []) {
|
|
224
|
+
var _a;
|
|
225
|
+
if (Array.isArray(values)) {
|
|
226
|
+
const result = [];
|
|
227
|
+
for (const item of values) {
|
|
228
|
+
if (!import_lodash.default.isPlainObject(item)) {
|
|
229
|
+
result.push(item);
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
const processed = await processValues(
|
|
233
|
+
ctx,
|
|
234
|
+
item,
|
|
235
|
+
updateAssociationValues,
|
|
236
|
+
aclParams,
|
|
237
|
+
collectionName,
|
|
238
|
+
lastFieldPath,
|
|
239
|
+
protectedKeys
|
|
240
|
+
);
|
|
241
|
+
if (processed !== null && processed !== void 0) {
|
|
242
|
+
result.push(processed);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return result;
|
|
246
|
+
}
|
|
247
|
+
if (!values || !import_lodash.default.isPlainObject(values)) {
|
|
248
|
+
return values;
|
|
249
|
+
}
|
|
250
|
+
const db = ctx.database;
|
|
251
|
+
const collection = db.getCollection(collectionName);
|
|
252
|
+
if (!collection) {
|
|
253
|
+
return values;
|
|
254
|
+
}
|
|
255
|
+
if (aclParams == null ? void 0 : aclParams.whitelist) {
|
|
256
|
+
const combined = import_lodash.default.uniq([...aclParams.whitelist, ...protectedKeys]);
|
|
257
|
+
values = import_lodash.default.pick(values, combined);
|
|
258
|
+
}
|
|
259
|
+
for (const [fieldName, fieldValue] of Object.entries(values)) {
|
|
260
|
+
if (protectedKeys.includes(fieldName)) {
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
const field = collection.getField(fieldName);
|
|
264
|
+
const isAssociation = field && ["hasOne", "hasMany", "belongsTo", "belongsToMany", "belongsToArray"].includes(field.type);
|
|
265
|
+
if (!isAssociation) {
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
const targetCollection = db.getCollection(field.target);
|
|
269
|
+
if (!targetCollection) {
|
|
270
|
+
delete values[fieldName];
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
const fieldPath = lastFieldPath ? `${lastFieldPath}.${fieldName}` : fieldName;
|
|
274
|
+
const recordKey = field.type === "hasOne" ? targetCollection.model.primaryKeyAttribute : field.targetKey;
|
|
275
|
+
const canUpdateAssociation = updateAssociationValues.includes(fieldPath);
|
|
276
|
+
if (!canUpdateAssociation) {
|
|
277
|
+
const normalized = normalizeAssociationValue(fieldValue, recordKey);
|
|
278
|
+
if (normalized === void 0 && !protectedKeys.includes(fieldName)) {
|
|
279
|
+
delete values[fieldName];
|
|
280
|
+
} else {
|
|
281
|
+
values[fieldName] = normalized;
|
|
282
|
+
}
|
|
283
|
+
ctx.log.debug(`Not allow to update association, only keep keys`, {
|
|
284
|
+
fieldPath,
|
|
285
|
+
fieldValue,
|
|
286
|
+
updateAssociationValues,
|
|
287
|
+
recordKey,
|
|
288
|
+
normalizedValue: values[fieldName]
|
|
289
|
+
});
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
const createParams = ctx.can({
|
|
293
|
+
roles: ctx.state.currentRoles,
|
|
294
|
+
resource: field.target,
|
|
295
|
+
action: "create"
|
|
296
|
+
});
|
|
297
|
+
const updateParams = ctx.can({
|
|
298
|
+
roles: ctx.state.currentRoles,
|
|
299
|
+
resource: field.target,
|
|
300
|
+
action: "update"
|
|
301
|
+
});
|
|
302
|
+
if (Array.isArray(fieldValue)) {
|
|
303
|
+
const processed = [];
|
|
304
|
+
let allowedRecordKeys;
|
|
305
|
+
let existingRecordKeys;
|
|
306
|
+
if (updateParams) {
|
|
307
|
+
const allowedResult = await collectAllowedRecordKeys(ctx, fieldValue, recordKey, updateParams, field.target);
|
|
308
|
+
allowedRecordKeys = allowedResult == null ? void 0 : allowedResult.allowedKeys;
|
|
309
|
+
if (createParams && ((_a = allowedResult == null ? void 0 : allowedResult.missingKeys) == null ? void 0 : _a.size)) {
|
|
310
|
+
existingRecordKeys = await collectExistingRecordKeys(ctx, recordKey, field.target, allowedResult.missingKeys);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
for (const item of fieldValue) {
|
|
314
|
+
const r2 = await processAssociationChild(
|
|
315
|
+
ctx,
|
|
316
|
+
item,
|
|
317
|
+
recordKey,
|
|
318
|
+
updateAssociationValues,
|
|
319
|
+
createParams,
|
|
320
|
+
updateParams,
|
|
321
|
+
field.target,
|
|
322
|
+
fieldPath,
|
|
323
|
+
allowedRecordKeys,
|
|
324
|
+
existingRecordKeys
|
|
325
|
+
);
|
|
326
|
+
if (r2 !== null && r2 !== void 0) {
|
|
327
|
+
processed.push(r2);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
values[fieldName] = processed;
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
const r = await processAssociationChild(
|
|
334
|
+
ctx,
|
|
335
|
+
fieldValue,
|
|
336
|
+
recordKey,
|
|
337
|
+
updateAssociationValues,
|
|
338
|
+
createParams,
|
|
339
|
+
updateParams,
|
|
340
|
+
field.target,
|
|
341
|
+
fieldPath
|
|
342
|
+
);
|
|
343
|
+
values[fieldName] = r;
|
|
344
|
+
}
|
|
345
|
+
return values;
|
|
346
|
+
}
|
|
347
|
+
const checkChangesWithAssociation = async (ctx, next) => {
|
|
348
|
+
var _a, _b;
|
|
349
|
+
const { resourceName, actionName } = ctx.action;
|
|
350
|
+
if (!["create", "firstOrCreate", "updateOrCreate", "update"].includes(actionName)) {
|
|
351
|
+
return next();
|
|
352
|
+
}
|
|
353
|
+
if ((_a = ctx.permission) == null ? void 0 : _a.skip) {
|
|
354
|
+
return next();
|
|
355
|
+
}
|
|
356
|
+
const roles = ctx.state.currentRoles;
|
|
357
|
+
if (roles.includes("root")) {
|
|
358
|
+
return next();
|
|
359
|
+
}
|
|
360
|
+
const acl = ctx.acl;
|
|
361
|
+
for (const role of roles) {
|
|
362
|
+
const aclRole = acl.getRole(role);
|
|
363
|
+
if (aclRole.snippetAllowed(`${resourceName}:${actionName}`)) {
|
|
364
|
+
return next();
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
const params = ctx.action.params || {};
|
|
368
|
+
const rawValues = params.values;
|
|
369
|
+
if (import_lodash.default.isEmpty(rawValues)) {
|
|
370
|
+
return next();
|
|
371
|
+
}
|
|
372
|
+
const protectedKeys = ["firstOrCreate", "updateOrCreate"].includes(actionName) ? params.filterKeys || [] : [];
|
|
373
|
+
const aclParams = ((_b = ctx.permission.can) == null ? void 0 : _b.params) || ctx.acl.fixedParamsManager.getParams(resourceName, actionName);
|
|
374
|
+
const processed = await processValues(
|
|
375
|
+
ctx,
|
|
376
|
+
rawValues,
|
|
377
|
+
params.updateAssociationValues || [],
|
|
378
|
+
aclParams,
|
|
379
|
+
resourceName,
|
|
380
|
+
"",
|
|
381
|
+
protectedKeys
|
|
382
|
+
);
|
|
383
|
+
ctx.action.params.values = processed;
|
|
384
|
+
await next();
|
|
385
|
+
};
|
|
386
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
387
|
+
0 && (module.exports = {
|
|
388
|
+
checkChangesWithAssociation
|
|
389
|
+
});
|
package/dist/server/server.js
CHANGED
|
@@ -56,6 +56,7 @@ var import_RoleResourceActionModel = require("./model/RoleResourceActionModel");
|
|
|
56
56
|
var import_RoleResourceModel = require("./model/RoleResourceModel");
|
|
57
57
|
var import_union_role = require("./actions/union-role");
|
|
58
58
|
var import_check_association_operate = require("./middlewares/check-association-operate");
|
|
59
|
+
var import_check_change_with_association = require("./middlewares/check-change-with-association");
|
|
59
60
|
class PluginACLServer extends import_server.Plugin {
|
|
60
61
|
get acl() {
|
|
61
62
|
return this.app.acl;
|
|
@@ -144,6 +145,7 @@ class PluginACLServer extends import_server.Plugin {
|
|
|
144
145
|
"roles.dataSourcesCollections:*",
|
|
145
146
|
"roles.dataSourceResources:*",
|
|
146
147
|
"dataSourcesRolesResourcesScopes:*",
|
|
148
|
+
"dataSourcesRolesResourcesActions:*",
|
|
147
149
|
"rolesResourcesScopes:*"
|
|
148
150
|
]
|
|
149
151
|
});
|
|
@@ -575,6 +577,12 @@ class PluginACLServer extends import_server.Plugin {
|
|
|
575
577
|
dataSource.acl.use(import_check_association_operate.checkAssociationOperate, {
|
|
576
578
|
before: "core"
|
|
577
579
|
});
|
|
580
|
+
if (dataSource.options.acl !== false && dataSource.options.useACL !== false) {
|
|
581
|
+
dataSource.resourceManager.registerPreActionHandler("create", import_check_change_with_association.checkChangesWithAssociation);
|
|
582
|
+
dataSource.resourceManager.registerPreActionHandler("firstOrCreate", import_check_change_with_association.checkChangesWithAssociation);
|
|
583
|
+
dataSource.resourceManager.registerPreActionHandler("updateOrCreate", import_check_change_with_association.checkChangesWithAssociation);
|
|
584
|
+
dataSource.resourceManager.registerPreActionHandler("update", import_check_change_with_association.checkChangesWithAssociation);
|
|
585
|
+
}
|
|
578
586
|
});
|
|
579
587
|
this.db.on("afterUpdateCollection", async (collection) => {
|
|
580
588
|
if (collection.options.loadedFromCollectionManager || collection.options.asStrategyResource) {
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"description": "Based on roles, resources, and actions, access control can precisely manage interface configuration permissions, data operation permissions, menu access permissions, and plugin permissions.",
|
|
7
7
|
"description.ru-RU": "На основе ролей, ресурсов и действий система контроля доступа может точно управлять разрешениями на изменение интерфейса, работу с данными, доступ к меню и разрешениями для подключаемых модулей.",
|
|
8
8
|
"description.zh-CN": "基于角色、资源和操作的权限控制,可以精确控制界面配置权限、数据操作权限、菜单访问权限、插件权限。",
|
|
9
|
-
"version": "2.0.0-alpha.
|
|
9
|
+
"version": "2.0.0-alpha.62",
|
|
10
10
|
"license": "AGPL-3.0",
|
|
11
11
|
"main": "./dist/server/index.js",
|
|
12
12
|
"homepage": "https://docs.nocobase.com/handbook/acl",
|
|
@@ -39,5 +39,5 @@
|
|
|
39
39
|
"url": "git+https://github.com/nocobase/nocobase.git",
|
|
40
40
|
"directory": "packages/plugins/acl"
|
|
41
41
|
},
|
|
42
|
-
"gitHead": "
|
|
42
|
+
"gitHead": "a6e543098afba0edc2189edc04f27c1726fff564"
|
|
43
43
|
}
|