mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-08 06:59:26 +08:00
feat: strategy with resources list (#4312)
* chore: strategy with resources list * chore: append strategy resource when collection loaded * chore: test * chore: no permission error * chore: test * fix: update strategy resources after update collection * fix: test * fix: snippet name * chore: error class import
This commit is contained in:
parent
819ac79f1a
commit
5f5d3f3d90
@ -415,4 +415,28 @@ describe('acl', () => {
|
|||||||
ctx1.permission.can.params.fields.push('createdById');
|
ctx1.permission.can.params.fields.push('createdById');
|
||||||
expect(ctx2.permission.can.params.fields).toEqual([]);
|
expect(ctx2.permission.can.params.fields).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not allow when strategyResources is set', async () => {
|
||||||
|
acl.setAvailableAction('create', {
|
||||||
|
displayName: 'create',
|
||||||
|
type: 'new-data',
|
||||||
|
});
|
||||||
|
|
||||||
|
const role = acl.define({
|
||||||
|
role: 'admin',
|
||||||
|
strategy: {
|
||||||
|
actions: ['create'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(acl.can({ role: 'admin', resource: 'users', action: 'create' })).toBeTruthy();
|
||||||
|
|
||||||
|
acl.setStrategyResources(['posts']);
|
||||||
|
|
||||||
|
expect(acl.can({ role: 'admin', resource: 'users', action: 'create' })).toBeNull();
|
||||||
|
|
||||||
|
acl.setStrategyResources(['posts', 'users']);
|
||||||
|
|
||||||
|
expect(acl.can({ role: 'admin', resource: 'users', action: 'create' })).toBeTruthy();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -7,8 +7,56 @@
|
|||||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { MockServer, createMockServer } from '@nocobase/test';
|
||||||
import { ACL } from '..';
|
import { ACL } from '..';
|
||||||
import SnippetManager from '../snippet-manager';
|
import SnippetManager from '../snippet-manager';
|
||||||
|
describe('nocobase snippet', () => {
|
||||||
|
let app: MockServer;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
app = await createMockServer({
|
||||||
|
plugins: ['nocobase'],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await app.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('snippet allowed', async () => {
|
||||||
|
const testRole = app.acl.define({
|
||||||
|
role: 'test',
|
||||||
|
});
|
||||||
|
|
||||||
|
testRole.snippets.add('!pm.users');
|
||||||
|
testRole.snippets.add('pm.*');
|
||||||
|
|
||||||
|
expect(
|
||||||
|
app.acl.can({
|
||||||
|
role: 'test',
|
||||||
|
resource: 'users',
|
||||||
|
action: 'list',
|
||||||
|
}),
|
||||||
|
).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow all snippets', async () => {
|
||||||
|
const testRole = app.acl.define({
|
||||||
|
role: 'test',
|
||||||
|
});
|
||||||
|
|
||||||
|
testRole.snippets.add('!pm.acl.roles');
|
||||||
|
testRole.snippets.add('pm.*');
|
||||||
|
|
||||||
|
expect(
|
||||||
|
app.acl.can({
|
||||||
|
role: 'test',
|
||||||
|
resource: 'users',
|
||||||
|
action: 'list',
|
||||||
|
}),
|
||||||
|
).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('acl snippet', () => {
|
describe('acl snippet', () => {
|
||||||
let acl: ACL;
|
let acl: ACL;
|
||||||
@ -86,6 +134,34 @@ describe('acl snippet', () => {
|
|||||||
|
|
||||||
expect(adminRole.snippetAllowed('other:list')).toBeNull();
|
expect(adminRole.snippetAllowed('other:list')).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return true when last rule allowd', () => {
|
||||||
|
acl.registerSnippet({
|
||||||
|
name: 'sc.collection-manager.fields',
|
||||||
|
actions: ['fields:list'],
|
||||||
|
});
|
||||||
|
|
||||||
|
acl.registerSnippet({
|
||||||
|
name: 'sc.collection-manager.gi',
|
||||||
|
actions: ['fields:list'],
|
||||||
|
});
|
||||||
|
|
||||||
|
acl.registerSnippet({
|
||||||
|
name: 'sc.users',
|
||||||
|
actions: ['users:*'],
|
||||||
|
});
|
||||||
|
|
||||||
|
const adminRole = acl.define({
|
||||||
|
role: 'admin',
|
||||||
|
});
|
||||||
|
|
||||||
|
adminRole.snippets.add('!sc.collection-manager.gi');
|
||||||
|
adminRole.snippets.add('!sc.users');
|
||||||
|
adminRole.snippets.add('sc.*');
|
||||||
|
|
||||||
|
expect(acl.can({ role: 'admin', resource: 'fields', action: 'list' })).toBeTruthy();
|
||||||
|
expect(acl.can({ role: 'admin', resource: 'users', action: 'list' })).toBeNull();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('snippet manager', () => {
|
describe('snippet manager', () => {
|
||||||
@ -135,5 +211,22 @@ describe('snippet manager', () => {
|
|||||||
|
|
||||||
expect(snippetManager.allow('fields:list', 'sc.collection-manager.fields')).toBeNull();
|
expect(snippetManager.allow('fields:list', 'sc.collection-manager.fields')).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not register snippet named with *', async () => {
|
||||||
|
const snippetManager = new SnippetManager();
|
||||||
|
|
||||||
|
let error;
|
||||||
|
|
||||||
|
try {
|
||||||
|
snippetManager.register({
|
||||||
|
name: 'sc.collection-manager.*',
|
||||||
|
actions: ['collections:*'],
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error).toBeDefined();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -107,6 +107,7 @@ export class ACLRole {
|
|||||||
|
|
||||||
public effectiveSnippets(): { allowed: Array<string>; rejected: Array<string> } {
|
public effectiveSnippets(): { allowed: Array<string>; rejected: Array<string> } {
|
||||||
const currentParams = this._serializeSet(this.snippets);
|
const currentParams = this._serializeSet(this.snippets);
|
||||||
|
|
||||||
if (this._snippetCache.params === currentParams) {
|
if (this._snippetCache.params === currentParams) {
|
||||||
return this._snippetCache.result;
|
return this._snippetCache.result;
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import { ACLRole, ResourceActionsOptions, RoleActionParams } from './acl-role';
|
|||||||
import { AllowManager, ConditionFunc } from './allow-manager';
|
import { AllowManager, ConditionFunc } from './allow-manager';
|
||||||
import FixedParamsManager, { Merger } from './fixed-params-manager';
|
import FixedParamsManager, { Merger } from './fixed-params-manager';
|
||||||
import SnippetManager, { SnippetOptions } from './snippet-manager';
|
import SnippetManager, { SnippetOptions } from './snippet-manager';
|
||||||
|
import { NoPermissionError } from './errors/no-permission-error';
|
||||||
|
|
||||||
interface CanResult {
|
interface CanResult {
|
||||||
role: string;
|
role: string;
|
||||||
@ -92,6 +93,8 @@ export class ACL extends EventEmitter {
|
|||||||
|
|
||||||
protected middlewares: Toposort<any>;
|
protected middlewares: Toposort<any>;
|
||||||
|
|
||||||
|
protected strategyResources: Set<string> | null = null;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -124,6 +127,25 @@ export class ACL extends EventEmitter {
|
|||||||
this.addCoreMiddleware();
|
this.addCoreMiddleware();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setStrategyResources(resources: Array<string> | null) {
|
||||||
|
this.strategyResources = new Set(resources);
|
||||||
|
}
|
||||||
|
|
||||||
|
getStrategyResources() {
|
||||||
|
return this.strategyResources ? [...this.strategyResources] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
appendStrategyResource(resource: string) {
|
||||||
|
if (!this.strategyResources) {
|
||||||
|
this.strategyResources = new Set();
|
||||||
|
}
|
||||||
|
this.strategyResources.add(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeStrategyResource(resource: string) {
|
||||||
|
this.strategyResources.delete(resource);
|
||||||
|
}
|
||||||
|
|
||||||
define(options: DefineOptions): ACLRole {
|
define(options: DefineOptions): ACLRole {
|
||||||
const roleName = options.role;
|
const roleName = options.role;
|
||||||
const role = new ACLRole(this, roleName);
|
const role = new ACLRole(this, roleName);
|
||||||
@ -230,7 +252,11 @@ export class ACL extends EventEmitter {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let roleStrategyParams = roleStrategy?.allow(resource, this.resolveActionAlias(action));
|
let roleStrategyParams;
|
||||||
|
|
||||||
|
if (this.strategyResources === null || this.strategyResources.has(resource)) {
|
||||||
|
roleStrategyParams = roleStrategy?.allow(resource, this.resolveActionAlias(action));
|
||||||
|
}
|
||||||
|
|
||||||
if (!roleStrategyParams && snippetAllowed) {
|
if (!roleStrategyParams && snippetAllowed) {
|
||||||
roleStrategyParams = {};
|
roleStrategyParams = {};
|
||||||
@ -391,7 +417,7 @@ export class ACL extends EventEmitter {
|
|||||||
if (params?.filter?.createdById) {
|
if (params?.filter?.createdById) {
|
||||||
const collection = ctx.db.getCollection(resourceName);
|
const collection = ctx.db.getCollection(resourceName);
|
||||||
if (!collection || !collection.getField('createdById')) {
|
if (!collection || !collection.getField('createdById')) {
|
||||||
return lodash.omit(params, 'filter.createdById');
|
throw new NoPermissionError('createdById field not found');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,25 +445,34 @@ export class ACL extends EventEmitter {
|
|||||||
|
|
||||||
ctx.log?.debug && ctx.log.debug('acl params', params);
|
ctx.log?.debug && ctx.log.debug('acl params', params);
|
||||||
|
|
||||||
if (params && resourcerAction.mergeParams) {
|
try {
|
||||||
const filteredParams = acl.filterParams(ctx, resourceName, params);
|
if (params && resourcerAction.mergeParams) {
|
||||||
const parsedParams = await acl.parseJsonTemplate(filteredParams, ctx);
|
const filteredParams = acl.filterParams(ctx, resourceName, params);
|
||||||
|
const parsedParams = await acl.parseJsonTemplate(filteredParams, ctx);
|
||||||
|
|
||||||
ctx.permission.parsedParams = parsedParams;
|
ctx.permission.parsedParams = parsedParams;
|
||||||
ctx.log?.debug && ctx.log.debug('acl parsedParams', parsedParams);
|
ctx.log?.debug && ctx.log.debug('acl parsedParams', parsedParams);
|
||||||
ctx.permission.rawParams = lodash.cloneDeep(resourcerAction.params);
|
ctx.permission.rawParams = lodash.cloneDeep(resourcerAction.params);
|
||||||
resourcerAction.mergeParams(parsedParams, {
|
resourcerAction.mergeParams(parsedParams, {
|
||||||
appends: (x, y) => {
|
appends: (x, y) => {
|
||||||
if (!x) {
|
if (!x) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
if (!y) {
|
if (!y) {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
return (x as any[]).filter((i) => y.includes(i.split('.').shift()));
|
return (x as any[]).filter((i) => y.includes(i.split('.').shift()));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
ctx.permission.mergedParams = lodash.cloneDeep(resourcerAction.params);
|
ctx.permission.mergedParams = lodash.cloneDeep(resourcerAction.params);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof NoPermissionError) {
|
||||||
|
ctx.throw(403, 'No permissions');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
await next();
|
await next();
|
||||||
|
10
packages/core/acl/src/errors/index.ts
Normal file
10
packages/core/acl/src/errors/index.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './no-permission-error';
|
10
packages/core/acl/src/errors/no-permission-error.ts
Normal file
10
packages/core/acl/src/errors/no-permission-error.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class NoPermissionError extends Error {}
|
@ -13,3 +13,4 @@ export * from './acl-available-strategy';
|
|||||||
export * from './acl-resource';
|
export * from './acl-resource';
|
||||||
export * from './acl-role';
|
export * from './acl-role';
|
||||||
export * from './skip-middleware';
|
export * from './skip-middleware';
|
||||||
|
export * from './errors';
|
||||||
|
@ -30,6 +30,12 @@ class SnippetManager {
|
|||||||
public snippets: Map<string, Snippet> = new Map();
|
public snippets: Map<string, Snippet> = new Map();
|
||||||
|
|
||||||
register(snippet: SnippetOptions) {
|
register(snippet: SnippetOptions) {
|
||||||
|
const name = snippet.name;
|
||||||
|
// throw error if name include * or end with dot
|
||||||
|
if (name.includes('*') || name.endsWith('.')) {
|
||||||
|
throw new Error(`Invalid snippet name: ${name}, name should not include * or end with dot.`);
|
||||||
|
}
|
||||||
|
|
||||||
this.snippets.set(snippet.name, snippet);
|
this.snippets.set(snippet.name, snippet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,6 +337,7 @@ describe('acl', () => {
|
|||||||
forceUpdate: true,
|
forceUpdate: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.acl.appendStrategyResource('posts');
|
||||||
expect(
|
expect(
|
||||||
acl.can({
|
acl.can({
|
||||||
role: 'new',
|
role: 'new',
|
||||||
@ -887,4 +888,27 @@ describe('acl', () => {
|
|||||||
expect(destroyResponse.statusCode).toEqual(200);
|
expect(destroyResponse.statusCode).toEqual(200);
|
||||||
expect(await db.getRepository('roles').findOne({ filterByTk: 'testRole' })).toBeNull();
|
expect(await db.getRepository('roles').findOne({ filterByTk: 'testRole' })).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should set acl strategy resources', async () => {
|
||||||
|
await db.getRepository('collections').create({
|
||||||
|
values: {
|
||||||
|
name: 'posts',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'title',
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
context: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(app.acl.getStrategyResources()).toContain('posts');
|
||||||
|
|
||||||
|
await db.getRepository('collections').destroy({
|
||||||
|
filterByTk: 'posts',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(app.acl.getStrategyResources()).not.toContain('posts');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -78,6 +78,46 @@ describe('middleware', () => {
|
|||||||
await app.destroy();
|
await app.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should no permission when createdById field not exists in collection', async () => {
|
||||||
|
await db.getRepository('collections').create({
|
||||||
|
values: {
|
||||||
|
name: 'foos',
|
||||||
|
autoGenId: false,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
name: 'name',
|
||||||
|
primaryKey: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
context: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
await db.getRepository('roles').update({
|
||||||
|
filterByTk: 'admin',
|
||||||
|
values: {
|
||||||
|
strategy: {
|
||||||
|
actions: ['create', 'update:own'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await adminAgent.resource('foos').create({
|
||||||
|
values: {
|
||||||
|
name: 'foo-name',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.statusCode).toEqual(200);
|
||||||
|
|
||||||
|
const updateRes = await adminAgent.resource('foos').update({
|
||||||
|
filterByTk: response.body.data.name,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(updateRes.statusCode).toEqual(403);
|
||||||
|
});
|
||||||
|
|
||||||
it('should throw 403 when no permission', async () => {
|
it('should throw 403 when no permission', async () => {
|
||||||
const response = await app.agent().resource('posts').create({
|
const response = await app.agent().resource('posts').create({
|
||||||
values: {},
|
values: {},
|
||||||
|
@ -99,6 +99,7 @@ describe('own test', () => {
|
|||||||
})
|
})
|
||||||
.set({ Authorization: 'Bearer ' + adminToken });
|
.set({ Authorization: 'Bearer ' + adminToken });
|
||||||
|
|
||||||
|
acl.appendStrategyResource('tests');
|
||||||
const response = await userAgent.get('/tests:list');
|
const response = await userAgent.get('/tests:list');
|
||||||
expect(response.statusCode).toEqual(200);
|
expect(response.statusCode).toEqual(200);
|
||||||
});
|
});
|
||||||
@ -113,6 +114,7 @@ describe('own test', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
acl.appendStrategyResource('posts');
|
||||||
let response = await userAgent.resource('posts').create({
|
let response = await userAgent.resource('posts').create({
|
||||||
values: {
|
values: {
|
||||||
title: 't1',
|
title: 't1',
|
||||||
|
@ -15,5 +15,6 @@ export async function prepareApp(): Promise<MockServer> {
|
|||||||
acl: true,
|
acl: true,
|
||||||
plugins: ['acl', 'error-handler', 'users', 'ui-schema-storage', 'data-source-main', 'auth', 'data-source-manager'],
|
plugins: ['acl', 'error-handler', 'users', 'ui-schema-storage', 'data-source-main', 'auth', 'data-source-manager'],
|
||||||
});
|
});
|
||||||
|
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,28 @@ describe('role api', () => {
|
|||||||
adminAgent = app.agent().login(admin);
|
adminAgent = app.agent().login(admin);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should have permission to users collection with strategy', async () => {
|
||||||
|
await db.getRepository('roles').create({
|
||||||
|
values: {
|
||||||
|
name: 'tests',
|
||||||
|
strategy: {
|
||||||
|
actions: ['view'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const user1 = await db.getRepository('users').create({
|
||||||
|
values: {
|
||||||
|
roles: ['tests'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const userAgent = app.agent().login(user1);
|
||||||
|
|
||||||
|
const response = await userAgent.resource('users').list();
|
||||||
|
expect(response.statusCode).toBe(200);
|
||||||
|
});
|
||||||
|
|
||||||
it('should list actions', async () => {
|
it('should list actions', async () => {
|
||||||
const response = await adminAgent.resource('availableActions').list();
|
const response = await adminAgent.resource('availableActions').list();
|
||||||
expect(response.statusCode).toEqual(200);
|
expect(response.statusCode).toEqual(200);
|
||||||
|
@ -9,8 +9,7 @@
|
|||||||
|
|
||||||
import lodash from 'lodash';
|
import lodash from 'lodash';
|
||||||
import { snakeCase } from '@nocobase/database';
|
import { snakeCase } from '@nocobase/database';
|
||||||
|
import { NoPermissionError } from '@nocobase/acl';
|
||||||
class NoPermissionError extends Error {}
|
|
||||||
|
|
||||||
function createWithACLMetaMiddleware() {
|
function createWithACLMetaMiddleware() {
|
||||||
return async (ctx: any, next) => {
|
return async (ctx: any, next) => {
|
||||||
|
@ -106,6 +106,8 @@ export class PluginACLServer extends Plugin {
|
|||||||
'dataSources:list',
|
'dataSources:list',
|
||||||
'roles.dataSourcesCollections:*',
|
'roles.dataSourcesCollections:*',
|
||||||
'roles.dataSourceResources:*',
|
'roles.dataSourceResources:*',
|
||||||
|
'dataSourcesRolesResourcesScopes:*',
|
||||||
|
'rolesResourcesScopes:*',
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -576,6 +578,22 @@ export class PluginACLServer extends Plugin {
|
|||||||
},
|
},
|
||||||
{ after: 'dataSource', group: 'with-acl-meta' },
|
{ after: 'dataSource', group: 'with-acl-meta' },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.db.on('afterUpdateCollection', async (collection) => {
|
||||||
|
if (collection.options.loadedFromCollectionManager) {
|
||||||
|
this.app.acl.appendStrategyResource(collection.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.db.on('afterDefineCollection', async (collection) => {
|
||||||
|
if (collection.options.loadedFromCollectionManager) {
|
||||||
|
this.app.acl.appendStrategyResource(collection.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.db.on('afterRemoveCollection', (collection) => {
|
||||||
|
this.app.acl.removeStrategyResource(collection.name);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async install() {
|
async install() {
|
||||||
|
@ -173,6 +173,7 @@ export class CollectionRepository extends Repository {
|
|||||||
|
|
||||||
const options = collection.options;
|
const options = collection.options;
|
||||||
const fields = [];
|
const fields = [];
|
||||||
|
|
||||||
for (const [name, field] of collection.fields) {
|
for (const [name, field] of collection.fields) {
|
||||||
fields.push({
|
fields.push({
|
||||||
name,
|
name,
|
||||||
|
@ -148,7 +148,7 @@ export default class PluginUsersServer extends Plugin {
|
|||||||
loggedInActions.forEach((action) => this.app.acl.allow('users', action, 'loggedIn'));
|
loggedInActions.forEach((action) => this.app.acl.allow('users', action, 'loggedIn'));
|
||||||
|
|
||||||
this.app.acl.registerSnippet({
|
this.app.acl.registerSnippet({
|
||||||
name: `pm.${this.name}.*`,
|
name: `pm.${this.name}`,
|
||||||
actions: ['users:*'],
|
actions: ['users:*'],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -200,6 +200,7 @@ export default class PluginUsersServer extends Plugin {
|
|||||||
async install(options) {
|
async install(options) {
|
||||||
const { rootNickname, rootPassword, rootEmail, rootUsername } = this.getInstallingData(options);
|
const { rootNickname, rootPassword, rootEmail, rootUsername } = this.getInstallingData(options);
|
||||||
const User = this.db.getCollection('users');
|
const User = this.db.getCollection('users');
|
||||||
|
|
||||||
if (await User.repository.findOne({ filter: { email: rootEmail } })) {
|
if (await User.repository.findOne({ filter: { email: rootEmail } })) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -214,6 +215,7 @@ export default class PluginUsersServer extends Plugin {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const repo = this.db.getRepository<any>('collections');
|
const repo = this.db.getRepository<any>('collections');
|
||||||
|
|
||||||
if (repo) {
|
if (repo) {
|
||||||
await repo.db2cm('users');
|
await repo.db2cm('users');
|
||||||
}
|
}
|
||||||
|
@ -229,7 +229,7 @@ export default class PluginWorkflowServer extends Plugin {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.app.acl.registerSnippet({
|
this.app.acl.registerSnippet({
|
||||||
name: 'ui.*',
|
name: 'ui.workflows',
|
||||||
actions: ['workflows:list'],
|
actions: ['workflows:list'],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user