Merge branch 'dev' of gitlab.corp.qunar.com:mfe/yapi into dev

This commit is contained in:
sean 2017-08-10 18:54:35 +08:00
commit 87220f2182
38 changed files with 2664 additions and 401 deletions

16
.tags
View File

@ -254,11 +254,6 @@ static.form /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroup
render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/ProjectList/UpDateModal.js /^ render() {$/;" function line:152
validator /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/ProjectList/UpDateModal.js /^ validator(rule, value, callback) {$/;" function line:191
validator /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/ProjectList/UpDateModal.js /^ validator(rule, value, callback) {$/;" function line:224
constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ constructor(props) {$/;" function line:27
state.login /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ this.state = {$/;" property line:29
static.checkLoginState /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ static propTypes = {$/;" property line:34
componentDidMount /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ componentDidMount() {$/;" function line:39
render /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ render() {$/;" function line:72
createStore /Users/qitmac000445/Desktop/YAPI/yapi/client/reducer/create.js /^export default function createStore(initialState = {}) {$/;" function line:8
module.exports.parser /Users/qitmac000445/Desktop/YAPI/yapi/client/.eslintrc.js /^module.exports = {$/;" property line:1
module.exports.extends /Users/qitmac000445/Desktop/YAPI/yapi/client/.eslintrc.js /^ parser: 'babel-eslint',$/;" property line:2
@ -411,3 +406,14 @@ inputNewGroupDesc /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Projec
selectGroup /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ selectGroup(e) {$/;" function line:151
searchGroup /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ searchGroup(e, value) {$/;" function line:175
render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ render () {$/;" function line:185
constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Group/Group.js /^ constructor(props) {$/;" function line:10
render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Group/Group.js /^ render () {$/;" function line:14
from.children /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Project/Project.js /^ static propTypes = {$/;" property line:6
constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Project/Project.js /^ constructor(props) {$/;" function line:13
componentWillMount /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Project/Project.js /^ componentWillMount() {$/;" function line:17
render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Project/Project.js /^ render () {$/;" function line:20
constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ constructor(props) {$/;" function line:26
state.login /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ this.state = {$/;" property line:28
static.checkLoginState /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ static propTypes = {$/;" property line:33
componentDidMount /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ componentDidMount() {$/;" function line:38
render /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ render() {$/;" function line:71

21
.tags1
View File

@ -4,19 +4,8 @@
!_TAG_PROGRAM_NAME Exuberant Ctags //
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
!_TAG_PROGRAM_VERSION 5.8 //
from.groupList /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ static propTypes = {$/;" property line:35
state.addGroupModalVisible /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ state = {$/;" property line:46
state.editGroupModalVisible /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ addGroupModalVisible: false,$/;" property line:47
state.newGroupName /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ editGroupModalVisible: false,$/;" property line:48
state.newGroupDesc /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ newGroupName: '',$/;" property line:49
state.currGroupName /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ newGroupDesc: '',$/;" property line:50
state.currGroupDesc /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ currGroupName: '',$/;" property line:51
state.groupList /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ currGroupDesc: '',$/;" property line:52
constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ constructor(props) {$/;" function line:56
showModal /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ showModal(type) {$/;" function line:80
hideModal /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ hideModal(type) {$/;" function line:95
inputNewGroupName /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ inputNewGroupName(e, type) {$/;" function line:134
inputNewGroupDesc /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ inputNewGroupDesc(e, type) {$/;" function line:142
selectGroup /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ selectGroup(e) {$/;" function line:151
searchGroup /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ searchGroup(e, value) {$/;" function line:175
render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ render () {$/;" function line:185
constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ constructor(props) {$/;" function line:26
state.login /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ this.state = {$/;" property line:28
static.checkLoginState /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ static propTypes = {$/;" property line:33
componentDidMount /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ componentDidMount() {$/;" function line:38
render /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ render() {$/;" function line:71

View File

@ -2,7 +2,7 @@ import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { Route, HashRouter, Redirect, Switch } from 'react-router-dom';
import { Home, ProjectGroups, Interface, News, AddInterface, Follows } from './containers/index';
import { Home, Group, Project, News, AddInterface, Follows, AddProject } from './containers/index';
import User from './containers/User/User.js';
import Header from './components/Header/Header';
import Footer from './components/Footer/Footer';
@ -52,13 +52,14 @@ export default class App extends Component {
<Route path="/" component={Home} exact />
<Switch>
<Redirect exact from='/group' to='/group/1' />
<Route exact path="/group/:groupName" component={requireAuthentication(ProjectGroups)} />
<Route exact path="/group/:groupName" component={requireAuthentication(Group)} />
</Switch>
<Route path="/project" component={requireAuthentication(Interface)} />
<Route path="/project" component={requireAuthentication(Project)} />
<Route path="/user" component={requireAuthentication(User)} />
<Route path="/news" component={requireAuthentication(News)} />
<Route path="/add-interface" component={requireAuthentication(AddInterface)} />
<Route path="/follow" component={requireAuthentication(Follows)} />
<Route path="/add-project" component={requireAuthentication(AddProject)} />
</div>
<Footer />
</div>

View File

@ -44,7 +44,7 @@ const ToolUser = (props)=> (
<li className="toolbar-li item-search">
<Srch groupList={props.groupList}/>
</li>
<Link to="/">
<Link to="/add-project">
<Tooltip placement="bottom" title={'新建项目'}>
<li className="toolbar-li">
<Icon className="dropdown-link" style={{ fontSize: 16 }} type="plus-circle" />

View File

@ -0,0 +1,28 @@
import './ProjectBox.scss'
import React, { Component } from 'react'
// import PropTypes from 'prop-types'
class ProjectBox extends Component {
constructor(props) {
super(props);
this.state = {
};
}
static propTypes = {
}
render() {
return (
<div className="p-box">
<div className="p-container"></div>
</div>
)
}
}
export default ProjectBox

View File

@ -0,0 +1,21 @@
@import '../../styles/mixin.scss';
.p-box{
min-width: 150px;
min-height: 200px;
// background-color: #dbd;
.p-container{
width: 100%;
height: 100%;
background: #fff;
border-radius: 2px;
font-size: 12px;
position: relative;
-webkit-transition: all .3s;
transition: all .3s;
&:hover{
box-shadow: 0 1px 6px rgba(0,0,0,.2);
border-color: transparent;
}
}
}

View File

@ -1,6 +1,7 @@
import React, { Component } from 'react';
import './Follows.scss';
import Subnav from '../../components/Subnav/Subnav.js';
import ProjectBox from '../../components/ProjectBox/ProjectBox.js';
class Follows extends Component {
render () {
@ -16,7 +17,14 @@ class Follows extends Component {
path: '/follow'
}]}/>
<div className="g-row">
我的关注页
<div className="follow-box">
<div className="follow-container">
<ProjectBox />
<ProjectBox />
<ProjectBox />
<ProjectBox />
</div>
</div>
</div>
</div>
)

View File

@ -1 +1,12 @@
@import '../../styles/common.scss';
.follow-box{
padding: 24px;
background-color: #FFF;
.follow-container{
display: flex;
display: -webkit-flex;
}
}

View File

@ -4,9 +4,9 @@ import ProjectList from './ProjectList/ProjectList.js';
import Subnav from '../../components/Subnav/Subnav.js';
import { Row, Col } from 'antd';
import './ProjectGroups.scss'
import './Group.scss'
export default class ProjectGroups extends Component {
export default class Group extends Component {
constructor(props) {
super(props)
}

View File

@ -0,0 +1,274 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Button, Form, Input, Icon, Tooltip, Select, message } from 'antd';
import { addProject, fetchProjectList, delProject, changeUpdateModal, changeTableLoading } from '../../../reducer/modules/project';
// import { Link } from 'react-router-dom'
// import variable from '../../../constants/variable';
// import common from '../../../common';
import { autobind } from 'core-decorators';
const { TextArea } = Input;
const FormItem = Form.Item;
const Option = Select.Option;
import './Addproject.scss'
// 确认删除项目 handleDelete, currGroup._id, fetchProjectList
// const deleteConfirm = (id, props) => {
// const { delProject, currGroup, fetchProjectList } = props;
// const handle = () => {
// delProject(id).then((res) => {
// if (res.payload.data.errcode == 0) {
// message.success('删除成功!')
// fetchProjectList(currGroup._id).then(() => {
// });
// } else {
// message.error(res.payload.data.errmsg);
// }
// });
// }
// return handle;
// };
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 6 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 14 }
}
};
@connect(
state => {
return {
projectList: state.project.projectList,
userInfo: state.project.userInfo,
tableLoading: state.project.tableLoading,
currGroup: state.group.currGroup,
total: state.project.total,
currPage: state.project.currPage
}
},
{
fetchProjectList,
addProject,
delProject,
changeUpdateModal,
changeTableLoading
}
)
class ProjectList extends Component {
constructor(props) {
super(props);
this.state = {
visible: false,
protocol: 'http:\/\/',
projectData: []
}
}
static propTypes = {
form: PropTypes.object,
fetchProjectList: PropTypes.func,
addProject: PropTypes.func,
delProject: PropTypes.func,
changeUpdateModal: PropTypes.func,
changeTableLoading: PropTypes.func,
projectList: PropTypes.array,
userInfo: PropTypes.object,
tableLoading: PropTypes.bool,
currGroup: PropTypes.object,
total: PropTypes.number,
currPage: PropTypes.number
}
// 显示模态框 - 创建项目
@autobind
showAddProjectModal() {
this.setState({
visible: true
});
}
// 确认添加项目
@autobind
handleOk(e) {
const { form, currGroup, changeTableLoading, addProject, fetchProjectList } = this.props;
const that = this;
e.preventDefault();
form.validateFields((err, values) => {
if (!err) {
values.protocol = this.state.protocol.split(':')[0];
// 获取当前分组id传入values
values.group_id = currGroup._id;
changeTableLoading(true);
addProject(values).then((res) => {
// 添加项目成功后再次请求列表
if (res.payload.data.errcode == 0) {
that.setState({
visible: false
});
form.resetFields();
message.success('创建成功! ');
fetchProjectList(currGroup._id, this.props.currPage).then(() => {
changeTableLoading(false);
});
} else {
changeTableLoading(false);
message.error(res.payload.data.errmsg);
}
}).catch(() => {
changeTableLoading(false);
});
}
});
}
// 取消修改
@autobind
handleCancel() {
this.props.form.resetFields();
this.setState({
visible: false
});
}
// 修改线上域名的协议类型 (http/https)
@autobind
protocolChange(value) {
this.setState({
protocol: value
})
}
// 分页逻辑
@autobind
paginationChange(pageNum) {
this.props.fetchProjectList(this.props.currGroup._id, pageNum).then((res) => {
if (res.payload.data.errcode) {
message.error(res.payload.data.errmsg);
} else {
this.props.changeTableLoading(false);
}
});
}
componentWillReceiveProps(nextProps) {
// 切换分组
if (this.props.currGroup !== nextProps.currGroup) {
if (nextProps.currGroup._id) {
this.props.fetchProjectList(nextProps.currGroup._id, this.props.currPage).then((res) => {
if (res.payload.data.errcode) {
message.error(res.payload.data.errmsg);
} else {
this.props.changeTableLoading(false);
}
});
} else {
// 无分组的时候停止loading状态
this.props.changeTableLoading(false);
}
}
// 切换项目列表
if (this.props.projectList !== nextProps.projectList) {
// console.log(nextProps.projectList);
const data = nextProps.projectList.map((item, index) => {
item.key = index;
return item;
});
this.setState({
projectData: data
});
}
}
render() {
const { getFieldDecorator } = this.props.form;
return (
<div className="g-row m-container">
<Form>
<FormItem
{...formItemLayout}
label="项目名称"
>
{getFieldDecorator('name', {
rules: [{
required: true, message: '请输入项目名称!'
}]
})(
<Input />
)}
</FormItem>
<FormItem
{...formItemLayout}
label={(
<span>
线上域名&nbsp;
<Tooltip title="将根据配置的线上域名访问mock数据">
<Icon type="question-circle-o" />
</Tooltip>
</span>
)}
>
{getFieldDecorator('prd_host', {
rules: [{
required: true,
message: '请输入项目线上域名!'
}]
})(
<Input addonBefore={(
<Select defaultValue="http://" onChange={this.protocolChange}>
<Option value="http://">{'http:\/\/'}</Option>
<Option value="https://">{'https:\/\/'}</Option>
</Select>)} />
)}
</FormItem>
<FormItem
{...formItemLayout}
label={(
<span>
基本路径&nbsp;
<Tooltip title="基本路径为空是根路径">
<Icon type="question-circle-o" />
</Tooltip>
</span>
)}
>
{getFieldDecorator('basepath', {
rules: [{
required: false, message: '请输入项目基本路径'
}]
})(
<Input />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="描述"
>
{getFieldDecorator('desc', {
rules: [{
required: false, message: '请输入描述!'
}]
})(
<TextArea rows={4} />
)}
</FormItem>
</Form>
<Button className="m-btn" icon="plus" type="primary"
onClick={this.showAddProjectModal}
disabled={this.props.currGroup._id ? false : true}>创建项目</Button>
</div>
);
}
}
export default Form.create()(ProjectList);

View File

@ -0,0 +1,6 @@
@import '../../../styles/common.scss';
.m-container {
margin: .24rem auto !important;
padding: .24rem !important;
}

View File

@ -0,0 +1,28 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
export default class GroupList extends Component {
static propTypes = {
children: PropTypes.element
}
state = {
}
constructor(props) {
super(props)
}
componentWillMount() {
}
render () {
return (
<div>
我是项目页喔
{this.props.children}
</div>
)
}
}

View File

@ -1,21 +1,25 @@
import Header from '../components/Header/Header.js'
import Home from './Home/Home.js'
import Login from './Login/LoginWrap.js'
import ProjectGroups from './ProjectGroups/ProjectGroups.js'
import Group from './Group/Group.js'
import Interface from './Interface/Interface.js'
import Project from './Project/Project.js'
import News from './News/News.js'
import AddInterface from './AddInterface/AddInterface.js'
import DevTools from './DevTools/DevTools.js'
import Follows from './Follows/Follows.js'
import AddProject from './Project/AddProject/AddProject.js'
export {
Header,
Home,
Login,
ProjectGroups,
Group,
Interface,
Project,
AddInterface,
News,
DevTools,
Follows
Follows,
AddProject
}

View File

@ -95,7 +95,6 @@ export function addProject(data) {
};
return {
type: PROJECT_ADD,
// payload 可以返回 Promise异步请求使用 axios 即可
payload: axios.post('/project/add', param)
};
}
@ -113,7 +112,6 @@ export function updateProject(data) {
};
return {
type: PROJECT_UPDATE,
// payload 可以返回 Promise异步请求使用 axios 即可
payload: axios.post('/project/up', param)
};
}
@ -122,7 +120,6 @@ export function delProject(id) {
const param = { id };
return {
type: PROJECT_DEL,
// payload 可以返回 Promise异步请求使用 axios 即可
payload: axios.post('/project/del', param)
};
}

View File

@ -1,24 +0,0 @@
import React from 'react'
import { Route, HashRouter } from 'react-router-dom'
import { Header, Home, ProjectGroups, Interface, News, AddInterface, Follows } from './containers/index'
import User from './containers/User/User.js'
export default () => {
return (
<HashRouter>
<div className="router-main">
<Header/>
<Route path="/" component={ Home } exact />
<Route path="/group" component={ ProjectGroups } >
<Route exact={false} path="/group/:groupName" component={ ProjectGroups } />
</Route>
<Route path="/project" component={ Interface } />
<Route path="/user" component={User} />
<Route path="/news" component={ News } />
<Route path="/add-interface" component={ AddInterface } />
<Route path="/follow" component={ Follows } />
</div>
</HashRouter>
)
}

View File

@ -61,6 +61,7 @@ em {
padding: 0 .24rem;
}
.nav-tooltip {
color: red;
.m-container {
margin: .24rem auto;
padding: .24rem;
}

View File

@ -23,16 +23,16 @@ class followController extends baseController {
}
/**
* 获取节点列表
* @interface /node/list
* 获取关注项目列表
* @interface /follow/list
* @method GET
* @category node
* @category follow
* @foldnumber 10
* @param {Number} uid 用户id 不能为空
* @param {Number} [page] 分页页码
* @param {Number} [limit] 分页大小
* @returns {Object}
* @example ./api/project/list.json
* @example /follow/list
*/
async list(ctx) {
@ -57,6 +57,18 @@ class followController extends baseController {
}
}
/**
* 取消关注
* @interface /follow/list
* @method POST
* @category follow
* @foldnumber 10
* @param {Number} id 关注id
* @returns {Object}
* @example /follow/del
*/
async del(ctx) {
let params = ctx.request.body;
@ -72,6 +84,20 @@ class followController extends baseController {
}
}
/**
* 添加关注
* @interface /follow/list
* @method POST
* @category follow
* @foldnumber 10
* @param {Number} uid 用户id
* @param {Number} projectid 项目id
* @param {String} projectname 项目名
* @param {String} icon 项目icon
* @returns {Object}
* @example /follow/add
*/
async add(ctx) {
let params = ctx.request.body;
params = yapi.commons.handleParams(params, {

View File

@ -27,16 +27,16 @@ class logController extends baseController {
}
/**
* 获取节点列表
* @interface /node/list
* 获取动态列表
* @interface /log/list
* @method GET
* @category node
* @category log
* @foldnumber 10
* @param {Number} uid 用户id 不能为空
* @param {Number} [page] 分页页码
* @param {Number} [limit] 分页大小
* @returns {Object}
* @example ./api/project/list.json
* @example /log/list
*/
async list(ctx) {

View File

@ -525,30 +525,60 @@ class projectController extends baseController {
* @param {String} project_id
*/
async download(ctx) {
const project_id = ctx.request.query.project_id;
let interfaceInst = yapi.getInst(interfaceModel);
let count = await interfaceInst.list(project_id);
console.log(count);
const arr = JSON.stringify(count.map(function(item) {
// 返回的json模板数据: item.res_body
const mockData = Mock.mock(
yapi.commons.json_parse(item.res_body)
);
return {
path: item.path,
mock: mockData
const project_id = ctx.request.query.project_id;
let interfaceInst = yapi.getInst(interfaceModel);
// 根据 project_id 获取接口数据
let count = await interfaceInst.list(project_id);
if (!project_id) {
return ctx.body = yapi.commons.resReturn(null, 405, '项目id不能为空');
} else if (!count) {
return ctx.body = yapi.commons.resReturn(null, 401, '项目id不存在');
}
}));
// console.log(arr);
const fileName = 'mock.js';
ctx.attachment(fileName);
await send(ctx, fileName, { root: __dirname + '/public' });
const arr = JSON.stringify(count.map(function(item) {
// 返回的json模板数据: item.res_body
const mockData = Mock.mock(
yapi.commons.json_parse(item.res_body)
);
return {
path: item.path,
mock: mockData
}
}));
const res = `
var data = ${arr}`
.trim();
return ctx.body = res;
const fileName = 'mock.js';
ctx.attachment(fileName);
await send(ctx, fileName, { root: __dirname + '/public' });
const res = `
var Mock = require('mockjs');
var xhook = require('xhook');
var data = ${arr};
function run() {
xhook.before(function(request, callback) {
setTimeout(function() {
var res;
data.forEach((item) => {
// 请求的接口在 data 中存在
if(request.url === item.path) {
res = {
status: 200,
text: Mock.mock(item.mock)
}
}
});
if (res) {
callback(res);
}else {
callback({ status: 405, text: '接口不存在' });
}
}, 500);
});
}
module.exports = run;`
.trim();
return ctx.body = res;
}
}

View File

@ -74,7 +74,6 @@ class interfaceModel extends baseModel {
}
list(project_id) {
console.log(project_id);
return this.model.find({
project_id: project_id
})

View File

@ -69,16 +69,16 @@ var followController = function (_baseController) {
}
/**
* 获取节点列表
* @interface /node/list
* 获取关注项目列表
* @interface /follow/list
* @method GET
* @category node
* @category follow
* @foldnumber 10
* @param {Number} uid 用户id 不能为空
* @param {Number} [page] 分页页码
* @param {Number} [limit] 分页大小
* @returns {Object}
* @example ./api/project/list.json
* @example /follow/list
*/
(0, _createClass3.default)(followController, [{
@ -140,6 +140,18 @@ var followController = function (_baseController) {
return list;
}()
/**
* 取消关注
* @interface /follow/list
* @method POST
* @category follow
* @foldnumber 10
* @param {Number} id 关注id
* @returns {Object}
* @example /follow/del
*/
}, {
key: 'del',
value: function () {
@ -190,6 +202,21 @@ var followController = function (_baseController) {
return del;
}()
/**
* 添加关注
* @interface /follow/list
* @method POST
* @category follow
* @foldnumber 10
* @param {Number} uid 用户id
* @param {Number} projectid 项目id
* @param {String} projectname 项目名
* @param {String} icon 项目icon
* @returns {Object}
* @example /follow/add
*/
}, {
key: 'add',
value: function () {

View File

@ -75,16 +75,16 @@ var logController = function (_baseController) {
}
/**
* 获取节点列表
* @interface /node/list
* 获取动态列表
* @interface /log/list
* @method GET
* @category node
* @category log
* @foldnumber 10
* @param {Number} uid 用户id 不能为空
* @param {Number} [page] 分页页码
* @param {Number} [limit] 分页大小
* @returns {Object}
* @example ./api/project/list.json
* @example /log/list
*/
(0, _createClass3.default)(logController, [{

View File

@ -1192,13 +1192,30 @@ var projectController = function (_baseController) {
case 0:
project_id = ctx.request.query.project_id;
interfaceInst = _yapi2.default.getInst(_interface2.default);
// 根据 project_id 获取接口数据
_context12.next = 4;
return interfaceInst.list(project_id);
case 4:
count = _context12.sent;
console.log(count);
if (project_id) {
_context12.next = 9;
break;
}
return _context12.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 405, '项目id不能为空'));
case 9:
if (count) {
_context12.next = 11;
break;
}
return _context12.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 401, '项目id不存在'));
case 11:
arr = (0, _stringify2.default)(count.map(function (item) {
// 返回的json模板数据: item.res_body
var mockData = _mockjs2.default.mock(_yapi2.default.commons.json_parse(item.res_body));
@ -1207,19 +1224,17 @@ var projectController = function (_baseController) {
mock: mockData
};
}));
// console.log(arr);
fileName = 'mock.js';
ctx.attachment(fileName);
_context12.next = 11;
_context12.next = 16;
return send(ctx, fileName, { root: __dirname + '/public' });
case 11:
res = ('\n var data = ' + arr).trim();
case 16:
res = ('\n var Mock = require(\'mockjs\');\n var xhook = require(\'xhook\');\n var data = ' + arr + ';\n function run() {\n xhook.before(function(request, callback) {\n setTimeout(function() {\n var res;\n data.forEach((item) => {\n // \u8BF7\u6C42\u7684\u63A5\u53E3\u5728 data \u4E2D\u5B58\u5728\n if(request.url === item.path) {\n res = {\n status: 200,\n text: Mock.mock(item.mock)\n }\n }\n });\n if (res) {\n callback(res);\n }else {\n callback({ status: 405, text: \'\u63A5\u53E3\u4E0D\u5B58\u5728\' });\n }\n }, 500);\n });\n }\n module.exports = run;').trim();
return _context12.abrupt('return', ctx.body = res);
case 13:
case 18:
case 'end':
return _context12.stop();
}

View File

@ -117,7 +117,6 @@ var interfaceModel = function (_baseModel) {
}, {
key: 'list',
value: function list(project_id) {
console.log(project_id);
return this.model.find({
project_id: project_id
}).sort({ _id: -1 }).exec();

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,10 @@
import yapi from '../yapi.js';
import projectModel from '../models/project.js';
import userModel from '../models/user.js';
import interfaceModel from '../models/interface.js'
import groupModel from '../models/group.js'
import _ from 'underscore'
const jwt = require('jsonwebtoken');
class baseController {
@ -87,7 +91,7 @@ class baseController {
async getLoginStatus(ctx) {
if (await this.checkLogin(ctx) === true) {
let result = yapi.commons.fieldSelect(this.$user, ['_id', 'username', 'email', 'up_time', 'add_time','role']);
let result = yapi.commons.fieldSelect(this.$user, ['_id', 'username', 'email', 'up_time', 'add_time', 'role']);
result.server_ip = yapi.WEBCONFIG.server_ip;
return ctx.body = yapi.commons.resReturn(result);
}
@ -98,44 +102,77 @@ class baseController {
return this.$user.role;
}
async jungeProjectAuth(id) {
let model = yapi.getInst(projectModel);
/**
*
* @param {*} id type对应的id
* @param {*} type enum[interface, project, group]
* @param {*} action enum[ danger , edit ] danger只有owner或管理员才能操作,edit只要是dev或以上就能执行
*/
async checkAuth(id, type, action) {
let result = {};
try {
if (this.getRole() === 'admin') {
return true;
}
if (type === 'interface') {
let interfaceInst = yapi.getInst(interfaceModel);
let interfaceData = await interfaceInst.get(id)
result.interfaceData = interfaceData;
if (interfaceData.uid === this.getUid()) {
return true;
}
type = 'project';
id = interfaceData.project_id;
}
if (this.getRole() === 'admin') {
return true;
}
if (type === 'project') {
let projectInst = yapi.getInst(projectModel);
let projectData = await projectInst.get(id);
if(projectData.uid === this.getUid()){
return true;
}
let memberData = _.find(projectData.members, (m) => {
if (m.uid === this.getUid()) {
return true;
}
})
if (memberData && memberData.role) {
if(action === 'danger' && memberData.role === 'owner'){
return true;
}
if(action === 'edit'){
return true;
}
}
type = 'group';
id = projectData.group_id
}
if (type === 'group') {
let groupInst = yapi.getInst(groupModel);
let groupData = await groupInst.get(id);
let groupMemberData = _.find(groupData.members, (m) => {
if (m.uid === this.getUid()) {
return true;
}
})
if (groupMemberData && groupMemberData.role) {
if(action === 'danger' && groupMemberData.role === 'owner'){
return true;
}
if(action === 'edit'){
return true;
}
}
}
if (!id) {
return false;
}
let result = await model.get(id);
if (result.uid === this.getUid()) {
return true;
}
return false;
}
async jungeMemberAuth(id, member_uid) {
let model = yapi.getInst(projectModel);
if (this.getRole() === 'admin') {
return true;
}
if (!id || !member_uid) {
catch (e) {
yapi.commons.log(e.message, 'error')
return false;
}
let result = await model.checkMemberRepeat(id, member_uid);
if (result > 0) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,213 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no" />
<title>YApi : ./server/controllers/follow.js</title>
<link type="text/css" rel="stylesheet" href="../../../source/code.css"/>
<script type="text/javascript" src="../../../source/shCore.js"></script>
<script type="text/javascript" src="../../../source/shBrush-js.js"></script>
<style>
.syntaxhighlighter .number1 .spaces,.syntaxhighlighter .toolbar{ display: none;}
.syntaxhighlighter table td.gutter .line.highlight { background-color: #6ce26c !important; color: white; }
</style>
</head>
<body>
<div class="ydoc">
<div class="ydoc-banner-bg">
<div class="ydoc-banner" id="content" tabindex="-1">
<div class="ydoc-banner-area">
<h1>YApi : ./server/controllers/follow.js</h1>
<p>源代码</p>
</div>
</div>
<div class="ydoc-container">
<div class="ydoc-container-content">
<div class="static-code-content" role="main">
<pre class="brush: js;">
import yapi from '../yapi.js';
import baseController from './base.js';
import followModel from '../models/follow';
class followController extends baseController {
constructor(ctx) {
super(ctx);
this.Model = yapi.getInst(followModel);
// try{
// var res = this.Model.save({
// uid: 107,
// projectid: 221,
// projectname: 'Flight',
// icon: 'code'
// });
// // var res = this.Model.del(107);
// ctx.body = yapi.commons.resReturn(null, 200,res);
// }catch(err){
// ctx.body = yapi.commons.resReturn(null, 402, err.message);
// }
}
/**
* 获取关注项目列表
* @interface /follow/list
* @method GET
* @category follow
* @foldnumber 10
* @param {Number} uid 用户id 不能为空
* @param {Number} [page] 分页页码
* @param {Number} [limit] 分页大小
* @returns {Object}
* @example /follow/list
*/
async list(ctx) {
let uid = ctx.request.query.uid,
page = ctx.request.query.page || 1,
limit = ctx.request.query.limit || 10;
if (!uid) {
return ctx.body = yapi.commons.resReturn(null, 400, '用户id不能为空');
}
try {
let result = await this.Model.listWithPaging(uid, page, limit);
let count = await this.Model.listCount(uid);
ctx.body = yapi.commons.resReturn({
total: Math.ceil(count / limit),
list: result
});
} catch (err) {
ctx.body = yapi.commons.resReturn(null, 402, err.message);
}
}
/**
* 取消关注
* @interface /follow/list
* @method POST
* @category follow
* @foldnumber 10
* @param {Number} id 关注id
* @returns {Object}
* @example /follow/del
*/
async del(ctx) {
let params = ctx.request.body;
if(params.followid){
return ctx.body = yapi.commons.resReturn(null, 400, '关注id不能为空');
}
try {
let result = await this.Model.del(params.id);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
/**
* 添加关注
* @interface /follow/list
* @method POST
* @category follow
* @foldnumber 10
* @param {Number} uid 用户id
* @param {Number} projectid 项目id
* @param {String} projectname 项目名
* @param {String} icon 项目icon
* @returns {Object}
* @example /follow/add
*/
async add(ctx) {
let params = ctx.request.body;
params = yapi.commons.handleParams(params, {
uid: 'number',
projectid: 'number',
projectname: 'string',
icon: 'string'
});
if (!params.uid) {
return ctx.body = yapi.commons.resReturn(null, 400, '用户id不为空');
}
if (!params.projectid) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
}
let checkRepeat = await this.Model.checkProjectRepeat(params.uid,params.projectid);
if (checkRepeat) {
return ctx.body = yapi.commons.resReturn(null, 401, '项目已关注');
}
if (!params.projectname) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目名不能为空');
}
if (!params.icon) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目图标标志不能为空');
}
let data = {
uid: params.uid,
projectid: params.projectid,
projectname: params.projectname,
icon: params.icon
};
try {
let result = await this.Model.save(data);
result = yapi.commons.fieldSelect(result, ['_id', 'uid', 'projectid', 'projectname', 'icon']);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
}
module.exports = followController;
</pre>
</div>
</div>
</div>
</div>
<!-- <div class="docs-header" id="content" tabindex="-1">
<div class="container">
<h1>YApi : ./server/controllers/follow.js</h1>
<p>源代码</p>
</div>
</div> -->
<footer class="docs-footer" role="contentinfo">
<div class="container">
<p></p>
</div>
</footer>
</div>
<script type="text/javascript">
SyntaxHighlighter.all();
function getTop(node){
return node.offsetTop + (node.offsetParent ? getTop(node.offsetParent) : 0);
}
document.addEventListener('DOMContentLoaded', function() {
setTimeout(function() {
try {
var lineNum = (parseInt(location.hash.replace(/#/g, '')) - 1) || 0,
node = document.querySelectorAll('div.line')[lineNum];
document.body.scrollTop = getTop(node);
node.className += ' highlight';
} catch(e) {}
}, 500);
}, false);
</script>
</body>
</html>

View File

@ -29,6 +29,7 @@
import yapi from '../yapi.js';
import baseController from './base.js';
import projectModel from '../models/project.js';
import userModel from '../models/user.js';
class groupController extends baseController {
constructor(ctx) {
@ -42,7 +43,8 @@ class groupController extends baseController {
* @category group
* @foldnumber 10
* @param {String} group_name 项目分组名称,不能为空
* @param {String} [group_desc] 项目分组描述
* @param {String} [group_desc] 项目分组描述
* @param {String} owner_uid 组长uid
* @returns {Object}
* @example ./api/group/add.json
*/
@ -51,7 +53,8 @@ class groupController extends baseController {
params = yapi.commons.handleParams(params, {
group_name: 'string',
group_desc: 'string'
group_desc: 'string',
owner_uid: 'number'
});
if (this.getRole() !== 'admin') {
@ -62,6 +65,14 @@ class groupController extends baseController {
return ctx.body = yapi.commons.resReturn(null, 400, '项目分组名不能为空');
}
if(!params.owner_uid){
return ctx.body = yapi.commons.resReturn(null, 400, '项目分组必须添加一个组长');
}
let groupUserdata = await this.getUserdata(params.owner_uid, 'owner');
if(groupUserdata === null){
return ctx.body = yapi.commons.resReturn(null, 400, '组长uid不存在')
}
let groupInst = yapi.getInst(groupModel);
let checkRepeat = await groupInst.checkRepeat(params.group_name);
@ -75,13 +86,14 @@ class groupController extends baseController {
group_desc: params.group_desc,
uid: this.getUid(),
add_time: yapi.commons.time(),
up_time: yapi.commons.time()
up_time: yapi.commons.time(),
members: [groupUserdata]
};
try {
let result = await groupInst.save(data);
result = yapi.commons.fieldSelect(result, ['_id', 'group_name', 'group_desc', 'uid']);
result = yapi.commons.fieldSelect(result, ['_id', 'group_name', 'group_desc', 'uid', 'members']);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
@ -89,6 +101,114 @@ class groupController extends baseController {
}
async getUserdata(uid, role){
role = role || 'dev';
let userInst = yapi.getInst(userModel);
let userData = await userInst.findById(uid);
if(!userData){
return null;
}
return {
role: role,
uid: userData._id,
username: userData.username,
email: userData.email
}
}
async addMember(ctx){
let params = ctx.request.body;
let groupInst = yapi.getInst(groupModel);
if (!params.member_uid) {
return ctx.body = yapi.commons.resReturn(null, 400, '分组成员uid不能为空');
}
if (!params.id) {
return ctx.body = yapi.commons.resReturn(null, 400, '分组id不能为空');
}
var check = await groupInst.checkMemberRepeat(params.id, params.member_uid);
if (check > 0) {
return ctx.body = yapi.commons.resReturn(null, 400, '成员已存在');
}
let groupUserdata = await this.getUserdata(params.member_uid);
if(groupUserdata === null){
return ctx.body = yapi.commons.resReturn(null, 400, '组长uid不存在')
}
try {
let result = await groupInst.addMember(params.id, groupUserdata);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
async changeMemberRole(ctx){
let params = ctx.request.body;
let groupInst = yapi.getInst(groupModel);
if (!params.member_uid) {
return ctx.body = yapi.commons.resReturn(null, 400, '分组成员uid不能为空');
}
if (!params.id) {
return ctx.body = yapi.commons.resReturn(null, 400, '分组id不能为空');
}
var check = await groupInst.checkMemberRepeat(params.id, params.member_uid);
if (check === 0) {
return ctx.body = yapi.commons.resReturn(null, 400, '分组成员不存在');
}
if (await this.checkAuth(id, 'group', 'danger') !== true) {
return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
}
params.role = params.role === 'owner' ? 'owner' : 'dev';
try {
let result = await groupInst.changeMemberRole(params.id, params.member_uid, params.role);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
async getMemberList(ctx) {
let params = ctx.request.query;
if (!params.id) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
}
try {
let groupInst = yapi.getInst(groupModel);
let group = await groupInst.get(params.id);
ctx.body = yapi.commons.resReturn(group.members);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
async delMember(ctx) {
let params = ctx.request.body;
let groupInst = yapi.getInst(groupModel);
if (!params.member_uid) {
return ctx.body = yapi.commons.resReturn(null, 400, '分组成员uid不能为空');
}
if (!params.id) {
return ctx.body = yapi.commons.resReturn(null, 400, '分组id不能为空');
}
var check = await groupInst.checkMemberRepeat(params.id, params.member_uid);
if (check === 0) {
return ctx.body = yapi.commons.resReturn(null, 400, '分组成员不存在');
}
if (await this.checkAuth(id, 'group', 'danger') !== true) {
return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
}
try {
let result = await groupInst.delMember(params.id, params.member_uid);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
/**
* 获取项目分组列表
* @interface /group/list
@ -158,12 +278,10 @@ class groupController extends baseController {
* @example ./api/group/up.json
*/
async up(ctx) {
if (this.getRole() !== 'admin') {
return ctx.body = yapi.commons.resReturn(null, 401, '没有权限');
if (await this.checkAuth(id, 'group', 'danger') !== true) {
return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
}
try {
ctx.request.body = yapi.commons.handleParams(ctx.request.body, {
id: 'number',
group_name: 'string',

View File

@ -0,0 +1,376 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no" />
<title>YApi : ./server/controllers/interfaceCol.js</title>
<link type="text/css" rel="stylesheet" href="../../../source/code.css"/>
<script type="text/javascript" src="../../../source/shCore.js"></script>
<script type="text/javascript" src="../../../source/shBrush-js.js"></script>
<style>
.syntaxhighlighter .number1 .spaces,.syntaxhighlighter .toolbar{ display: none;}
.syntaxhighlighter table td.gutter .line.highlight { background-color: #6ce26c !important; color: white; }
</style>
</head>
<body>
<div class="ydoc">
<div class="ydoc-banner-bg">
<div class="ydoc-banner" id="content" tabindex="-1">
<div class="ydoc-banner-area">
<h1>YApi : ./server/controllers/interfaceCol.js</h1>
<p>源代码</p>
</div>
</div>
<div class="ydoc-container">
<div class="ydoc-container-content">
<div class="static-code-content" role="main">
<pre class="brush: js;">
import interfaceColModel from '../models/interfaceCol.js';
import interfaceCaseModel from '../models/interfaceCase.js';
import baseController from './base.js';
import yapi from '../yapi.js';
class interfaceColController extends baseController{
constructor(ctx) {
super(ctx);
this.colModel = yapi.getInst(interfaceColModel);
this.caseModel = yapi.getInst(interfaceCaseModel);
}
/**
* 获取所有接口集
* @interface /col/list
* @method GET
* @category col
* @foldnumber 10
* @param {String} project_id email名称不能为空
* @returns {Object}
* @example
*/
async list(ctx){
try {
let id = ctx.query.project_id;
let inst = this.colModel(interfaceColModel);
let result = await inst.list(id);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
/**
* 增加接口集
* @interface /col/add_col
* @method POST
* @category col
* @foldnumber 10
* @param {Number} project_id
* @param {String} name
* @param {String} desc
* @returns {Object}
* @example
*/
async addCol(ctx){
try{
let params = ctx.request.body;
params = yapi.commons.handleParams(params, {
name: 'string',
project_id: 'number',
desc: 'string'
});
if (!params.project_id) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
}
if(!params.name){
return ctx.body = yapi.commons.resReturn(null, 400, '名称不能为空');
}
let result = await this.colModel.save({
name: params.name,
project_id: params.project_id,
desc: params.desc,
uid: this.getUid(),
add_time: yapi.commons.time(),
up_time: yapi.commons.time()
})
ctx.body = yapi.commons.resReturn(result);
}catch(e){
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
/**
* 获取一个接口集下的所有的接口用例
* @interface /col/case_list
* @method GET
* @category col
* @foldnumber 10
* @param {String} col_id 接口集id
* @returns {Object}
* @example
*/
async getCaseList(ctx){
try {
let id = ctx.query.col_id;
let inst = yapi.getInst(interfaceCaseModel);
let result = await inst.list(id);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
/**
* 增加一个接口用例
* @interface /col/add_case
* @method POST
* @category col
* @foldnumber 10
* @param {String} casename
* @param {Number} col_id
* @param {Number} project_id
* @param {String} env
* @param {String} domain
* @param {String} path
* @param {String} method
* @param {Object} req_query
* @param {Object} req_headers
* @param {String} req_body_type
* @param {Array} req_body_form
* @param {String} req_body_other
* @returns {Object}
* @example
*/
async addCase(ctx){
try{
let params = ctx.request.body;
params = yapi.commons.handleParams(params, {
casename: 'string',
project_id: 'number',
col_id: 'number',
env: 'string',
domain: 'string',
method: 'string'
});
if (!params.project_id) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
}
if (!params.col_id) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
}
if (!params.env) {
return ctx.body = yapi.commons.resReturn(null, 400, '缺少环境配置');
}
if (!params.path) {
return ctx.body = yapi.commons.resReturn(null, 400, 'path 不能为空');
}
if(!params.casename){
return ctx.body = yapi.commons.resReturn(null, 400, '用例名称不能为空');
}
params.uid = this.getUid();
params.index = 0;
params.add_time = yapi.commons.time();
params.up_time = yapi.commons.time();
let result = await this.caseModel.save(params);
ctx.body = yapi.commons.resReturn(result);
}catch(e){
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
/**
* 获取一个接口用例详情
* @interface /col/case
* @method GET
* @category col
* @foldnumber 10
* @param {String} caseid
* @returns {Object}
* @example
*/
async getCase(ctx){
try{
let id = ctx.query.caseid;
let result = await this.caseModel.get(id);
ctx.body = yapi.commons.resReturn(result);
}catch(e){
ctx.body = yapi.commons.resReturn(null, 400, e.message)
}
}
/**
* 更新一个接口集name或描述
* @interface /col/up_col
* @method POST
* @category col
* @foldnumber 10
* @param {String} name
* @param {String} desc
* @returns {Object}
* @example
*/
async upCol(ctx){
try{
let params = ctx.request.body;
let result = await this.caseModel.up(params.col_id, {
name: params.col_name,
desc: params.col_desc,
up_time: yapi.commons.time()
})
ctx.body = yapi.commons.resReturn(result)
}catch(e){
ctx.body = yapi.commons.resReturn(null, 400, e.message)
}
}
/**
* 更新多个接口case index
* @interface /col/up_col_index
* @method POST
* @category col
* @foldnumber 10
* @param {Array} [id, index]
* @returns {Object}
* @example
*/
async upCaseIndex(ctx){
try{
let params = ctx.request.body;
if(!params || !Array.isArray(params)){
ctx.body = yapi.commons.resReturn(null, 400, "请求参数必须是数组")
}
params.forEach((item) => {
if(item.id && item.index){
this.caseModel.upCaseIndex(item.id, item.index).then((res) => {}, (err) => {
yapi.commons.log(err.message, 'error')
})
}
})
return ctx.body = yapi.commons.resReturn('success')
}catch(e){
ctx.body = yapi.commons.resReturn(null, 400, e.message)
}
}
/**
* 删除一个接口集
* @interface /col/del_col
* @method GET
* @category col
* @foldnumber 10
* @param {String}
* @returns {Object}
* @example
*/
async delCol(ctx){
try{
let id = ctx.request.body.colid;
let colData = await this.colModel.get(id);
if(!colData){
ctx.body = yapi.commons.resReturn(null, 400, "不存在的id")
}
if(colData.uid !== this.getUid()){
let auth = await this.checkAuth(colData.project_id, 'project', 'danger')
if(!auth){
return ctx.body = yapi.commons.resReturn(null, 400, '没有权限');
}
}
let result = await this.colModel.del(caseid);
return ctx.body = yapi.commons.resReturn(result);
}catch(e){
yapi.commons.resReturn(null, 400, e.message)
}
}
/**
*
* @param {*} ctx
*/
async delCase(ctx){
try{
let caseid = ctx.request.body.caseid;
let caseData = await this.caseModel.get(caseid);
if(!caseData){
ctx.body = yapi.commons.resReturn(null, 400, "不存在的caseid")
}
if(caseData.uid !== this.getUid()){
let auth = await this.checkAuth(caseData.project_id, 'project', 'danger')
if(!auth){
return ctx.body = yapi.commons.resReturn(null, 400, '没有权限');
}
}
let result = await this.caseModel.del(caseid);
return ctx.body = yapi.commons.resReturn(result);
}catch(e){
yapi.commons.resReturn(null, 400, e.message)
}
}
}
module.exports = interfaceColController
</pre>
</div>
</div>
</div>
</div>
<!-- <div class="docs-header" id="content" tabindex="-1">
<div class="container">
<h1>YApi : ./server/controllers/interfaceCol.js</h1>
<p>源代码</p>
</div>
</div> -->
<footer class="docs-footer" role="contentinfo">
<div class="container">
<p></p>
</div>
</footer>
</div>
<script type="text/javascript">
SyntaxHighlighter.all();
function getTop(node){
return node.offsetTop + (node.offsetParent ? getTop(node.offsetParent) : 0);
}
document.addEventListener('DOMContentLoaded', function() {
setTimeout(function() {
try {
var lineNum = (parseInt(location.hash.replace(/#/g, '')) - 1) || 0,
node = document.querySelectorAll('div.line')[lineNum];
document.body.scrollTop = getTop(node);
node.className += ' highlight';
} catch(e) {}
}, 500);
}, false);
</script>
</body>
</html>

View File

@ -35,33 +35,49 @@ class logController extends baseController {
super(ctx);
this.Model = yapi.getInst(logModel);
this.groupModel = yapi.getInst(groupModel);
try{
// var res = this.Model.save({
// uid: 107,
// typeid: 21,
// type: 'project',
// username: '小明明宝宝',
// content: '小明应该修改了的项目宝宝',
// time: yapi.commons.time()
// });
// var res = this.Model.del(107);
// ctx.body = yapi.commons.resReturn(null, 200,res);
}catch(err){
// ctx.body = yapi.commons.resReturn(null, 402, err.message);
}
}
/**
* 获取节点列表
* @interface /node/list
* 获取动态列表
* @interface /log/list
* @method GET
* @category node
* @category log
* @foldnumber 10
* @param {Number} uid 用户id 不能为空
* @param {Number} [page] 分页页码
* @param {Number} [limit] 分页大小
* @returns {Object}
* @example ./api/project/list.json
* @example /log/list
*/
async list(ctx) {
let uid = ctx.request.query.uid,
let typeid = ctx.request.query.typeid,
page = ctx.request.query.page || 1,
limit = ctx.request.query.limit || 10;
if (!uid) {
return ctx.body = yapi.commons.resReturn(null, 400, '用户id不能为空');
if (!typeid) {
return ctx.body = yapi.commons.resReturn(null, 400, 'typeid不能为空');
}
try {
let result = await this.Model.listWithPaging(uid, page, limit);
let count = await this.Model.listCount(uid);
let result = await this.Model.listWithPaging(typeid, page, limit);
let count = await this.Model.listCount(typeid);
ctx.body = yapi.commons.resReturn({
total: Math.ceil(count / limit),

View File

@ -32,6 +32,8 @@ import interfaceModel from '../models/interface.js';
import groupModel from '../models/group';
import commons from '../utils/commons.js';
import userModel from '../models/user.js';
import Mock from 'mockjs';
const send = require('koa-send');
class projectController extends baseController {
@ -85,6 +87,11 @@ class projectController extends baseController {
group_id: 'number',
desc: 'string'
});
if (await this.checkAuth(params.group_id, 'group', 'edit') !== true) {
return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
}
if (!params.group_id) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目分组id不能为空');
}
@ -99,7 +106,7 @@ class projectController extends baseController {
return ctx.body = yapi.commons.resReturn(null, 401, '已存在的项目名');
}
if (!params.prd_host) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目domain不能为空');
}
@ -120,13 +127,16 @@ class projectController extends baseController {
return ctx.body = yapi.commons.resReturn(null, 401, '已存在domain和basepath');
}
let data = {
name: params.name,
desc: params.desc,
prd_host: params.prd_host,
basepath: params.basepath,
protocol: params.protocol || 'http',
members: [this.getUid()],
members: [],
project_type: params.project_type || 'private',
uid: this.getUid(),
group_id: params.group_id,
add_time: yapi.commons.time(),
@ -161,12 +171,23 @@ class projectController extends baseController {
return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
}
if (await this.checkAuth(params.id, 'project', 'edit') !== true) {
return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
}
var check = await this.Model.checkMemberRepeat(params.id, params.member_uid);
if (check > 0) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目成员已存在');
}
let userdata = await this.getUserdata(params.member_uid);
if(userdata === null){
return ctx.body = yapi.commons.resReturn(null, 400, '成员uid不存在')
}
try {
let result = await this.Model.addMember(params.id, params.member_uid);
let result = await this.Model.addMember(params.id, userdata);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
@ -198,6 +219,10 @@ class projectController extends baseController {
return ctx.body = yapi.commons.resReturn(null, 400, '项目成员不存在');
}
if (await this.checkAuth(params.id, 'project', 'danger') !== true) {
return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
}
try {
let result = await this.Model.delMember(params.id, params.member_uid);
ctx.body = yapi.commons.resReturn(result);
@ -206,6 +231,22 @@ class projectController extends baseController {
}
}
async getUserdata(uid, role){
role = role || 'dev';
let userInst = yapi.getInst(userModel);
let userData = await userInst.findById(uid);
if(!userData){
return null;
}
return {
role: role,
uid: userData._id,
username: userData.username,
email: userData.email
}
}
/**
* 获取项目成员列表
* @interface /project/get_member_list
@ -225,10 +266,7 @@ class projectController extends baseController {
try {
let project = await this.Model.get(params.id);
let userInst = yapi.getInst(userModel);
let result = await userInst.findByUids(project.members);
ctx.body = yapi.commons.resReturn(result);
ctx.body = yapi.commons.resReturn(project.members);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
@ -265,24 +303,20 @@ class projectController extends baseController {
* @category project
* @foldnumber 10
* @param {Number} group_id 项目group_id不能为空
* @param {Number} [page] 分页页码
* @param {Number} [limit] 每页数据条目默认为10
* @returns {Object}
* @example ./api/project/list.json
*/
async list(ctx) {
let group_id = ctx.request.query.group_id,
page = ctx.request.query.page || 1,
limit = ctx.request.query.limit || 10;
let group_id = ctx.request.query.group_id
if (!group_id) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目分组id不能为空');
}
let auth =await this.checkAuth(group_id, 'group', 'edit')
try {
let result = await this.Model.listWithPaging(group_id, page, limit);
let count = await this.Model.listCount(group_id);
let result = await this.Model.list(group_id, auth);
let uids = [];
result.forEach((item) => {
if (uids.indexOf(item.uid) === -1) {
@ -295,7 +329,6 @@ class projectController extends baseController {
_users[item._id] = item;
});
ctx.body = yapi.commons.resReturn({
total: Math.ceil(count / limit),
list: result,
userinfo: _users
});
@ -327,7 +360,7 @@ class projectController extends baseController {
return ctx.body = yapi.commons.resReturn(null, 400, '请先删除该项目下所有接口');
}
if (await this.jungeProjectAuth(id) !== true) {
if (await this.checkAuth(id, 'project', 'danger') !== true) {
return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
}
let result = await this.Model.del(id);
@ -337,6 +370,33 @@ class projectController extends baseController {
}
}
async changeMemberRole(ctx){
let params = ctx.request.body;
let groupInst = yapi.getInst(groupModel);
if (!params.member_uid) {
return ctx.body = yapi.commons.resReturn(null, 400, '分组成员uid不能为空');
}
if (!params.id) {
return ctx.body = yapi.commons.resReturn(null, 400, '分组id不能为空');
}
var check = await groupInst.checkMemberRepeat(params.id, params.member_uid);
if (check === 0) {
return ctx.body = yapi.commons.resReturn(null, 400, '分组成员不存在');
}
if (await this.checkAuth(id, 'group', 'danger') !== true) {
return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
}
params.role = params.role === 'owner' ? 'owner' : 'dev';
try {
let result = await groupInst.changeMemberRole(params.id, params.member_uid, params.role);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
/**
* 编辑项目
* @interface /project/up
@ -372,7 +432,7 @@ class projectController extends baseController {
return ctx.body = yapi.commons.resReturn(null, 405, '项目id不能为空');
}
if (await this.jungeMemberAuth(id, this.getUid()) !== true) {
if (await this.checkAuth(id, 'project', 'edit') !== true) {
return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
}
@ -409,7 +469,6 @@ class projectController extends baseController {
}
let data = {
uid: this.getUid(),
up_time: yapi.commons.time()
};
@ -483,6 +542,71 @@ class projectController extends baseController {
return ctx.body = yapi.commons.resReturn(queryList, 0, 'ok');
}
/**
* 下载项目的 Mock 数据
* @interface /project/download
* @method GET
* @category project
* @foldnumber 10
* @param {String} project_id
*/
async download(ctx) {
const project_id = ctx.request.query.project_id;
let interfaceInst = yapi.getInst(interfaceModel);
// 根据 project_id 获取接口数据
let count = await interfaceInst.list(project_id);
if (!project_id) {
return ctx.body = yapi.commons.resReturn(null, 405, '项目id不能为空');
} else if (!count) {
return ctx.body = yapi.commons.resReturn(null, 401, '项目id不存在');
}
const arr = JSON.stringify(count.map(function(item) {
// 返回的json模板数据: item.res_body
const mockData = Mock.mock(
yapi.commons.json_parse(item.res_body)
);
return {
path: item.path,
mock: mockData
}
}));
const fileName = 'mock.js';
ctx.attachment(fileName);
await send(ctx, fileName, { root: __dirname + '/public' });
const res = `
var Mock = require('mockjs');
var xhook = require('xhook');
var data = ${arr};
function run() {
xhook.before(function(request, callback) {
setTimeout(function() {
var res;
data.forEach((item) => {
// 请求的接口在 data 中存在
if(request.url === item.path) {
res = {
status: 200,
text: Mock.mock(item.mock)
}
}
});
if (res) {
callback(res);
}else {
callback({ status: 405, text: '接口不存在' });
}
}, 500);
});
}
module.exports = run;`;
.trim();
return ctx.body = res;
}
}
module.exports = projectController;

View File

@ -34,6 +34,7 @@ import common from '../utils/commons.js';
import interfaceModel from '../models/interface.js'
import groupModel from '../models/group.js'
import projectModel from '../models/project.js'
import avatarModel from '../models/avatar.js'
const jwt = require('jsonwebtoken');
@ -168,12 +169,13 @@ class userController extends baseController {
passsalt: passsalt,
role: 'member',
add_time: yapi.commons.time(),
up_time: yapi.commons.time()
up_time: yapi.commons.time(),
type: 'third'
};
user = await userInst.save(data);
yapi.commons.sendMail({
to: email,
contents: `<h3>亲爱的用户:</h3><p>您好感谢使用YApi,系统检测您是第一次用Qsso账号登录YApi服务,您的Email是 ${email} ,初始化密码为:${passsalt}</p>`
contents: `<h3>亲爱的用户:</h3><p>您好感谢使用YApi平台.</p>`
});
}
@ -237,10 +239,6 @@ class userController extends baseController {
}
}
async forgetPassword() { }
async resetPassword() { }
setLoginCookie(uid, passsalt) {
let token = jwt.sign({ uid: uid }, passsalt, { expiresIn: '7 days' });
@ -298,7 +296,8 @@ class userController extends baseController {
passsalt: passsalt,
role: 'member',
add_time: yapi.commons.time(),
up_time: yapi.commons.time()
up_time: yapi.commons.time(),
type: "site"
};
if (!data.username) {
@ -460,10 +459,6 @@ class userController extends baseController {
up_time: yapi.commons.time()
};
if (this.getRole() === 'admin') {
params.role && (data.role = params.role);
}
params.username && (data.username = params.username);
params.email && (data.email = params.email);
@ -482,6 +477,65 @@ class userController extends baseController {
}
}
/**
*
* @param {*} basecode base64编码通过h5 api传给后端
*/
async uploadAvatar(ctx) {
try {
let basecode = ctx.request.body.basecode;
if(!basecode){
return ctx.body = yapi.commons.resReturn(null, 400, 'basecode不能为空')
}
let pngPrefix = 'data:image/png;base64,';
let jpegPrefix = 'data:image/jpeg;base64,';
let type;
if(basecode.substr(0, pngPrefix.length ) === pngPrefix){
basecode = basecode.substr(pngPrefix.length);
type = 'image/png';
}else if(basecode.substr(0, jpegPrefix.length ) === jpegPrefix){
basecode = basecode.substr(jpegPrefix.length);
type = 'image/jpeg';
}else{
return ctx.body = yapi.commons.resReturn(null, 400, '仅支持jpeg和png格式的图片')
}
let strLength = basecode.length;
if(parseInt(strLength-(strLength/8)*2) > 200000){
return ctx.body = yapi.commons.resReturn(null, 400, '图片大小不能超过200kb');
}
let avatarInst = yapi.getInst(avatarModel);
let result = await avatarInst.up(this.getUid(), basecode, type)
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 401, e.message);
}
}
async avatar(ctx) {
try{
let avatarInst = yapi.getInst(avatarModel);
let data = await avatarInst.get(this.getUid());
let dataBuffer, type;
if(!data || !data.basecode){
dataBuffer = yapi.fs.readFileSync(yapi.path.join(yapi.WEBROOT, 'static/image/avatar.png'));
type = 'image/png'
}else{
type = data.type;
dataBuffer = new Buffer(data.basecode, 'base64');
}
ctx.set('Content-type', type);
ctx.body = dataBuffer;
}catch(err){
ctx.body = 'error:' + err.message
}
}
/**
* 模糊搜索用户名或者email
* @interface /user/search
@ -523,7 +577,6 @@ class userController extends baseController {
];
let filteredRes = common.filterRes(queryList, rules);
console.log(queryList); // eslint-disable-line
return ctx.body = yapi.commons.resReturn(filteredRes, 0, 'ok');
}
@ -548,6 +601,7 @@ class userController extends baseController {
let interfaceData = await interfaceInst.get(id)
result["interface_id"] = interfaceData._id;
result["interface_name"] = interfaceData.path;
type = 'project';
id = interfaceData.project_id;
}