@tachybase/module-acl 0.23.8

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.
Files changed (75) hide show
  1. package/.turbo/turbo-build.log +14 -0
  2. package/LICENSE +201 -0
  3. package/README.md +11 -0
  4. package/README.zh-CN.md +11 -0
  5. package/client.d.ts +2 -0
  6. package/client.js +1 -0
  7. package/dist/client/NewRole.d.ts +2 -0
  8. package/dist/client/RolesManagement.d.ts +2 -0
  9. package/dist/client/RolesManagerProvider.d.ts +4 -0
  10. package/dist/client/RolesMenu.d.ts +7 -0
  11. package/dist/client/hooks/load-more-observer.d.ts +7 -0
  12. package/dist/client/index.d.ts +8 -0
  13. package/dist/client/index.js +9 -0
  14. package/dist/client/locale.d.ts +1 -0
  15. package/dist/client/permissions/ActionPermissions.d.ts +4 -0
  16. package/dist/client/permissions/AvailableActions.d.ts +3 -0
  17. package/dist/client/permissions/GeneralPermissions.d.ts +4 -0
  18. package/dist/client/permissions/MenuItemsProvider.d.ts +4 -0
  19. package/dist/client/permissions/MenuPermissions.d.ts +4 -0
  20. package/dist/client/permissions/Permissions.d.ts +4 -0
  21. package/dist/client/permissions/PluginPermissions.d.ts +4 -0
  22. package/dist/client/permissions/RolesResourcesActions.d.ts +3 -0
  23. package/dist/client/permissions/ScopeSelect.d.ts +3 -0
  24. package/dist/client/permissions/StrategyActions.d.ts +2 -0
  25. package/dist/client/permissions/style.d.ts +1 -0
  26. package/dist/client/roles-manager.d.ts +10 -0
  27. package/dist/client/schemas/roles.d.ts +55 -0
  28. package/dist/client/schemas/scopes.d.ts +11 -0
  29. package/dist/externalVersion.js +19 -0
  30. package/dist/index.d.ts +2 -0
  31. package/dist/index.js +39 -0
  32. package/dist/locale/en-US.json +6 -0
  33. package/dist/locale/ko_KR.json +4 -0
  34. package/dist/locale/zh-CN.json +11 -0
  35. package/dist/server/actions/available-actions.d.ts +7 -0
  36. package/dist/server/actions/available-actions.js +42 -0
  37. package/dist/server/actions/role-check.d.ts +1 -0
  38. package/dist/server/actions/role-check.js +67 -0
  39. package/dist/server/actions/role-collections.d.ts +7 -0
  40. package/dist/server/actions/role-collections.js +75 -0
  41. package/dist/server/actions/user-setDefaultRole.d.ts +2 -0
  42. package/dist/server/actions/user-setDefaultRole.js +65 -0
  43. package/dist/server/collections/roles-users.d.ts +2 -0
  44. package/dist/server/collections/roles-users.js +30 -0
  45. package/dist/server/collections/roles.d.ts +2 -0
  46. package/dist/server/collections/roles.js +119 -0
  47. package/dist/server/collections/rolesResources.d.ts +2 -0
  48. package/dist/server/collections/rolesResources.js +55 -0
  49. package/dist/server/collections/rolesResourcesActions.d.ts +2 -0
  50. package/dist/server/collections/rolesResourcesActions.js +51 -0
  51. package/dist/server/collections/rolesResourcesScopes.d.ts +2 -0
  52. package/dist/server/collections/rolesResourcesScopes.js +45 -0
  53. package/dist/server/collections/users.d.ts +2 -0
  54. package/dist/server/collections/users.js +52 -0
  55. package/dist/server/index.d.ts +6 -0
  56. package/dist/server/index.js +50 -0
  57. package/dist/server/middlewares/setCurrentRole.d.ts +2 -0
  58. package/dist/server/middlewares/setCurrentRole.js +74 -0
  59. package/dist/server/middlewares/with-acl-meta.d.ts +2 -0
  60. package/dist/server/middlewares/with-acl-meta.js +242 -0
  61. package/dist/server/migrations/20221214072638-set-role-snippets.d.ts +6 -0
  62. package/dist/server/migrations/20221214072638-set-role-snippets.js +43 -0
  63. package/dist/server/model/RoleModel.d.ts +8 -0
  64. package/dist/server/model/RoleModel.js +46 -0
  65. package/dist/server/model/RoleResourceActionModel.d.ts +12 -0
  66. package/dist/server/model/RoleResourceActionModel.js +85 -0
  67. package/dist/server/model/RoleResourceModel.d.ts +18 -0
  68. package/dist/server/model/RoleResourceModel.js +79 -0
  69. package/dist/server/server.d.ts +34 -0
  70. package/dist/server/server.js +648 -0
  71. package/dist/swagger/index.d.ts +366 -0
  72. package/dist/swagger/index.js +395 -0
  73. package/package.json +40 -0
  74. package/server.d.ts +3 -0
  75. package/server.js +1 -0
