refactor: app middlewares
This commit is contained in:
parent
6906ccadb0
commit
17362a8444
52
.env.example
52
.env.example
@ -1,29 +1,47 @@
|
|||||||
|
########## DOCKER COMPOSE ENV ##########
|
||||||
|
|
||||||
|
DB_MYSQL_PORT=3306
|
||||||
|
DB_POSTGRES_PORT=5432
|
||||||
|
API_PORT=23000
|
||||||
|
VERDACCIO_PORT=4873
|
||||||
|
|
||||||
|
########## NOCOBASE ENV ##########
|
||||||
|
|
||||||
|
# DATABASE
|
||||||
|
|
||||||
DB_DIALECT=postgres
|
DB_DIALECT=postgres
|
||||||
DB_HOST=localhost
|
DB_HOST=localhost
|
||||||
DB_PORT=5432
|
DB_PORT=5432
|
||||||
DB_DATABASE=nocobase
|
DB_DATABASE=nocobase
|
||||||
DB_USER=test
|
DB_USER=nocobase
|
||||||
DB_PASSWORD=test
|
DB_PASSWORD=nocobase
|
||||||
|
|
||||||
# set to 'on' to enable log
|
# set to 'on' to enable log
|
||||||
DB_LOG_SQL=
|
DB_LOG_SQL=
|
||||||
|
|
||||||
# DB_DIALECT=mysql
|
# API & APP
|
||||||
# DB_PORT=3306
|
|
||||||
|
|
||||||
DB_MYSQL_PORT=3306
|
|
||||||
DB_POSTGRES_PORT=5432
|
|
||||||
|
|
||||||
|
NOCOBASE_ENV=
|
||||||
API_PORT=23000
|
API_PORT=23000
|
||||||
|
APP_USE_STATIC_SERVER=true
|
||||||
|
APP_DIST=packages/app/dist
|
||||||
|
|
||||||
VERDACCIO_PORT=4873
|
# ADMIN USER (Initialization only)
|
||||||
|
|
||||||
APP_DIST=
|
ADMIN_EMAIL=admin@nocobase.com
|
||||||
USE_STATIC_SERVER=true
|
ADMIN_PASSWORD=admin
|
||||||
LOCAL_STORAGE_BASE_URL=http://localhost:23000/uploads
|
|
||||||
STORAGE_BASE_URL=http://localhost:23000/uploads
|
|
||||||
|
|
||||||
ALIYUN_OSS_REGION=oss-cn-beijing
|
# STORAGE (Initialization only)
|
||||||
ALIYUN_OSS_ACCESS_KEY_ID=
|
|
||||||
ALIYUN_OSS_ACCESS_KEY_SECRET=
|
# local or ali-oss
|
||||||
ALIYUN_OSS_BUCKET=
|
STORAGE_TYPE=local
|
||||||
|
|
||||||
|
# LOCAL STORAGE
|
||||||
|
LOCAL_STORAGE_USE_STATIC_SERVER=true
|
||||||
|
LOCAL_STORAGE_BASE_URL=http://localhost:23000
|
||||||
|
|
||||||
|
# ALI OSS STORAGE
|
||||||
|
ALI_OSS_STORAGE_BASE_URL=
|
||||||
|
ALI_OSS_REGION=oss-cn-beijing
|
||||||
|
ALI_OSS_ACCESS_KEY_ID=
|
||||||
|
ALI_OSS_ACCESS_KEY_SECRET=
|
||||||
|
ALI_OSS_BUCKET=
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"watch": ["packages/"],
|
"watch": ["packages/", ".env"],
|
||||||
"ignore": ["packages/app"],
|
"ignore": ["packages/app"],
|
||||||
"ext": "ts",
|
"ext": "ts",
|
||||||
"exec": "ts-node ./packages/api/src/dev.ts"
|
"exec": "ts-node -r dotenv/config ./packages/api/src/index.ts"
|
||||||
}
|
}
|
@ -10,8 +10,7 @@
|
|||||||
"bootstrap": "lerna bootstrap --no-ci",
|
"bootstrap": "lerna bootstrap --no-ci",
|
||||||
"build": "father-build",
|
"build": "father-build",
|
||||||
"clean": "lerna clean",
|
"clean": "lerna clean",
|
||||||
"db-migrate": "cd packages/api && npm run db-migrate",
|
"db-migrate": "ts-node -r dotenv/config ./packages/api/src/migrate.ts",
|
||||||
"db:start": "docker-compose up -d",
|
|
||||||
"lint": "eslint --ext .ts,.tsx,.js \"packages/*/src/**.@(ts|tsx|js)\" --fix",
|
"lint": "eslint --ext .ts,.tsx,.js \"packages/*/src/**.@(ts|tsx|js)\" --fix",
|
||||||
"test": "npm run lint && jest",
|
"test": "npm run lint && jest",
|
||||||
"debug": "node --inspect-brk node_modules/.bin/jest --runInBand",
|
"debug": "node --inspect-brk node_modules/.bin/jest --runInBand",
|
||||||
|
@ -4,10 +4,7 @@
|
|||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"types": "./lib/index.d.ts",
|
"types": "./lib/index.d.ts",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {},
|
||||||
"start": "nodemon",
|
|
||||||
"db-migrate": "ts-node ./src/migrate.ts"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nocobase/actions": "^0.4.0-alpha.1",
|
"@nocobase/actions": "^0.4.0-alpha.1",
|
||||||
"@nocobase/client": "^0.4.0-alpha.1",
|
"@nocobase/client": "^0.4.0-alpha.1",
|
||||||
|
@ -2,9 +2,9 @@ import Api from '@nocobase/server';
|
|||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const sync = global.sync || {
|
const sync = global.sync || {
|
||||||
force: true,
|
force: false,
|
||||||
alter: {
|
alter: {
|
||||||
drop: true,
|
drop: false,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
import path from 'path';
|
|
||||||
import dotenv from 'dotenv';
|
|
||||||
|
|
||||||
dotenv.config({
|
|
||||||
path: path.resolve(__dirname, '../../../.env'),
|
|
||||||
});
|
|
||||||
|
|
||||||
import './index';
|
|
@ -1,61 +1,16 @@
|
|||||||
import api from './app';
|
import api from './app';
|
||||||
import actions from '@nocobase/actions';
|
import { middlewares } from '@nocobase/server';
|
||||||
import send from 'koa-send';
|
|
||||||
import serve from 'koa-static';
|
|
||||||
|
|
||||||
api.resourcer.use(async (ctx: actions.Context, 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();
|
|
||||||
});
|
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
|
api.resourcer.use(middlewares.actionParams());
|
||||||
|
|
||||||
await api.loadPlugins();
|
await api.loadPlugins();
|
||||||
|
|
||||||
api.database.getModel('users').addHook('beforeUpdate', function (model) {
|
if (process.env.NOCOBASE_ENV === 'demo') {
|
||||||
console.log('users.beforeUpdate', model.get(), model.changed('password' as any));
|
api.resourcer.use(middlewares.demoBlacklistedActions({
|
||||||
});
|
emails: [process.env.ADMIN_EMAIL],
|
||||||
|
}));
|
||||||
api.resourcer.use(async (ctx, next) => {
|
}
|
||||||
if (process.env.NOCOBASE_ENV !== 'demo') {
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
const currentUser = ctx.state.currentUser;
|
|
||||||
if (currentUser && currentUser.username === 'admin') {
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
const { actionName } = ctx.action.params;
|
|
||||||
if (['create', 'update', 'destroy', 'sort', 'upload'].includes(actionName)) {
|
|
||||||
ctx.body = {
|
|
||||||
data: {},
|
|
||||||
meta: {},
|
|
||||||
};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await next();
|
|
||||||
});
|
|
||||||
|
|
||||||
await api.database.getModel('collections').load({skipExisting: true});
|
await api.database.getModel('collections').load({skipExisting: true});
|
||||||
await api.database.getModel('collections').load({where: {
|
await api.database.getModel('collections').load({where: {
|
||||||
@ -63,17 +18,14 @@ api.resourcer.use(async (ctx: actions.Context, next) => {
|
|||||||
}});
|
}});
|
||||||
await api.database.getModel('automations').load();
|
await api.database.getModel('automations').load();
|
||||||
|
|
||||||
api.use(async (ctx, next) => {
|
api.use(middlewares.appDistServe({
|
||||||
if (!process.env.APP_DIST || !process.env.USE_STATIC_SERVER || process.env.USE_STATIC_SERVER === 'false') {
|
root: process.env.APP_DIST,
|
||||||
return next();
|
useStaticServer: !(process.env.APP_USE_STATIC_SERVER === 'false' || !process.env.APP_USE_STATIC_SERVER),
|
||||||
}
|
}));
|
||||||
await serve(process.env.APP_DIST)(ctx, next);
|
|
||||||
if (ctx.status == 404) {
|
|
||||||
return send(ctx, 'index.html', { root: process.env.APP_DIST });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
api.listen(process.env.API_PORT, () => {
|
if (require.main === module) {
|
||||||
console.log(`http://localhost:${process.env.API_PORT}/`);
|
api.listen(process.env.API_PORT, () => {
|
||||||
});
|
console.log(`http://localhost:${process.env.API_PORT}/`);
|
||||||
|
});
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const keys = process.argv;
|
const keys = process.argv;
|
||||||
|
|
||||||
|
@ -76,47 +76,31 @@ const data = [
|
|||||||
await Collection.import(table.getOptions(), { update: true, migrate: false });
|
await Collection.import(table.getOptions(), { update: true, migrate: false });
|
||||||
}
|
}
|
||||||
await Page.import(data);
|
await Page.import(data);
|
||||||
let user = await User.findOne({
|
|
||||||
where: {
|
const user = await User.create({
|
||||||
username: "admin",
|
email: process.env.ADMIN_EMAIL,
|
||||||
},
|
password: process.env.ADMIN_PASSWORD,
|
||||||
});
|
});
|
||||||
if (!user) {
|
|
||||||
user = await User.create({
|
|
||||||
nickname: "超级管理员",
|
|
||||||
password: "admin",
|
|
||||||
username: "admin",
|
|
||||||
email: 'dev@nocobase.com',
|
|
||||||
token: "38979f07e1fca68fb3d2",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const Storage = database.getModel('storages');
|
const Storage = database.getModel('storages');
|
||||||
// await Storage.create({
|
await Storage.create({
|
||||||
// title: '本地存储',
|
title: '本地存储',
|
||||||
// name: `local`,
|
name: `local`,
|
||||||
// type: 'local',
|
type: 'local',
|
||||||
// baseUrl: process.env.LOCAL_STORAGE_BASE_URL,
|
baseUrl: process.env.LOCAL_STORAGE_BASE_URL,
|
||||||
// default: true
|
default: process.env.STORAGE_TYPE === 'local',
|
||||||
// });
|
});
|
||||||
const storage = await Storage.findOne({
|
await Storage.create({
|
||||||
where: {
|
name: `ali-oss`,
|
||||||
name: "ali-oss",
|
type: 'ali-oss',
|
||||||
},
|
baseUrl: process.env.ALI_OSS_STORAGE_BASE_URL,
|
||||||
|
options: {
|
||||||
|
region: process.env.ALI_OSS_REGION,
|
||||||
|
accessKeyId: process.env.ALI_OSS_ACCESS_KEY_ID,
|
||||||
|
accessKeySecret: process.env.ALI_OSS_ACCESS_KEY_SECRET,
|
||||||
|
bucket: process.env.ALI_OSS_BUCKET,
|
||||||
|
},
|
||||||
|
default: process.env.STORAGE_TYPE === 'ali-oss',
|
||||||
});
|
});
|
||||||
if (!storage) {
|
|
||||||
await Storage.create({
|
|
||||||
name: `ali-oss`,
|
|
||||||
type: 'ali-oss',
|
|
||||||
baseUrl: process.env.ALIYUN_STORAGE_BASE_URL,
|
|
||||||
options: {
|
|
||||||
region: process.env.ALIYUN_OSS_REGION,
|
|
||||||
accessKeyId: process.env.ALIYUN_OSS_ACCESS_KEY_ID,
|
|
||||||
accessKeySecret: process.env.ALIYUN_OSS_ACCESS_KEY_SECRET,
|
|
||||||
bucket: process.env.ALIYUN_OSS_BUCKET,
|
|
||||||
},
|
|
||||||
default: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const Role = database.getModel('roles');
|
const Role = database.getModel('roles');
|
||||||
if (Role) {
|
if (Role) {
|
||||||
const roles = await Role.bulkCreate([
|
const roles = await Role.bulkCreate([
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"watch": ["../"],
|
|
||||||
"ignore": ["../app"],
|
|
||||||
"ext": "ts",
|
|
||||||
"exec": "ts-node ../api/src/dev.ts"
|
|
||||||
}
|
|
@ -2,7 +2,8 @@
|
|||||||
"name": "@nocobase/app",
|
"name": "@nocobase/app",
|
||||||
"version": "0.4.0-alpha.1",
|
"version": "0.4.0-alpha.1",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "concurrently \"nodemon\" \"umi dev\"",
|
"start": "concurrently \"cd ../../ && nodemon\" \"umi dev\"",
|
||||||
|
"dev": "umi dev",
|
||||||
"build": "umi build",
|
"build": "umi build",
|
||||||
"postinstall": "umi generate tmp",
|
"postinstall": "umi generate tmp",
|
||||||
"prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
|
"prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
|
||||||
|
@ -54,7 +54,7 @@ export function middleware(app) {
|
|||||||
// 否则都忽略,交给其他 server 来提供(如 nginx/cdn 等)
|
// 否则都忽略,交给其他 server 来提供(如 nginx/cdn 等)
|
||||||
// TODO(bug): https、端口 80 默认值和其他本地 ip/hostname 的情况未考虑
|
// TODO(bug): https、端口 80 默认值和其他本地 ip/hostname 的情况未考虑
|
||||||
// TODO 实际应该用 NOCOBASE_ENV 来判断,或者抛给 env 处理
|
// TODO 实际应该用 NOCOBASE_ENV 来判断,或者抛给 env 处理
|
||||||
if (process.env.USE_STATIC_SERVER) {
|
if (process.env.LOCAL_STORAGE_USE_STATIC_SERVER) {
|
||||||
const basePath = url.pathname.startsWith('/') ? url.pathname : `/${url.pathname}`;
|
const basePath = url.pathname.startsWith('/') ? url.pathname : `/${url.pathname}`;
|
||||||
app.use(mount(basePath, serve(getDocumentRoot(storage))));
|
app.use(mount(basePath, serve(getDocumentRoot(storage))));
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
"koa": "^2.13.0",
|
"koa": "^2.13.0",
|
||||||
"koa-bodyparser": "^4.3.0",
|
"koa-bodyparser": "^4.3.0",
|
||||||
|
"koa-static": "^5.0.0",
|
||||||
"mockjs": "^1.1.0",
|
"mockjs": "^1.1.0",
|
||||||
"mysql2": "^2.1.0",
|
"mysql2": "^2.1.0",
|
||||||
"pg": "^8.3.3",
|
"pg": "^8.3.3",
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import { actions, middlewares } from '@nocobase/actions';
|
import { actions, middlewares as m } from '@nocobase/actions';
|
||||||
import Application from './application';
|
import Application from './application';
|
||||||
import bodyParser from 'koa-bodyparser';
|
import bodyParser from 'koa-bodyparser';
|
||||||
import cors from '@koa/cors';
|
import cors from '@koa/cors';
|
||||||
import middleware from './middleware';
|
import { dbResourceRouter } from './middlewares';
|
||||||
|
|
||||||
export * from './application';
|
export * from './application';
|
||||||
export * from './middleware';
|
export * from './middleware';
|
||||||
|
export * as middlewares from './middlewares';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
/**
|
/**
|
||||||
@ -29,10 +30,10 @@ export default {
|
|||||||
await next();
|
await next();
|
||||||
});
|
});
|
||||||
|
|
||||||
app.resourcer.use(middlewares.associated);
|
app.resourcer.use(m.associated);
|
||||||
app.use(middlewares.dataWrapping);
|
app.use(m.dataWrapping);
|
||||||
|
|
||||||
app.use(middleware({
|
app.use(dbResourceRouter({
|
||||||
database: app.database,
|
database: app.database,
|
||||||
resourcer: app.resourcer,
|
resourcer: app.resourcer,
|
||||||
...(options.resourcer||{}),
|
...(options.resourcer||{}),
|
||||||
|
31
packages/server/src/middlewares/action-params.ts
Normal file
31
packages/server/src/middlewares/action-params.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { actions } from '@nocobase/actions';
|
||||||
|
|
||||||
|
export function actionParams(options: any = {}) {
|
||||||
|
return async (ctx: actions.Context, next: actions.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();
|
||||||
|
}
|
||||||
|
}
|
25
packages/server/src/middlewares/app-dist-serve.ts
Normal file
25
packages/server/src/middlewares/app-dist-serve.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import path from 'path';
|
||||||
|
import send from 'koa-send';
|
||||||
|
import serve from 'koa-static';
|
||||||
|
import actions from '@nocobase/actions';
|
||||||
|
|
||||||
|
export interface AppDistServeOptions {
|
||||||
|
root?: string;
|
||||||
|
useStaticServer?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function appDistServe(options: AppDistServeOptions = {}) {
|
||||||
|
return async (ctx: actions.Context, next: actions.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 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
133
packages/server/src/middlewares/db-resource-router.ts
Normal file
133
packages/server/src/middlewares/db-resource-router.ts
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
import compose from 'koa-compose';
|
||||||
|
import { pathToRegexp } from 'path-to-regexp';
|
||||||
|
import Resourcer, { getNameByParams, KoaMiddlewareOptions, parseRequest, parseQuery, ResourcerContext, ResourceType } from '@nocobase/resourcer';
|
||||||
|
import Database, { BELONGSTO, BELONGSTOMANY, HASMANY, HASONE } from '@nocobase/database';
|
||||||
|
|
||||||
|
interface MiddlewareOptions extends KoaMiddlewareOptions {
|
||||||
|
resourcer?: Resourcer;
|
||||||
|
database?: Database;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* database + resourcer 结合的中间件(暂时不知道起什么名好)
|
||||||
|
*
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
export function dbResourceRouter(options: MiddlewareOptions = {}) {
|
||||||
|
const {
|
||||||
|
prefix,
|
||||||
|
database,
|
||||||
|
resourcer,
|
||||||
|
accessors,
|
||||||
|
paramsKey = 'params',
|
||||||
|
nameRule = getNameByParams,
|
||||||
|
} = options;
|
||||||
|
return async (ctx: ResourcerContext, next: () => Promise<any>) => {
|
||||||
|
ctx.resourcer = resourcer;
|
||||||
|
let params = parseRequest({
|
||||||
|
path: ctx.request.path,
|
||||||
|
method: ctx.request.method,
|
||||||
|
}, {
|
||||||
|
prefix,
|
||||||
|
accessors,
|
||||||
|
});
|
||||||
|
if (!params) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const resourceName = nameRule(params);
|
||||||
|
// 如果资源名称未被定义
|
||||||
|
if (!resourcer.isDefined(resourceName)) {
|
||||||
|
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(fieldName) as BELONGSTO | HASMANY | BELONGSTOMANY | HASONE;
|
||||||
|
if (!fieldName || field) {
|
||||||
|
let resourceType: ResourceType = 'single';
|
||||||
|
let actions = {};
|
||||||
|
if (field) {
|
||||||
|
if (field instanceof HASONE) {
|
||||||
|
resourceType = 'hasOne';
|
||||||
|
} else if (field instanceof HASMANY) {
|
||||||
|
resourceType = 'hasMany';
|
||||||
|
} else if (field instanceof BELONGSTO) {
|
||||||
|
resourceType = 'belongsTo';
|
||||||
|
} else if (field instanceof BELONGSTOMANY) {
|
||||||
|
resourceType = 'belongsToMany';
|
||||||
|
}
|
||||||
|
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,
|
||||||
|
name: resourceName,
|
||||||
|
actions,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const resource = resourcer.getResource(resourceName);
|
||||||
|
// 为关系资源时,暂时需要再执行一遍 parseRequest
|
||||||
|
if (resource.options.type !== 'single') {
|
||||||
|
params = parseRequest({
|
||||||
|
path: ctx.request.path,
|
||||||
|
method: ctx.request.method,
|
||||||
|
type: resource.options.type,
|
||||||
|
}, {
|
||||||
|
prefix,
|
||||||
|
accessors,
|
||||||
|
});
|
||||||
|
if (!params) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// console.log(resource);
|
||||||
|
// action 需要 clone 之后再赋给 ctx
|
||||||
|
ctx.action = resourcer.getAction(resourceName, params.actionName).clone();
|
||||||
|
ctx.action.setContext(ctx);
|
||||||
|
// 自带 query 处理的不太给力,需要用 qs 转一下
|
||||||
|
const query = parseQuery(ctx.request.querystring);
|
||||||
|
// 兼容 ctx.params 的处理,之后的版本里会去掉
|
||||||
|
ctx[paramsKey] = {
|
||||||
|
table: params.resourceName,
|
||||||
|
tableKey: params.resourceKey,
|
||||||
|
relatedTable: params.associatedName,
|
||||||
|
relatedKey: params.resourceKey,
|
||||||
|
action: params.actionName,
|
||||||
|
};
|
||||||
|
if (pathToRegexp('/resourcer/{:associatedName.}?:resourceName{\\::actionName}').test(ctx.request.path)) {
|
||||||
|
await ctx.action.mergeParams({
|
||||||
|
...query,
|
||||||
|
...params,
|
||||||
|
...ctx.request.body,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await ctx.action.mergeParams({
|
||||||
|
...query,
|
||||||
|
...params,
|
||||||
|
values: ctx.request.body,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return compose(ctx.action.getHandlers())(ctx, next);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
packages/server/src/middlewares/demo-blacklisted-actions.ts
Normal file
27
packages/server/src/middlewares/demo-blacklisted-actions.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { actions } 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: actions.Context, next: actions.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();
|
||||||
|
}
|
||||||
|
}
|
4
packages/server/src/middlewares/index.ts
Normal file
4
packages/server/src/middlewares/index.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export * from './action-params';
|
||||||
|
export * from './app-dist-serve';
|
||||||
|
export * from './db-resource-router';
|
||||||
|
export * from './demo-blacklisted-actions';
|
Loading…
Reference in New Issue
Block a user