@nocobase/plugin-acl 0.7.0-alpha.1

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 (98) hide show
  1. package/LICENSE +201 -0
  2. package/esm/actions/available-actions.d.ts +7 -0
  3. package/esm/actions/available-actions.js +26 -0
  4. package/esm/actions/available-actions.js.map +1 -0
  5. package/esm/actions/role-check.d.ts +1 -0
  6. package/esm/actions/role-check.js +38 -0
  7. package/esm/actions/role-check.js.map +1 -0
  8. package/esm/actions/role-collections.d.ts +7 -0
  9. package/esm/actions/role-collections.js +54 -0
  10. package/esm/actions/role-collections.js.map +1 -0
  11. package/esm/collections/roles.d.ts +3 -0
  12. package/esm/collections/roles.js +78 -0
  13. package/esm/collections/roles.js.map +1 -0
  14. package/esm/collections/rolesResources.d.ts +3 -0
  15. package/esm/collections/rolesResources.js +30 -0
  16. package/esm/collections/rolesResources.js.map +1 -0
  17. package/esm/collections/rolesResourcesActions.d.ts +3 -0
  18. package/esm/collections/rolesResourcesActions.js +27 -0
  19. package/esm/collections/rolesResourcesActions.js.map +1 -0
  20. package/esm/collections/rolesResourcesScopes.d.ts +3 -0
  21. package/esm/collections/rolesResourcesScopes.js +22 -0
  22. package/esm/collections/rolesResourcesScopes.js.map +1 -0
  23. package/esm/index.d.ts +1 -0
  24. package/esm/index.js +2 -0
  25. package/esm/index.js.map +1 -0
  26. package/esm/model/RoleModel.d.ts +7 -0
  27. package/esm/model/RoleModel.js +15 -0
  28. package/esm/model/RoleModel.js.map +1 -0
  29. package/esm/model/RoleResourceActionModel.d.ts +12 -0
  30. package/esm/model/RoleResourceActionModel.js +65 -0
  31. package/esm/model/RoleResourceActionModel.js.map +1 -0
  32. package/esm/model/RoleResourceModel.d.ts +16 -0
  33. package/esm/model/RoleResourceModel.js +55 -0
  34. package/esm/model/RoleResourceModel.js.map +1 -0
  35. package/esm/server.d.ts +33 -0
  36. package/esm/server.js +366 -0
  37. package/esm/server.js.map +1 -0
  38. package/lib/actions/available-actions.d.ts +7 -0
  39. package/lib/actions/available-actions.js +29 -0
  40. package/lib/actions/available-actions.js.map +1 -0
  41. package/lib/actions/role-check.d.ts +1 -0
  42. package/lib/actions/role-check.js +42 -0
  43. package/lib/actions/role-check.js.map +1 -0
  44. package/lib/actions/role-collections.d.ts +7 -0
  45. package/lib/actions/role-collections.js +57 -0
  46. package/lib/actions/role-collections.js.map +1 -0
  47. package/lib/collections/roles.d.ts +3 -0
  48. package/lib/collections/roles.js +80 -0
  49. package/lib/collections/roles.js.map +1 -0
  50. package/lib/collections/rolesResources.d.ts +3 -0
  51. package/lib/collections/rolesResources.js +32 -0
  52. package/lib/collections/rolesResources.js.map +1 -0
  53. package/lib/collections/rolesResourcesActions.d.ts +3 -0
  54. package/lib/collections/rolesResourcesActions.js +29 -0
  55. package/lib/collections/rolesResourcesActions.js.map +1 -0
  56. package/lib/collections/rolesResourcesScopes.d.ts +3 -0
  57. package/lib/collections/rolesResourcesScopes.js +24 -0
  58. package/lib/collections/rolesResourcesScopes.js.map +1 -0
  59. package/lib/index.d.ts +1 -0
  60. package/lib/index.js +9 -0
  61. package/lib/index.js.map +1 -0
  62. package/lib/model/RoleModel.d.ts +7 -0
  63. package/lib/model/RoleModel.js +19 -0
  64. package/lib/model/RoleModel.js.map +1 -0
  65. package/lib/model/RoleResourceActionModel.d.ts +12 -0
  66. package/lib/model/RoleResourceActionModel.js +69 -0
  67. package/lib/model/RoleResourceActionModel.js.map +1 -0
  68. package/lib/model/RoleResourceModel.d.ts +16 -0
  69. package/lib/model/RoleResourceModel.js +59 -0
  70. package/lib/model/RoleResourceModel.js.map +1 -0
  71. package/lib/server.d.ts +33 -0
  72. package/lib/server.js +371 -0
  73. package/lib/server.js.map +1 -0
  74. package/package.json +30 -0
  75. package/src/__tests__/acl.test.ts +533 -0
  76. package/src/__tests__/association-field.test.ts +297 -0
  77. package/src/__tests__/configuration.test.ts +45 -0
  78. package/src/__tests__/middleware.test.ts +233 -0
  79. package/src/__tests__/own.test.ts +140 -0
  80. package/src/__tests__/prepare.ts +39 -0
  81. package/src/__tests__/role-check.test.ts +35 -0
  82. package/src/__tests__/role-resource.test.ts +187 -0
  83. package/src/__tests__/role.test.ts +92 -0
  84. package/src/__tests__/scope.test.ts +51 -0
  85. package/src/actions/available-actions.ts +18 -0
  86. package/src/actions/role-check.ts +39 -0
  87. package/src/actions/role-collections.ts +55 -0
  88. package/src/collections/roles.ts +79 -0
  89. package/src/collections/rolesResources.ts +31 -0
  90. package/src/collections/rolesResourcesActions.ts +28 -0
  91. package/src/collections/rolesResourcesScopes.ts +23 -0
  92. package/src/index.ts +2 -0
  93. package/src/model/RoleModel.ts +21 -0
  94. package/src/model/RoleResourceActionModel.ts +80 -0
  95. package/src/model/RoleResourceModel.ts +61 -0
  96. package/src/server.ts +398 -0
  97. package/tsconfig.build.json +9 -0
  98. package/tsconfig.json +5 -0
