diff --git a/packages/app/src/api/index.ts b/packages/app/src/api/index.ts index da74889c3..b3298d5be 100644 --- a/packages/app/src/api/index.ts +++ b/packages/app/src/api/index.ts @@ -1,9 +1,10 @@ import Server from '@nocobase/server'; +import { registerActions } from '@nocobase/actions'; import dotenv from 'dotenv'; import path from 'path'; const start = Date.now(); -console.log('startAt', new Date().toUTCString()); +console.log('starting... ', new Date().toUTCString()); dotenv.config({ path: path.resolve(__dirname, '../../../../.env'), @@ -39,11 +40,17 @@ const api = new Server({ resourcer: { prefix: '/api', }, + dataWrapping: true, }); -console.log(`@nocobase/preset-nocobase/${__filename.endsWith('.ts') ? 'src' : 'lib'}/index`); +registerActions(api); -api.registerPlugin('@nocobase/preset-nocobase', require(`@nocobase/preset-nocobase/${__filename.endsWith('.ts') ? 'src' : 'lib'}/index`).default); +const file = `${__filename.endsWith('.ts') ? 'src' : 'lib'}/index`; + +api.registerPlugin( + '@nocobase/preset-nocobase', + require(`@nocobase/preset-nocobase/${file}`).default, +); if (process.argv.length < 3) { process.argv.push('start', '--port', '2000'); diff --git a/packages/database/src/database.ts b/packages/database/src/database.ts index 9dc01f391..eee4f26d9 100644 --- a/packages/database/src/database.ts +++ b/packages/database/src/database.ts @@ -461,36 +461,10 @@ type HookType = * 关闭数据库连接 */ public async close() { + this.removeAllListeners(); return this.sequelize.close(); } - /** - * 添加 hook - * - * @param hookType - * @param fn - */ - public addHook(hookType: HookType | string, fn: Function) { - const hooks = this.hooks[hookType] || []; - hooks.push(fn); - this.hooks[hookType] = hooks; - } - - /** - * 运行 hook - * - * @param hookType - * @param args - */ - public async runHooks(hookType: HookType | string, ...args) { - const hooks = this.hooks[hookType] || []; - for (const hook of hooks) { - if (typeof hook === 'function') { - await hook(...args); - } - } - } - public getFieldByPath(fieldPath: string) { const [tableName, fieldName] = fieldPath.split('.'); return this.getTable(tableName).getField(fieldName); diff --git a/packages/database/src/fields/option-types.ts b/packages/database/src/fields/option-types.ts index 69519a843..2db7e558d 100644 --- a/packages/database/src/fields/option-types.ts +++ b/packages/database/src/fields/option-types.ts @@ -221,7 +221,8 @@ export type ColumnOptions = AbstractFieldOptions | JsonOptions | VirtualOptions | FormulaOptions - | ReferenceOptions; + | ReferenceOptions + | SortOptions; export type ElementOptions = BooleanOptions | IntegerOptions @@ -236,7 +237,8 @@ export type ElementOptions = BooleanOptions | DateOnlyOptions | ArrayOptions | JsonOptions - | VirtualOptions; + | VirtualOptions + | SortOptions; export type RelationOptions = HasOneOptions | HasManyOptions | BelongsToOptions | BelongsToManyOptions; diff --git a/packages/database/src/model.ts b/packages/database/src/model.ts index 0e194a6de..0caffbe97 100644 --- a/packages/database/src/model.ts +++ b/packages/database/src/model.ts @@ -530,7 +530,7 @@ export abstract class Model extends SequelizeModel { }); } - await this.database.runHooks('afterUpdateAssociations', this, { + await this.database.emitAsync('afterUpdateAssociations', this, { ...options, transaction, }); diff --git a/packages/database/src/table.ts b/packages/database/src/table.ts index e586f5fc3..52e24b4b8 100644 --- a/packages/database/src/table.ts +++ b/packages/database/src/table.ts @@ -139,7 +139,7 @@ export class Table { constructor(options: TableOptions, context: TabelContext) { const { database } = context; - database.runHooks('beforeTableInit', options); + database.emit('beforeTableInit', options); const { model, fields = [], @@ -157,7 +157,7 @@ export class Table { // this.modelInit('modelOnly'); this.setFields(fields); this.initSortable(); - database.runHooks('afterTableInit', this); + database.emit('afterTableInit', this); } public initSortable() { @@ -312,7 +312,7 @@ export class Table { * @param reinitialize */ public addField(options: FieldOptions, reinitialize: Reinitialize = true) { - this.database.runHooks('beforeAddField', options, this); + this.database.emit('beforeAddField', options, this); const { name, index } = options; const field = buildField(options, { sourceTable: this, @@ -348,7 +348,7 @@ export class Table { this.modelAttributes[name] = field.getAttributeOptions(); } this.modelInit(reinitialize); - this.database.runHooks('afterAddField', field, this); + this.database.emit('afterAddField', field, this); return field; } diff --git a/packages/plugin-action-logs/package.json b/packages/plugin-action-logs/package.json index dadc8187c..8ca5234bf 100644 --- a/packages/plugin-action-logs/package.json +++ b/packages/plugin-action-logs/package.json @@ -9,7 +9,7 @@ }, "devDependencies": { "@nocobase/actions": "^0.4.0-alpha.7", - "@nocobase/server": "^0.4.0-alpha.7" + "@nocobase/test": "^0.4.0-alpha.7" }, "gitHead": "f0b335ac30f29f25c95d7d137655fa64d8d67f1e" } diff --git a/packages/plugin-action-logs/src/__tests__/hook.test.ts b/packages/plugin-action-logs/src/__tests__/hook.test.ts index 06a8121f7..337ee74c1 100644 --- a/packages/plugin-action-logs/src/__tests__/hook.test.ts +++ b/packages/plugin-action-logs/src/__tests__/hook.test.ts @@ -1,15 +1,22 @@ import Database from '@nocobase/database'; -import Application from '@nocobase/server'; -import { getApp, getAPI, getAgent } from '.'; +import { registerActions } from '@nocobase/actions'; +import { mockServer, MockServer } from '@nocobase/test'; +import logPlugin from '../server'; describe('hook', () => { - let app: Application; + let api: MockServer; let db: Database; - let api; beforeEach(async () => { - app = await getApp(); - db = app.database; + api = mockServer(); + api.registerPlugin({ + collections: require('@nocobase/plugin-collections/src/server').default, + users: require('@nocobase/plugin-users/src/server').default, + logs: logPlugin, + }); + registerActions(api); + await api.loadPlugins(); + db = api.database; db.table({ name: 'posts', logging: true, @@ -28,14 +35,11 @@ describe('hook', () => { await db.sync(); const User = db.getModel('users'); const user = await User.create({ nickname: 'a', token: 'token1' }); - console.log('beforeEach', user); - const userAgent = getAgent(app); - userAgent.set('Authorization', `Bearer ${user.token}`); - api = getAPI(userAgent); + api.agent().set('Authorization', `Bearer ${user.token}`); }); afterEach(async () => { - await db.close(); + await api.destroy(); }); it('database', async () => { diff --git a/packages/plugin-action-logs/src/__tests__/index.ts b/packages/plugin-action-logs/src/__tests__/index.ts deleted file mode 100644 index 52699b0e3..000000000 --- a/packages/plugin-action-logs/src/__tests__/index.ts +++ /dev/null @@ -1,122 +0,0 @@ -import path from 'path'; -import qs from 'qs'; -import supertest from 'supertest'; -import bodyParser from 'koa-bodyparser'; -import { Dialect } from 'sequelize'; -import Database from '@nocobase/database'; -import { actions, middlewares } from '@nocobase/actions'; -import { Application } from '@nocobase/server'; -import middleware from '@nocobase/server/src/middleware'; -import plugin from '../server'; - -function getTestKey() { - const { id } = require.main; - const key = id - .replace(`${process.env.PWD}/packages`, '') - .replace(/src\/__tests__/g, '') - .replace('.test.ts', '') - .replace(/[^\w]/g, '_') - .replace(/_+/g, '_'); - return key -} - -const config = { - username: process.env.DB_USER, - password: process.env.DB_PASSWORD, - database: process.env.DB_DATABASE, - host: process.env.DB_HOST, - port: Number.parseInt(process.env.DB_PORT, 10), - dialect: process.env.DB_DIALECT as Dialect, - logging: process.env.DB_LOG_SQL === 'on', - sync: { - force: true, - alter: { - drop: true, - }, - }, - hooks: { - beforeDefine(columns, model) { - model.tableName = `${getTestKey()}_${model.tableName || model.name.plural}`; - } - }, -}; - -export function getDatabase() { - return new Database(config); -}; - -export async function getApp(): Promise { - const app = new Application({ - database: config, - resourcer: { - prefix: '/api', - }, - }); - app.registerPlugin({ - collections: path.resolve(__dirname, '../../../plugin-collections'), - users: path.resolve(__dirname, '../../../plugin-users'), - logs: plugin - }); - await app.loadPlugins(); - await app.database.sync(); - return app; -} - -interface ActionParams { - resourceKey?: string | number; - // resourceName?: string; - // associatedName?: string; - associatedKey?: string | number; - fields?: any; - filter?: any; - values?: any; - [key: string]: any; -} - -interface Handler { - get: (params?: ActionParams) => Promise; - list: (params?: ActionParams) => Promise; - create: (params?: ActionParams) => Promise; - update: (params?: ActionParams) => Promise; - destroy: (params?: ActionParams) => Promise; - [name: string]: (params?: ActionParams) => Promise; -} - -export interface Agent { - resource: (name: string) => Handler; -} - -export function getAgent(app: Application) { - return supertest.agent(app.callback()); -} - -export function getAPI(agent) { - return { - resource(name: string): any { - return new Proxy({}, { - get(target, method: string, receiver) { - return (params: ActionParams = {}) => { - const { associatedKey, resourceKey, values = {}, filePath, ...restParams } = params; - let url = `/api/${name}`; - if (associatedKey) { - url = `/api/${name.split('.').join(`/${associatedKey}/`)}`; - } - url += `:${method as string}`; - if (resourceKey) { - url += `/${resourceKey}`; - } - - switch (method) { - case 'list': - case 'get': - return agent.get(`${url}?${qs.stringify(restParams)}`); - - default: - return agent.post(`${url}?${qs.stringify(restParams)}`).send(values); - } - } - } - }); - } - }; -} diff --git a/packages/plugin-action-logs/src/__tests__/tables/comments.ts b/packages/plugin-action-logs/src/__tests__/tables/comments.ts deleted file mode 100644 index 6f752ff1b..000000000 --- a/packages/plugin-action-logs/src/__tests__/tables/comments.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { TableOptions } from "@nocobase/database"; - -export default { - name: 'comments', - fields: [ - { - type: 'string', - name: 'content', - }, - { - type: 'belongsTo', - name: 'post', - }, - ] -} as TableOptions; diff --git a/packages/plugin-action-logs/src/__tests__/tables/posts.ts b/packages/plugin-action-logs/src/__tests__/tables/posts.ts deleted file mode 100644 index 85c5f340f..000000000 --- a/packages/plugin-action-logs/src/__tests__/tables/posts.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { TableOptions } from "@nocobase/database"; - -export default { - name: 'posts', - // 目前默认就带了 - // createdBy: true, - fields: [ - { - type: 'string', - name: 'title', - }, - { - type: 'string', - name: 'status', - defaultValue: 'draft', - }, - { - type: 'hasMany', - name: 'comments', - } - ] -} as TableOptions; diff --git a/packages/plugin-action-logs/src/collections/action_changes.ts b/packages/plugin-action-logs/src/collections/action_changes.ts index c8967000d..60b8e5d1b 100644 --- a/packages/plugin-action-logs/src/collections/action_changes.ts +++ b/packages/plugin-action-logs/src/collections/action_changes.ts @@ -12,18 +12,18 @@ export default { type: 'belongsTo', name: 'log', target: 'action_logs', - foreignKey: 'log_id', + foreignKey: 'action_log_id', }, { - type: 'jsonb', + type: 'json', name: 'field', }, { - type: 'jsonb', + type: 'json', name: 'before', }, { - type: 'jsonb', + type: 'json', name: 'after', } ], diff --git a/packages/plugin-action-logs/src/collections/action_logs.ts b/packages/plugin-action-logs/src/collections/action_logs.ts index aecdfe480..bf042b7d9 100644 --- a/packages/plugin-action-logs/src/collections/action_logs.ts +++ b/packages/plugin-action-logs/src/collections/action_logs.ts @@ -18,12 +18,16 @@ export default { target: 'users', }, { - type: 'belongsTo', - name: 'collection', - target: 'collections', - targetKey: 'name', - constraints: false, + type: 'string', + name: 'collection_name', }, + // { + // type: 'belongsTo', + // name: 'collection', + // target: 'collections', + // targetKey: 'name', + // constraints: false, + // }, { type: 'string', name: 'type', @@ -36,7 +40,7 @@ export default { type: 'hasMany', name: 'changes', target: 'action_changes', - foreignKey: 'log_id', + foreignKey: 'action_log_id', } ], } as TableOptions; diff --git a/packages/plugin-action-logs/src/collections/collections.ts b/packages/plugin-action-logs/src/collections/collections.ts deleted file mode 100644 index 25cf0dae9..000000000 --- a/packages/plugin-action-logs/src/collections/collections.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { extend } from '@nocobase/database'; - -// TODO(bug): collections 表创建关联字段有问题 -export default extend({ - name: 'collections', - logging: false -}); diff --git a/packages/plugin-collections/src/actions/fields.ts b/packages/plugin-collections/src/actions/fields.ts index 048b834b7..11d47ca8a 100644 --- a/packages/plugin-collections/src/actions/fields.ts +++ b/packages/plugin-collections/src/actions/fields.ts @@ -1,10 +1,7 @@ -import { Model, ModelCtor } from '@nocobase/database'; -import { actions, middlewares } from '@nocobase/actions'; -import { sort } from '@nocobase/actions/src/actions/common'; -import { cloneDeep, omit } from 'lodash'; +import { actions, Context, Next } from '@nocobase/actions'; -export const create = async (ctx: actions.Context, next: actions.Next) => { - await actions.common.create(ctx, async () => {}); +export const create = async (ctx: Context, next: Next) => { + await actions.create(ctx, async () => {}); const { associated } = ctx.action.params; await ctx.body.generateReverseField(); await associated.migrate(); diff --git a/packages/plugin-collections/src/actions/index.ts b/packages/plugin-collections/src/actions/index.ts index f2b2fc893..631ab8b3b 100644 --- a/packages/plugin-collections/src/actions/index.ts +++ b/packages/plugin-collections/src/actions/index.ts @@ -1,9 +1,6 @@ -import { Model, ModelCtor } from '@nocobase/database'; -import { actions, middlewares } from '@nocobase/actions'; -import { sort } from '@nocobase/actions/src/actions/common'; -import { cloneDeep, omit } from 'lodash'; +import { actions, Context, Next } from '@nocobase/actions'; -export const findAll = async (ctx: actions.Context, next: actions.Next) => { +export const findAll = async (ctx: Context, next: Next) => { const Collection = ctx.db.getModel('collections'); const collections = await Collection.findAll(Collection.parseApiJson({ sort: 'sort', @@ -16,7 +13,7 @@ export const findAll = async (ctx: actions.Context, next: actions.Next) => { await next(); } -export const createOrUpdate = async (ctx: actions.Context, next: actions.Next) => { +export const createOrUpdate = async (ctx: Context, next: Next) => { const { values } = ctx.action.params; const Collection = ctx.db.getModel('collections'); let collection; @@ -55,4 +52,5 @@ export const createOrUpdate = async (ctx: actions.Context, next: actions.Next) = throw error; } ctx.body = collection; + await next(); } diff --git a/packages/plugin-collections/src/server.ts b/packages/plugin-collections/src/server.ts index 005a545d5..df297c604 100644 --- a/packages/plugin-collections/src/server.ts +++ b/packages/plugin-collections/src/server.ts @@ -11,8 +11,8 @@ export default async function (this: Application, options = {}) { database.import({ directory: path.resolve(__dirname, 'collections'), }); - this.on('server.beforeStart', async () => { - console.log('server.beforeStart'); + this.on('plugins.afterLoad', async () => { + console.log('plugins.afterLoad'); await database.getModel('collections').load(); }); const [Collection, Field] = database.getModels(['collections', 'fields']); diff --git a/packages/resourcer/src/resourcer.ts b/packages/resourcer/src/resourcer.ts index 958d06530..936446e3b 100644 --- a/packages/resourcer/src/resourcer.ts +++ b/packages/resourcer/src/resourcer.ts @@ -10,7 +10,6 @@ import _ from 'lodash'; export interface ResourcerContext { resourcer?: Resourcer; action?: Action; - params?: ParsedParams; [key: string]: any; }