feat: improve code

This commit is contained in:
chenos 2021-09-16 00:38:48 +08:00
parent 09c42abdcc
commit b7eb720eb4
11 changed files with 164 additions and 275 deletions

View File

@ -7,6 +7,7 @@
"scripts": { "scripts": {
"bootstrap": "lerna bootstrap", "bootstrap": "lerna bootstrap",
"clean": "lerna clean", "clean": "lerna clean",
"examples": "ts-node-dev -r dotenv/config ./examples",
"start": "cd packages/app && npm start", "start": "cd packages/app && npm start",
"start-client": "cd packages/app && npm run start-client", "start-client": "cd packages/app && npm run start-client",
"start-server": "nodemon", "start-server": "nodemon",

View File

@ -6,6 +6,7 @@ import Database, { DatabaseOptions, TableOptions } from '@nocobase/database';
import Resourcer, { ResourceOptions } from '@nocobase/resourcer'; import Resourcer, { ResourceOptions } from '@nocobase/resourcer';
import { dataWrapping, table2resource } from './middlewares'; import { dataWrapping, table2resource } from './middlewares';
import { PluginType, Plugin, PluginOptions } from './plugin'; import { PluginType, Plugin, PluginOptions } from './plugin';
import { registerActions } from '@nocobase/actions';
export interface ResourcerOptions { export interface ResourcerOptions {
prefix?: string; prefix?: string;
@ -20,6 +21,7 @@ export interface ApplicationOptions {
} }
export class Application extends Koa { export class Application extends Koa {
public readonly db: Database; public readonly db: Database;
public readonly resourcer: Resourcer; public readonly resourcer: Resourcer;
@ -31,7 +33,12 @@ export class Application extends Koa {
constructor(options: ApplicationOptions) { constructor(options: ApplicationOptions) {
super(); super();
if (options.database instanceof Database) {
this.db = options.database;
} else {
this.db = new Database(options.database); this.db = new Database(options.database);
}
this.resourcer = new Resourcer({ ...options.resourcer }); this.resourcer = new Resourcer({ ...options.resourcer });
this.cli = new Command(); this.cli = new Command();
@ -55,17 +62,19 @@ export class Application extends Koa {
}); });
if (options.dataWrapping !== false) { if (options.dataWrapping !== false) {
this.use(dataWrapping); this.use(dataWrapping());
} }
this.use(table2resource); this.use(table2resource());
this.use(this.resourcer.restApiMiddleware()); this.use(this.resourcer.restApiMiddleware());
registerActions(this);
this.cli this.cli
.command('db sync') .command('db sync')
.option('-f, --force') .option('-f, --force')
.action(async (...args) => { .action(async (...args) => {
console.log('db sync'); console.log('db sync...');
const cli = args.pop(); const cli = args.pop();
const force = cli.opts()?.force; const force = cli.opts()?.force;
await this.load(); await this.load();
@ -120,6 +129,10 @@ export class Application extends Koa {
return this.resourcer.define(options); return this.resourcer.define(options);
} }
actions(handlers: any) {
return this.resourcer.registerActions(handlers);
}
command(nameAndArgs: string, opts?: CommandOptions) { command(nameAndArgs: string, opts?: CommandOptions) {
return this.cli.command(nameAndArgs, opts); return this.cli.command(nameAndArgs, opts);
} }
@ -216,58 +229,13 @@ export class Application extends Koa {
return true; return true;
} }
// registerPlugin(key: string | object, plugin?: any) { async parse(argv = process.argv) {
// if (typeof key === 'object') {
// Object.keys(key).forEach((k) => {
// this.registerPlugin(k, key[k]);
// });
// } else {
// const config = {};
// if (Array.isArray(plugin)) {
// const [entry, options = {}] = plugin;
// Object.assign(config, { entry, options });
// } else {
// Object.assign(config, { entry: plugin, options: {} });
// }
// this.plugins.set(key, config);
// }
// }
// async loadPlugins() {
// await this.emitAsync('plugins.beforeLoad');
// const allPlugins = this.plugins.values();
// for (const plugin of allPlugins) {
// plugin.instance = await this.loadPlugin(plugin);
// }
// await this.emitAsync('plugins.afterLoad');
// }
async start(argv = process.argv) {
return this.cli.parseAsync(argv); return this.cli.parseAsync(argv);
} }
async destroy() { async destroy() {
await this.db.close(); await this.db.close();
} }
// protected async loadPlugin({
// entry,
// options = {},
// }: {
// entry: string | Function;
// options: any;
// }) {
// let main: any;
// if (typeof entry === 'function') {
// main = entry;
// } else if (typeof entry === 'string') {
// const pathname = `${entry}/${
// __filename.endsWith('.ts') ? 'src' : 'lib'
// }/server`;
// main = require(pathname).default;
// }
// return main && (await main.call(this, options));
// }
} }
export default Application; export default Application;

View File

@ -1,31 +0,0 @@
import { Context, Next } from '@nocobase/actions';
export function actionParams(options: any = {}) {
return async (ctx: Context, next: Next) => {
const { actionName, resourceField, resourceName, fields = {} } = ctx.action.params;
const table = ctx.db.getTable(resourceField ? resourceField.options.target : resourceName);
// ctx.state.developerMode = {[Op.not]: null};
ctx.state.developerMode = false;
if (table && table.hasField('developerMode') && ctx.state.developerMode === false) {
ctx.action.mergeParams({ filter: { "developerMode.$isFalsy": true } }, { filter: 'and' });
}
if (table && ['get', 'list'].includes(actionName)) {
const except = [];
const appends = [];
for (const [name, field] of table.getFields()) {
if (field.options.hidden) {
except.push(field.options.name);
}
// if (field.options.appends) {
// appends.push(field.options.name);
// }
}
ctx.action.mergeParams({ fields: {
except,
appends
} }, { fields: 'append' });
// console.log('ctx.action.params.fields', ctx.action.params.fields, except, appends);
}
await next();
}
}

View File

@ -1,25 +0,0 @@
import path from 'path';
import send from 'koa-send';
import serve from 'koa-static';
import { Context, Next } from '@nocobase/actions';
export interface AppDistServeOptions {
root?: string;
useStaticServer?: boolean;
}
export function appDistServe(options: AppDistServeOptions = {}) {
return async (ctx: Context, next: Next) => {
if (!options.root || !options.useStaticServer) {
return next();
}
let root = options.root;
if (!root.startsWith('/')) {
root = path.resolve(process.cwd(), root);
}
await serve(root)(ctx, next);
if (ctx.status == 404) {
return send(ctx, 'index.html', { root });
}
}
}

View File

@ -1,6 +1,7 @@
import { Context, Next } from '@nocobase/actions'; import { Context, Next } from '@nocobase/actions';
export async function dataWrapping(ctx: Context, next: Next) { export function dataWrapping() {
return async function dataWrapping(ctx: Context, next: Next) {
await next(); await next();
if (ctx.withoutDataWrapping) { if (ctx.withoutDataWrapping) {
return; return;
@ -25,6 +26,7 @@ export async function dataWrapping(ctx: Context, next: Next) {
data: ctx.body, data: ctx.body,
}; };
} }
}
} }
export default dataWrapping; export default dataWrapping;

View File

@ -1,27 +0,0 @@
import { Context, Next } from '@nocobase/actions';
export interface DemoBlackListedActionsOptions {
emails?: string[];
blacklist?: string[];
}
const defaultBlacklist = ['create', 'update', 'destroy', 'sort', 'upload'];
export function demoBlacklistedActions(options: DemoBlackListedActionsOptions = {}) {
const { emails, blacklist = defaultBlacklist } = options;
return async (ctx: Context, next: Next) => {
const currentUser = ctx.state.currentUser;
if (currentUser && emails.includes(currentUser.email)) {
return next();
}
const { actionName } = ctx.action.params;
if (blacklist.includes(actionName)) {
ctx.body = {
data: {},
meta: {},
};
return;
}
await next();
}
}

View File

@ -1,5 +1,2 @@
export * from './action-params';
export * from './app-dist-serve';
export * from './demo-blacklisted-actions';
export * from './table2resource'; export * from './table2resource';
export * from './data-wrapping'; export * from './data-wrapping';

View File

@ -6,12 +6,13 @@ import {
} from '@nocobase/resourcer'; } from '@nocobase/resourcer';
import { BELONGSTO, BELONGSTOMANY, HASMANY, HASONE } from '@nocobase/database'; import { BELONGSTO, BELONGSTOMANY, HASMANY, HASONE } from '@nocobase/database';
export async function table2resource( export function table2resource() {
return async function table2resource(
ctx: ResourcerContext, ctx: ResourcerContext,
next: () => Promise<any>, next: () => Promise<any>,
) { ) {
const resourcer = ctx.resourcer; const resourcer = ctx.resourcer;
const database = ctx.database; const database = ctx.db;
let params = parseRequest( let params = parseRequest(
{ {
path: ctx.request.path, path: ctx.request.path,
@ -67,6 +68,7 @@ export async function table2resource(
}); });
} }
return next(); return next();
};
} }
export default table2resource; export default table2resource;

View File

@ -28,7 +28,7 @@ describe('mock server', () => {
}); });
it('resource', async () => { it('resource', async () => {
const response = await api.resource('test').list(); const response = await api.agent().resource('test').list();
expect(response.body).toEqual([1, 2]); expect(response.body).toEqual([1, 2]);
}); });
}); });

