fix: 解决冲突

This commit is contained in:
喻希里 2017-09-27 15:07:09 +08:00
commit 998affe57a
14 changed files with 284 additions and 141 deletions

View File

@ -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>

View File

@ -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

View File

@ -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">

View File

@ -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>
}
>

View File

@ -22,11 +22,17 @@
margin-left: 5px;
display: none;
}
.btns {
display: none;
}
}
.menu-title:hover {
.case-delete-icon {
display: block;
}
.btns {
display: block;
}
}
}

View File

@ -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"}`}

View File

@ -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 {

View File

@ -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>

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);
})
}

View File

@ -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) {

View File

@ -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);