refactor(plugin-users): improve extendibility of middlewares (#677)

* refactor(plugin-users): improve extendibility of middlewares

* fix(plugin-users): fix typo

* fix: test error

* fix: allowConfigure condition

Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
Junyi 2022-07-25 19:33:23 +08:00 committed by GitHub
parent 5b61587a39
commit 49a4ab4818
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 649 additions and 603 deletions

View File

@ -19,7 +19,9 @@ export class AllowManager {
}
const roleInstance = await ctx.db.getRepository('roles').findOne({
name: roleName,
filter: {
name: roleName
},
});
return roleInstance?.get('allowConfigure');

View File

@ -1,6 +1,7 @@
import { ActionName } from './action';
import { requireModule } from './utils';
import { HandlerType } from './resourcer';
import compose from 'koa-compose';
export type MiddlewareType = string | string[] | HandlerType | HandlerType[] | MiddlewareOptions | MiddlewareOptions[];
@ -73,3 +74,19 @@ export class Middleware {
}
export default Middleware;
export class MiddlewareManager {
protected middlewares: HandlerType[] = [];
compose() {
return (ctx, next) => compose(this.middlewares)(ctx, next);
}
use(middleware: HandlerType) {
this.middlewares.push(middleware);
}
unuse(middleware: HandlerType) {
this.middlewares.splice(this.middlewares.indexOf(middleware), 1);
}
}

View File

@ -14,6 +14,7 @@
"dependencies": {
"@nocobase/acl": "0.7.3-alpha.1",
"@nocobase/database": "0.7.3-alpha.1",
"@nocobase/plugin-users": "0.7.3-alpha.1",
"@nocobase/server": "0.7.3-alpha.1"
},
"repository": {

View File

@ -1,13 +1,16 @@
import { ACL } from '@nocobase/acl';
import { Database } from '@nocobase/database';
import { MockServer } from '@nocobase/test';
import { changeMockRole, prepareApp } from './prepare';
import UsersPlugin from '@nocobase/plugin-users';
import { UiSchemaRepository } from '@nocobase/plugin-ui-schema-storage';
import { prepareApp } from './prepare';
describe('acl', () => {
let app: MockServer;
let db: Database;
let acl: ACL;
let admin;
let adminAgent;
let uiSchemaRepository: UiSchemaRepository;
@ -20,38 +23,41 @@ describe('acl', () => {
db = app.db;
acl = app.acl;
const UserRepo = db.getCollection('users').repository;
admin = await UserRepo.create({
values: {
roles: ['admin']
}
});
const userPlugin = app.getPlugin('@nocobase/plugin-users') as UsersPlugin;
adminAgent = app.agent().auth(userPlugin.jwtService.sign({
userId: admin.get('id'),
}), { type: 'bearer' });
uiSchemaRepository = db.getRepository('uiSchemas');
});
it('should works with universal actions', async () => {
await db.getRepository('roles').create({
values: {
name: 'admin',
title: 'Admin User',
allowConfigure: true,
},
});
const role = await db.getRepository('roles').findOne({
filter: {
name: 'admin',
name: 'new'
},
});
expect(
acl.can({
role: 'admin',
role: 'new',
resource: 'posts',
action: 'create',
}),
).toBeNull();
// grant universal action
await app
.agent()
await adminAgent
.resource('roles')
.update({
resourceIndex: 'admin',
resourceIndex: 'new',
values: {
strategy: {
actions: ['create'],
@ -61,31 +67,27 @@ describe('acl', () => {
expect(
acl.can({
role: 'admin',
role: 'new',
resource: 'posts',
action: 'create',
}),
).toMatchObject({
role: 'admin',
role: 'new',
resource: 'posts',
action: 'create',
});
});
it('should deny when resource action has no resource', async () => {
const role = await db.getRepository('roles').create({
await db.getRepository('roles').create({
values: {
name: 'admin',
title: 'Admin User',
allowConfigure: true,
name: 'new',
strategy: {
actions: ['update:own', 'destroy:own', 'create', 'view'],
},
},
});
changeMockRole('admin');
// create c1 collection
await db.getRepository('collections').create({
values: {
@ -102,9 +104,8 @@ describe('acl', () => {
},
});
await app
.agent()
.resource('roles.resources', 'admin')
await adminAgent
.resource('roles.resources', 'new')
.create({
values: {
name: 'c1',
@ -115,7 +116,7 @@ describe('acl', () => {
expect(
acl.can({
role: 'admin',
role: 'new',
resource: 'c1',
action: 'list',
}),
@ -125,17 +126,13 @@ describe('acl', () => {
it('should works with resources actions', async () => {
const role = await db.getRepository('roles').create({
values: {
name: 'admin',
title: 'Admin User',
allowConfigure: true,
name: 'new',
strategy: {
actions: ['list'],
},
},
});
changeMockRole('admin');
// create c1 collection
await db.getRepository('collections').create({
values: {
@ -153,8 +150,7 @@ describe('acl', () => {
});
// create c1 published scope
await app
.agent()
const { body: { data: publishedScope } } = await adminAgent
.resource('rolesResourcesScopes')
.create({
values: {
@ -166,12 +162,11 @@ describe('acl', () => {
},
});
const publishedScope = await db.getRepository('rolesResourcesScopes').findOne();
// await db.getRepository('rolesResourcesScopes').findOne();
// set admin resources
await app
.agent()
.resource('roles.resources', 'admin')
await adminAgent
.resource('roles.resources', 'new')
.create({
values: {
name: 'c1',
@ -179,7 +174,7 @@ describe('acl', () => {
actions: [
{
name: 'create',
scope: publishedScope.get('id'),
scope: publishedScope.id,
},
{
name: 'view',
@ -191,12 +186,12 @@ describe('acl', () => {
expect(
acl.can({
role: 'admin',
role: 'new',
resource: 'c1',
action: 'create',
}),
).toMatchObject({
role: 'admin',
role: 'new',
resource: 'c1',
action: 'create',
params: {
@ -206,12 +201,12 @@ describe('acl', () => {
expect(
acl.can({
role: 'admin',
role: 'new',
resource: 'c1',
action: 'view',
}),
).toMatchObject({
role: 'admin',
role: 'new',
resource: 'c1',
action: 'view',
params: {
@ -220,8 +215,7 @@ describe('acl', () => {
});
// revoke action
const response = await app
.agent()
const response = await adminAgent
.resource('roles.resources', role.get('name'))
.list({
appends: ['actions'],
@ -232,8 +226,7 @@ describe('acl', () => {
const actions = response.body.data[0].actions;
const collectionName = response.body.data[0].name;
await app
.agent()
await adminAgent
.resource('roles.resources', role.get('name'))
.update({
filterByTk: collectionName,
@ -251,7 +244,7 @@ describe('acl', () => {
expect(
acl.can({
role: 'admin',
role: 'new',
resource: 'c1',
action: 'create',
}),
@ -259,11 +252,9 @@ describe('acl', () => {
});
it('should revoke resource when collection destroy', async () => {
const role = await db.getRepository('roles').create({
await db.getRepository('roles').create({
values: {
name: 'admin',
title: 'Admin User',
allowConfigure: true,
name: 'new'
},
});
@ -281,11 +272,10 @@ describe('acl', () => {
},
});
await app
.agent()
await adminAgent
.resource('roles.resources')
.create({
associatedIndex: role.get('name') as string,
associatedIndex: 'new',
values: {
name: 'posts',
usingActionsConfig: true,
@ -300,7 +290,7 @@ describe('acl', () => {
expect(
acl.can({
role: 'admin',
role: 'new',
resource: 'posts',
action: 'view',
}),
@ -314,7 +304,7 @@ describe('acl', () => {
expect(
acl.can({
role: 'admin',
role: 'new',
resource: 'posts',
action: 'view',
}),
@ -324,15 +314,7 @@ describe('acl', () => {
it('should revoke actions when not using actions config', async () => {
await db.getRepository('roles').create({
values: {
name: 'admin',
title: 'Admin User',
allowConfigure: true,
},
});
const role = await db.getRepository('roles').findOne({
filter: {
name: 'admin',
name: 'new'
},
});
@ -343,11 +325,10 @@ describe('acl', () => {
},
});
await app
.agent()
await adminAgent
.resource('roles.resources')
.create({
associatedIndex: role.get('name') as string,
associatedIndex: 'new',
values: {
name: 'posts',
usingActionsConfig: true,
@ -361,25 +342,24 @@ describe('acl', () => {
expect(
acl.can({
role: 'admin',
role: 'new',
resource: 'posts',
action: 'create',
}),
).toMatchObject({
role: 'admin',
role: 'new',
resource: 'posts',
action: 'create',
});
await app
.agent()
.resource('roles.resources', role.get('name'))
await adminAgent
.resource('roles.resources', 'new')
.update({
filterByTk: (
await db.getRepository('rolesResources').findOne({
filter: {
name: 'posts',
roleName: 'admin',
roleName: 'new',
},
})
).get('name') as string,
@ -390,21 +370,20 @@ describe('acl', () => {
expect(
acl.can({
role: 'admin',
role: 'new',
resource: 'posts',
action: 'create',
}),
).toBeNull();
await app
.agent()
.resource('roles.resources', role.get('name'))
await adminAgent
.resource('roles.resources', 'new')
.update({
filterByTk: (
await db.getRepository('rolesResources').findOne({
filter: {
name: 'posts',
roleName: 'admin',
roleName: 'new',
},
})
).get('name') as string,
@ -415,23 +394,21 @@ describe('acl', () => {
expect(
acl.can({
role: 'admin',
role: 'new',
resource: 'posts',
action: 'create',
}),
).toMatchObject({
role: 'admin',
role: 'new',
resource: 'posts',
action: 'create',
});
});
it('should add fields when field created', async () => {
const role = await db.getRepository('roles').create({
await db.getRepository('roles').create({
values: {
name: 'admin',
title: 'Admin User',
allowConfigure: true,
name: 'new'
},
});
@ -449,11 +426,10 @@ describe('acl', () => {
},
});
await app
.agent()
await adminAgent
.resource('roles.resources')
.create({
associatedIndex: role.get('name') as string,
associatedIndex: 'new',
values: {
name: 'posts',
usingActionsConfig: true,
@ -467,7 +443,7 @@ describe('acl', () => {
});
const allowFields = acl.can({
role: 'admin',
role: 'new',
resource: 'posts',
action: 'view',
})['params']['fields'];
@ -483,7 +459,7 @@ describe('acl', () => {
});
const newAllowFields = acl.can({
role: 'admin',
role: 'new',
resource: 'posts',
action: 'view',
})['params']['fields'];
@ -494,18 +470,14 @@ describe('acl', () => {
it('should get role menus', async () => {
const role = await db.getRepository('roles').create({
values: {
name: 'admin',
title: 'Admin User',
allowConfigure: true,
name: 'new',
strategy: {
actions: ['view'],
},
},
});
changeMockRole('admin');
const menuResponse = await app.agent().resource('roles.menuUiSchemas', 'admin').list();
const menuResponse = await adminAgent.resource('roles.menuUiSchemas', 'new').list();
expect(menuResponse.statusCode).toEqual(200);
});
@ -513,16 +485,23 @@ describe('acl', () => {
it('should toggle role menus', async () => {
const role = await db.getRepository('roles').create({
values: {
name: 'admin',
title: 'Admin User',
allowConfigure: true,
name: 'new',
strategy: {
actions: ['*'],
},
},
});
const UserRepo = db.getCollection('users').repository;
const user = await UserRepo.create({
values: {
roles: ['new']
}
});
changeMockRole('admin');
const userPlugin = app.getPlugin('@nocobase/plugin-users') as UsersPlugin;
const userAgent = app.agent().auth(userPlugin.jwtService.sign({
userId: user.get('id'),
}), { type: 'bearer' });
const schema = {
'x-uid': 'test',
@ -530,9 +509,9 @@ describe('acl', () => {
await uiSchemaRepository.insert(schema);
const response = await app
.agent()
.resource('roles.menuUiSchemas', 'admin')
const response = await userAgent
// @ts-ignore
.resource('roles.menuUiSchemas', 'new')
.toggle({
values: { tk: 'test' },
});
@ -543,9 +522,7 @@ describe('acl', () => {
it('should sync data to acl before app start', async () => {
const role = await db.getRepository('roles').create({
values: {
name: 'admin',
title: 'Admin User',
allowConfigure: true,
name: 'new',
resources: [
{
name: 'posts',
@ -562,20 +539,20 @@ describe('acl', () => {
hooks: false,
});
expect(acl.getRole('admin')).toBeUndefined();
expect(acl.getRole('new')).toBeUndefined();
await app.start();
expect(acl.getRole('admin')).toBeDefined();
expect(acl.getRole('new')).toBeDefined();
expect(
acl.can({
role: 'admin',
role: 'new',
resource: 'posts',
action: 'view',
}),
).toMatchObject({
role: 'admin',
role: 'new',
resource: 'posts',
action: 'view',
});

View File

@ -1,5 +1,6 @@
import { ACL } from '@nocobase/acl';
import { Database, HasManyRepository, Model } from '@nocobase/database';
import { Database, HasManyRepository } from '@nocobase/database';
import UsersPlugin from '@nocobase/plugin-users';
import { MockServer } from '@nocobase/test';
import { prepareApp } from './prepare';
@ -8,7 +9,10 @@ describe('association field acl', () => {
let db: Database;
let acl: ACL;
let role: Model;
let user;
let userAgent;
let admin;
let adminAgent;
afterEach(async () => {
await app.destroy();
@ -19,20 +23,44 @@ describe('association field acl', () => {
db = app.db;
acl = app.acl;
role = await db.getRepository('roles').create({
await db.getRepository('roles').create({
values: {
name: 'admin',
title: 'Admin User',
name: 'new',
allowConfigure: true,
},
});
await db.getRepository('collections').create({
await db.getRepository('roles').create({
values: {
name: 'users',
name: 'testAdmin',
allowConfigure: true,
},
context: {},
});
const UserRepo = db.getCollection('users').repository;
user = await UserRepo.create({
values: {
roles: ['new'],
},
});
admin = await UserRepo.create({
values: {
roles: ['testAdmin'],
},
});
const userPlugin = app.getPlugin('@nocobase/plugin-users') as UsersPlugin;
userAgent = app.agent().auth(
userPlugin.jwtService.sign({
userId: user.get('id'),
}),
{ type: 'bearer' },
);
adminAgent = app.agent().auth(
userPlugin.jwtService.sign({
userId: admin.get('id'),
}),
{ type: 'bearer' },
);
await db.getRepository('collections').create({
values: {
@ -75,56 +103,48 @@ describe('association field acl', () => {
context: {},
});
await app
.agent()
.resource('roles.resources')
.create({
associatedIndex: 'admin',
values: {
name: 'users',
usingActionsConfig: true,
actions: [
{
name: 'create',
fields: ['orders'],
},
{
name: 'view',
fields: ['orders'],
},
],
},
});
await adminAgent.resource('roles.resources', 'new').create({
values: {
name: 'users',
usingActionsConfig: true,
actions: [
{
name: 'create',
fields: ['orders'],
},
{
name: 'view',
fields: ['orders'],
},
],
},
});
});
it('should revoke target action on association action revoke', async () => {
expect(
acl.can({
role: 'admin',
role: 'new',
resource: 'orders',
action: 'list',
}),
).toMatchObject({
role: 'admin',
role: 'new',
resource: 'orders',
action: 'list',
});
await app
.agent()
.resource('roles.resources')
.update({
associatedIndex: 'admin',
values: {
name: 'users',
usingActionsConfig: true,
actions: [],
},
});
await adminAgent.resource('roles.resources', 'new').update({
values: {
name: 'users',
usingActionsConfig: true,
actions: [],
},
});
expect(
acl.can({
role: 'admin',
role: 'new',
resource: 'orders',
action: 'list',
}),
@ -134,12 +154,12 @@ describe('association field acl', () => {
it('should revoke association action on action revoke', async () => {
expect(
acl.can({
role: 'admin',
role: 'new',
resource: 'users.orders',
action: 'add',
}),
).toMatchObject({
role: 'admin',
role: 'new',
resource: 'users.orders',
action: 'add',
});
@ -152,27 +172,23 @@ describe('association field acl', () => {
const actionId = viewAction.get('id') as number;
const response = await app
.agent()
.resource('roles.resources')
.update({
associatedIndex: 'admin',
values: {
name: 'users',
usingActionsConfig: true,
actions: [
{
id: actionId,
},
],
},
});
const response = await adminAgent.resource('roles.resources', 'new').update({
values: {
name: 'users',
usingActionsConfig: true,
actions: [
{
id: actionId,
},
],
},
});
expect(response.statusCode).toEqual(200);
expect(
acl.can({
role: 'admin',
role: 'new',
resource: 'users.orders',
action: 'add',
}),
@ -180,30 +196,26 @@ describe('association field acl', () => {
});
it('should revoke association action on field deleted', async () => {
await app
.agent()
.resource('roles.resources')
.update({
associatedIndex: 'admin',
values: {
name: 'users',
usingActionsConfig: true,
actions: [
{
name: 'create',
fields: ['name', 'age'],
},
],
},
});
await adminAgent.resource('roles.resources', 'new').update({
values: {
name: 'users',
usingActionsConfig: true,
actions: [
{
name: 'create',
fields: ['name', 'age'],
},
],
},
});
expect(
acl.can({
role: 'admin',
role: 'new',
resource: 'users',
action: 'create',
}),
).toMatchObject({
role: 'admin',
role: 'new',
resource: 'users',
action: 'create',
params: {
@ -236,12 +248,12 @@ describe('association field acl', () => {
expect(
acl.can({
role: 'admin',
role: 'new',
resource: 'users',
action: 'create',
}),
).toMatchObject({
role: 'admin',
role: 'new',
resource: 'users',
action: 'create',
params: {
@ -251,45 +263,44 @@ describe('association field acl', () => {
});
it('should allow association fields access', async () => {
const createResponse = await app
.agent()
.resource('users')
.create({
values: {
orders: [
{
content: 'apple',
},
],
},
});
const createResponse = await userAgent.resource('users').create({
values: {
orders: [
{
content: 'apple',
},
],
},
});
expect(createResponse.statusCode).toEqual(200);
const user = await db.getRepository('users').findOne();
const user = await db.getRepository('users').findOne({
filterByTk: createResponse.body.data.id,
});
// @ts-ignore
expect(await user.countOrders()).toEqual(1);
expect(
acl.can({
role: 'admin',
role: 'new',
resource: 'users.orders',
action: 'list',
}),
).toMatchObject({
role: 'admin',
role: 'new',
resource: 'users.orders',
action: 'list',
});
expect(
acl.can({
role: 'admin',
role: 'new',
resource: 'orders',
action: 'list',
}),
).toMatchObject({
role: 'admin',
role: 'new',
resource: 'orders',
action: 'list',
});

View File

@ -1,15 +1,16 @@
import { MockServer } from '@nocobase/test';
import { Database } from '@nocobase/database';
import { ACL } from '@nocobase/acl';
import { UiSchemaRepository } from '@nocobase/plugin-ui-schema-storage';
import { changeMockRole, prepareApp } from './prepare';
import UsersPlugin from '@nocobase/plugin-users';
import { MockServer } from '@nocobase/test';
import { prepareApp } from './prepare';
describe('configuration', () => {
let app: MockServer;
let db: Database;
let acl: ACL;
let uiSchemaRepository: UiSchemaRepository;
let admin;
let adminAgent;
let user;
let userAgent;
let guestAgent;
afterEach(async () => {
await app.destroy();
@ -18,28 +19,56 @@ describe('configuration', () => {
beforeEach(async () => {
app = await prepareApp();
db = app.db;
acl = app.acl;
uiSchemaRepository = db.getRepository('uiSchemas');
});
it('should list collections', async () => {
expect((await app.agent().resource('collections').create()).statusCode).toEqual(403);
expect((await app.agent().resource('collections').list()).statusCode).toEqual(200);
});
it('should allow when role has allowConfigure with true value', async () => {
await db.getRepository('roles').create({
values: {
name: 'admin1',
title: 'admin allowConfigure',
name: 'test1',
allowConfigure: true,
},
});
changeMockRole('admin1');
await db.getRepository('roles').create({
values: {
name: 'test2',
},
});
expect((await app.agent().resource('collections').create()).statusCode).toEqual(200);
expect((await app.agent().resource('collections').list()).statusCode).toEqual(200);
const UserRepo = db.getCollection('users').repository;
admin = await UserRepo.create({
values: {
roles: ['test1']
}
});
user = await UserRepo.create({
values: {
roles: ['test2']
}
});
const userPlugin = app.getPlugin('@nocobase/plugin-users') as UsersPlugin;
adminAgent = app.agent().auth(userPlugin.jwtService.sign({
userId: admin.get('id'),
}), { type: 'bearer' });
userAgent = app.agent().auth(userPlugin.jwtService.sign({
userId: user.get('id'),
}), { type: 'bearer' });
guestAgent = app.agent();
});
it('should list collections', async () => {
expect((await userAgent.resource('collections').create()).statusCode).toEqual(403);
expect((await userAgent.resource('collections').list()).statusCode).toEqual(200);
});
it('should not create/list collections', async () => {
expect((await guestAgent.resource('collections').create()).statusCode).toEqual(403);
expect((await guestAgent.resource('collections').list()).statusCode).toEqual(403);
});
it('should allow when role has allowConfigure with true value', async () => {
expect((await adminAgent.resource('collections').create()).statusCode).toEqual(200);
expect((await adminAgent.resource('collections').list()).statusCode).toEqual(200);
});
});

View File

@ -1,33 +1,40 @@
import { ACL } from '@nocobase/acl';
import { Database, Model } from '@nocobase/database';
import { MockServer } from '@nocobase/test';
import { changeMockUser, prepareApp } from './prepare';
import UsersPlugin from '@nocobase/plugin-users';
import { prepareApp } from './prepare';
describe('middleware', () => {
let app: MockServer;
let role: Model;
let db: Database;
let acl: ACL;
let admin;
let adminAgent;
beforeEach(async () => {
app = await prepareApp();
db = app.db;
acl = app.acl;
await db.getRepository('roles').create({
values: {
name: 'admin',
title: 'Admin User',
allowConfigure: true,
},
});
role = await db.getRepository('roles').findOne({
filter: {
name: 'admin',
},
});
const UserRepo = db.getCollection('users').repository;
admin = await UserRepo.create({
values: {
roles: ['admin']
}
});
const userPlugin = app.getPlugin('@nocobase/plugin-users') as UsersPlugin;
adminAgent = app.agent().auth(userPlugin.jwtService.sign({
userId: admin.get('id'),
}), { type: 'bearer' });
await db.getRepository('collections').create({
values: {
name: 'posts',
@ -82,7 +89,7 @@ describe('middleware', () => {
},
});
const response = await app.agent().resource('posts').create({
const response = await adminAgent.resource('posts').create({
values: {},
});
@ -90,8 +97,7 @@ describe('middleware', () => {
});
it('should limit fields on view actions', async () => {
await app
.agent()
await adminAgent
.resource('roles.resources', role.get('name'))
.create({
values: {
@ -110,8 +116,7 @@ describe('middleware', () => {
},
});
await app
.agent()
await adminAgent
.resource('posts')
.create({
values: {
@ -124,10 +129,10 @@ describe('middleware', () => {
expect(post.get('title')).toEqual('post-title');
expect(post.get('description')).toEqual('post-description');
const response = await app.agent().resource('posts').list({});
const response = await adminAgent.resource('posts').list({});
expect(response.statusCode).toEqual(200);
const data = response.body.data[0];
const [data] = response.body.data;
expect(data['id']).not.toBeUndefined();
expect(data['title']).toEqual('post-title');
@ -135,12 +140,7 @@ describe('middleware', () => {
});
it('should parse template value on action params', async () => {
changeMockUser({
id: 2,
});
const res = await app
.agent()
const res = await adminAgent
.resource('rolesResourcesScopes')
.create({
values: {
@ -151,8 +151,7 @@ describe('middleware', () => {
},
});
await app
.agent()
await adminAgent
.resource('roles.resources', role.get('name'))
.create({
values: {
@ -172,8 +171,7 @@ describe('middleware', () => {
},
});
await app
.agent()
await adminAgent
.resource('posts')
.create({
values: {
@ -183,8 +181,7 @@ describe('middleware', () => {
},
});
await app
.agent()
await adminAgent
.resource('posts')
.create({
values: {
@ -194,14 +191,13 @@ describe('middleware', () => {
},
});
const response = await app.agent().resource('posts').list();
const response = await adminAgent.resource('posts').list();
const data = response.body.data;
expect(data.length).toEqual(1);
});
it('should change fields params to whitelist in create action', async () => {
await app
.agent()
await adminAgent
.resource('roles.resources', role.get('name'))
.create({
values: {
@ -216,8 +212,7 @@ describe('middleware', () => {
},
});
await app
.agent()
await adminAgent
.resource('posts')
.create({
values: {

View File

@ -1,11 +1,9 @@
import { ACL } from '@nocobase/acl';
import { Database } from '@nocobase/database';
import PluginACL from '@nocobase/plugin-acl';
import PluginCollectionManager from '@nocobase/plugin-collection-manager';
import PluginUiSchema from '@nocobase/plugin-ui-schema-storage';
import PluginUser from '@nocobase/plugin-users';
import { mockServer, MockServer } from '@nocobase/test';
import supertest from 'supertest';
import { MockServer } from '@nocobase/test';
import { prepareApp } from './prepare';
describe('own test', () => {
let app: MockServer;
@ -21,28 +19,15 @@ describe('own test', () => {
let role;
let agent;
let adminAgent;
let userAgent;
afterEach(async () => {
await app.destroy();
});
beforeEach(async () => {
app = mockServer({
registerActions: true,
});
await app.cleanDb();
app.plugin(PluginUiSchema);
app.plugin(PluginCollectionManager);
app.plugin(PluginUser, {
jwt: {
secret: process.env.APP_KEY || 'test-key',
},
});
app.plugin(PluginACL);
await app.loadAndInstall();
app = await prepareApp();
db = app.db;
const PostCollection = db.collection({
@ -68,9 +53,9 @@ describe('own test', () => {
fields: [{ type: 'string', name: 'name' }],
});
await app.db.sync();
await db.sync();
agent = supertest.agent(app.callback());
agent = app.agent();
acl = app.acl;
@ -86,6 +71,8 @@ describe('own test', () => {
adminToken = pluginUser.jwtService.sign({ userId: admin.get('id') });
adminAgent = app.agent().auth(adminToken, { type: 'bearer' });
user = await db.getRepository('users').create({
values: {
nickname: 'test',
@ -94,10 +81,12 @@ describe('own test', () => {
});
userToken = pluginUser.jwtService.sign({ userId: user.get('id') });
userAgent = app.agent().auth(userToken, { type: 'bearer' });
});
it('should list without createBy', async () => {
let response = await agent
await adminAgent
.patch('/roles/admin')
.send({
strategy: {
@ -106,33 +95,38 @@ describe('own test', () => {
})
.set({ Authorization: 'Bearer ' + adminToken });
response = await agent.get('/tests:list').set({ Authorization: 'Bearer ' + userToken });
const response = await userAgent.get('/tests:list');
expect(response.statusCode).toEqual(200);
});
it('should delete with createdBy', async () => {
let response = await agent
.patch('/roles/admin')
.send({
strategy: {
actions: ['view:own', 'create', 'destroy:own'],
},
})
.set({ Authorization: 'Bearer ' + adminToken });
await adminAgent
.resource('roles')
.update({
filterByTk: 'admin',
values: {
strategy: {
actions: ['view:own', 'create', 'destroy:own'],
},
}
});
response = await agent
.get('/posts:create')
.send({
title: 't1',
})
.set({ Authorization: 'Bearer ' + userToken });
let response = await userAgent
.resource('posts')
.create({
values: {
title: 't1',
}
});
expect(response.statusCode).toEqual(200);
const data = response.body;
const id = data.data['id'];
response = await agent.delete(`/posts/${id}`).set({ Authorization: 'Bearer ' + userToken });
response = await userAgent.resource('posts').destroy({
filterByTk: id
});
expect(response.statusCode).toEqual(200);
expect(await db.getRepository('posts').count()).toEqual(0);
});

View File

@ -1,18 +1,10 @@
import PluginUsers from '@nocobase/plugin-users';
import PluginCollectionManager from '@nocobase/plugin-collection-manager';
import PluginUiSchema from '@nocobase/plugin-ui-schema-storage';
import { mockServer } from '@nocobase/test';
import PluginACL from '../server';
let mockRole: string = 'admin';
let mockUser = {};
export function changeMockRole(role: string) {
mockRole = role;
}
export function changeMockUser(user: any) {
mockUser = user;
}
export async function prepareApp() {
const app = mockServer({
@ -21,15 +13,10 @@ export async function prepareApp() {
await app.cleanDb();
app.plugin(PluginUsers);
app.plugin(PluginUiSchema);
app.plugin(PluginCollectionManager);
app.resourcer.use(async (ctx, next) => {
ctx.state.currentRole = mockRole;
ctx.state.currentUser = mockUser;
await next();
});
app.plugin(PluginACL);
await app.loadAndInstall();

View File

@ -1,6 +1,8 @@
import { MockServer } from '@nocobase/test';
import { changeMockRole, changeMockUser, prepareApp } from './prepare';
import { Database } from '@nocobase/database';
import UsersPlugin from '@nocobase/plugin-users';
import { prepareApp } from './prepare';
describe('role check action', () => {
let app: MockServer;
@ -21,14 +23,18 @@ describe('role check action', () => {
name: 'test',
},
});
changeMockUser({
id: 2,
const user = await db.getRepository('users').create({
values: {
roles: ['test']
}
});
const userPlugin = app.getPlugin('@nocobase/plugin-users') as UsersPlugin;
const agent = app.agent().auth(userPlugin.jwtService.sign({
userId: user.get('id'),
}), { type: 'bearer' });
changeMockRole('test');
const response = await app.agent().get('/roles:check');
// @ts-ignore
const response = await agent.resource('roles').check();
expect(response.statusCode).toEqual(200);
});

View File

@ -1,4 +1,5 @@
import { Database, Model } from '@nocobase/database';
import UsersPlugin from '@nocobase/plugin-users';
import { CollectionRepository } from '@nocobase/plugin-collection-manager';
import { MockServer } from '@nocobase/test';
import { prepareApp } from './prepare';
@ -7,6 +8,8 @@ describe('role resource api', () => {
let app: MockServer;
let db: Database;
let role: Model;
let admin;
let adminAgent;
afterEach(async () => {
await app.destroy();
@ -16,19 +19,23 @@ describe('role resource api', () => {
app = await prepareApp();
db = app.db;
await db.getRepository('roles').create({
values: {
name: 'admin',
title: 'Admin User',
allowConfigure: true,
},
});
role = await db.getRepository('roles').findOne({
filter: {
name: 'admin',
},
});
const UserRepo = db.getCollection('users').repository;
admin = await UserRepo.create({
values: {
roles: ['admin']
}
});
const userPlugin = app.getPlugin('@nocobase/plugin-users') as UsersPlugin;
adminAgent = app.agent().auth(userPlugin.jwtService.sign({
userId: admin.get('id'),
}), { type: 'bearer' });
});
it('should grant resource by createRepository', async () => {
@ -91,8 +98,7 @@ describe('role resource api', () => {
});
// get collections list
let response = await app
.agent()
let response = await adminAgent
.resource('roles.collections', 'admin')
.list({
filter: {
@ -119,8 +125,7 @@ describe('role resource api', () => {
]);
// set resource actions
response = await app
.agent()
response = await adminAgent
.resource('roles.resources', 'admin')
.create({
values: {
@ -137,8 +142,7 @@ describe('role resource api', () => {
expect(response.statusCode).toEqual(200);
// get collections list
response = await app
.agent()
response = await adminAgent
.resource('roles.collections')
.list({
associatedIndex: role.get('name') as string,
@ -149,8 +153,7 @@ describe('role resource api', () => {
expect(response.body.data[0]['usingConfig']).toEqual('resourceAction');
response = await app
.agent()
response = await adminAgent
.resource('roles.resources')
.list({
associatedIndex: role.get('name') as string,
@ -164,8 +167,7 @@ describe('role resource api', () => {
expect(resourceAction['name']).toEqual('create');
// update resource actions
response = await app
.agent()
response = await adminAgent
.resource('roles.resources')
.update({
associatedIndex: role.get('name') as string,

View File

@ -2,7 +2,6 @@ import Database, { BelongsToManyRepository } from '@nocobase/database';
import PluginACL from '@nocobase/plugin-acl';
import UsersPlugin from '@nocobase/plugin-users';
import { MockServer, mockServer } from '@nocobase/test';
import { userPluginConfig } from './utils';
describe('role', () => {
let api: MockServer;
@ -13,7 +12,7 @@ describe('role', () => {
beforeEach(async () => {
api = mockServer();
await api.cleanDb();
api.plugin(UsersPlugin, userPluginConfig);
api.plugin(UsersPlugin);
api.plugin(PluginACL);
await api.loadAndInstall();
@ -113,7 +112,7 @@ describe('role', () => {
.set({
Authorization: `Bearer ${userToken}`,
});
expect(response.statusCode).toEqual(200);
const userRoles = await userRolesRepo.find();

View File

@ -1,6 +1,6 @@
import { MockServer } from '@nocobase/test';
import { CollectionRepository } from '@nocobase/plugin-collection-manager';
import { Database, Model } from '@nocobase/database';
import UsersPlugin from '@nocobase/plugin-users';
import { prepareApp } from './prepare';
@ -19,32 +19,37 @@ describe('role api', () => {
describe('grant', () => {
let role: Model;
let admin: Model;
let adminAgent;
beforeEach(async () => {
await db.getRepository('roles').create({
values: {
name: 'admin',
title: 'Admin User',
allowConfigure: true,
},
});
role = await db.getRepository('roles').findOne({
filter: {
name: 'admin',
},
});
const UserRepo = db.getCollection('users').repository;
admin = await UserRepo.create({
values: {
roles: ['admin']
}
});
const userPlugin = app.getPlugin('@nocobase/plugin-users') as UsersPlugin;
adminAgent = app.agent().auth(userPlugin.jwtService.sign({
userId: admin.get('id'),
}), { type: 'bearer' });
});
it('should list actions', async () => {
const response = await app.agent().resource('availableActions').list();
const response = await adminAgent.resource('availableActions').list();
expect(response.statusCode).toEqual(200);
});
it('should grant universal role actions', async () => {
// grant role actions
const response = await app
.agent()
const response = await adminAgent
.resource('roles')
.update({
values: {

View File

@ -1,11 +1,15 @@
import { prepareApp } from './prepare';
import { MockServer } from '@nocobase/test';
import { Database } from '@nocobase/database';
import UsersPlugin from '@nocobase/plugin-users';
describe('scope api', () => {
let app: MockServer;
let db: Database;
let admin;
let adminAgent;
afterEach(async () => {
await app.destroy();
});
@ -13,18 +17,22 @@ describe('scope api', () => {
beforeEach(async () => {
app = await prepareApp();
db = app.db;
await db.getRepository('roles').create({
const UserRepo = db.getCollection('users').repository;
admin = await UserRepo.create({
values: {
name: 'admin',
title: 'Admin User',
allowConfigure: true,
},
roles: ['admin']
}
});
const userPlugin = app.getPlugin('@nocobase/plugin-users') as UsersPlugin;
adminAgent = app.agent().auth(userPlugin.jwtService.sign({
userId: admin.get('id'),
}), { type: 'bearer' });
});
it('should create scope of resource', async () => {
const response = await app
.agent()
const response = await adminAgent
.resource('rolesResourcesScopes')
.create({
values: {

View File

@ -0,0 +1,83 @@
import Database from '@nocobase/database';
import UsersPlugin from '@nocobase/plugin-users';
import { MockServer } from '@nocobase/test';
import { setCurrentRole } from '../middlewares/setCurrentRole';
import { prepareApp } from './prepare';
describe('role', () => {
let api: MockServer;
let db: Database;
let usersPlugin: UsersPlugin;
let ctx;
beforeEach(async () => {
api = await prepareApp();
db = api.db;
usersPlugin = api.getPlugin('@nocobase/plugin-users');
ctx = {
db,
state: {
currentRole: '',
}
}
});
afterEach(async () => {
await api.destroy();
});
it('should set role with X-Role when exists', async () => {
ctx.state.currentUser = await db.getRepository('users').findOne({
appends: ['roles'],
});
ctx.get = function(name) {
if (name === 'X-Role') {
return 'admin';
}
};
await setCurrentRole(ctx, () => {});
expect(ctx.state.currentRole).toBe('admin');
});
it('should set role with default', async () => {
ctx.state.currentUser = await db.getRepository('users').findOne({
appends: ['roles'],
});
ctx.get = function (name) {
if (name === 'X-Role') {
return '';
}
};
await setCurrentRole(ctx, () => {});
expect(ctx.state.currentRole).toBe('root');
});
it('should set role with default when x-role does not exist', async () => {
ctx.state.currentUser = await db.getRepository('users').findOne({
appends: ['roles'],
});
ctx.get = function (name) {
if (name === 'X-Role') {
return 'abc';
}
};
await setCurrentRole(ctx, () => {});
expect(ctx.state.currentRole).toBe('root');
});
it('should set role with anonymous', async () => {
ctx.state.currentUser = await db.getRepository('users').findOne({
appends: ['roles'],
});
ctx.get = function (name) {
if (name === 'X-Role') {
return 'anonymous';
}
};
await setCurrentRole(ctx, () => {});
expect(ctx.state.currentRole).toBe('anonymous');
});
});

View File

@ -0,0 +1,45 @@
import { Context, Next } from '@nocobase/actions';
export async function setDefaultRole(ctx: Context, next: Next) {
const {
values: { roleName },
} = ctx.action.params;
const {
db,
state: { currentUser },
action: { params: { values } }
} = ctx;
if (values.roleName == 'anonymous') {
return next();
}
const repository = db.getRepository('rolesUsers');
await db.sequelize.transaction(async transaction => {
await repository.update({
filter: {
userId: currentUser.get('id'),
},
values: {
default: false,
},
transaction,
});
await repository.update({
filter: {
userId: currentUser.get('id'),
roleName,
},
values: {
default: true,
},
transaction,
});
});
ctx.body = 'ok';
await next();
}

View File

@ -0,0 +1,30 @@
import { extend } from '@nocobase/database';
export default extend({
name: 'users',
fields: [
{
interface: 'm2m',
type: 'belongsToMany',
name: 'roles',
target: 'roles',
foreignKey: 'userId',
otherKey: 'roleName',
sourceKey: 'id',
targetKey: 'name',
through: 'rolesUsers',
uiSchema: {
type: 'array',
title: '{{t("Roles")}}',
'x-component': 'RecordPicker',
'x-component-props': {
multiple: true,
fieldNames: {
label: 'title',
value: 'name',
},
},
},
}
],
});

View File

@ -0,0 +1,35 @@
export async function setCurrentRole(ctx, next) {
if (!ctx.state.currentUser) {
return next();
}
let currentRole = ctx.get('X-Role');
if (currentRole === 'anonymous') {
ctx.state.currentRole = currentRole;
return next();
}
const RolesUsers = ctx.db.getCollection('rolesUsers').model;
const userRoles = await RolesUsers.findAll({
where: {
userId: ctx.state.currentUser.id
}
});
if (userRoles.length == 1) {
currentRole = userRoles[0].roleName;
} else if (userRoles.length > 1) {
const role = userRoles.find((item) => item.roleName === currentRole);
if (!role) {
const defaultRole = userRoles.find((item) => item.default);
currentRole = (defaultRole || userRoles[0])?.roleName;
}
}
if (currentRole) {
ctx.state.currentRole = currentRole;
}
await next();
}

View File

@ -1,10 +1,13 @@
import { Context } from '@nocobase/actions';
import { Collection } from '@nocobase/database';
import UsersPlugin from '@nocobase/plugin-users';
import { Plugin } from '@nocobase/server';
import { resolve } from 'path';
import { availableActionResource } from './actions/available-actions';
import { checkAction } from './actions/role-check';
import { roleCollectionsResource } from './actions/role-collections';
import { setDefaultRole } from './actions/user-setDefaultRole';
import { setCurrentRole } from './middlewares/setCurrentRole';
import { RoleModel } from './model/RoleModel';
import { RoleResourceActionModel } from './model/RoleResourceActionModel';
import { RoleResourceModel } from './model/RoleResourceModel';
@ -134,6 +137,22 @@ export class PluginACL extends Plugin {
this.app.resourcer.registerActionHandler('roles:check', checkAction);
this.app.resourcer.registerActionHandler(`users:setDefaultRole`, setDefaultRole);
this.db.on('users.afterCreateWithAssociations', async (model, options) => {
const { transaction } = options;
const repository = this.app.db.getRepository('roles');
const defaultRole = await repository.findOne({
filter: {
default: true,
},
transaction,
});
if (defaultRole && (await model.countRoles({ transaction })) == 0) {
await model.addRoles(defaultRole, { transaction });
}
});
this.app.db.on('roles.afterSaveWithAssociations', async (model, options) => {
const { transaction } = options;
@ -271,7 +290,7 @@ export class PluginACL extends Plugin {
title: '{{t("Admin")}}',
allowConfigure: true,
allowNewMenu: true,
strategy: { actions: ['create', 'export', 'view', 'update', 'destroy'] },
strategy: { actions: ['create', 'view', 'update', 'destroy'] },
},
{
name: 'member',
@ -301,6 +320,11 @@ export class PluginACL extends Plugin {
});
});
const usersPlugin = this.app.pm.get('@nocobase/plugin-users') as UsersPlugin;
usersPlugin.tokenMiddleware.use(setCurrentRole);
this.app.acl.allow('users', 'setDefaultRole', 'loggedIn');
this.app.acl.allow('roles', 'check', 'loggedIn');
this.app.acl.allow('roles', ['create', 'update', 'destroy'], 'allowConfigure');
@ -392,6 +416,24 @@ export class PluginACL extends Plugin {
if (repo) {
await repo.db2cm('roles');
}
const User = this.db.getCollection('users');
await User.repository.update({
values: {
roles: ['root', 'admin', 'member']
}
});
const RolesUsers = this.db.getCollection('rolesUsers');
await RolesUsers.repository.update({
filter: {
userId: 1,
roleName: 'root'
},
values: {
default: true
}
});
}
async load() {

View File

@ -1,4 +1,5 @@
import { BelongsToManyRepository, Database } from '@nocobase/database';
import PluginUsers from '@nocobase/plugin-users';
import PluginACL from '@nocobase/plugin-acl';
import PluginCollectionManager from '@nocobase/plugin-collection-manager';
import UiSchemaStoragePlugin, { UiSchemaRepository } from '@nocobase/plugin-ui-schema-storage';
@ -24,6 +25,7 @@ describe('server hooks', () => {
app.plugin(UiSchemaStoragePlugin);
app.plugin(PluginCollectionManager);
app.plugin(PluginUsers);
app.plugin(PluginACL);
await app.loadAndInstall();

View File

@ -1,104 +0,0 @@
import Database from '@nocobase/database';
import PluginACL from '@nocobase/plugin-acl';
import UsersPlugin from '@nocobase/plugin-users';
import { MockServer, mockServer } from '@nocobase/test';
import { setCurrentRole } from '../middlewares/parseToken';
import { userPluginConfig } from './utils';
describe('role', () => {
let api: MockServer;
let db: Database;
let usersPlugin: UsersPlugin;
beforeEach(async () => {
api = mockServer();
await api.cleanDb();
api.plugin(UsersPlugin, userPluginConfig);
api.plugin(PluginACL);
await api.loadAndInstall();
db = api.db;
usersPlugin = api.getPlugin('@nocobase/plugin-users');
});
afterEach(async () => {
await api.destroy();
});
it('should set role with X-Role when exists', async () => {
const currentUser = await db.getRepository('users').findOne({
appends: ['roles'],
});
const ctx = {
get(name) {
if (name === 'X-Role') {
return 'admin';
}
},
state: {
currentUser,
currentRole: '',
}
}
setCurrentRole(ctx);
expect(ctx.state.currentRole).toBe('admin');
});
it('should set role with default', async () => {
const currentUser = await db.getRepository('users').findOne({
appends: ['roles'],
});
const ctx = {
get(name) {
if (name === 'X-Role') {
return '';
}
},
state: {
currentUser,
currentRole: '',
}
}
setCurrentRole(ctx);
expect(ctx.state.currentRole).toBe('root');
});
it('should set role with default when x-role does not exist', async () => {
const currentUser = await db.getRepository('users').findOne({
appends: ['roles'],
});
const ctx = {
get(name) {
if (name === 'X-Role') {
return 'abc';
}
},
state: {
currentUser,
currentRole: '',
}
}
setCurrentRole(ctx);
expect(ctx.state.currentRole).toBe('root');
});
it('should set role with anonymous', async () => {
const currentUser = await db.getRepository('users').findOne({
appends: ['roles'],
});
const ctx = {
get(name) {
if (name === 'X-Role') {
return 'anonymous';
}
},
state: {
currentUser,
currentRole: '',
}
}
setCurrentRole(ctx);
expect(ctx.state.currentRole).toBe('anonymous');
});
});

View File

@ -150,15 +150,3 @@ export async function changePassword(ctx: Context, next: Next) {
ctx.body = ctx.state.currentUser.toJSON();
await next();
}
export async function setDefaultRole(ctx: Context, next: Next) {
const {
values: { roleName },
} = ctx.action.params;
await ctx.state.currentUser.setDefaultRole(roleName);
ctx.body = 'ok';
await next();
}

View File

@ -51,29 +51,6 @@ export default {
'x-component': 'Password',
},
},
{
interface: 'm2m',
type: 'belongsToMany',
name: 'roles',
target: 'roles',
foreignKey: 'userId',
otherKey: 'roleName',
sourceKey: 'id',
targetKey: 'name',
through: 'rolesUsers',
uiSchema: {
type: 'array',
title: '{{t("Roles")}}',
'x-component': 'RecordPicker',
'x-component-props': {
multiple: true,
fieldNames: {
label: 'title',
value: 'name',
},
},
},
},
{
type: 'string',
name: 'appLang',

View File

@ -1,40 +1,17 @@
import { Context, Next } from '@nocobase/actions';
import { MiddlewareManager } from '@nocobase/resourcer';
import UsersPlugin from '../server';
export function parseToken(options?: { plugin: UsersPlugin }) {
return async function parseToken(ctx: Context, next: Next) {
const middleware = new MiddlewareManager();
middleware.use(async function (ctx: Context, next: Next) {
const user = await findUserByToken(ctx, options.plugin);
if (user) {
ctx.state.currentUser = user;
setCurrentRole(ctx);
}
return next();
};
}
export function setCurrentRole(ctx) {
let currentRole = ctx.get('X-Role');
if (currentRole === 'anonymous') {
ctx.state.currentRole = currentRole;
return;
}
const userRoles = ctx.state.currentUser.roles;
if (userRoles.length == 1) {
currentRole = userRoles[0].name;
} else if (userRoles.length > 1) {
const role = userRoles.find((role) => role.name === currentRole);
if (!role) {
const defaultRole = userRoles.find((role) => role?.rolesUsers?.default);
currentRole = (defaultRole || userRoles[0])?.name;
}
}
if (currentRole) {
ctx.state.currentRole = currentRole;
}
});
return middleware;
}
async function findUserByToken(ctx: Context, plugin: UsersPlugin) {
@ -46,7 +23,7 @@ async function findUserByToken(ctx: Context, plugin: UsersPlugin) {
try {
const { userId } = await plugin.jwtService.decode(token);
const collection = ctx.db.getCollection('users');
const appends = ['roles'];
const appends = [];
for (const [, field] of collection.fields) {
if (field.type === 'belongsTo') {
appends.push(field.name);

View File

@ -1,44 +0,0 @@
import Database, { Model, Transactionable } from '@nocobase/database';
export class UserModel extends Model {
async setDefaultRole(roleName: string, options: Transactionable = {}) {
if (roleName == 'anonymous') {
return false;
}
const db = (this.constructor as any).database as Database;
const repository = db.getRepository('rolesUsers');
if (!repository) {
return false;
}
const transaction = options.transaction || (await db.sequelize.transaction());
try {
await repository.update({
filter: {
userId: this.get('id'),
},
values: {
default: false,
},
transaction,
});
await repository.update({
filter: {
userId: this.get('id'),
roleName,
},
values: {
default: true,
},
transaction,
});
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
return true;
}
}

View File

@ -7,7 +7,6 @@ import * as actions from './actions/users';
import { JwtOptions, JwtService } from './jwt-service';
import { enUS, zhCN } from './locale';
import * as middlewares from './middlewares';
import { UserModel } from './models/UserModel';
export interface UserPluginConfig {
jwt: JwtOptions;
@ -16,9 +15,12 @@ export interface UserPluginConfig {
export default class UsersPlugin extends Plugin<UserPluginConfig> {
public jwtService: JwtService;
public tokenMiddleware;
constructor(app, options) {
super(app, options);
this.jwtService = new JwtService(options?.jwt || {});
this.tokenMiddleware = middlewares.parseToken({ plugin: this });
}
async beforeLoad() {
@ -43,23 +45,6 @@ export default class UsersPlugin extends Plugin<UserPluginConfig> {
};
},
});
this.db.registerModels({ UserModel });
this.db.on('users.afterCreateWithAssociations', async (model, options) => {
const { transaction } = options;
const repository = this.app.db.getRepository('roles');
if (!repository) {
return;
}
const defaultRole = await repository.findOne({
filter: {
default: true,
},
transaction,
});
if (defaultRole && (await model.countRoles({ transaction })) == 0) {
await model.addRoles(defaultRole, { transaction });
}
});
this.db.on('afterDefineCollection', (collection: Collection) => {
let { createdBy, updatedBy } = collection.options;
@ -100,10 +85,10 @@ export default class UsersPlugin extends Plugin<UserPluginConfig> {
this.app.resourcer.registerActionHandler(`users:${key}`, action);
}
this.app.resourcer.use(middlewares.parseToken({ plugin: this }));
this.app.resourcer.use(this.tokenMiddleware.compose());
const publicActions = ['check', 'signin', 'signup', 'lostpassword', 'resetpassword', 'getUserByResetToken'];
const loggedInActions = ['signout', 'updateProfile', 'changePassword', 'setDefaultRole'];
const loggedInActions = ['signout', 'updateProfile', 'changePassword'];
publicActions.forEach((action) => this.app.acl.allow('users', action));
loggedInActions.forEach((action) => this.app.acl.allow('users', action, 'loggedIn'));
@ -132,17 +117,14 @@ export default class UsersPlugin extends Plugin<UserPluginConfig> {
async install(options) {
const { rootNickname, rootPassword, rootEmail } = this.getInstallingData(options);
const User = this.db.getCollection('users');
const user = await User.repository.create<UserModel>({
const user = await User.repository.create({
values: {
email: rootEmail,
password: rootPassword,
nickname: rootNickname,
roles: ['root', 'admin', 'member'],
nickname: rootNickname
},
});
await user.setDefaultRole('root');
const repo = this.db.getRepository<any>('collections');
if (repo) {
await repo.db2cm('users');