mirror of
https://github.com/YMFE/yapi.git
synced 2025-01-18 13:04:46 +08:00
fix: 解决冲突
This commit is contained in:
commit
998affe57a
@ -16,7 +16,8 @@ import './Group.scss';
|
||||
state => {
|
||||
return {
|
||||
curGroupId: state.group.currGroup._id,
|
||||
curUserRole: state.group.currGroup.role
|
||||
curUserRole: state.group.currGroup.role,
|
||||
currGroup: state.group.currGroup
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -30,7 +31,8 @@ export default class Group extends Component {
|
||||
static propTypes = {
|
||||
fetchNewsData: PropTypes.func,
|
||||
curGroupId: PropTypes.number,
|
||||
curUserRole: PropTypes.string
|
||||
curUserRole: PropTypes.string,
|
||||
currGroup: PropTypes.object
|
||||
}
|
||||
onTabClick(key){
|
||||
if(key == 3){
|
||||
@ -40,7 +42,7 @@ export default class Group extends Component {
|
||||
render () {
|
||||
const GroupContent = (
|
||||
<Layout style={{minHeight: 'calc(100vh - 100px)', marginLeft: '24px', marginTop: '24px'}}>
|
||||
<Sider style={{ height: '100%', overflowY: 'scroll'}} width={300}>
|
||||
<Sider style={{ height: '100%' }} width={300}>
|
||||
<div className="logo" />
|
||||
<GroupList></GroupList>
|
||||
</Sider>
|
||||
@ -48,7 +50,7 @@ export default class Group extends Component {
|
||||
<Content style={{ height: '100%', margin: '0 24px 0 16px', overflow: 'initial',backgroundColor: '#fff'}}>
|
||||
<Tabs onTabClick={this.onTabClick.bind(this)} type="card" className="m-tab" style={{height: '100%'}}>
|
||||
<TabPane tab="项目列表" key="1"><ProjectList/></TabPane>
|
||||
<TabPane tab="成员列表" key="2"><MemberList/></TabPane>
|
||||
{this.props.currGroup.type === 'public'?<TabPane tab="成员列表" key="2"><MemberList/></TabPane>:null}
|
||||
{["admin","owner","guest","dev"].indexOf(this.props.curUserRole)>-1?<TabPane tab="分组动态" key="3"><GroupLog/></TabPane>:""}
|
||||
</Tabs>
|
||||
</Content>
|
||||
|
@ -240,38 +240,42 @@ export default class GroupList extends Component {
|
||||
const delmark = <Menu.Item>
|
||||
<span onClick={() => this.showModal(TYPE_EDIT)}>编辑分组</span>
|
||||
</Menu.Item>
|
||||
// <Icon className="edit-group" type="edit" title="编辑分组" onClick={() => this.showModal(TYPE_EDIT)} />
|
||||
const editmark = <Menu.Item>
|
||||
<span onClick={() => { this.showConfirm() }}>删除分组</span>
|
||||
</Menu.Item>
|
||||
// <Icon className="delete-group" onClick={() => { this.showConfirm() }} type="delete" title="删除分组" />
|
||||
</Menu.Item>
|
||||
const addmark = <Menu.Item>
|
||||
<span onClick={this.showModal}>添加分组</span>
|
||||
</Menu.Item>
|
||||
// <Icon className="edit-group" onClick={this.showModal} type="plus" title="添加分组" />
|
||||
|
||||
let menu = <Menu>
|
||||
{
|
||||
this.props.curUserRole === "admin" ? (editmark) : ''
|
||||
this.props.curUserRole === "admin" ? (editmark) : ''
|
||||
}
|
||||
{
|
||||
this.props.curUserRole === "admin" || currGroup.role ==='owner' ? (delmark) : ''
|
||||
this.props.curUserRole === "admin" || currGroup.role === 'owner' ? (delmark) : ''
|
||||
}
|
||||
{
|
||||
this.props.curUserRole === 'admin' ? (addmark) : ''
|
||||
}
|
||||
</Menu>;
|
||||
menu = currGroup.role ==='owner'?<a className="editSet"><Icon type="setting" onClick={() => this.showModal(TYPE_EDIT)} /></a>:<Dropdown overlay={menu}>
|
||||
menu = currGroup.role === 'owner' ? <a className="editSet"><Icon type="setting" onClick={() => this.showModal(TYPE_EDIT)} /></a> : <Dropdown overlay={menu}>
|
||||
<a className="ant-dropdown-link" href="#">
|
||||
<Icon type="setting" />
|
||||
</a>
|
||||
</Dropdown>;
|
||||
|
||||
if( this.props.currGroup.type==='private'){
|
||||
menu = null;
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className="m-group">
|
||||
<div className="group-bar">
|
||||
<div className="curr-group">
|
||||
<div className="curr-group-name">
|
||||
<span className="name">{currGroup.group_name}</span>
|
||||
{ this.props.curUserRole === "admin" || currGroup.role ==='owner' ? (menu) : '' }
|
||||
{this.props.curUserRole === "admin" || currGroup.role === 'owner' ? (menu) : ''}
|
||||
</div>
|
||||
<div className="curr-group-desc">简介: {currGroup.group_desc}</div>
|
||||
</div>
|
||||
@ -290,14 +294,17 @@ export default class GroupList extends Component {
|
||||
{
|
||||
this.state.groupList.map((group) => (
|
||||
<Menu.Item key={`${group._id}`} className="group-item">
|
||||
<Icon type="folder-open" />{group.group_name}
|
||||
{group.type === 'private' ?
|
||||
<Icon type="user" /> :
|
||||
<Icon type="folder-open" />
|
||||
}{group.group_name}
|
||||
</Menu.Item>
|
||||
))
|
||||
}
|
||||
</Menu>
|
||||
</div>
|
||||
{
|
||||
this.state.addGroupModalVisible?<Modal
|
||||
this.state.addGroupModalVisible ? <Modal
|
||||
title="添加分组"
|
||||
visible={this.state.addGroupModalVisible}
|
||||
onOk={this.addGroup}
|
||||
@ -322,7 +329,7 @@ export default class GroupList extends Component {
|
||||
<UsernameAutoComplete callbackState={this.onUserSelect} />
|
||||
</Col>
|
||||
</Row>
|
||||
</Modal>:''
|
||||
</Modal> : ''
|
||||
}
|
||||
|
||||
<Modal
|
||||
|
@ -83,7 +83,7 @@ class Interface extends Component {
|
||||
// console.log(matchPath(this.props.location.pathname, contentRouter));
|
||||
return (
|
||||
<Layout style={{minHeight: 'calc(100vh - 156px)', marginLeft: '24px', marginTop: '24px'}}>
|
||||
<Sider style={{ height: '100%', overflowY: 'scroll'}} width={300}>
|
||||
<Sider style={{ height: '100%' }} width={300}>
|
||||
<div className="left-menu">
|
||||
<Tabs type="card" activeKey={activeKey} onChange={this.onChange}>
|
||||
<Tabs.TabPane tab="接口列表" key="api">
|
||||
|
@ -5,7 +5,7 @@ import PropTypes from 'prop-types'
|
||||
import { fetchInterfaceColList, fetchInterfaceCaseList, setColData } from '../../../../reducer/modules/interfaceCol'
|
||||
import { autobind } from 'core-decorators';
|
||||
import axios from 'axios';
|
||||
import { Input, Icon, Button, Modal, message, Tooltip, Tree, Dropdown, Menu, Form } from 'antd';
|
||||
import { Input, Icon, Button, Modal, message, Tooltip, Tree, Form } from 'antd';
|
||||
|
||||
const TreeNode = Tree.TreeNode;
|
||||
const FormItem = Form.Item;
|
||||
@ -197,20 +197,20 @@ export default class InterfaceColMenu extends Component {
|
||||
const { currColId, currCaseId, isShowCol } = this.props;
|
||||
const { colModalType, colModalVisible, filterValue } = this.state;
|
||||
|
||||
const menu = (col) => {
|
||||
return (
|
||||
<Menu>
|
||||
<Menu.Item>
|
||||
<span onClick={() => this.showColModal('edit', col)}>修改集合</span>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<span onClick={() => {
|
||||
this.showDelColConfirm(col._id)
|
||||
}}>删除集合</span>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
)
|
||||
};
|
||||
// const menu = (col) => {
|
||||
// return (
|
||||
// <Menu>
|
||||
// <Menu.Item>
|
||||
// <span onClick={() => this.showColModal('edit', col)}>修改集合</span>
|
||||
// </Menu.Item>
|
||||
// <Menu.Item>
|
||||
// <span onClick={() => {
|
||||
// this.showDelColConfirm(col._id)
|
||||
// }}>删除集合</span>
|
||||
// </Menu.Item>
|
||||
// </Menu>
|
||||
// )
|
||||
// };
|
||||
|
||||
let isFilterCat = false;
|
||||
|
||||
@ -237,7 +237,7 @@ export default class InterfaceColMenu extends Component {
|
||||
return true;
|
||||
}
|
||||
isFilterCat = false;
|
||||
|
||||
|
||||
let caseList = col.caseList.filter(item=>{
|
||||
return item.casename.indexOf(filterValue) !== -1
|
||||
})
|
||||
@ -248,9 +248,13 @@ 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)} trigger={['click']} onClick={e => e.stopPropagation()}>
|
||||
<div className="btns">
|
||||
<Icon type='delete' className="interface-delete-icon" onClick={() => {this.showDelColConfirm(col._id)}} />
|
||||
<Icon type='edit' className="interface-delete-icon" onClick={() => {this.showColModal('edit', col)}} />
|
||||
</div>
|
||||
{/*<Dropdown overlay={menu(col)} trigger={['click']} onClick={e => e.stopPropagation()}>
|
||||
<Icon className="opts-icon" type='ellipsis'/>
|
||||
</Dropdown>
|
||||
</Dropdown>*/}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
|
@ -22,11 +22,17 @@
|
||||
margin-left: 5px;
|
||||
display: none;
|
||||
}
|
||||
.btns {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.menu-title:hover {
|
||||
.case-delete-icon {
|
||||
display: block;
|
||||
}
|
||||
.btns {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types'
|
||||
import { fetchInterfaceList, fetchInterfaceData, deleteInterfaceData, deleteInterfaceCatData, initInterface } from '../../../../reducer/modules/interface.js';
|
||||
import { getProject } from '../../../../reducer/modules/project.js';
|
||||
import { Menu, Input, Icon, Button, Modal, message, Tree, Dropdown } from 'antd';
|
||||
import { Input, Icon, Button, Modal, message, Tree } from 'antd';
|
||||
import AddInterfaceForm from './AddInterfaceForm';
|
||||
import AddInterfaceCatForm from './AddInterfaceCatForm';
|
||||
import axios from 'axios'
|
||||
@ -322,56 +322,59 @@ class InterfaceMenu extends Component {
|
||||
// case 'DELETE': color = 'red'; break;
|
||||
// default: color = "yellow";
|
||||
// }
|
||||
const menu = (item) => {
|
||||
return <Menu>
|
||||
<Menu.Item>
|
||||
<span onClick={() => { this.showConfirm(item._id) }}>删除接口</span>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<span onClick={() => {
|
||||
this.copyInterface(item)
|
||||
}}>复制接口</span>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
};
|
||||
// const menu = (item) => {
|
||||
// return <Menu>
|
||||
// <Menu.Item>
|
||||
// <span onClick={() => { this.showConfirm(item._id) }}>删除接口</span>
|
||||
// </Menu.Item>
|
||||
// <Menu.Item>
|
||||
// <span onClick={() => {
|
||||
// this.copyInterface(item)
|
||||
// }}>复制接口</span>
|
||||
// </Menu.Item>
|
||||
// </Menu>
|
||||
// };
|
||||
|
||||
return <TreeNode
|
||||
title={<div onMouseEnter={() => this.enterItem(item._id)} onMouseLeave={this.leaveItem} >
|
||||
title={<div className="container-title" onMouseEnter={() => this.enterItem(item._id)} onMouseLeave={this.leaveItem} >
|
||||
<Link className="interface-item" to={"/project/" + matchParams.id + "/interface/api/" + item._id} >{item.title}</Link>
|
||||
{/*<Icon type='delete' className="interface-delete-icon" onClick={() => { this.showConfirm(item._id) }} style={{ display: this.state.delIcon == item._id ? 'block' : 'none' }} />*/}
|
||||
<Dropdown overlay={menu(item)} trigger={['click']} onClick={e => e.stopPropagation()}>
|
||||
<div className="btns">
|
||||
<Icon type='delete' className="interface-delete-icon" onClick={() => { this.showConfirm(item._id) }} style={{ display: this.state.delIcon == item._id ? 'block' : 'none' }} />
|
||||
<Icon type='copy' className="interface-delete-icon" onClick={() => { this.copyInterface(item) }} style={{ display: this.state.delIcon == item._id ? 'block' : 'none' }} />
|
||||
</div>
|
||||
{/*<Dropdown overlay={menu(item)} trigger={['click']} onClick={e => e.stopPropagation()}>
|
||||
<Icon type='ellipsis' className="interface-delete-icon" style={{ opacity: this.state.delIcon == item._id ? 1 : 0 }}/>
|
||||
</Dropdown>
|
||||
</Dropdown>*/}
|
||||
</div>}
|
||||
key={'' + item._id} />
|
||||
|
||||
}
|
||||
|
||||
const menu = (item) => {
|
||||
return <Menu>
|
||||
<Menu.Item>
|
||||
<span onClick={() => {
|
||||
this.changeModal('visible', true);
|
||||
this.setState({
|
||||
curCatid: item._id
|
||||
})
|
||||
}}>添加接口</span>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<span onClick={() => {
|
||||
this.changeModal('change_cat_modal_visible', true);
|
||||
this.setState({
|
||||
curCatdata: item
|
||||
})
|
||||
}}>修改分类</span>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<span onClick={() => {
|
||||
this.showDelCatConfirm(item._id)
|
||||
}}>删除分类</span>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
};
|
||||
// const menu = (item) => {
|
||||
// return <Menu>
|
||||
// <Menu.Item>
|
||||
// <span onClick={() => {
|
||||
// this.changeModal('visible', true);
|
||||
// this.setState({
|
||||
// curCatid: item._id
|
||||
// })
|
||||
// }}>添加接口</span>
|
||||
// </Menu.Item>
|
||||
// <Menu.Item>
|
||||
// <span onClick={() => {
|
||||
// this.changeModal('change_cat_modal_visible', true);
|
||||
// this.setState({
|
||||
// curCatdata: item
|
||||
// })
|
||||
// }}>修改分类</span>
|
||||
// </Menu.Item>
|
||||
// <Menu.Item>
|
||||
// <span onClick={() => {
|
||||
// this.showDelCatConfirm(item._id)
|
||||
// }}>删除分类</span>
|
||||
// </Menu.Item>
|
||||
// </Menu>
|
||||
// };
|
||||
|
||||
|
||||
|
||||
@ -414,11 +417,27 @@ class InterfaceMenu extends Component {
|
||||
>
|
||||
<TreeNode className="item-all-interface" title={<Link style={{ fontSize: '14px' }} to={"/project/" + matchParams.id + "/interface/api"}><Icon type="folder" style={{ marginRight: 5 }} />全部接口</Link>} key="root" />
|
||||
{menuList.map((item) => {
|
||||
return <TreeNode title={<div>
|
||||
return <TreeNode title={<div className="container-title" onMouseEnter={() => this.enterItem(item._id)} onMouseLeave={this.leaveItem} >
|
||||
<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)} trigger={['click']} onClick={e => e.stopPropagation()}>
|
||||
<div className="btns">
|
||||
<Icon type='delete' className="interface-delete-icon" onClick={() => { this.showDelCatConfirm(item._id) }} style={{ display: this.state.delIcon == item._id ? 'block' : 'none' }}/>
|
||||
<Icon type='edit' className="interface-delete-icon" style={{ display: this.state.delIcon == item._id ? 'block' : 'none' }} onClick={() => {
|
||||
this.changeModal('change_cat_modal_visible', true);
|
||||
this.setState({
|
||||
curCatdata: item
|
||||
})
|
||||
}} />
|
||||
<Icon type='plus' className="interface-delete-icon" style={{ display: this.state.delIcon == item._id ? 'block' : 'none' }} onClick={() => {
|
||||
this.changeModal('visible', true);
|
||||
this.setState({
|
||||
curCatid: item._id
|
||||
});
|
||||
}} />
|
||||
</div>
|
||||
|
||||
{/*<Dropdown overlay={menu(item)} trigger={['click']} onClick={e => e.stopPropagation()}>
|
||||
<Icon type='ellipsis' className="interface-delete-icon" />
|
||||
</Dropdown>
|
||||
</Dropdown>*/}
|
||||
</div>}
|
||||
key={'cat_' + item._id}
|
||||
className={`interface-item-nav ${item.list.length?"":"cat_switch_hidden"}`}
|
||||
|
@ -71,6 +71,25 @@
|
||||
.ant-tree li .ant-tree-node-content-wrapper {
|
||||
width: calc(100% - 28px);
|
||||
position: relative;
|
||||
.container-title {
|
||||
overflow: hidden;
|
||||
text-overflow:ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.btns {
|
||||
background-color: #eef7fe;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
transform: translateY(-60%);
|
||||
transition: all .2s;
|
||||
}
|
||||
}
|
||||
.ant-tree li .ant-tree-node-selected {
|
||||
.btns {
|
||||
background-color: #d5ebfc;
|
||||
transition: all .2s;
|
||||
}
|
||||
}
|
||||
|
||||
.interface-delete-icon{
|
||||
@ -78,7 +97,7 @@
|
||||
right: 0;
|
||||
float: right;
|
||||
line-height: 25px;
|
||||
width: 30px;
|
||||
width: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.anticon-ellipsis {
|
||||
|
@ -4,7 +4,7 @@ import PropTypes from 'prop-types'
|
||||
import { Route, Switch, Redirect, matchPath } from 'react-router-dom';
|
||||
import { Subnav } from '../../components/index';
|
||||
import { fetchGroupMsg } from '../../reducer/modules/group';
|
||||
import { setBreadcrumb } from '../../reducer/modules/user';
|
||||
import { setBreadcrumb } from '../../reducer/modules/user';
|
||||
import { getProject } from '../../reducer/modules/project';
|
||||
import Interface from './Interface/Interface.js'
|
||||
import Activity from './Activity/Activity.js'
|
||||
@ -38,14 +38,20 @@ export default class Project extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
currGroup: {}
|
||||
}
|
||||
}
|
||||
|
||||
async componentWillMount() {
|
||||
await this.props.getProject(this.props.match.params.id);
|
||||
const groupMsg = await this.props.fetchGroupMsg(this.props.curProject.group_id);
|
||||
this.setState({
|
||||
currGroup: groupMsg.payload.data.data
|
||||
})
|
||||
this.props.setBreadcrumb([{
|
||||
name: groupMsg.payload.data.data.group_name,
|
||||
href: '/group/'+groupMsg.payload.data.data._id
|
||||
href: '/group/' + groupMsg.payload.data.data._id
|
||||
}, {
|
||||
name: this.props.curProject.name
|
||||
}]);
|
||||
@ -53,7 +59,7 @@ export default class Project extends Component {
|
||||
|
||||
render() {
|
||||
const { match, location } = this.props;
|
||||
const routers = {
|
||||
let routers = {
|
||||
activity: { name: '动态', path: "/project/:id/activity" },
|
||||
interface: { name: '接口', path: "/project/:id/interface/:action" },
|
||||
setting: { name: '设置', path: "/project/:id/setting" },
|
||||
@ -71,32 +77,43 @@ export default class Project extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
let subnavData = [{
|
||||
name: routers.interface.name,
|
||||
path: `/project/${match.params.id}/interface/api`
|
||||
}, {
|
||||
name: routers.activity.name,
|
||||
path: `/project/${match.params.id}/activity`
|
||||
}, {
|
||||
name: routers.data.name,
|
||||
path: `/project/${match.params.id}/data`
|
||||
}, {
|
||||
name: routers.members.name,
|
||||
path: `/project/${match.params.id}/members`
|
||||
}, {
|
||||
name: routers.setting.name,
|
||||
path: `/project/${match.params.id}/setting`
|
||||
}];
|
||||
if(this.state.currGroup.type === 'private'){
|
||||
subnavData = subnavData.filter(item=>{
|
||||
return item.name != '成员管理'
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Subnav
|
||||
default={defaultName}
|
||||
data={[{
|
||||
name: routers.interface.name,
|
||||
path: `/project/${match.params.id}/interface/api`
|
||||
}, {
|
||||
name: routers.activity.name,
|
||||
path: `/project/${match.params.id}/activity`
|
||||
}, {
|
||||
name: routers.data.name,
|
||||
path: `/project/${match.params.id}/data`
|
||||
},{
|
||||
name: routers.members.name,
|
||||
path: `/project/${match.params.id}/members`
|
||||
}, {
|
||||
name: routers.setting.name,
|
||||
path: `/project/${match.params.id}/setting`
|
||||
}]} />
|
||||
data={subnavData} />
|
||||
<Switch>
|
||||
<Redirect exact from="/project/:id" to={`/project/${match.params.id}/interface/api`} />
|
||||
<Route path={routers.activity.path} component={Activity} />
|
||||
<Route path={routers.interface.path} component={Interface} />
|
||||
<Route path={routers.setting.path} component={Setting} />
|
||||
<Route path={routers.members.path} component={ProjectMember} />
|
||||
{this.state.currGroup.type !== 'private' ?
|
||||
<Route path={routers.members.path} component={ProjectMember} />
|
||||
: null
|
||||
}
|
||||
|
||||
<Route path={routers.data.path} component={ProjectData} />
|
||||
</Switch>
|
||||
</div>
|
||||
|
@ -83,6 +83,11 @@ class baseController {
|
||||
getUsername() {
|
||||
return this.$user.username;
|
||||
}
|
||||
|
||||
getEmail(){
|
||||
return this.$user.email;
|
||||
}
|
||||
|
||||
async getProjectRole(id, type) {
|
||||
let result = {};
|
||||
try {
|
||||
@ -129,6 +134,11 @@ class baseController {
|
||||
if (type === 'group') {
|
||||
let groupInst = yapi.getInst(groupModel);
|
||||
let groupData = await groupInst.get(id);
|
||||
if (groupData.uid === this.getUid()) {
|
||||
return 'owner';
|
||||
}
|
||||
|
||||
|
||||
let groupMemberData = _.find(groupData.members, (m) => {
|
||||
if (m.uid === this.getUid()) {
|
||||
return true;
|
||||
|
@ -31,6 +31,9 @@ class groupController extends baseController {
|
||||
let result = await groupInst.getGroupById(params.id);
|
||||
result = result.toObject();
|
||||
result.role = await this.getProjectRole(params.id, 'group');
|
||||
if(result.type === 'private'){
|
||||
result.group_name = '个人空间';
|
||||
}
|
||||
ctx.body = yapi.commons.resReturn(result);
|
||||
} catch (e) {
|
||||
ctx.body = yapi.commons.resReturn(null, 400, e.message)
|
||||
@ -334,8 +337,23 @@ class groupController extends baseController {
|
||||
async list(ctx) {
|
||||
try {
|
||||
var groupInst = yapi.getInst(groupModel);
|
||||
let projectInst = yapi.getInst(projectModel);
|
||||
let userInst = yapi.getInst(userModel);
|
||||
let result = await groupInst.list();
|
||||
let privateGroup = await groupInst.getByPrivateUid(this.getUid())
|
||||
let newResult = [];
|
||||
|
||||
if(!privateGroup){
|
||||
privateGroup = await groupInst.save({
|
||||
uid: this.getUid(),
|
||||
group_name: 'User-' + this.getUid(),
|
||||
add_time: yapi.commons.time(),
|
||||
up_time: yapi.commons.time(),
|
||||
type: 'private'
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
if(result && result.length > 0){
|
||||
for(let i=0; i< result.length; i++){
|
||||
result[i] = result[i].toObject();
|
||||
@ -343,11 +361,21 @@ class groupController extends baseController {
|
||||
if(result[i].role !== 'member'){
|
||||
newResult.unshift(result[i]);
|
||||
}else{
|
||||
newResult.push(result[i]);
|
||||
let publicCount = await projectInst.countWithPublic(result[i].id);
|
||||
if(publicCount > 0){
|
||||
newResult.push(result[i]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(privateGroup){
|
||||
privateGroup = privateGroup.toObject();
|
||||
privateGroup.group_name = '个人空间';
|
||||
privateGroup.role = 'owner';
|
||||
newResult.unshift(privateGroup);
|
||||
}
|
||||
|
||||
ctx.body = yapi.commons.resReturn(newResult);
|
||||
} catch (e) {
|
||||
ctx.body = yapi.commons.resReturn(null, 402, e.message);
|
||||
|
@ -24,7 +24,7 @@ class userController extends baseController {
|
||||
* @foldnumber 10
|
||||
* @param {String} email email名称,不能为空
|
||||
* @param {String} password 密码,不能为空
|
||||
* @returns {Object}
|
||||
* @returns {Object}
|
||||
* @example ./api/user/login.json
|
||||
*/
|
||||
async login(ctx) { //登录
|
||||
@ -68,7 +68,7 @@ class userController extends baseController {
|
||||
* @method GET
|
||||
* @category user
|
||||
* @foldnumber 10
|
||||
* @returns {Object}
|
||||
* @returns {Object}
|
||||
* @example ./api/user/logout.json
|
||||
*/
|
||||
|
||||
@ -144,6 +144,7 @@ class userController extends baseController {
|
||||
type: 'third'
|
||||
};
|
||||
user = await userInst.save(data);
|
||||
await this.handlePrivateGroup(user._id, username, email);
|
||||
yapi.commons.sendMail({
|
||||
to: email,
|
||||
contents: `<h3>亲爱的用户:</h3><p>您好,感谢使用YApi平台,你的邮箱账号是:${email}</p>`
|
||||
@ -210,6 +211,18 @@ class userController extends baseController {
|
||||
}
|
||||
}
|
||||
|
||||
async handlePrivateGroup(uid, username, email){
|
||||
var groupInst = yapi.getInst(groupModel);
|
||||
await groupInst.save({
|
||||
uid: uid,
|
||||
group_name: 'User-' + uid,
|
||||
add_time: yapi.commons.time(),
|
||||
up_time: yapi.commons.time(),
|
||||
type: 'private'
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
setLoginCookie(uid, passsalt) {
|
||||
let token = jwt.sign({ uid: uid }, passsalt, { expiresIn: '7 days' });
|
||||
|
||||
@ -232,7 +245,7 @@ class userController extends baseController {
|
||||
* @param {String} email email名称,不能为空
|
||||
* @param {String} password 密码,不能为空
|
||||
* @param {String} [username] 用户名
|
||||
* @returns {Object}
|
||||
* @returns {Object}
|
||||
* @example ./api/user/login.json
|
||||
*/
|
||||
async reg(ctx) { //注册
|
||||
@ -279,6 +292,7 @@ class userController extends baseController {
|
||||
let user = await userInst.save(data);
|
||||
|
||||
this.setLoginCookie(user._id, user.passsalt);
|
||||
await this.handlePrivateGroup(user._id, user.username, user.email);
|
||||
ctx.body = yapi.commons.resReturn({
|
||||
uid: user._id,
|
||||
email: user.email,
|
||||
@ -305,8 +319,8 @@ class userController extends baseController {
|
||||
* @foldnumber 10
|
||||
* @param {Number} [page] 分页页码
|
||||
* @param {Number} [limit] 分页大小,默认为10条
|
||||
* @returns {Object}
|
||||
* @example
|
||||
* @returns {Object}
|
||||
* @example
|
||||
*/
|
||||
async list(ctx) {
|
||||
let page = ctx.request.query.page || 1,
|
||||
@ -333,8 +347,8 @@ class userController extends baseController {
|
||||
* @param id 用户uid
|
||||
* @category user
|
||||
* @foldnumber 10
|
||||
* @returns {Object}
|
||||
* @example
|
||||
* @returns {Object}
|
||||
* @example
|
||||
*/
|
||||
async findById(ctx) { //根据id获取用户信息
|
||||
try {
|
||||
@ -372,8 +386,8 @@ class userController extends baseController {
|
||||
* @param id 用户uid
|
||||
* @category user
|
||||
* @foldnumber 10
|
||||
* @returns {Object}
|
||||
* @example
|
||||
* @returns {Object}
|
||||
* @example
|
||||
*/
|
||||
async del(ctx) { //根据id删除一个用户
|
||||
try {
|
||||
@ -406,8 +420,8 @@ class userController extends baseController {
|
||||
* @param [email] String
|
||||
* @category user
|
||||
* @foldnumber 10
|
||||
* @returns {Object}
|
||||
* @example
|
||||
* @returns {Object}
|
||||
* @example
|
||||
*/
|
||||
async update(ctx) { //更新用户信息
|
||||
try {
|
||||
@ -454,11 +468,11 @@ class userController extends baseController {
|
||||
/**
|
||||
* 上传用户头像
|
||||
* @interface /user/upload_avatar
|
||||
* @method POST
|
||||
* @method POST
|
||||
* @param {*} basecode base64编码,通过h5 api传给后端
|
||||
* @category user
|
||||
* @returns {Object}
|
||||
* @example
|
||||
* @returns {Object}
|
||||
* @example
|
||||
*/
|
||||
|
||||
async uploadAvatar(ctx) {
|
||||
@ -470,7 +484,7 @@ class userController extends baseController {
|
||||
let pngPrefix = 'data:image/png;base64,';
|
||||
let jpegPrefix = 'data:image/jpeg;base64,';
|
||||
let type;
|
||||
if(basecode.substr(0, pngPrefix.length ) === pngPrefix){
|
||||
if(basecode.substr(0, pngPrefix.length ) === pngPrefix){
|
||||
basecode = basecode.substr(pngPrefix.length);
|
||||
type = 'image/png';
|
||||
}else if(basecode.substr(0, jpegPrefix.length ) === jpegPrefix){
|
||||
@ -478,7 +492,7 @@ class userController extends baseController {
|
||||
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');
|
||||
@ -487,7 +501,7 @@ class userController extends baseController {
|
||||
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);
|
||||
}
|
||||
@ -497,15 +511,15 @@ class userController extends baseController {
|
||||
/**
|
||||
* 根据用户uid头像
|
||||
* @interface /user/avatar
|
||||
* @method GET
|
||||
* @param {*} uid
|
||||
* @method GET
|
||||
* @param {*} uid
|
||||
* @category user
|
||||
* @returns {Object}
|
||||
* @example
|
||||
* @returns {Object}
|
||||
* @example
|
||||
*/
|
||||
|
||||
async avatar(ctx) {
|
||||
|
||||
async avatar(ctx) {
|
||||
|
||||
try{
|
||||
let uid = ctx.query.uid ? ctx.query.uid: this.getUid();
|
||||
let avatarInst = yapi.getInst(avatarModel);
|
||||
@ -516,7 +530,7 @@ class userController extends baseController {
|
||||
type = 'image/png'
|
||||
}else{
|
||||
type = data.type;
|
||||
dataBuffer = new Buffer(data.basecode, 'base64');
|
||||
dataBuffer = new Buffer(data.basecode, 'base64');
|
||||
}
|
||||
|
||||
ctx.set('Content-type', type);
|
||||
@ -578,9 +592,9 @@ class userController extends baseController {
|
||||
* @category user
|
||||
* @foldnumber 10
|
||||
* @param {String} type 可选group|interface|project
|
||||
* @param {Number} id
|
||||
* @param {Number} id
|
||||
* @return {Object}
|
||||
* @example
|
||||
* @example
|
||||
*/
|
||||
async project(ctx) {
|
||||
let { id, type } = ctx.request.query;
|
||||
@ -589,7 +603,7 @@ class userController extends baseController {
|
||||
if (type === 'interface') {
|
||||
let interfaceInst = yapi.getInst(interfaceModel);
|
||||
let interfaceData = await interfaceInst.get(id)
|
||||
result.interface = interfaceData;
|
||||
result.interface = interfaceData;
|
||||
type = 'project';
|
||||
id = interfaceData.project_id;
|
||||
}
|
||||
@ -616,7 +630,7 @@ class userController extends baseController {
|
||||
if (type === 'group') {
|
||||
let groupInst = yapi.getInst(groupModel);
|
||||
let groupData = await groupInst.get(id);
|
||||
result.group = groupData.toObject();
|
||||
result.group = groupData.toObject();
|
||||
let ownerAuth = await this.checkAuth(id, 'group', 'danger'), devAuth;
|
||||
if(ownerAuth){
|
||||
result.group.role = 'owner'
|
||||
@ -628,7 +642,7 @@ class userController extends baseController {
|
||||
result.group.role = 'member'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return ctx.body = yapi.commons.resReturn(result)
|
||||
@ -640,4 +654,4 @@ class userController extends baseController {
|
||||
|
||||
}
|
||||
|
||||
module.exports = userController;
|
||||
module.exports = userController;
|
||||
|
@ -13,8 +13,7 @@ function install() {
|
||||
let exist = yapi.commons.fileExist(yapi.path.join(yapi.WEBROOT_RUNTIME, 'init.lock'));
|
||||
|
||||
if (exist) {
|
||||
yapi.commons.log('runtime/init.lock文件已存在,请确认您是否已安装。如果需要重新安装,请删掉runtime/init.lock文件');
|
||||
process.exit(0);
|
||||
throw new Error('init.lock文件已存在,请确认您是否已安装。如果需要重新安装,请删掉init.lock文件');
|
||||
}
|
||||
|
||||
setupSql();
|
||||
@ -26,14 +25,14 @@ function setupSql() {
|
||||
let result = userInst.save({
|
||||
username: yapi.WEBCONFIG.adminAccount.substr(0, yapi.WEBCONFIG.adminAccount.indexOf('@')),
|
||||
email: yapi.WEBCONFIG.adminAccount,
|
||||
password: yapi.commons.generatePassword('qunar.com', passsalt),
|
||||
password: yapi.commons.generatePassword('ymfe.org', passsalt),
|
||||
passsalt: passsalt,
|
||||
role: 'admin',
|
||||
add_time: yapi.commons.time(),
|
||||
up_time: yapi.commons.time()
|
||||
});
|
||||
|
||||
yapi.connect.then(function () {
|
||||
yapi.connect.then(function () {
|
||||
let userCol = mongoose.connection.db.collection('user')
|
||||
userCol.ensureIndex({
|
||||
username: 1
|
||||
@ -127,13 +126,16 @@ function setupSql() {
|
||||
|
||||
result.then(function () {
|
||||
fs.ensureFileSync(yapi.path.join(yapi.WEBROOT_RUNTIME, 'init.lock'));
|
||||
console.log(`初始化管理员账号 "${yapi.WEBCONFIG.adminAccount}" 成功`); // eslint-disable-line
|
||||
console.log(`初始化管理员账号成功,账号名:"${yapi.WEBCONFIG.adminAccount}",密码:"ymfe.org"`); // eslint-disable-line
|
||||
process.exit(0);
|
||||
}, function (err) {
|
||||
console.log(`初始化管理员账号 "${yapi.WEBCONFIG.adminAccount}" 失败, ${err.message}`); // eslint-disable-line
|
||||
process.exit(0);
|
||||
throw new Error(`初始化管理员账号 "${yapi.WEBCONFIG.adminAccount}" 失败, ${err.message}`); // eslint-disable-line
|
||||
|
||||
});
|
||||
|
||||
|
||||
}).catch(function(err){
|
||||
throw new Error(err.message);
|
||||
})
|
||||
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ class groupModel extends baseModel {
|
||||
group_desc: String,
|
||||
add_time: Number,
|
||||
up_time: Number,
|
||||
type: {type:String,default: 'private', enum: ['public', 'private']},
|
||||
members: [
|
||||
{
|
||||
uid: Number,
|
||||
@ -35,10 +36,17 @@ class groupModel extends baseModel {
|
||||
}).exec();
|
||||
}
|
||||
|
||||
getByPrivateUid(uid){
|
||||
return this.model.findOne({
|
||||
uid: uid,
|
||||
type: 'private'
|
||||
}).select('group_name _id group_desc add_time up_time type').exec();
|
||||
}
|
||||
|
||||
getGroupById(id) {
|
||||
return this.model.findOne({
|
||||
_id: id
|
||||
}).select("uid group_name group_desc add_time up_time").exec();
|
||||
}).select("uid group_name group_desc add_time up_time type").exec();
|
||||
}
|
||||
|
||||
checkRepeat(name) {
|
||||
@ -86,7 +94,9 @@ class groupModel extends baseModel {
|
||||
}
|
||||
|
||||
list() {
|
||||
return this.model.find().select('group_name _id group_desc add_time up_time').exec();
|
||||
return this.model.find({
|
||||
type: 'public'
|
||||
}).select('group_name _id group_desc add_time up_time type uid').exec();
|
||||
}
|
||||
|
||||
del(id) {
|
||||
|
@ -69,6 +69,11 @@ class projectModel extends baseModel {
|
||||
return this.model.find(params).select("_id uid name basepath desc group_id project_type color icon env add_time up_time").sort({ _id: -1 }).exec();
|
||||
}
|
||||
|
||||
countWithPublic(group_id){
|
||||
let params = {group_id: group_id, project_type: 'public'};
|
||||
return this.model.count(params);
|
||||
}
|
||||
|
||||
listWithPaging(group_id, page, limit) {
|
||||
page = parseInt(page);
|
||||
limit = parseInt(limit);
|
||||
|
Loading…
Reference in New Issue
Block a user