@@ -0,0 +1,39 @@
1
+ import PluginCollectionManager from '@nocobase/plugin-collection-manager';
2
+ import PluginUiSchema from '@nocobase/plugin-ui-schema-storage';
3
+ import { mockServer } from '@nocobase/test';
4
+ import PluginACL from '../server';
5
+
6
+ let mockRole: string = 'admin';
7
+ let mockUser = {};
8
+
9
+ export function changeMockRole(role: string) {
10
+ mockRole = role;
11
+ }
12
+
13
+ export function changeMockUser(user: any) {
14
+ mockUser = user;
15
+ }
16
+
17
+ export async function prepareApp() {
18
+ const app = mockServer({
19
+ registerActions: true,
20
+ });
21
+
22
+ await app.cleanDb();
23
+
24
+ app.plugin(PluginUiSchema);
25
+ app.plugin(PluginCollectionManager);
26
+
27
+ app.resourcer.use(async (ctx, next) => {
28
+ ctx.state.currentRole = mockRole;
29
+ ctx.state.currentUser = mockUser;
30
+ await next();
31
+ });
32
+
33
+ app.plugin(PluginACL);
34
+ await app.loadAndInstall();
35
+
36
+ await app.db.sync();
37
+
38
+ return app;
39
+ }
@@ -0,0 +1,35 @@
1
+ import { MockServer } from '@nocobase/test';
2
+ import { changeMockRole, changeMockUser, prepareApp } from './prepare';
3
+ import { Database } from '@nocobase/database';
4
+
5
+ describe('role check action', () => {
6
+ let app: MockServer;
7
+ let db: Database;
8
+
9
+ beforeEach(async () => {
10
+ app = await prepareApp();
11
+ db = app.db;
12
+ });
13
+
14
+ afterEach(async () => {
15
+ await app.destroy();
16
+ });
17
+
18
+ it('should return role info', async () => {
19
+ const role = await db.getRepository('roles').create({
20
+ values: {
21
+ name: 'test',
22
+ },
23
+ });
24
+
25
+ changeMockUser({
26
+ id: 2,
27
+ });
28
+
29
+ changeMockRole('test');
30
+
31
+ const response = await app.agent().get('/roles:check');
32
+
33
+ expect(response.statusCode).toEqual(200);
34
+ });
35
+ });
@@ -0,0 +1,187 @@
1
+ import { Database, Model } from '@nocobase/database';
2
+ import { CollectionRepository } from '@nocobase/plugin-collection-manager';
3
+ import { MockServer } from '@nocobase/test';
4
+ import { prepareApp } from './prepare';
5
+
6
+ describe('role resource api', () => {
7
+ let app: MockServer;
8
+ let db: Database;
9
+ let role: Model;
10
+
11
+ afterEach(async () => {
12
+ await app.destroy();
13
+ });
14
+
15
+ beforeEach(async () => {
16
+ app = await prepareApp();
17
+ db = app.db;
18
+
19
+ await db.getRepository('roles').create({
20
+ values: {
21
+ name: 'admin',
22
+ title: 'Admin User',
23
+ allowConfigure: true,
24
+ },
25
+ });
26
+
27
+ role = await db.getRepository('roles').findOne({
28
+ filter: {
29
+ name: 'admin',
30
+ },
31
+ });
32
+ });
33
+
34
+ it('should grant resource by createRepository', async () => {
35
+ const collectionManager = db.getRepository('collections') as CollectionRepository;
36
+ await collectionManager.create({
37
+ values: {
38
+ name: 'c1',
39
+ title: 'table1',
40
+ },
41
+ context: {},
42
+ });
43
+
44
+ await collectionManager.create({
45
+ values: {
46
+ name: 'c2',
47
+ title: 'table2',
48
+ },
49
+ context: {},
50
+ });
51
+
52
+ await db.getRepository('roles').create({
53
+ values: {
54
+ name: 'testRole',
55
+ resources: [
56
+ {
57
+ name: 'c1',
58
+ actions: [
59
+ {
60
+ name: 'create',
61
+ },
62
+ ],
63
+ },
64
+ ],
65
+ },
66
+ });
67
+
68
+ const acl = app.acl;
69
+ const testRole = acl.getRole('testRole');
70
+ const resource = testRole.getResource('c1');
71
+ expect(resource).toBeDefined();
72
+ });
73
+
74
+ it('should grant resource action', async () => {
75
+ const collectionManager = db.getRepository('collections') as CollectionRepository;
76
+
77
+ await collectionManager.create({
78
+ values: {
79
+ name: 'c1',
80
+ title: 'table1',
81
+ },
82
+ context: {},
83
+ });
84
+
85
+ await collectionManager.create({
86
+ values: {
87
+ name: 'c2',
88
+ title: 'table2',
89
+ },
90
+ context: {},
91
+ });
92
+
93
+ // get collections list
94
+ let response = await app
95
+ .agent()
96
+ .resource('roles.collections', 'admin')
97
+ .list({
98
+ filter: {
99
+ $or: [{ name: 'c1' }, { name: 'c2' }],
100
+ },
101
+ sort: ['sort'],
102
+ });
103
+
104
+ expect(response.statusCode).toEqual(200);
105
+
106
+ expect(response.body.data).toMatchObject([
107
+ {
108
+ name: 'c1',
109
+ title: 'table1',
110
+ usingConfig: 'strategy',
111
+ exists: false,
112
+ },
113
+ {
114
+ name: 'c2',
115
+ title: 'table2',
116
+ usingConfig: 'strategy',
117
+ exists: false,
118
+ },
119
+ ]);
120
+
121
+ // set resource actions
122
+ response = await app
123
+ .agent()
124
+ .resource('roles.resources', 'admin')
125
+ .create({
126
+ values: {
127
+ name: 'c1',
128
+ usingActionsConfig: true,
129
+ actions: [
130
+ {
131
+ name: 'create',
132
+ },
133
+ ],
134
+ },
135
+ });
136
+
137
+ expect(response.statusCode).toEqual(200);
138
+
139
+ // get collections list
140
+ response = await app
141
+ .agent()
142
+ .resource('roles.collections')
143
+ .list({
144
+ associatedIndex: role.get('name') as string,
145
+ filter: {
146
+ name: 'c1',
147
+ },
148
+ });
149
+
150
+ expect(response.body.data[0]['usingConfig']).toEqual('resourceAction');
151
+
152
+ response = await app
153
+ .agent()
154
+ .resource('roles.resources')
155
+ .list({
156
+ associatedIndex: role.get('name') as string,
157
+ appends: 'actions',
158
+ });
159
+
160
+ expect(response.statusCode).toEqual(200);
161
+ const resources = response.body.data;
162
+ const resourceAction = resources[0]['actions'][0];
163
+
164
+ expect(resourceAction['name']).toEqual('create');
165
+
166
+ // update resource actions
167
+ response = await app
168
+ .agent()
169
+ .resource('roles.resources')
170
+ .update({
171
+ associatedIndex: role.get('name') as string,
172
+ values: {
173
+ name: 'c1',
174
+ usingActionsConfig: true,
175
+ actions: [
176
+ {
177
+ name: 'view',
178
+ },
179
+ ],
180
+ },
181
+ });
182
+
183
+ expect(response.statusCode).toEqual(200);
184
+ expect(response.body.data[0]['actions'].length).toEqual(1);
185
+ expect(response.body.data[0]['actions'][0]['name']).toEqual('view');
186
+ });
187
+ });
@@ -0,0 +1,92 @@
1
+ import { MockServer } from '@nocobase/test';
2
+ import { CollectionRepository } from '@nocobase/plugin-collection-manager';
3
+ import { Database, Model } from '@nocobase/database';
4
+
5
+ import { prepareApp } from './prepare';
6
+
7
+ describe('role api', () => {
8
+ let app: MockServer;
9
+ let db: Database;
10
+
11
+ afterEach(async () => {
12
+ await app.destroy();
13
+ });
14
+
15
+ beforeEach(async () => {
16
+ app = await prepareApp();
17
+ db = app.db;
18
+ });
19
+
20
+ describe('grant', () => {
21
+ let role: Model;
22
+
23
+ beforeEach(async () => {
24
+ await db.getRepository('roles').create({
25
+ values: {
26
+ name: 'admin',
27
+ title: 'Admin User',
28
+ allowConfigure: true,
29
+ },
30
+ });
31
+
32
+ role = await db.getRepository('roles').findOne({
33
+ filter: {
34
+ name: 'admin',
35
+ },
36
+ });
37
+ });
38
+
39
+ it('should list actions', async () => {
40
+ const response = await app.agent().resource('availableActions').list();
41
+ expect(response.statusCode).toEqual(200);
42
+ });
43
+
44
+ it('should grant universal role actions', async () => {
45
+ // grant role actions
46
+ const response = await app
47
+ .agent()
48
+ .resource('roles')
49
+ .update({
50
+ values: {
51
+ strategy: {
52
+ actions: ['create:all', 'view:own'],
53
+ },
54
+ },
55
+ });
56
+
57
+ expect(response.statusCode).toEqual(200);
58
+
59
+ await role.reload();
60
+
61
+ expect(role.get('strategy')).toMatchObject({
62
+ actions: ['create:all', 'view:own'],
63
+ });
64
+ });
65
+ });
66
+
67
+ it('should works with default option', async () => {
68
+ await db.getRepository('roles').create({
69
+ values: {
70
+ name: 'role1',
71
+ title: 'admin 1',
72
+ default: true,
73
+ },
74
+ });
75
+
76
+ await db.getRepository('roles').create({
77
+ values: {
78
+ name: 'role2',
79
+ default: true,
80
+ },
81
+ });
82
+
83
+ const defaultRole = await db.getRepository('roles').find({
84
+ filter: {
85
+ default: true,
86
+ },
87
+ });
88
+
89
+ expect(defaultRole.length).toEqual(1);
90
+ expect(defaultRole[0].get('name')).toEqual('role2');
91
+ });
92
+ });
@@ -0,0 +1,51 @@
1
+ import { prepareApp } from './prepare';
2
+ import { MockServer } from '@nocobase/test';
3
+ import { Database } from '@nocobase/database';
4
+
5
+ describe('scope api', () => {
6
+ let app: MockServer;
7
+ let db: Database;
8
+
9
+ afterEach(async () => {
10
+ await app.destroy();
11
+ });
12
+
13
+ beforeEach(async () => {
14
+ app = await prepareApp();
15
+ db = app.db;
16
+ await db.getRepository('roles').create({
17
+ values: {
18
+ name: 'admin',
19
+ title: 'Admin User',
20
+ allowConfigure: true,
21
+ },
22
+ });
23
+ });
24
+
25
+ it('should create scope of resource', async () => {
26
+ const response = await app
27
+ .agent()
28
+ .resource('rolesResourcesScopes')
29
+ .create({
30
+ values: {
31
+ resourceName: 'posts',
32
+ name: 'published posts',
33
+ scope: {
34
+ published: true,
35
+ },
36
+ },
37
+ });
38
+
39
+ expect(response.statusCode).toEqual(200);
40
+
41
+ const scope = await db.getRepository('rolesResourcesScopes').findOne({
42
+ filter: {
43
+ name: 'published posts',
44
+ },
45
+ });
46
+
47
+ expect(scope.get('scope')).toMatchObject({
48
+ published: true,
49
+ });
50
+ });
51
+ });
@@ -0,0 +1,18 @@
1
+ const availableActionResource = {
2
+ name: 'availableActions',
3
+ actions: {
4
+ async list(ctx, next) {
5
+ const acl = ctx.app.acl;
6
+ const availableActions = acl.getAvailableActions();
7
+ ctx.body = Array.from(availableActions.entries()).map(([, { name, options }]) => {
8
+ return {
9
+ ...options,
10
+ name,
11
+ };
12
+ });
13
+ await next();
14
+ },
15
+ },
16
+ };
17
+
18
+ export { availableActionResource };
@@ -0,0 +1,39 @@
1
+ const map2obj = (map: Map<string, string>) => {
2
+ const obj = {};
3
+ for(let [key, value] of map){
4
+ obj[key] = value;
5
+ }
6
+ return obj;
7
+ }
8
+
9
+ export async function checkAction(ctx, next) {
10
+ const currentRole = ctx.state.currentRole;
11
+ if (currentRole) {
12
+ const roleInstance = await ctx.db.getRepository('roles').findOne({
13
+ filter: {
14
+ name: currentRole,
15
+ },
16
+ appends: ['menuUiSchemas'],
17
+ });
18
+
19
+ const anonymous = await ctx.db.getRepository('roles').findOne({
20
+ filter: {
21
+ name: 'anonymous',
22
+ },
23
+ });
24
+
25
+ const role = ctx.app.acl.getRole(currentRole);
26
+
27
+ ctx.body = {
28
+ ...role.toJSON(),
29
+ resources: [...role.resources.keys()],
30
+ actionAlias: map2obj(ctx.app.acl.actionAlias),
31
+ allowAll: currentRole === 'root',
32
+ allowConfigure: roleInstance.get('allowConfigure'),
33
+ allowMenuItemIds: roleInstance.get('menuUiSchemas').map((uiSchema) => uiSchema.get('x-uid')),
34
+ allowAnonymous: !!anonymous,
35
+ };
36
+ }
37
+
38
+ await next();
39
+ }
@@ -0,0 +1,55 @@
1
+ import { Database } from '@nocobase/database';
2
+
3
+ type UsingConfigType = 'strategy' | 'resourceAction';
4
+
5
+ const roleCollectionsResource = {
6
+ name: 'roles.collections',
7
+ actions: {
8
+ async list(ctx, next) {
9
+ const role = ctx.action.params.associatedIndex;
10
+
11
+ const db: Database = ctx.db;
12
+ const collectionRepository = db.getRepository('collections');
13
+
14
+ // all collections
15
+ const collections = await collectionRepository.find({
16
+ filter: ctx.action.params.filter,
17
+ });
18
+
19
+ // role collections
20
+ const roleResources = await db.getRepository('rolesResources').find({
21
+ filter: {
22
+ roleName: role,
23
+ },
24
+ });
25
+
26
+ // role collections
27
+ const roleResourcesNames = roleResources.map((roleResource) => roleResource.get('name'));
28
+ const roleResourceActionResourceNames = roleResources
29
+ .filter((roleResources) => roleResources.get('usingActionsConfig'))
30
+ .map((roleResources) => roleResources.get('name'));
31
+
32
+ ctx.body = collections
33
+ .map((collection) => {
34
+ const exists = roleResourcesNames.includes(collection.get('name'));
35
+
36
+ const usingConfig: UsingConfigType = roleResourceActionResourceNames.includes(collection.get('name'))
37
+ ? 'resourceAction'
38
+ : 'strategy';
39
+
40
+ return {
41
+ name: collection.get('name') as string,
42
+ title: collection.get('title') as string,
43
+ roleName: role,
44
+ usingConfig,
45
+ exists,
46
+ };
47
+ })
48
+ .sort((a, b) => (a.name > b.name ? 1 : -1));
49
+
50
+ await next();
51
+ },
52
+ },
53
+ };
54
+
55
+ export { roleCollectionsResource };
@@ -0,0 +1,79 @@
1
+ import { CollectionOptions } from '@nocobase/database';
2
+
3
+ export default {
4
+ name: 'roles',
5
+ title: '{{t("Roles")}}',
6
+ autoGenId: false,
7
+ model: 'RoleModel',
8
+ filterTargetKey: 'name',
9
+ // targetKey: 'name',
10
+ sortable: true,
11
+ fields: [
12
+ {
13
+ type: 'uid',
14
+ name: 'name',
15
+ prefix: 'r_',
16
+ primaryKey: true,
17
+ interface: 'input',
18
+ uiSchema: {
19
+ type: 'string',
20
+ title: '{{t("Role UID")}}',
21
+ 'x-component': 'Input',
22
+ },
23
+ },
24
+ {
25
+ type: 'string',
26
+ name: 'title',
27
+ unique: true,
28
+ interface: 'input',
29
+ uiSchema: {
30
+ type: 'string',
31
+ title: '{{t("Role name")}}',
32
+ 'x-component': 'Input',
33
+ },
34
+ },
35
+ {
36
+ type: 'boolean',
37
+ name: 'default',
38
+ },
39
+ {
40
+ type: 'string',
41
+ name: 'description',
42
+ },
43
+ {
44
+ type: 'json',
45
+ name: 'strategy',
46
+ },
47
+ {
48
+ type: 'boolean',
49
+ name: 'default',
50
+ defaultValue: false,
51
+ },
52
+ {
53
+ type: 'boolean',
54
+ name: 'hidden',
55
+ defaultValue: false,
56
+ },
57
+ {
58
+ type: 'boolean',
59
+ name: 'allowConfigure',
60
+ },
61
+ {
62
+ type: 'boolean',
63
+ name: 'allowNewMenu',
64
+ },
65
+ {
66
+ type: 'belongsToMany',
67
+ name: 'menuUiSchemas',
68
+ target: 'uiSchemas',
69
+ targetKey: 'x-uid',
70
+ },
71
+ {
72
+ type: 'hasMany',
73
+ name: 'resources',
74
+ target: 'rolesResources',
75
+ sourceKey: 'name',
76
+ targetKey: 'name',
77
+ },
78
+ ],
79
+ } as CollectionOptions;
@@ -0,0 +1,31 @@
1
+ import { CollectionOptions } from '@nocobase/database';
2
+
3
+ export default {
4
+ name: 'rolesResources',
5
+ model: 'RoleResourceModel',
6
+ indexes: [
7
+ {
8
+ unique: true,
9
+ fields: ['roleName', 'name'],
10
+ },
11
+ ],
12
+ fields: [
13
+ {
14
+ type: 'belongsTo',
15
+ name: 'role',
16
+ },
17
+ {
18
+ type: 'string',
19
+ name: 'name',
20
+ },
21
+ {
22
+ type: 'boolean',
23
+ name: 'usingActionsConfig',
24
+ },
25
+ {
26
+ type: 'hasMany',
27
+ name: 'actions',
28
+ target: 'rolesResourcesActions',
29
+ },
30
+ ],
31
+ } as CollectionOptions;
@@ -0,0 +1,28 @@
1
+ import { CollectionOptions } from '@nocobase/database';
2
+
3
+ export default {
4
+ name: 'rolesResourcesActions',
5
+ model: 'RoleResourceActionModel',
6
+ fields: [
7
+ {
8
+ type: 'belongsTo',
9
+ name: 'resource',
10
+ foreignKey: 'rolesResourceId',
11
+ target: 'rolesResources',
12
+ },
13
+ {
14
+ type: 'string',
15
+ name: 'name',
16
+ },
17
+ {
18
+ type: 'array',
19
+ name: 'fields',
20
+ defaultValue: [],
21
+ },
22
+ {
23
+ type: 'belongsTo',
24
+ name: 'scope',
25
+ target: 'rolesResourcesScopes',
26
+ },
27
+ ],
28
+ } as CollectionOptions;
@@ -0,0 +1,23 @@
1
+ import { CollectionOptions } from '@nocobase/database';
2
+
3
+ export default {
4
+ name: 'rolesResourcesScopes',
5
+ fields: [
6
+ {
7
+ type: 'uid',
8
+ name: 'key',
9
+ },
10
+ {
11
+ type: 'string',
12
+ name: 'name',
13
+ },
14
+ {
15
+ type: 'string',
16
+ name: 'resourceName',
17
+ },
18
+ {
19
+ type: 'json',
20
+ name: 'scope',
21
+ },
22
+ ],
23
+ } as CollectionOptions;
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { default } from './server';
2
+