diff --git a/packages/plugin-acl/src/server.ts b/packages/plugin-acl/src/server.ts index ac139015d..a9944f43d 100644 --- a/packages/plugin-acl/src/server.ts +++ b/packages/plugin-acl/src/server.ts @@ -82,17 +82,13 @@ export default class PluginACL extends Plugin { }); } - async load() { - this.app.db.registerModels({ - RoleResourceActionModel, - RoleResourceModel, - }); - + async beforeLoad() { const acl = createACL(); this.acl = acl; - await this.app.db.import({ - directory: path.resolve(__dirname, 'collections'), + this.app.db.registerModels({ + RoleResourceActionModel, + RoleResourceModel, }); this.registerAssociationFieldsActions(); @@ -100,8 +96,6 @@ export default class PluginACL extends Plugin { this.app.resourcer.define(availableActionResource); this.app.resourcer.define(roleCollectionsResource); - this.app.resourcer.use(this.acl.middleware()); - this.app.db.on('roles.afterSave', async (model, options) => { const { transaction } = options; const roleName = model.get('name'); @@ -187,4 +181,12 @@ export default class PluginACL extends Plugin { } }); } + + async load() { + await this.app.db.import({ + directory: path.resolve(__dirname, 'collections'), + }); + + this.app.resourcer.use(this.acl.middleware()); + } } diff --git a/packages/plugin-action-logs/src/server.ts b/packages/plugin-action-logs/src/server.ts index a3a36b4ed..a61c4cd64 100644 --- a/packages/plugin-action-logs/src/server.ts +++ b/packages/plugin-action-logs/src/server.ts @@ -1,16 +1,17 @@ import path from 'path'; -import { Plugin } from '@nocobase/server'; import { afterCreate, afterUpdate, afterDestroy } from './hooks'; +import { Plugin } from '@nocobase/server'; + +export default class PluginActionLogs extends Plugin { + async beforeLoad() { + this.db.on('afterCreate', afterCreate); + this.db.on('afterUpdate', afterUpdate); + this.db.on('afterDestroy', afterDestroy); + } -export default class extends Plugin { - name: 'action-logs'; async load() { - const database = this.app.db; - await database.import({ + await this.db.import({ directory: path.resolve(__dirname, 'collections'), }); - database.on('afterCreate', afterCreate); - database.on('afterUpdate', afterUpdate); - database.on('afterDestroy', afterDestroy); } -}; +} diff --git a/packages/plugin-china-region/src/server.ts b/packages/plugin-china-region/src/server.ts index 71d4d1ebf..7fcef871a 100644 --- a/packages/plugin-china-region/src/server.ts +++ b/packages/plugin-china-region/src/server.ts @@ -51,18 +51,17 @@ async function importData(model) { console.log(`${count} rows of region data imported in ${(Date.now() - timer) / 1000}s`); } -export default { - name: 'china-region', - async load(this: Plugin) { - const db = this.app.db; - - await db.import({ - directory: path.resolve(__dirname, 'collections'), - }); - - this.app.on('db.init', async () => { - const ChinaRegion = db.getCollection('china_regions').model; +export default class PluginChinaRegion extends Plugin { + async beforeLoad() { + this.app.on('installing', async () => { + const ChinaRegion = this.db.getCollection('china_regions').model; await importData(ChinaRegion); }); - }, -}; + } + + async load() { + await this.db.import({ + directory: path.resolve(__dirname, 'collections'), + }); + } +} diff --git a/packages/plugin-collection-manager/src/index.ts b/packages/plugin-collection-manager/src/index.ts index 698b26da4..e815bc463 100644 --- a/packages/plugin-collection-manager/src/index.ts +++ b/packages/plugin-collection-manager/src/index.ts @@ -10,16 +10,12 @@ import { afterCreateForReverseField } from './hooks/afterCreateForReverseField'; export * from './repositories/collection-repository'; export default class CollectionManagerPlugin extends Plugin { - async load() { + async beforeLoad() { this.app.db.registerModels({ CollectionModel, FieldModel, }); - await this.app.db.import({ - directory: path.resolve(__dirname, './collections'), - }); - // 要在 beforeInitOptions 之前处理 this.app.db.on('fields.beforeCreate', beforeCreateForReverseField(this.app.db)); this.app.db.on('fields.beforeCreate', beforeCreateForChildrenCollection(this.app.db)); @@ -47,4 +43,10 @@ export default class CollectionManagerPlugin extends Plugin { } }); } + + async load() { + await this.app.db.import({ + directory: path.resolve(__dirname, './collections'), + }); + } } diff --git a/packages/plugin-file-manager/src/server.ts b/packages/plugin-file-manager/src/server.ts index e8f7df20a..f58ea3130 100644 --- a/packages/plugin-file-manager/src/server.ts +++ b/packages/plugin-file-manager/src/server.ts @@ -1,44 +1,41 @@ import path from 'path'; -import Database from '@nocobase/database'; -import Resourcer from '@nocobase/resourcer'; -import { PluginOptions } from '@nocobase/server'; +import { Plugin } from '@nocobase/server'; import { action as uploadAction, middleware as uploadMiddleware } from './actions/upload'; import { getStorageConfig } from './storages'; import { STORAGE_TYPE_LOCAL } from './constants'; -export default { - name: 'file-manager', - async load() { - const database: Database = this.app.db; - const resourcer: Resourcer = this.app.resourcer; - - await database.import({ - directory: path.resolve(__dirname, 'collections'), - }); - - // 暂时中间件只能通过 use 加进来 - resourcer.use(uploadMiddleware); - resourcer.registerActionHandler('upload', uploadAction); - - const { DEFAULT_STORAGE_TYPE } = process.env; - - if (process.env.NOCOBASE_ENV !== 'production') { - await getStorageConfig(STORAGE_TYPE_LOCAL).middleware(this.app); - } - - this.app.on('db.init', async () => { - const defaultStorageConfig = getStorageConfig(DEFAULT_STORAGE_TYPE); +export default class PluginFileManager extends Plugin { + storageType() { + return process.env.DEFAULT_STORAGE_TYPE; + } + async beforeLoad() { + this.app.on('installing', async () => { + const defaultStorageConfig = getStorageConfig(this.storageType()); if (defaultStorageConfig) { - const Storage = database.getCollection('storages'); + const Storage = this.db.getCollection('storages'); await Storage.repository.create({ values: { ...defaultStorageConfig.defaults(), - type: DEFAULT_STORAGE_TYPE, + type: this.storageType(), default: true, }, }); } }); - }, -} as PluginOptions; + } + + async load() { + await this.db.import({ + directory: path.resolve(__dirname, 'collections'), + }); + + // 暂时中间件只能通过 use 加进来 + this.app.resourcer.use(uploadMiddleware); + this.app.resourcer.registerActionHandler('upload', uploadAction); + + if (process.env.NOCOBASE_ENV !== 'production') { + await getStorageConfig(STORAGE_TYPE_LOCAL).middleware(this.app); + } + } +} diff --git a/packages/plugin-notifications/src/server.ts b/packages/plugin-notifications/src/server.ts index 76b1c1327..faf4665f2 100644 --- a/packages/plugin-notifications/src/server.ts +++ b/packages/plugin-notifications/src/server.ts @@ -1,11 +1,10 @@ import path from 'path'; -import { PluginOptions } from '@nocobase/server'; +import { Plugin } from '@nocobase/server'; -export default { - name: 'notifications', +export default class PluginNotifications extends Plugin { async load() { await this.app.db.import({ directory: path.resolve(__dirname, 'collections'), }); } -} as PluginOptions +} diff --git a/packages/plugin-system-settings/src/server.ts b/packages/plugin-system-settings/src/server.ts index 207e9f02f..67bef9f75 100644 --- a/packages/plugin-system-settings/src/server.ts +++ b/packages/plugin-system-settings/src/server.ts @@ -1,19 +1,10 @@ import path from 'path'; -import { PluginOptions } from '@nocobase/server'; +import { Plugin, PluginOptions } from '@nocobase/server'; -export default { - name: 'system-settings', - async load() { - const database = this.app.db; - - await database.import({ - directory: path.resolve(__dirname, 'collections'), - }); - - const SystemSetting = database.getCollection('system_settings'); - - this.app.on('db.init', async () => { - await SystemSetting.repository.create({ +export default class PluginSystemSettings extends Plugin { + async beforeLoad() { + this.app.on('installing', async () => { + await this.db.getRepository('system_settings').create({ values: { title: 'NocoBase', logo: { @@ -26,5 +17,11 @@ export default { }, }); }); - }, -} as PluginOptions; + } + + async load() { + await this.app.db.import({ + directory: path.resolve(__dirname, 'collections'), + }); + } +} diff --git a/packages/plugin-ui-schema-storage/src/__tests__/ui-schema-model.test.ts b/packages/plugin-ui-schema-storage/src/__tests__/ui-schema-model.test.ts index abd046a0e..dcade8141 100644 --- a/packages/plugin-ui-schema-storage/src/__tests__/ui-schema-model.test.ts +++ b/packages/plugin-ui-schema-storage/src/__tests__/ui-schema-model.test.ts @@ -1,6 +1,6 @@ import { mockServer, MockServer } from '@nocobase/test'; import { Collection, Database } from '@nocobase/database'; -import PluginUiSchema, { UiSchemaRepository } from '@nocobase/plugin-ui-schema'; +import PluginUiSchema, { UiSchemaRepository } from '..'; describe('ui schema model', () => { let app: MockServer; diff --git a/packages/plugin-ui-schema-storage/src/__tests__/ui-schema.test.ts b/packages/plugin-ui-schema-storage/src/__tests__/ui-schema.test.ts index e3be671a0..10decd3c6 100644 --- a/packages/plugin-ui-schema-storage/src/__tests__/ui-schema.test.ts +++ b/packages/plugin-ui-schema-storage/src/__tests__/ui-schema.test.ts @@ -1,7 +1,7 @@ import { ISchema } from '@formily/json-schema'; import { mockServer, MockServer } from '@nocobase/test'; import { Collection, Database } from '@nocobase/database'; -import PluginUiSchema, { UiSchemaRepository } from '@nocobase/plugin-ui-schema'; +import PluginUiSchema, { UiSchemaRepository } from '..'; describe('ui-schema', () => { let app: MockServer; diff --git a/packages/plugin-ui-schema-storage/src/server.ts b/packages/plugin-ui-schema-storage/src/server.ts index 729ebfdc2..306d5566b 100644 --- a/packages/plugin-ui-schema-storage/src/server.ts +++ b/packages/plugin-ui-schema-storage/src/server.ts @@ -11,17 +11,13 @@ export default class PluginUiSchema extends Plugin { }); } - async load() { + async beforeLoad() { const db = this.app.db; this.app.db.registerModels({ MagicAttributeModel }); this.registerRepository(); - await db.import({ - directory: path.resolve(__dirname, 'collections'), - }); - db.on('ui_schemas.beforeCreate', (model) => { model.set('uid', model.get('x-uid')); }); @@ -44,23 +40,15 @@ export default class PluginUiSchema extends Plugin { }); }); - await db.getCollection('ui_schemas').sync({ - force: false, - alter: { - drop: false, - }, - }); - - await db.getCollection('ui_schema_tree_path').sync({ - force: false, - alter: { - drop: false, - }, - }); - this.app.resourcer.define({ name: 'ui_schemas', actions: uiSchemaActions, }); } + + async load() { + await this.db.import({ + directory: path.resolve(__dirname, 'collections'), + }); + } } diff --git a/packages/plugin-users/src/__tests__/role.test.ts b/packages/plugin-users/src/__tests__/role.test.ts index 0794ac16c..70308d8ae 100644 --- a/packages/plugin-users/src/__tests__/role.test.ts +++ b/packages/plugin-users/src/__tests__/role.test.ts @@ -11,7 +11,7 @@ describe('role', () => { await api.cleanDb(); api.plugin(require('../server').default); api.plugin(PluginACL); - await api.loadAndSync(); + await api.loadAndInstall(); db = api.db; }); diff --git a/packages/plugin-users/src/server.ts b/packages/plugin-users/src/server.ts index 2122214df..2defbf130 100644 --- a/packages/plugin-users/src/server.ts +++ b/packages/plugin-users/src/server.ts @@ -2,16 +2,12 @@ import path from 'path'; import * as actions from './actions/users'; import * as middlewares from './middlewares'; import { Collection } from '@nocobase/database'; -import { PluginOptions } from '@nocobase/server'; +import { Plugin, PluginOptions } from '@nocobase/server'; -export default { - name: 'users', - async load() { - const database = this.app.db; - const resourcer = this.app.resourcer; - - this.app.on('db.init', async () => { - const User = database.getCollection('users'); +export default class PluginUsers extends Plugin { + async beforeLoad() { + this.app.on('installing', async () => { + const User = this.db.getCollection('users'); await User.model.create({ nickname: 'Super Admin', email: process.env.ADMIN_EMAIL || 'admin@nocobase.com', @@ -19,7 +15,7 @@ export default { }); }); - database.on('users.afterCreateWithAssociations', async (model, options) => { + this.db.on('users.afterCreateWithAssociations', async (model, options) => { const { transaction } = options; const defaultRole = await this.app.db.getRepository('roles').findOne({ @@ -34,7 +30,7 @@ export default { } }); - database.on('afterDefineCollection', (collection: Collection) => { + this.db.on('afterDefineCollection', (collection: Collection) => { let { createdBy, updatedBy } = collection.options; if (createdBy === true) { collection.setField('createdById', { @@ -65,14 +61,16 @@ export default { } }); - await database.import({ - directory: path.resolve(__dirname, 'collections'), - }); - for (const [key, action] of Object.entries(actions)) { - resourcer.registerActionHandler(`users:${key}`, action); + this.app.resourcer.registerActionHandler(`users:${key}`, action); } - resourcer.use(middlewares.parseToken({})); - }, -} as PluginOptions; + this.app.resourcer.use(middlewares.parseToken({})); + } + + async load() { + await this.db.import({ + directory: path.resolve(__dirname, 'collections'), + }); + } +} diff --git a/packages/server/src/__tests__/application.test.ts b/packages/server/src/__tests__/application.test.ts index ff8656675..8a03b6c73 100644 --- a/packages/server/src/__tests__/application.test.ts +++ b/packages/server/src/__tests__/application.test.ts @@ -3,7 +3,7 @@ import { Application } from '../application'; import { Plugin } from '../plugin'; class MyPlugin extends Plugin { - load() {} + async load() {} } describe('application', () => { diff --git a/packages/server/src/application.ts b/packages/server/src/application.ts index d8ccdfa3b..24c4c49f3 100644 --- a/packages/server/src/application.ts +++ b/packages/server/src/application.ts @@ -65,10 +65,12 @@ interface ListenOptions { } interface StartOptions { + cliArgs?: any[]; listen?: ListenOptions; } interface InstallOptions { + cliArgs?: any[]; clean?: CleanOptions | boolean; sync?: SyncOptions; } @@ -174,8 +176,8 @@ export class Application exten await this.emitAsync('afterStart', this, options); } - async stop() { - await this.emitAsync('beforeStop', this); + async stop(options?: any) { + await this.emitAsync('beforeStop', this, options); // close database connection await this.db.close(); @@ -188,7 +190,6 @@ export class Application exten if (err) { return reject(err); } - this.listenServer = null; resolve(true); }); @@ -197,13 +198,13 @@ export class Application exten await closeServer(); } - await this.emitAsync('afterStop', this); + await this.emitAsync('afterStop', this, options); } - async destroy() { - await this.emitAsync('beforeDestroy', this); - await this.stop(); - await this.emitAsync('afterDestroy', this); + async destroy(options?: any) { + await this.emitAsync('beforeDestroy', this, options); + await this.stop(options); + await this.emitAsync('afterDestroy', this, options); } async install(options?: InstallOptions) { @@ -211,7 +212,9 @@ export class Application exten await this.db.clean(isBoolean(options.clean) ? { drop: options.clean } : options.clean); } await this.db.sync(options?.sync); + await this.emitAsync('beforeInstall', this, options); + await this.emitAsync('installing', this, options); await this.emitAsync('afterInstall', this, options); } diff --git a/packages/server/src/helper.ts b/packages/server/src/helper.ts index 2aa4acf12..75f5fb703 100644 --- a/packages/server/src/helper.ts +++ b/packages/server/src/helper.ts @@ -1,13 +1,13 @@ -import { DefaultContext, DefaultState } from 'koa'; -import bodyParser from 'koa-bodyparser'; import cors from '@koa/cors'; import Database from '@nocobase/database'; import Resourcer from '@nocobase/resourcer'; import { Command } from 'commander'; +import i18next from 'i18next'; +import { DefaultContext, DefaultState } from 'koa'; +import bodyParser from 'koa-bodyparser'; import Application, { ApplicationOptions } from './application'; import { dataWrapping } from './middlewares/data-wrapping'; import { table2resource } from './middlewares/table2resource'; -import i18next from 'i18next'; export function createDatabase(options: ApplicationOptions) { if (options.database instanceof Database) { @@ -37,12 +37,11 @@ export function createCli(app: Application, options: ApplicationOptions) { cli .command('db:sync') .option('-f, --force') - .action(async (...args) => { + .action(async (...cliArgs) => { + const [opts] = cliArgs; console.log('db sync...'); - const cli = args.pop(); - const force = cli.opts()?.force; await app.db.sync( - force + opts.force ? { force: true, alter: { @@ -51,44 +50,44 @@ export function createCli(app: Application, options: ApplicationOptions) { } : {}, ); - await app.destroy(); + await app.stop({ + cliArgs, + }); }); cli - .command('init') + .command('install') .option('-f, --force') - .action(async (opts, ...args) => { - if (!opts?.force) { - const tables = await app.db.sequelize.getQueryInterface().showAllTables(); - if (tables.includes('collections')) { - console.log('NocoBase is already installed. To reinstall, please execute:'); - console.log(); - let command = 'yarn nocobase init --force'; - for (const [key, value] of Object.entries(opts || {})) { - command += value === true ? ` --${key}` : ` --${key}=${value}`; - } - console.log(command); - console.log(); - return; - } - } - await app.db.sync({ - force: true, + .action(async (...cliArgs) => { + const [opts] = cliArgs; + await app.install({ + cliArgs, + sync: { + force: opts.force, + }, + }); + await app.stop({ + cliArgs, }); - await app.emitAsync('db.init', opts, ...args); - await app.destroy(); }); cli .command('start') .option('-p, --port [port]') - .action(async (...args) => { - const cli = args.pop(); - const opts = cli.opts(); - await app.emitAsync('beforeStart'); - await app.start(opts.port || 3000); - console.log(`http://localhost:${opts.port || 3000}/`); + .action(async (...cliArgs) => { + const [opts] = cliArgs; + const port = opts.port || 3000; + + await app.start({ + cliArgs, + listen: { + port, + }, + }); + + console.log(`http://localhost:${port}/`); }); + return cli; } diff --git a/packages/server/src/plugin.ts b/packages/server/src/plugin.ts index 37429fdb9..b75525d71 100644 --- a/packages/server/src/plugin.ts +++ b/packages/server/src/plugin.ts @@ -1,5 +1,6 @@ import { Database } from '@nocobase/database'; import { Application } from './application'; +import path from 'path'; export interface PluginInterface { beforeLoad?: () => void; @@ -41,5 +42,16 @@ export abstract class Plugin implements PluginInterface { beforeLoad() {} - abstract load(); + async load() { + const collectionPath = this.collectionPath(); + if (collectionPath) { + await this.db.import({ + directory: collectionPath, + }); + } + } + + collectionPath() { + return null; + } }