mirror of
https://github.com/YMFE/yapi.git
synced 2024-12-09 05:00:30 +08:00
fix: merge interface.scss文件解决冲突
This commit is contained in:
commit
822ed6ba6d
@ -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": [
|
||||
|
@ -31,7 +31,6 @@
|
||||
"/fekit_modules/*",
|
||||
"/node_modules/*",
|
||||
"/bower_components/*",
|
||||
"/plugins/*",
|
||||
"/dev/*",
|
||||
"/prd/*"
|
||||
]
|
||||
|
@ -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")
|
||||
|
@ -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>
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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">
|
||||
|
@ -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}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
19
common/config.js
Normal 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
26
common/lib.js
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
118
exts/yapi-plugin-advanced-mock/AdvMock.js
Normal file
118
exts/yapi-plugin-advanced-mock/AdvMock.js
Normal 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));
|
10
exts/yapi-plugin-advanced-mock/client.js
Normal file
10
exts/yapi-plugin-advanced-mock/client.js
Normal 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
|
||||
}
|
||||
})
|
||||
}
|
54
exts/yapi-plugin-advanced-mock/controller.js
Normal file
54
exts/yapi-plugin-advanced-mock/controller.js
Normal 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;
|
62
exts/yapi-plugin-advanced-mock/model.js
Normal file
62
exts/yapi-plugin-advanced-mock/model.js
Normal 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;
|
61
exts/yapi-plugin-advanced-mock/server.js
Normal file
61
exts/yapi-plugin-advanced-mock/server.js
Normal 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;
|
||||
})
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
{
|
||||
"watch": ["server/", "common/", "plugins"]
|
||||
"watch": ["server/", "common/", "plugins", "exts/"]
|
||||
}
|
@ -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());
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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) {
|
||||
|
156
server/plugin.js
156
server/plugin.js
@ -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
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user