@@ -0,0 +1,34 @@
1
+ import { Plugin } from '@tachybase/server';
2
+ import { RoleModel } from './model/RoleModel';
3
+ import { RoleResourceActionModel } from './model/RoleResourceActionModel';
4
+ import { RoleResourceModel } from './model/RoleResourceModel';
5
+ export interface AssociationFieldAction {
6
+ associationActions: string[];
7
+ targetActions?: string[];
8
+ }
9
+ interface AssociationFieldActions {
10
+ [availableActionName: string]: AssociationFieldAction;
11
+ }
12
+ export interface AssociationFieldsActions {
13
+ [associationType: string]: AssociationFieldActions;
14
+ }
15
+ export declare class GrantHelper {
16
+ resourceTargetActionMap: Map<string, string[]>;
17
+ targetActionResourceMap: Map<string, string[]>;
18
+ constructor();
19
+ }
20
+ export declare class PluginACL extends Plugin {
21
+ associationFieldsActions: AssociationFieldsActions;
22
+ grantHelper: GrantHelper;
23
+ get acl(): import("packages/acl/lib").ACL;
24
+ registerAssociationFieldAction(associationType: string, value: AssociationFieldActions): void;
25
+ registerAssociationFieldsActions(): void;
26
+ writeResourceToACL(resourceModel: RoleResourceModel, transaction: any): Promise<void>;
27
+ writeActionToACL(actionModel: RoleResourceActionModel, transaction: any): Promise<void>;
28
+ writeRolesToACL(options: any): Promise<void>;
29
+ writeRoleToACL(role: RoleModel, options?: any): Promise<void>;
30
+ beforeLoad(): Promise<void>;
31
+ install(): Promise<void>;
32
+ load(): Promise<void>;
33
+ }
34
+ export default PluginACL;
@@ -0,0 +1,648 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+ var server_exports = {};
29
+ __export(server_exports, {
30
+ GrantHelper: () => GrantHelper,
31
+ PluginACL: () => PluginACL,
32
+ default: () => server_default
33
+ });
34
+ module.exports = __toCommonJS(server_exports);
35
+ var import_path = require("path");
36
+ var import_worker_threads = require("worker_threads");
37
+ var import_actions = require("@tachybase/actions");
38
+ var import_database = require("@tachybase/database");
39
+ var import_server = require("@tachybase/server");
40
+ var import_async_mutex = require("async-mutex");
41
+ var import_lodash = __toESM(require("lodash"));
42
+ var import_available_actions = require("./actions/available-actions");
43
+ var import_role_check = require("./actions/role-check");
44
+ var import_role_collections = require("./actions/role-collections");
45
+ var import_user_setDefaultRole = require("./actions/user-setDefaultRole");
46
+ var import_setCurrentRole = require("./middlewares/setCurrentRole");
47
+ var import_with_acl_meta = require("./middlewares/with-acl-meta");
48
+ var import_RoleModel = require("./model/RoleModel");
49
+ var import_RoleResourceActionModel = require("./model/RoleResourceActionModel");
50
+ var import_RoleResourceModel = require("./model/RoleResourceModel");
51
+ class GrantHelper {
52
+ resourceTargetActionMap = /* @__PURE__ */ new Map();
53
+ targetActionResourceMap = /* @__PURE__ */ new Map();
54
+ constructor() {
55
+ }
56
+ }
57
+ class PluginACL extends import_server.Plugin {
58
+ // association field actions config
59
+ associationFieldsActions = {};
60
+ grantHelper = new GrantHelper();
61
+ get acl() {
62
+ return this.app.acl;
63
+ }
64
+ registerAssociationFieldAction(associationType, value) {
65
+ this.associationFieldsActions[associationType] = value;
66
+ }
67
+ registerAssociationFieldsActions() {
68
+ this.registerAssociationFieldAction("hasOne", {
69
+ view: {
70
+ associationActions: ["list", "get", "view"]
71
+ },
72
+ create: {
73
+ associationActions: ["create", "set"]
74
+ },
75
+ update: {
76
+ associationActions: ["update", "remove", "set"]
77
+ }
78
+ });
79
+ this.registerAssociationFieldAction("hasMany", {
80
+ view: {
81
+ associationActions: ["list", "get", "view"]
82
+ },
83
+ create: {
84
+ associationActions: ["create", "set", "add"]
85
+ },
86
+ update: {
87
+ associationActions: ["update", "remove", "set"]
88
+ }
89
+ });
90
+ this.registerAssociationFieldAction("belongsTo", {
91
+ view: {
92
+ associationActions: ["list", "get", "view"]
93
+ },
94
+ create: {
95
+ associationActions: ["create", "set"]
96
+ },
97
+ update: {
98
+ associationActions: ["update", "remove", "set"]
99
+ }
100
+ });
101
+ this.registerAssociationFieldAction("belongsToMany", {
102
+ view: {
103
+ associationActions: ["list", "get", "view"]
104
+ },
105
+ create: {
106
+ associationActions: ["create", "set", "add"]
107
+ },
108
+ update: {
109
+ associationActions: ["update", "remove", "set", "toggle"]
110
+ }
111
+ });
112
+ }
113
+ async writeResourceToACL(resourceModel, transaction) {
114
+ await resourceModel.writeToACL({
115
+ acl: this.acl,
116
+ associationFieldsActions: this.associationFieldsActions,
117
+ transaction,
118
+ grantHelper: this.grantHelper
119
+ });
120
+ }
121
+ async writeActionToACL(actionModel, transaction) {
122
+ const resource = actionModel.get("resource");
123
+ const role = this.acl.getRole(resource.get("roleName"));
124
+ await actionModel.writeToACL({
125
+ acl: this.acl,
126
+ role,
127
+ resourceName: resource.get("name"),
128
+ associationFieldsActions: this.associationFieldsActions,
129
+ grantHelper: this.grantHelper
130
+ });
131
+ }
132
+ async writeRolesToACL(options) {
133
+ const roles = await this.app.db.getRepository("roles").find({
134
+ appends: ["resources", "resources.actions"]
135
+ });
136
+ for (const role of roles) {
137
+ await this.writeRoleToACL(role, options);
138
+ }
139
+ }
140
+ async writeRoleToACL(role, options = {}) {
141
+ const transaction = options == null ? void 0 : options.transaction;
142
+ role.writeToAcl({ acl: this.acl, withOutStrategy: true });
143
+ if (options.withOutResources) {
144
+ return;
145
+ }
146
+ let resources = role.get("resources");
147
+ if (!resources) {
148
+ resources = await role.getResources({ transaction });
149
+ }
150
+ for (const resource of resources) {
151
+ await this.writeResourceToACL(resource, transaction);
152
+ }
153
+ }
154
+ async beforeLoad() {
155
+ this.db.addMigrations({
156
+ namespace: this.name,
157
+ directory: (0, import_path.resolve)(__dirname, "./migrations"),
158
+ context: {
159
+ plugin: this
160
+ }
161
+ });
162
+ this.app.db.registerModels({
163
+ RoleResourceActionModel: import_RoleResourceActionModel.RoleResourceActionModel,
164
+ RoleResourceModel: import_RoleResourceModel.RoleResourceModel,
165
+ RoleModel: import_RoleModel.RoleModel
166
+ });
167
+ this.app.acl.registerSnippet({
168
+ name: `pm.${this.name}.roles`,
169
+ actions: [
170
+ "roles:*",
171
+ "roles.snippets:*",
172
+ "availableActions:list",
173
+ "roles.collections:list",
174
+ "roles.resources:*",
175
+ "uiSchemas:getProperties",
176
+ "roles.menuUiSchemas:*",
177
+ "roles.users:*"
178
+ ]
179
+ });
180
+ this.app.acl.beforeGrantAction((ctx) => {
181
+ const actionName = this.app.acl.resolveActionAlias(ctx.actionName);
182
+ const collection = this.app.db.getCollection(ctx.resourceName);
183
+ if (!collection) {
184
+ return;
185
+ }
186
+ const fieldsParams = ctx.params.fields;
187
+ if (!fieldsParams) {
188
+ return;
189
+ }
190
+ if (actionName === "view" || actionName === "export") {
191
+ const associationsFields = fieldsParams.filter((fieldName) => {
192
+ const field = collection.getField(fieldName);
193
+ return field instanceof import_database.RelationField;
194
+ });
195
+ ctx.params = {
196
+ ...ctx.params,
197
+ fields: import_lodash.default.difference(fieldsParams, associationsFields),
198
+ appends: associationsFields
199
+ };
200
+ }
201
+ });
202
+ this.registerAssociationFieldsActions();
203
+ this.app.resourcer.define(import_available_actions.availableActionResource);
204
+ this.app.resourcer.define(import_role_collections.roleCollectionsResource);
205
+ this.app.resourcer.registerActionHandler("roles:check", import_role_check.checkAction);
206
+ this.app.resourcer.registerActionHandler(`users:setDefaultRole`, import_user_setDefaultRole.setDefaultRole);
207
+ this.db.on("users.afterCreateWithAssociations", async (model, options) => {
208
+ const { transaction } = options;
209
+ const repository = this.app.db.getRepository("roles");
210
+ const defaultRole = await repository.findOne({
211
+ filter: {
212
+ default: true
213
+ },
214
+ transaction
215
+ });
216
+ if (defaultRole && await model.countRoles({ transaction }) === 0) {
217
+ await model.addRoles(defaultRole, { transaction });
218
+ }
219
+ });
220
+ this.app.on("acl:writeRoleToACL", async (roleModel) => {
221
+ await this.writeRoleToACL(roleModel, {
222
+ withOutResources: true
223
+ });
224
+ await this.app.db.getRepository("dataSourcesRoles").updateOrCreate({
225
+ values: {
226
+ roleName: roleModel.get("name"),
227
+ dataSourceKey: "main",
228
+ strategy: roleModel.get("strategy")
229
+ },
230
+ filterKeys: ["roleName", "dataSourceKey"]
231
+ });
232
+ });
233
+ this.app.db.on("roles.afterCreateWithAssociations", async (model, options) => {
234
+ const { transaction } = options;
235
+ await this.app.db.getRepository("dataSourcesRoles").updateOrCreate({
236
+ values: {
237
+ roleName: model.get("name"),
238
+ dataSourceKey: "main",
239
+ strategy: model.get("strategy")
240
+ },
241
+ filterKeys: ["roleName", "dataSourceKey"],
242
+ transaction
243
+ });
244
+ });
245
+ this.app.db.on("roles.afterSaveWithAssociations", async (model, options) => {
246
+ const { transaction } = options;
247
+ await this.writeRoleToACL(model, {
248
+ withOutResources: true
249
+ });
250
+ await this.app.db.getRepository("dataSourcesRoles").updateOrCreate({
251
+ values: {
252
+ roleName: model.get("name"),
253
+ dataSourceKey: "main"
254
+ },
255
+ filterKeys: ["roleName", "dataSourceKey"],
256
+ transaction
257
+ });
258
+ await this.app.emitAsync("acl:writeResources", {
259
+ roleName: model.get("name"),
260
+ transaction
261
+ });
262
+ if (model.get("default")) {
263
+ await this.app.db.getRepository("roles").update({
264
+ values: {
265
+ default: false
266
+ },
267
+ filter: {
268
+ "name.$ne": model.get("name")
269
+ },
270
+ hooks: false,
271
+ transaction
272
+ });
273
+ }
274
+ });
275
+ this.app.db.on("roles.afterDestroy", (model) => {
276
+ const roleName = model.get("name");
277
+ this.acl.removeRole(roleName);
278
+ });
279
+ this.app.db.on("rolesResources.afterSaveWithAssociations", async (model, options) => {
280
+ await this.writeResourceToACL(model, options.transaction);
281
+ });
282
+ this.app.db.on("rolesResourcesActions.afterUpdateWithAssociations", async (model, options) => {
283
+ const { transaction } = options;
284
+ const resource = await model.getResource({
285
+ transaction
286
+ });
287
+ await this.writeResourceToACL(resource, transaction);
288
+ });
289
+ this.app.db.on("collections.afterDestroy", async (model, options) => {
290
+ const { transaction } = options;
291
+ await this.app.db.getRepository("dataSourcesRolesResources").destroy({
292
+ filter: {
293
+ name: model.get("name"),
294
+ dataSourceKey: "main"
295
+ },
296
+ transaction
297
+ });
298
+ });
299
+ this.app.db.on("fields.afterCreate", async (model, options) => {
300
+ const { transaction } = options;
301
+ const collectionName = model.get("collectionName");
302
+ const fieldName = model.get("name");
303
+ const resourceActions = await this.app.db.getRepository("dataSourcesRolesResourcesActions").find({
304
+ filter: {
305
+ "resource.name": collectionName,
306
+ "resource.dataSourceKey": "main"
307
+ },
308
+ transaction,
309
+ appends: ["resource"]
310
+ });
311
+ for (const resourceAction of resourceActions) {
312
+ const fields = resourceAction.get("fields");
313
+ const newFields = [...fields, fieldName];
314
+ await this.app.db.getRepository("dataSourcesRolesResourcesActions").update({
315
+ filterByTk: resourceAction.get("id"),
316
+ values: {
317
+ fields: newFields
318
+ },
319
+ transaction
320
+ });
321
+ }
322
+ });
323
+ const mutex = new import_async_mutex.Mutex();
324
+ this.app.db.on("fields.afterDestroy", async (model, options) => {
325
+ await mutex.runExclusive(async () => {
326
+ const collectionName = model.get("collectionName");
327
+ const fieldName = model.get("name");
328
+ const resourceActions = await this.app.db.getRepository("dataSourcesRolesResourcesActions").find({
329
+ filter: {
330
+ "resource.name": collectionName,
331
+ "fields.$anyOf": [fieldName],
332
+ "resource.dataSourceKey": "main"
333
+ },
334
+ transaction: options.transaction
335
+ });
336
+ for (const resourceAction of resourceActions) {
337
+ const fields = resourceAction.get("fields");
338
+ const newFields = fields.filter((field) => field !== fieldName);
339
+ await this.app.db.getRepository("dataSourcesRolesResourcesActions").update({
340
+ filterByTk: resourceAction.get("id"),
341
+ values: {
342
+ fields: newFields
343
+ },
344
+ transaction: options.transaction
345
+ });
346
+ }
347
+ });
348
+ });
349
+ this.app.db.on("rolesUsers.afterSave", async (model) => {
350
+ const cache = this.app.cache;
351
+ await cache.del(`roles:${model.get("userId")}`);
352
+ });
353
+ this.app.db.on("rolesUsers.afterDestroy", async (model) => {
354
+ const cache = this.app.cache;
355
+ await cache.del(`roles:${model.get("userId")}`);
356
+ });
357
+ const writeRolesToACL = async (app, options) => {
358
+ const exists = await this.app.db.collectionExistsInDb("roles");
359
+ if (exists) {
360
+ this.log.info("write roles to ACL", { method: "writeRolesToACL" });
361
+ await this.writeRolesToACL(options);
362
+ }
363
+ };
364
+ if (import_worker_threads.isMainThread) {
365
+ this.app.on("afterStart", async () => {
366
+ await writeRolesToACL(this.app, {
367
+ withOutResources: true
368
+ });
369
+ });
370
+ }
371
+ this.app.on("afterInstallPlugin", async (plugin) => {
372
+ if (plugin.getName() !== "user") {
373
+ return;
374
+ }
375
+ const User = this.db.getCollection("users");
376
+ await User.repository.update({
377
+ filter: {
378
+ id: 1
379
+ },
380
+ values: {
381
+ roles: ["root", "admin", "member"]
382
+ },
383
+ forceUpdate: true
384
+ });
385
+ const RolesUsers = this.db.getCollection("rolesUsers");
386
+ await RolesUsers.repository.update({
387
+ filter: {
388
+ userId: 1,
389
+ roleName: "root"
390
+ },
391
+ values: {
392
+ default: true
393
+ }
394
+ });
395
+ });
396
+ this.app.on("beforeInstallPlugin", async (plugin) => {
397
+ if (plugin.getName() !== "user") {
398
+ return;
399
+ }
400
+ const roles = this.app.db.getRepository("roles");
401
+ await roles.createMany({
402
+ records: [
403
+ {
404
+ name: "root",
405
+ title: '{{t("Root")}}',
406
+ hidden: true,
407
+ snippets: ["ui.*", "pm", "pm.*"]
408
+ },
409
+ {
410
+ name: "admin",
411
+ title: '{{t("Admin")}}',
412
+ allowConfigure: true,
413
+ allowNewMenu: true,
414
+ strategy: { actions: ["create", "view", "update", "destroy"] },
415
+ snippets: ["ui.*", "pm", "pm.*"]
416
+ },
417
+ {
418
+ name: "member",
419
+ title: '{{t("Member")}}',
420
+ allowNewMenu: true,
421
+ strategy: { actions: ["view", "update:own", "destroy:own", "create"] },
422
+ default: true,
423
+ snippets: ["!ui.*", "!pm", "!pm.*"]
424
+ }
425
+ ]
426
+ });
427
+ const rolesResourcesScopes = this.app.db.getRepository("dataSourcesRolesResourcesScopes");
428
+ await rolesResourcesScopes.createMany({
429
+ records: [
430
+ {
431
+ key: "all",
432
+ name: '{{t("All records")}}',
433
+ scope: {}
434
+ },
435
+ {
436
+ key: "own",
437
+ name: '{{t("Own records")}}',
438
+ scope: {
439
+ createdById: "{{ ctx.state.currentUser.id }}"
440
+ }
441
+ }
442
+ ]
443
+ });
444
+ });
445
+ this.app.on("beforeSignOut", ({ userId }) => {
446
+ this.app.cache.del(`roles:${userId}`);
447
+ });
448
+ this.app.resourcer.use(import_setCurrentRole.setCurrentRole, { tag: "setCurrentRole", before: "acl", after: "auth" });
449
+ this.app.acl.allow("users", "setDefaultRole", "loggedIn");
450
+ this.app.acl.allow("roles", "check", "loggedIn");
451
+ this.app.acl.allow("*", "*", (ctx) => {
452
+ return ctx.state.currentRole === "root";
453
+ });
454
+ this.app.acl.addFixedParams("collections", "destroy", () => {
455
+ return {
456
+ filter: {
457
+ $and: [{ "name.$ne": "roles" }, { "name.$ne": "rolesUsers" }]
458
+ }
459
+ };
460
+ });
461
+ this.app.acl.addFixedParams("rolesResourcesScopes", "destroy", () => {
462
+ return {
463
+ filter: {
464
+ $and: [{ "key.$ne": "all" }, { "key.$ne": "own" }]
465
+ }
466
+ };
467
+ });
468
+ this.app.acl.addFixedParams("rolesResourcesScopes", "update", () => {
469
+ return {
470
+ filter: {
471
+ $and: [{ "key.$ne": "all" }, { "key.$ne": "own" }]
472
+ }
473
+ };
474
+ });
475
+ this.app.acl.addFixedParams("roles", "destroy", () => {
476
+ return {
477
+ filter: {
478
+ $and: [{ "name.$ne": "root" }, { "name.$ne": "admin" }, { "name.$ne": "member" }]
479
+ }
480
+ };
481
+ });
482
+ this.app.resourcer.use(
483
+ async (ctx, next) => {
484
+ const { actionName, resourceName, params } = ctx.action;
485
+ const { showAnonymous } = params || {};
486
+ if (actionName === "list" && resourceName === "roles") {
487
+ if (!showAnonymous) {
488
+ ctx.action.mergeParams({
489
+ filter: {
490
+ "name.$ne": "anonymous"
491
+ }
492
+ });
493
+ }
494
+ }
495
+ if (actionName === "update" && resourceName === "roles.resources") {
496
+ ctx.action.mergeParams({
497
+ updateAssociationValues: ["actions"]
498
+ });
499
+ }
500
+ await next();
501
+ },
502
+ { tag: "resource-association-update" }
503
+ );
504
+ this.app.acl.use(
505
+ async (ctx, next) => {
506
+ var _a, _b, _c, _d, _e;
507
+ const { actionName, resourceName } = ctx.action;
508
+ if (actionName === "get" || actionName === "list") {
509
+ if (!Array.isArray((_c = (_b = (_a = ctx == null ? void 0 : ctx.permission) == null ? void 0 : _a.can) == null ? void 0 : _b.params) == null ? void 0 : _c.fields)) {
510
+ return next();
511
+ }
512
+ let collection;
513
+ if (resourceName.includes(".")) {
514
+ const [collectionName, associationName] = resourceName.split(".");
515
+ const field = (_e = (_d = ctx.db.getCollection(collectionName)) == null ? void 0 : _d.getField) == null ? void 0 : _e.call(_d, associationName);
516
+ if (field.target) {
517
+ collection = ctx.db.getCollection(field.target);
518
+ }
519
+ } else {
520
+ collection = ctx.db.getCollection(resourceName);
521
+ }
522
+ if (collection && collection.hasField("createdById")) {
523
+ ctx.permission.can.params.fields.push("createdById");
524
+ }
525
+ }
526
+ return next();
527
+ },
528
+ { tag: "permission-management" }
529
+ );
530
+ const parseJsonTemplate = this.app.acl.parseJsonTemplate;
531
+ this.app.acl.beforeGrantAction(async (ctx) => {
532
+ const actionName = this.app.acl.resolveActionAlias(ctx.actionName);
533
+ if (import_lodash.default.isPlainObject(ctx.params)) {
534
+ if (actionName === "view" && ctx.params.fields) {
535
+ const appendFields = [];
536
+ const collection = this.app.db.getCollection(ctx.resourceName);
537
+ if (!collection) {
538
+ return;
539
+ }
540
+ if (collection.model.primaryKeyAttribute) {
541
+ appendFields.push(collection.model.primaryKeyAttribute);
542
+ }
543
+ if (collection.model.rawAttributes["createdAt"]) {
544
+ appendFields.push("createdAt");
545
+ }
546
+ if (collection.model.rawAttributes["updatedAt"]) {
547
+ appendFields.push("updatedAt");
548
+ }
549
+ ctx.params = {
550
+ ...import_lodash.default.omit(ctx.params, "fields"),
551
+ fields: [...ctx.params.fields, ...appendFields]
552
+ };
553
+ }
554
+ }
555
+ });
556
+ this.app.acl.use(
557
+ async (ctx, next) => {
558
+ var _a, _b, _c;
559
+ const { actionName, resourceName, resourceOf } = ctx.action;
560
+ if (resourceName.includes(".") && resourceOf) {
561
+ if (!((_b = (_a = ctx == null ? void 0 : ctx.permission) == null ? void 0 : _a.can) == null ? void 0 : _b.params)) {
562
+ return next();
563
+ }
564
+ delete ctx.permission.can.params.filter;
565
+ const [collectionName] = resourceName.split(".");
566
+ const action = ctx.can({ resource: collectionName, action: actionName });
567
+ const availableAction = this.app.acl.getAvailableAction(actionName);
568
+ if ((_c = availableAction == null ? void 0 : availableAction.options) == null ? void 0 : _c.onNewRecord) {
569
+ if (action) {
570
+ ctx.permission.skip = true;
571
+ } else {
572
+ ctx.permission.can = false;
573
+ }
574
+ } else {
575
+ const filteredParams = this.app.acl.filterParams(ctx, collectionName, (action == null ? void 0 : action.params) || {});
576
+ const params = await parseJsonTemplate(filteredParams, ctx);
577
+ const sourceInstance = await ctx.db.getRepository(collectionName).findOne({
578
+ filterByTk: resourceOf,
579
+ filter: params.filter || {}
580
+ });
581
+ if (!sourceInstance) {
582
+ ctx.permission.can = false;
583
+ }
584
+ }
585
+ }
586
+ await next();
587
+ },
588
+ {
589
+ before: "core"
590
+ }
591
+ );
592
+ this.app.acl.use(
593
+ async (ctx, next) => {
594
+ var _a, _b;
595
+ const action = (_b = (_a = ctx.permission) == null ? void 0 : _a.can) == null ? void 0 : _b.action;
596
+ if (action === "destroy" && !ctx.action.resourceName.includes(".")) {
597
+ const repository = import_actions.utils.getRepositoryFromParams(ctx);
598
+ if (!repository) {
599
+ await next();
600
+ return;
601
+ }
602
+ const filteredCount = await repository.count(ctx.permission.mergedParams);
603
+ const queryCount = await repository.count(ctx.permission.rawParams);
604
+ if (queryCount > filteredCount) {
605
+ ctx.throw(403, "No permissions");
606
+ return;
607
+ }
608
+ }
609
+ await next();
610
+ },
611
+ {
612
+ after: "core",
613
+ group: "after"
614
+ }
615
+ );
616
+ const withACLMeta = (0, import_with_acl_meta.createWithACLMetaMiddleware)();
617
+ this.app.use(
618
+ async (ctx, next) => {
619
+ try {
620
+ await withACLMeta(ctx, next);
621
+ } catch (error) {
622
+ ctx.logger.error(error);
623
+ }
624
+ },
625
+ { after: "restApi", group: "after" }
626
+ );
627
+ }
628
+ async install() {
629
+ const repo = this.db.getRepository("collections");
630
+ if (repo) {
631
+ await repo.db2cm("roles");
632
+ }
633
+ }
634
+ async load() {
635
+ await this.importCollections((0, import_path.resolve)(__dirname, "collections"));
636
+ this.db.extendCollection({
637
+ name: "rolesUischemas",
638
+ dumpRules: "required",
639
+ origin: this.options.packageName
640
+ });
641
+ }
642
+ }
643
+ var server_default = PluginACL;
644
+ // Annotate the CommonJS export names for ESM import in node:
645
+ 0 && (module.exports = {
646
+ GrantHelper,
647
+ PluginACL
648
+ });