View File

@ -1,5 +1,5 @@
import qs from 'qs'; import qs from 'qs';
import supertest from 'supertest'; import supertest, { SuperAgentTest } from 'supertest';
import Application, { ApplicationOptions } from '@nocobase/server'; import Application, { ApplicationOptions } from '@nocobase/server';
import { getConfig } from './mockDatabase'; import { getConfig } from './mockDatabase';
@ -46,20 +46,14 @@ interface Resource {
} }
export class MockServer extends Application { export class MockServer extends Application {
agent(): SuperAgentTest & { resource: (name: string) => Resource } {
protected agentInstance: supertest.SuperAgentTest; const agent = supertest.agent(this.callback());
agent() {
if (!this.agentInstance) {
this.agentInstance = supertest.agent(this.callback());
}
return this.agentInstance;
}
resource(name: string) {
const agent = this.agent();
const keys = name.split('.');
const prefix = this.resourcer.options.prefix; const prefix = this.resourcer.options.prefix;
const proxy = new Proxy({}, {
get(target, method: string, receiver) {
if (method === 'resource') {
return (name: string) => {
const keys = name.split('.');
const proxy = new Proxy({}, { const proxy = new Proxy({}, {
get(target, method: string, receiver) { get(target, method: string, receiver) {
return (params: ActionParams = {}) => { return (params: ActionParams = {}) => {
@ -98,7 +92,15 @@ export class MockServer extends Application {
}; };
}, },
}); });
return proxy as Resource; return proxy;
}
}
return (...args: any[]) => {
return agent[method](...args);
};
}
});
return proxy as any;
} }
} }

View File

@ -16,7 +16,7 @@
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {
"@nocobase/*": [ "@nocobase/*": [
"./packages/*" "./packages/*/src"
] ]
} }
} }