fix: merge interface.scss文件解决冲突

This commit is contained in:
wenbo.dong 2017-09-19 20:06:21 +08:00
commit 822ed6ba6d
27 changed files with 690 additions and 137 deletions

View File

@ -5,7 +5,7 @@ module.exports = {
"es6": true,
"node": true
},
"extends": "eslint:recommended",
extends: ["eslint:recommended", "plugin:react/recommended"],
"parser": "babel-eslint",
"parserOptions": {
"ecmaFeatures": {
@ -14,8 +14,9 @@ module.exports = {
},
"sourceType": "module"
},
"plugins": [
"react"
plugins: [
"react",
"import"
],
"rules": {
"indent": [

View File

@ -31,7 +31,6 @@
"/fekit_modules/*",
"/node_modules/*",
"/bower_components/*",
"/plugins/*",
"/dev/*",
"/prd/*"
]

View File

@ -2,6 +2,25 @@ import React from 'react';
import moment from 'moment';
import constants from './constants/variable';
const Roles = {
0 : 'admin',
10: 'owner',
20: 'dev',
30: 'guest',
40: 'member'
}
const roleAction = {
'manageUserlist' : 'admin',
'changeMemberRole': 'owner',
'editInterface': 'dev',
'viewPrivateInterface': 'guest',
'viewGroup': 'guest'
}
exports.checkAuth = (action, role)=>{
return Roles[roleAction[action]] <= Roles[role];
}
exports.formatTime = (timestamp) => {
return moment.unix(timestamp).format("YYYY-MM-DD HH:mm:ss")

View File

@ -215,9 +215,9 @@ export default class InterfaceColMenu extends Component {
return (
<div>
<div className="interface-filter">
<Input placeholder="Filter by name" style={{ width: "70%" }} onChange={this.filterCol} />
<Input placeholder="Filter by name" onChange={this.filterCol} />
<Tooltip placement="bottom" title="添加集合">
<Tag color="#108ee9" style={{ marginLeft: "16px" }} onClick={() => this.showColModal('add')} ><Icon type="plus" /></Tag>
<Tag color="#108ee9" style={{ marginLeft: "16px" }} onClick={() => this.showColModal('add')} className="btn-filter" ><Icon type="plus" /></Tag>
</Tooltip>
</div>
<Tree
@ -235,8 +235,8 @@ export default class InterfaceColMenu extends Component {
title={
<div className="menu-title">
<span><Icon type="folder-open" style={{marginRight: 5}} /><span>{col.name}</span></span>
<Dropdown overlay={menu(col)}>
<Icon type='bars'/>
<Dropdown overlay={menu(col)} trigger={['click']} onClick={e => e.stopPropagation()}>
<Icon className="opts-icon" type='ellipsis'/>
</Dropdown>
</div>
}

View File

@ -1,7 +1,17 @@
.col-list-tree {
line-height: 25px;
.ant-tree-node-content-wrapper {
width: calc(100% - 24px);
}
.opts-icon, .case-delete-icon {
line-height: 25px;
width: 30px;
}
.opts-icon:hover, .case-delete-icon:hover {
color: #2395f1;
border-radius: 4px;
box-shadow: inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);
}
.menu-title {
display: flex;
justify-content: space-between;
@ -13,9 +23,6 @@
margin-left: 5px;
display: none;
}
i:before{
line-height: 17px;
}
}
.menu-title:hover {
.case-delete-icon {

View File

@ -8,7 +8,7 @@ import View from './View.js'
import { fetchInterfaceData } from '../../../../reducer/modules/interface.js';
import { withRouter } from 'react-router-dom';
import Run from './Run/Run.js'
const plugin = require('client/plugin.js');
const TabPane = Tabs.TabPane;
@connect(
@ -72,24 +72,33 @@ class Content extends Component {
}
render() {
const tabs = <Tabs onChange={this.onChange} activeKey={this.state.curtab} defaultActiveKey="view" >
<TabPane tab="预览" key="view">
{/* <View /> */}
</TabPane>
<TabPane tab="编辑" key="edit">
let InterfaceTabs = {
view: {
component: View,
name: '预览'
},
edit: {
component: Edit,
name: '编辑'
},
run: {
component: Run,
name: '运行'
}
}
</TabPane>
<TabPane tab="运行" key="run">
{/* <Run /> */}
</TabPane>
plugin.emitHook('interface_tab', InterfaceTabs);
const tabs = <Tabs onChange={this.onChange} activeKey={this.state.curtab} defaultActiveKey="view" >
{Object.keys(InterfaceTabs).map(key=>{
let item = InterfaceTabs[key];
return <TabPane tab={item.name} key={key}></TabPane>
})}
</Tabs>;
let tabContent;
if (this.state.curtab === 'view') {
tabContent = <View />;
} else if (this.state.curtab === 'edit') {
tabContent = <Edit switchToView={this.switchToView} />
} else if (this.state.curtab === 'run') {
tabContent = <Run />
let tabContent = null;
if (this.state.curtab) {
let C = InterfaceTabs[this.state.curtab].component;
tabContent = <C switchToView={this.switchToView} />;
}
return <div className="interface-content">

View File

@ -12,7 +12,6 @@ import { Link, withRouter } from 'react-router-dom';
const confirm = Modal.confirm;
const TreeNode = Tree.TreeNode;
@connect(
state => {
@ -384,8 +383,8 @@ class InterfaceMenu extends Component {
{menuList.map((item) => {
return <TreeNode title={<div>
<Link className="interface-item" to={"/project/" + matchParams.id + "/interface/api/cat_" + item._id} ><Icon type="folder-open" style={{ marginRight: 5 }} />{item.name}</Link>
<Dropdown overlay={menu(item)}>
<Icon type='setting' className="interface-delete-icon" />
<Dropdown overlay={menu(item)} trigger={['click']} onClick={e => e.stopPropagation()}>
<Icon type='ellipsis' className="interface-delete-icon" />
</Dropdown>
</div>}
key={'cat_' + item._id}

View File

@ -94,18 +94,53 @@
.interface-item-nav{
line-height:25px;
}
.interface-list{
.cat_switch_hidden{
.ant-tree-switcher{
visibility: hidden;
}
}
a{
color: #333
}
.btn-http{
height: 23px;
font-size: 10px;
margin-right: 7px;
padding: 0 5px;
width:auto !important;
}
.interface-item{
display: inline-block;
overflow: hidden;
top: 0px;
line-height: 100%;
text-decoration: none;
}
.interface-item-nav{
line-height:25px;
}
.ant-tree-node-content-wrapper{
width: 100%
}
.interface-delete-icon{
position: relative;
right: 21px;
// top: 2px;
float: right;
line-height: 25px;
width: 30px;
.interface-delete-icon{
position: relative;
right: 21px;
// top: 2px;
float: right;
line-height: 25px;
width: 30px;
}
.interface-delete-icon:hover {
color: #2395f1;
border-radius: 4px;
box-shadow: inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);
}
}
}
}

View File

@ -1,3 +1,4 @@
let initPlugins = require('common/lib.js').initPlugins;
const config = process.env.config;
let hooks, pluginModule, systemPlugins;
@ -9,12 +10,12 @@ let hooks, pluginModule, systemPlugins;
*/
hooks = {
'third_login': {
third_login: {
type: 'component',
mulit: false,
listener: null
},
'add_interface': {
add_interface: {
type: 'listener',
mulit: true,
listener: []
@ -23,18 +24,21 @@ hooks = {
type: 'listener',
mulit: true,
listener: []
},
interface_tab: {
type: 'listener',
mulit: true,
listener: []
}
};
pluginModule = {
hooks: hooks,
bindHook: bindHook,
emitHook: emitHook
}
systemPlugins = ['import-postman', 'import-har']
//初始化配置
systemPlugins = require('common/config.js').exts;
systemPlugins = initPlugins(systemPlugins);
config.plugins = config.plugins && Array.isArray(config.plugins) ? config.plugins: [];
config.plugins = config.plugins && Array.isArray(config.plugins) ? config.plugins : [];
config.plugins = initPlugins(config.plugins);
function bindHook(name, listener) {
if (!name) throw new Error('缺少hookname');
@ -49,38 +53,52 @@ function bindHook(name, listener) {
}
function emitHook(name, ...args){
if(!hooks[name]) throw new Error('不存在的hook name');
function emitHook(name, ...args) {
if (!hooks[name]) throw new Error('不存在的hook name');
let hook = hooks[name];
if(hook.mulit === true && hook.type === 'listener'){
if(Array.isArray(hook.listener)){
hook.listener.forEach(item=>{
if(typeof item === 'function'){
if (hook.mulit === true && hook.type === 'listener') {
if (Array.isArray(hook.listener)) {
hook.listener.forEach(item => {
if (typeof item === 'function') {
item.call(pluginModule, ...args)
}
})
}
}else if(hook.mulit === false && hook.type === 'listener'){
if(typeof hook.listener === 'function'){
} else if (hook.mulit === false && hook.type === 'listener') {
if (typeof hook.listener === 'function') {
hook.listener.call(pluginModule, ...args);
}
}else if( hook.type === 'component'){
} else if (hook.type === 'component') {
return hook.listener;
}
}
if (config.plugins && Array.isArray(config.plugins)) {
config.plugins.forEach(plugin => {
let p = require(`plugins/yapi-plugin-${plugin}/client.js`);
p.call(pluginModule) ;
})
pluginModule = {
hooks: hooks,
bindHook: bindHook,
emitHook: emitHook
}
config.plugins.forEach(plugin => {
if (!plugin) return null;
if (!plugin.enable) return null;
if (plugin.client) {
let p = require(`plugins/yapi-plugin-${plugin.name}/client.js`);
p.call(pluginModule, plugin);
}
})
systemPlugins.forEach(plugin => {
let p = require(`exts/yapi-plugin-${plugin}/client.js`);
p.call(pluginModule) ;
if (!plugin) return null;
if (!plugin.enable) return null;
if (plugin.client) {
let p = require(`exts/yapi-plugin-${plugin.name}/client.js`);
p.call(pluginModule, plugin);
}
})
module.exports = pluginModule;

19
common/config.js Normal file
View File

@ -0,0 +1,19 @@
module.exports = {
exts: [
{
name: 'import-postman',
server: false,
client: true
},
{
name: 'import-har',
server: false,
client: true
},
{
name: 'advanced-mock',
server: true,
client: true
}
]
}

26
common/lib.js Normal file
View File

@ -0,0 +1,26 @@
const defaultPluginConfig = {
name: null,
server: true,
client: true,
enable: true
}
module.exports = {
initPlugins: function (plugins) {
if (!plugins) {
return [];
}
if (typeof plugins !== 'object' || !Array.isArray(plugins)) {
console.error('插件配置有误,请检查', plugins);
return [];
}
return plugins.map(item => {
if (item && typeof item === 'string') {
return Object.assign({}, defaultPluginConfig, { name: item })
} else if (item && typeof item === 'object') {
return Object.assign({}, defaultPluginConfig, item)
}
})
}
}

View File

@ -0,0 +1,118 @@
import React, { Component } from 'react'
// import { connect } from 'react-redux'
import axios from 'axios'
import PropTypes from 'prop-types'
import { withRouter } from 'react-router-dom';
import { Form, Switch, Button, message } from 'antd';
import mockEditor from 'client/containers/Project/Interface/InterfaceList/mockEditor';
const FormItem = Form.Item;
class AdvMock extends Component {
static propTypes = {
form: PropTypes.object,
match: PropTypes.object
}
constructor(props) {
super(props);
this.state = {
enable: false,
mock_script: ''
}
}
handleSubmit = (e) => {
e.preventDefault();
let projectId = this.props.match.params.id;
let interfaceId = this.props.match.params.actionId;
let params = {
project_id: projectId,
interface_id: interfaceId,
mock_script: this.state.mock_script,
enable: this.state.enable
}
axios.post('/api/plugin/advmock/save', params).then(res => {
if (res.data.errcode === 0) {
message.success('保存成功');
} else {
message.error(res.data.errmsg);
}
})
}
componentWillMount() {
this.getAdvMockData();
}
async getAdvMockData() {
let interfaceId = this.props.match.params.actionId;
let result = await axios.get('/api/plugin/advmock/get?interface_id=' + interfaceId);
if (result.data.errcode === 0) {
let mockData = result.data.data;
this.setState({
enable: mockData.enable,
mock_script: mockData.mock_script
})
}
let that = this;
mockEditor({
container: 'mock-script',
data: that.state.mock_script,
onChange: function (d) {
that.setState({
mock_script: d.text
})
}
})
}
onChange = (v) => {
this.setState({
enable: v
})
}
render() {
const formItemLayout = {
labelCol: {
sm: { span: 4 }
},
wrapperCol: {
sm: { span: 16 }
}
};
const tailFormItemLayout = {
wrapperCol: {
sm: {
span: 16,
offset: 11
}
}
};
return <div style={{ padding: '20px 10px' }}>
<Form onSubmit={this.handleSubmit}>
<FormItem
label="是否开启"
{...formItemLayout}
>
<Switch checked={this.state.enable} onChange={this.onChange} checkedChildren="开" unCheckedChildren="关" />
</FormItem>
<FormItem
label="Mock脚本"
{...formItemLayout}
>
<div id="mock-script" style={{ minHeight: '500px' }} ></div>
</FormItem>
<FormItem {...tailFormItemLayout}>
<Button type="primary" htmlType="submit">保存</Button>
</FormItem>
</Form>
</div>
}
}
module.exports = Form.create()(withRouter(AdvMock));

View File

@ -0,0 +1,10 @@
import AdvMock from './AdvMock.js'
module.exports = function(){
this.bindHook('interface_tab', function(tabs){
tabs.advMock = {
name: '高级Mock',
component: AdvMock
}
})
}

View File

@ -0,0 +1,54 @@
const baseController = require('controllers/base.js');
const advModel = require('./model.js');
const yapi = require('yapi.js');
class advMockController extends baseController{
constructor(ctx){
super(ctx);
this.Model = yapi.getInst(advModel);
}
async getMock(ctx){
let id = ctx.query.interface_id;
let mockData = await this.Model.get(id);
if(!mockData){
return ctx.body = yapi.commons.resReturn(null, 408, 'mock脚本不存在');
}
return ctx.body = yapi.commons.resReturn(mockData);
}
async upMock(ctx){
let params = ctx.request.body;
try{
if(!params.interface_id){
return yapi.commons.resReturn(null, 408, '缺少interface_id');
}
if(!params.project_id){
return yapi.commons.resReturn(null, 408, '缺少project_id');
}
if(!params.mock_script){
return yapi.commons.resReturn(null, 408, '缺少mock_script');
}
let data = {
interface_id: params.interface_id,
mock_script: params.mock_script,
project_id: params.project_id,
uid: this.getUid(),
enable: params.enable === true ? true : false
}
let result;
let mockData = await this.Model.get(data.interface_id);
if(mockData){
result = await this.Model.up(data);
}else{
result = await this.Model.save(data);
}
return ctx.body = yapi.commons.resReturn(result);
}catch(e){
return ctx.body = yapi.commons.resReturn(null, 400, e.message);
}
}
}
module.exports = advMockController;

View File

@ -0,0 +1,62 @@
const yapi = require('yapi.js');
const baseModel = require('models/base.js');
class advMockModel extends baseModel {
getName() {
return 'adv_mock';
}
getSchema() {
return {
interface_id: { type: Number, required: true },
project_id: {type: Number, required: true},
enable: {type: Boolean, default: false}, //1表示开启0关闭
mock_script: String,
uid: String,
up_time: Number
};
}
get(interface_id) {
return this.model.findOne({
interface_id: interface_id
});
}
delByInterfaceId(interface_id) {
console.log(interface_id);
return this.model.deleteOne({
interface_id: interface_id
});
}
delByProjectId(project_id){
return this.model.deleteMany({
project_id: project_id
})
}
save(data) {
data.up_time = yapi.commons.time();
let m = new this.model(data);
return m.save();
}
up(data) {
data.up_time = yapi.commons.time();
return this.model.update({
interface_id: data.interface_id
}, {
uid: data.uid,
up_time: data.up_time,
mock_script: data.mock_script,
enable: data.enable
}, {
upsert: true
})
}
}
module.exports = advMockModel;

View File

@ -0,0 +1,61 @@
const controller = require('./controller');
const advModel = require('./model.js');
const yapi = require('yapi.js');
module.exports = function(){
this.bindHook('add_router', function(addRouter){
addRouter({
controller: controller,
method: 'get',
path: 'advmock/get',
action: 'getMock'
})
addRouter({
controller: controller,
method: 'post',
path: 'advmock/save',
action: 'upMock'
})
})
this.bindHook('interface_del', async function(id){
let inst = yapi.getInst(advModel);
await inst.delByInterfaceId(id);
})
this.bindHook('project_del', async function(id){
let inst = yapi.getInst(advModel);
await inst.delByProjectId(id);
})
/**
* let context = {
projectData: project,
interfaceData: interfaceData,
ctx: ctx,
mockJson: res
}
*/
this.bindHook('mock_after', async function(context){
let interfaceId = context.interfaceData._id;
let inst = yapi.getInst(advModel);
let data = await inst.get(interfaceId);
if(!data || !data.enable || !data.mock_script){
return context;
}
let script = data.mock_script;
let sandbox = {
header: context.ctx.header,
query: context.ctx.query,
body: context.ctx.request.body,
mockJson: context.mockJson
}
sandbox.cookie = {};
context.ctx.header.cookie && context.ctx.header.cookie.split(';').forEach(function( Cookie ) {
var parts = Cookie.split('=');
sandbox.cookie[ parts[ 0 ].trim() ] = ( parts[ 1 ] || '' ).trim();
});
sandbox = yapi.commons.sandbox(sandbox, script);
context.mockJson = sandbox.mockJson;
})
}

View File

@ -1,3 +1,3 @@
{
"watch": ["server/", "common/", "plugins"]
"watch": ["server/", "common/", "plugins", "exts/"]
}

View File

@ -1,22 +1,25 @@
process.env.NODE_PATH = __dirname;
require('module').Module._initPaths();
const yapi = require('./yapi.js');
const commons = require('./utils/commons');
yapi.commons = commons;
const dbModule = require('./utils/db.js');
const mockServer = require('./middleware/mockServer.js');
const plugins = require('./plugin.js');
const websockify = require('koa-websocket');
const websocket = require('./websocket.js');
const Koa = require('koa');
const koaStatic = require('koa-static');
const bodyParser = require('koa-bodyparser');
const router = require('./router.js');
const websockify = require('koa-websocket');
const websocket = require('./websocket.js');
const plugins = require('./plugin.js');
let indexFile = process.argv[2] === 'dev' ? 'dev.html' : 'index.html';
yapi.connect = dbModule.connect();
const app = websockify(new Koa());
yapi.app = app;
plugins();
app.use(mockServer);
app.use(bodyParser({multipart: true}));
app.use(router.routes());

View File

@ -24,7 +24,8 @@ class baseController {
'/api/user/login',
'/api/user/reg',
'/api/user/status',
'/api/user/logout'
'/api/user/logout',
'/api/user/avatar'
];
if (ignoreRouter.indexOf(ctx.path) > -1) {
this.$auth = true;

View File

@ -228,6 +228,9 @@ class interfaceController extends baseController {
async list(ctx) {
let project_id = ctx.request.query.project_id;
let project = await this.projectModel.getBaseInfo(project_id);
if(!project){
return ctx.body = yapi.commons.resReturn(null, 407, '不存在的项目');
}
if (project.project_type === 'private') {
if (await this.checkAuth(project._id, 'project', 'edit') !== true) {
return ctx.body = yapi.commons.resReturn(null, 406, '没有权限');
@ -516,6 +519,7 @@ class interfaceController extends baseController {
let inter = await this.Model.get(id);
let result = await this.Model.del(id);
yapi.emitHook('interface_del', id).then();
await this.caseModel.delByInterfaceId(id);
let username = this.getUsername();
this.catModel.get(inter.catid).then((cate) => {
@ -664,7 +668,17 @@ class interfaceController extends baseController {
username: username,
typeid: catData.project_id
});
let interfaceData = await this.Model.listByCatid(id);
interfaceData.forEach(async item=>{
try{
yapi.emitHook('interface_del', item._id).then();
await this.caseModel.delByInterfaceId(item._id);
}catch(e){
yapi.commons.log(e.message, 'error');
}
})
await this.catModel.del(id);
let r = await this.Model.delByCatid(id);
return ctx.body = yapi.commons.resReturn(r);

View File

@ -403,7 +403,7 @@ class projectController extends baseController {
await interfaceInst.delByProjectId(id)
await interfaceCaseInst.delByProjectId(id)
await interfaceColInst.delByProjectId(id)
yapi.emitHook('project_del', id).then();
let result = await this.Model.del(id);
ctx.body = yapi.commons.resReturn(result);
} catch (err) {

View File

@ -125,20 +125,28 @@ module.exports = async (ctx, next) => {
ctx.set("Access-Control-Allow-Origin", "*")
if (interfaceData.res_body_type === 'json') {
try {
const res = mockExtra(
let res = mockExtra(
yapi.commons.json_parse(interfaceData.res_body),
{
query: ctx.request.query,
body: ctx.request.body
}
);
return ctx.body = Mock.mock(res);
res = Mock.mock(res);
let context = {
projectData: project,
interfaceData: interfaceData,
ctx: ctx,
mockJson: res
}
await yapi.emitHook('mock_after', context);
return ctx.body = context.mockJson;
} catch (e) {
yapi.commons.log(e, 'error')
return ctx.body = {
errcode: 400,
errmsg: 'mock json数据格式有误',
data: interfaceData.res_body
errmsg: '解析出错请检查。Error: '+ e.message,
data: null
}
}
}

View File

@ -1,6 +1,5 @@
const yapi = require('../yapi.js');
const baseModel = require('./base.js');
// const userModel = require('../models/user.js');
class avatarModel extends baseModel {
getName() {

View File

@ -131,11 +131,10 @@ class interfaceModel extends baseModel {
.exec();
}
listByCatid(catid, select){
select = select || '_id title uid path method project_id catid edit_uid status desc add_time up_time'
listByCatid(catid){
return this.model.find({
catid: catid
}).select(select).exec();
}).exec();
}
del(id) {

View File

@ -1,60 +1,124 @@
const yapi = require('./yapi.js');
const plugin_path = yapi.path.join(yapi.WEBROOT, 'plugins')
const plugin_path = yapi.path.join(yapi.WEBROOT, 'plugins');
const plugin_system_path = yapi.path.join(yapi.WEBROOT, 'exts');
const initPlugins = require('../common/lib.js').initPlugins;
var extConfig = require('../common/config.js').exts;
var hooks = {
'third_login': {
type: 'single',
listener: null
},
'add_interface': {
type: 'mulit',
listener: []
}
//第三方sso登录钩子暂只支持设置一个
'third_login': {
type: 'single',
listener: null
},
//增加接口成功后触发
'interface_add': {
type: 'multi',
listener: []
},
//删除接口成功后触发
'interface_del': {
type: 'multi',
listener: []
},
'project_add':{
type: 'multi',
listener: []
},
'project_del':{
type: 'multi',
listener: []
},
//MockServer生成mock数据后触发
mock_after: {
type: 'multi',
listener: []
},
//增加路由的钩子
add_router: {
type: 'multi',
listener: []
}
};
function bindHook(name, listener){
if(!name) throw new Error('缺少hookname');
if(name in hooks === false){
throw new Error('不存在的hookname');
}
if(hooks[name].type === 'multi'){
hooks[name].listener.push(listener);
}else{
hooks[name].listener = listener;
}
function bindHook(name, listener) {
if (!name) throw new Error('缺少hookname');
if (name in hooks === false) {
throw new Error('不存在的hookname');
}
if (hooks[name].type === 'multi') {
hooks[name].listener.push(listener);
} else {
if (typeof hooks[name].listener === 'function') {
throw new Error('重复绑定singleHook(' + name + '), 请检查');
}
hooks[name].listener = listener;
}
}
function emitHook(name){
if(!name) throw new Error('缺少hookname');
if(name in hooks === false){
throw new Error('不存在的hookname');
}
if(hooks[name] && typeof hooks[name] === 'object'){
if(hooks[name].type === 'single' && typeof hooks[name].listener === 'function'){
return hooks[name].listener.apply(yapi, Array.prototype.slice.call(arguments, 1));
}
if(Array.isArray(hooks[name.listener])){
hooks[name].listener.forEach(listener=>{
listener.apply(yapi, Array.prototype.slice.call(arguments,1))
})
}
}
async function emitHook(name) {
if (hooks[name] && typeof hooks[name] === 'object') {
let args = Array.prototype.slice.call(arguments, 1);
if (hooks[name].type === 'single' && typeof hooks[name].listener === 'function') {
return await hooks[name].listener.apply(yapi, args);
}
if (Array.isArray(hooks[name].listener)) {
let listenerList = hooks[name].listener;
for(let i=0, l = listenerList.length; i< l; i++){
await listenerList[i].apply(yapi, args);
}
}
}
}
function emitHookSync(name) {
if (hooks[name] && typeof hooks[name] === 'object') {
let args = Array.prototype.slice.call(arguments, 1);
if (hooks[name].type === 'single' && typeof hooks[name].listener === 'function') {
return hooks[name].listener.apply(yapi, args);
}
if (Array.isArray(hooks[name].listener)) {
hooks[name].listener.forEach((listener) => {
listener.apply(yapi, args)
})
}
}
}
yapi.bindHook = bindHook;
yapi.emitHook = emitHook;
yapi.emitHookSync = emitHookSync;
module.exports = function(){
if(yapi.WEBCONFIG.plugins && Array.isArray(yapi.WEBCONFIG.plugins)){
yapi.WEBCONFIG.plugins.forEach(plugin=>{
if(!yapi.commons.fileExist(yapi.path.join(plugin_path, 'yapi-plugin-' + plugin + '/server.js'))){
console.error(`config.json配置了插件${plugin},但plugins目录没有找到此插件请安装此插件?`);
let pluginsConfig = initPlugins(yapi.WEBCONFIG.plugins);
pluginsConfig.forEach(plugin => {
if (!plugin || plugin.enable === false || plugin.server === false) return null;
if (!yapi.commons.fileExist(yapi.path.join(plugin_path, 'yapi-plugin-' + plugin.name + '/server.js'))) {
console.error(`config.json配置了插件${plugin},但plugins目录没有找到此插件请安装此插件`);
process.exit();
}
let pluginModule = require(yapi.path.join(plugin_path, 'yapi-plugin-' + plugin + '/server.js'));
pluginModule.apply(yapi)
})
}
}
}
let pluginModule = require(yapi.path.join(plugin_path, 'yapi-plugin-' + plugin.name + '/server.js'));
pluginModule.call(yapi, plugin)
})
extConfig = initPlugins(extConfig);
extConfig.forEach(plugin => {
if (!plugin || plugin.enable === false || plugin.server === false) return null;
if (!yapi.commons.fileExist(yapi.path.join(plugin_system_path, 'yapi-plugin-' + plugin.name + '/server.js'))) {
console.error(`config.json配置了插件${plugin},但plugins目录没有找到此插件请安装此插件`);
process.exit();
}
let pluginModule = require(yapi.path.join(plugin_system_path, 'yapi-plugin-' + plugin.name + '/server.js'));
pluginModule.call(yapi, plugin)
yapi.commons.log('init plugins success...')
})
//delete bindHook方法避免误操作
delete yapi.bindHook

View File

@ -19,7 +19,7 @@ const authLevel = {
guest:100
}
const INTERFACE_CONFIG = {
let INTERFACE_CONFIG = {
interface: {
prefix: '/interface/',
controller: interfaceController
@ -50,7 +50,7 @@ const INTERFACE_CONFIG = {
}
};
const routerConfig = {
let routerConfig = {
"group": [
{
"action": "list",
@ -350,23 +350,42 @@ const routerConfig = {
]
}
let pluginsRouterPath = [];
function addPluginRouter(config){
if(!config.path || !config.controller || !config.action){
throw new Error('Plugin Route config Error');
}
let method = config.method || 'GET';
let routerPath = '/plugin/' + config.path;
if(pluginsRouterPath.indexOf(routerPath) > -1){
throw new Error('Plugin Route path conflict, please try rename the path')
}
pluginsRouterPath.push(routerPath);
createAction(config.controller, config.action, routerPath, method);
}
yapi.emitHookSync('add_router', addPluginRouter);
for(let ctrl in routerConfig){
let actions = routerConfig[ctrl];
actions.forEach( (item) => {
createAction(ctrl, item.action, item.path, item.method);
let routerController = INTERFACE_CONFIG[ctrl].controller;
let routerPath = INTERFACE_CONFIG[ctrl].prefix + item.path;
createAction(routerController, item.action, routerPath, item.method);
} )
}
/**
*
* @param {*} controller controller_name
* @param {*} path request_path
* @param {*} routerController controller
* @param {*} path routerPath
* @param {*} method request_method , post get put delete ...
* @param {*} action controller_action_name
* @param {*} action controller action_name
*/
function createAction(controller, action, path, method) {
router[method]("/api" + INTERFACE_CONFIG[controller].prefix + path, async (ctx) => {
let inst = new INTERFACE_CONFIG[controller].controller(ctx);
function createAction(routerController, action, path, method) {
router[method]("/api" + path, async (ctx) => {
let inst = new routerController(ctx);
await inst.init(ctx);

View File

@ -172,6 +172,15 @@ exports.verifyPath = (path) => {
}
};
exports.sandbox = (sandbox, script) => {
const vm = require('vm');
sandbox = sandbox || {};
script = new vm.Script(script);
const context = new vm.createContext(sandbox);
script.runInContext(context);
return sandbox;
}
function trim(str) {
if (!str) {
return str;
@ -241,7 +250,7 @@ exports.saveLog = (logData) => {
logInst.save(data).then(
);
} catch(e) {
} catch (e) {
yapi.commons.log(e, 'error'); // eslint-disable-line
}
};