diff --git a/packages/app/src/api/migrations/init.ts b/packages/app/src/api/migrations/init.ts index e4ada9195..9e9d4738f 100644 --- a/packages/app/src/api/migrations/init.ts +++ b/packages/app/src/api/migrations/init.ts @@ -142,9 +142,9 @@ const data = [ const [Collection, Page, User] = database.getModels(['collections', 'pages', 'users']); const tables = database.getTables([]); for (let table of tables) { - console.log(table.getName()); + // console.log(table.getName()); if (table.getName() === 'roles') { - console.log('roles', table.getOptions()) + // console.log('roles', table.getOptions()) } await Collection.import(table.getOptions(), { update: true, migrate: false }); } diff --git a/packages/database/src/table.ts b/packages/database/src/table.ts index e12f24941..eea7cd5da 100644 --- a/packages/database/src/table.ts +++ b/packages/database/src/table.ts @@ -205,8 +205,12 @@ export class Table { return this.options.name; } - public getOptions(): TableOptions { - return this.options; + /** + * + * @param key 获取数据表配置,也可以指定 key + */ + public getOptions(key?: any): TableOptions { + return key ? _.get(this.options, key) : this.options; } public getModel(): ModelCtor { diff --git a/packages/plugin-collections/src/models/collection.ts b/packages/plugin-collections/src/models/collection.ts index 37489226f..831c7bc5a 100644 --- a/packages/plugin-collections/src/models/collection.ts +++ b/packages/plugin-collections/src/models/collection.ts @@ -55,10 +55,12 @@ export class CollectionModel extends BaseModel { */ async loadTableOptions(opts: any = {}) { const options = await this.getOptions(); - const prevTable = this.database.getTable(this.get('name')); - const prevOptions = prevTable ? prevTable.getOptions() : {}; + // const prevTable = this.database.getTable(this.get('name')); + // const prevOptions = prevTable ? prevTable.getOptions() : {}; // table 是初始化和重新初始化 - const table = this.database.table({...prevOptions, ...options}); + const table = this.database.extend(options); + // console.log({options, actions: table.getOptions()['actions']}) + // 如果关系表未加载,一起处理 // const associationTableNames = []; // for (const [key, association] of table.getAssociations()) { @@ -120,6 +122,7 @@ export class CollectionModel extends BaseModel { async getOptions(): Promise { return { ...this.get(), + actions: await this.getActions(), fields: await this.getFieldsOptions(), }; } diff --git a/packages/plugin-permissions/src/actions/roles.collections.ts b/packages/plugin-permissions/src/actions/roles.collections.ts index 053535a6b..281d177b7 100644 --- a/packages/plugin-permissions/src/actions/roles.collections.ts +++ b/packages/plugin-permissions/src/actions/roles.collections.ts @@ -37,8 +37,6 @@ export async function get(ctx: actions.Context, next: actions.Next) { limit: 1, }); - console.log(permission); - ctx.body = { ...permissions, description: _.get(permission, 'description'), diff --git a/packages/plugin-permissions/src/collections/actions_scopes.ts b/packages/plugin-permissions/src/collections/actions_scopes.ts index cd1e50ddb..c448b224f 100644 --- a/packages/plugin-permissions/src/collections/actions_scopes.ts +++ b/packages/plugin-permissions/src/collections/actions_scopes.ts @@ -30,6 +30,16 @@ export default { showInForm: true, }, }, + { + interface: 'boolean', + type: 'boolean', + name: 'locked', + title: '锁定', + defaultValue: false, + component: { + showInTable: true, + } + }, { type: 'belongsTo', name: 'collection', diff --git a/packages/plugin-permissions/src/collections/collections.ts b/packages/plugin-permissions/src/collections/collections.ts index b9fbf7984..3b1a2cb08 100644 --- a/packages/plugin-permissions/src/collections/collections.ts +++ b/packages/plugin-permissions/src/collections/collections.ts @@ -14,6 +14,16 @@ export default extend({ list: { sort: 'id', }, + update: { + filter: { + locked: false + } + }, + destroy: { + filter: { + locked: false + } + } }, component: { type: 'drawerSelect', diff --git a/packages/plugin-permissions/src/collections/roles.ts b/packages/plugin-permissions/src/collections/roles.ts index 4af3e615a..c7a2274ce 100644 --- a/packages/plugin-permissions/src/collections/roles.ts +++ b/packages/plugin-permissions/src/collections/roles.ts @@ -84,6 +84,39 @@ export default { name: 'permissions' }, ], + actions: [ + { + type: 'list', + name: 'list', + title: '查看', + }, + // { + // type: 'get', + // name: 'get', + // title: '详情', + // }, + { + type: 'create', + name: 'create', + title: '新增', + viewName: 'form', + }, + { + type: 'update', + name: 'update', + title: '编辑', + viewName: 'form', + }, + { + type: 'destroy', + name: 'destroy', + title: '删除', + filter: { + type: ROLE_TYPE_USER, + default: false + } + }, + ], views: [ { type: 'form', diff --git a/packages/plugin-permissions/src/server.ts b/packages/plugin-permissions/src/server.ts index 86981a32c..87af2fa63 100644 --- a/packages/plugin-permissions/src/server.ts +++ b/packages/plugin-permissions/src/server.ts @@ -35,18 +35,20 @@ export class Permissions { }); database.getModel('collections').addHook('afterCreate', async (model: any, options) => { - console.log('plugin-permissions hook'); + // console.log('plugin-permissions hook'); await model.updateAssociations({ scopes: [ { title: '全部数据', filter: {}, + locked: true }, { title: '用户自己的数据', filter: { "created_by_id.$currentUser": true, }, + locked: true }, ] }, options); diff --git a/packages/server/src/__tests__/middleware.test.ts b/packages/server/src/__tests__/middleware.test.ts index bf91b9a4a..a8a0bc456 100644 --- a/packages/server/src/__tests__/middleware.test.ts +++ b/packages/server/src/__tests__/middleware.test.ts @@ -1,5 +1,5 @@ import Koa from 'koa'; -import request from 'supertest'; +import supertest from 'supertest'; import http from 'http'; import Resourcer from '@nocobase/resourcer'; import Database from '@nocobase/database'; @@ -9,6 +9,7 @@ describe('middleware', () => { let app: Koa; let resourcer: Resourcer; let database: Database; + let agent; beforeAll(() => { app = new Koa(); @@ -39,6 +40,7 @@ describe('middleware', () => { collate: 'utf8mb4_unicode_ci', }, }); + agent = supertest.agent(app.callback()); app.use(middleware({ prefix: '/api', database, @@ -49,7 +51,7 @@ describe('middleware', () => { database.table({ name: 'tests', }); - const response = await request(http.createServer(app.callback())).get('/api/tests'); + const response = await agent.get('/api/tests'); expect(response.body).toEqual([1,2]); }); it('shound work', async () => { @@ -71,9 +73,9 @@ describe('middleware', () => { }, ], }); - let response = await request(http.createServer(app.callback())).get('/api/foos/1/bars'); + let response = await agent.get('/api/foos/1/bars'); expect(response.body).toEqual([1,2]); - response = await request(http.createServer(app.callback())).get('/api/bars/1/foo'); + response = await agent.get('/api/bars/1/foo'); expect(response.body).toEqual([3,4]); }); it('shound work', async () => { @@ -95,9 +97,9 @@ describe('middleware', () => { }, ], }); - let response = await request(http.createServer(app.callback())).get('/api/foo2s/1/bar2s'); + let response = await agent.get('/api/foo2s/1/bar2s'); expect(response.body).toEqual([5,6]); - response = await request(http.createServer(app.callback())).get('/api/bar2s/1/foo2s'); + response = await agent.get('/api/bar2s/1/foo2s'); expect(response.body).toEqual([1,2]); }); }); diff --git a/packages/server/src/middleware.ts b/packages/server/src/middleware.ts index 3bf2f183b..49ae21eac 100644 --- a/packages/server/src/middleware.ts +++ b/packages/server/src/middleware.ts @@ -1,7 +1,6 @@ -import qs from 'qs'; import compose from 'koa-compose'; import { pathToRegexp } from 'path-to-regexp'; -import Resourcer, { getNameByParams, KoaMiddlewareOptions, parseRequest, parseQuery, ResourcerContext } from '@nocobase/resourcer'; +import Resourcer, { getNameByParams, KoaMiddlewareOptions, parseRequest, parseQuery, ResourcerContext, ResourceType } from '@nocobase/resourcer'; import Database, { BELONGSTO, BELONGSTOMANY, HASMANY, HASONE } from '@nocobase/database'; interface MiddlewareOptions extends KoaMiddlewareOptions { @@ -36,22 +35,25 @@ export function middleware(options: MiddlewareOptions = {}) { } try { const resourceName = nameRule(params); + // 如果资源名称未被定义 if (!resourcer.isDefined(resourceName)) { - const names = resourceName.split('.'); - const tableName = names.shift(); + const [tableName, fieldName] = resourceName.split('.'); const Collection = database.getModel('collections'); + // 检查资源对应的表名是否已经定义 if (!database.isDefined(tableName) && Collection) { + // 未定义则尝试通过 collection 表来加载 await Collection.load({ where: { name: tableName, }, }); } + // 如果经过加载后是已经定义的表 if (database.isDefined(tableName)) { const table = database.getTable(tableName); - const field = table.getField(names[0]) as BELONGSTO | HASMANY | BELONGSTOMANY | HASONE; - if (names.length == 0 || field) { - let resourceType = 'single'; + const field = table.getField(fieldName) as BELONGSTO | HASMANY | BELONGSTOMANY | HASONE; + if (!fieldName || field) { + let resourceType: ResourceType = 'single'; let actions = {}; if (field) { if (field instanceof HASONE) { @@ -66,9 +68,14 @@ export function middleware(options: MiddlewareOptions = {}) { if (field.options.actions) { actions = field.options.actions; } + } else { + const items = table.getOptions('actions')||[]; + for (const item of (items as any[])) { + actions[item.name] = item; + } } resourcer.define({ - type: resourceType as any, + type: resourceType, name: resourceName, actions, });