mirror of
https://github.com/YMFE/yapi.git
synced 2025-02-23 13:59:28 +08:00
feat: 项目复制
This commit is contained in:
parent
c8e13ce7e3
commit
21bb99b240
@ -1,22 +1,31 @@
|
||||
import './ProjectCard.scss';
|
||||
import React, { PureComponent as Component } from 'react';
|
||||
import { Card, Icon, Tooltip } from 'antd';
|
||||
import { connect } from 'react-redux'
|
||||
import { delFollow, addFollow } from '../../reducer/modules/follow';
|
||||
import { Card, Icon, Tooltip, Modal, Alert, Input, message } from 'antd';
|
||||
import { connect } from 'react-redux';
|
||||
import { delFollow, addFollow } from '../../reducer/modules/follow';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withRouter } from 'react-router';
|
||||
import { debounce } from '../../common';
|
||||
import constants from '../../constants/variable.js';
|
||||
import produce from 'immer';
|
||||
import { getProject, checkProjectName, copyProjectMsg } from '../../reducer/modules/project';
|
||||
import { trim } from '../../common.js';
|
||||
const confirm = Modal.confirm;
|
||||
|
||||
|
||||
@connect(
|
||||
state => {
|
||||
return {
|
||||
uid: state.user.uid
|
||||
}
|
||||
uid: state.user.uid,
|
||||
currPage: state.project.currPage
|
||||
};
|
||||
},
|
||||
{
|
||||
delFollow,
|
||||
addFollow
|
||||
addFollow,
|
||||
getProject,
|
||||
checkProjectName,
|
||||
copyProjectMsg
|
||||
}
|
||||
)
|
||||
@withRouter
|
||||
@ -25,6 +34,7 @@ class ProjectCard extends Component {
|
||||
super(props);
|
||||
this.add = debounce(this.add, 400);
|
||||
this.del = debounce(this.del, 400);
|
||||
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
@ -34,18 +44,79 @@ class ProjectCard extends Component {
|
||||
callbackResult: PropTypes.func,
|
||||
history: PropTypes.object,
|
||||
delFollow: PropTypes.func,
|
||||
addFollow: PropTypes.func
|
||||
}
|
||||
addFollow: PropTypes.func,
|
||||
isShow: PropTypes.bool,
|
||||
getProject: PropTypes.func,
|
||||
checkProjectName: PropTypes.func,
|
||||
copyProjectMsg: PropTypes.func,
|
||||
currPage: PropTypes.number
|
||||
|
||||
};
|
||||
|
||||
copy = async (projectName) => {
|
||||
const id = this.props.projectData._id;
|
||||
|
||||
let projectData = await this.props.getProject(id);
|
||||
let data = projectData.payload.data.data;
|
||||
let newData = produce(data, draftData => {
|
||||
draftData.preName = draftData.name;
|
||||
draftData.name = projectName;
|
||||
|
||||
})
|
||||
|
||||
await this.props.copyProjectMsg(newData);
|
||||
message.success('项目复制成功')
|
||||
this.props.callbackResult();
|
||||
};
|
||||
|
||||
|
||||
|
||||
// 复制项目的二次确认
|
||||
showConfirm = () => {
|
||||
const that = this;
|
||||
|
||||
confirm({
|
||||
title: '确认复制 ' + that.props.projectData.name + ' 项目吗?',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
content: (
|
||||
<div style={{ marginTop: '10px', fontSize: '13px', lineHeight: '25px' }}>
|
||||
<Alert
|
||||
message={`该操作将会复制 ${
|
||||
that.props.projectData.name
|
||||
} 下的所有接口集合,但不包括测试集合中的接口`}
|
||||
type="info"
|
||||
/>
|
||||
<div style={{ marginTop: '16px' }}>
|
||||
<p>
|
||||
<b>分组名称:</b>
|
||||
</p>
|
||||
<Input id="project_name" placeholder="项目名称"/>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
async onOk() {
|
||||
const projectName = trim(document.getElementById('project_name').value);
|
||||
|
||||
// 查询项目名称是否重复
|
||||
const group_id = that.props.projectData.group_id
|
||||
await that.props.checkProjectName(projectName, group_id)
|
||||
that.copy(projectName)
|
||||
},
|
||||
iconType: 'copy',
|
||||
onCancel() {}
|
||||
});
|
||||
};
|
||||
|
||||
del = () => {
|
||||
const id = this.props.projectData.projectid || this.props.projectData._id;
|
||||
this.props.delFollow(id).then((res) => {
|
||||
this.props.delFollow(id).then(res => {
|
||||
if (res.payload.data.errcode === 0) {
|
||||
this.props.callbackResult();
|
||||
// message.success('已取消关注!'); // 星号已做出反馈 无需重复提醒用户
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
add = () => {
|
||||
const { uid, projectData } = this.props;
|
||||
@ -55,32 +126,60 @@ class ProjectCard extends Component {
|
||||
projectname: projectData.name,
|
||||
icon: projectData.icon || constants.PROJECT_ICON[0],
|
||||
color: projectData.color || constants.PROJECT_COLOR.blue
|
||||
}
|
||||
this.props.addFollow(param).then((res) => {
|
||||
};
|
||||
this.props.addFollow(param).then(res => {
|
||||
if (res.payload.data.errcode === 0) {
|
||||
this.props.callbackResult();
|
||||
// message.success('已添加关注!'); // 星号已做出反馈 无需重复提醒用户
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { projectData, inFollowPage } = this.props;
|
||||
const { projectData, inFollowPage, isShow } = this.props;
|
||||
return (
|
||||
<div className="card-container">
|
||||
<Card bordered={false} className="m-card" onClick={() => this.props.history.push('/project/' + (projectData.projectid || projectData._id))}>
|
||||
<Icon type={projectData.icon || 'star-o'} className="ui-logo" style={{ backgroundColor: constants.PROJECT_COLOR[projectData.color] || constants.PROJECT_COLOR.blue }} />
|
||||
<Card
|
||||
bordered={false}
|
||||
className="m-card"
|
||||
onClick={() =>
|
||||
this.props.history.push('/project/' + (projectData.projectid || projectData._id))
|
||||
}
|
||||
>
|
||||
<Icon
|
||||
type={projectData.icon || 'star-o'}
|
||||
className="ui-logo"
|
||||
style={{
|
||||
backgroundColor:
|
||||
constants.PROJECT_COLOR[projectData.color] || constants.PROJECT_COLOR.blue
|
||||
}}
|
||||
/>
|
||||
<h4 className="ui-title">{projectData.name || projectData.projectname}</h4>
|
||||
</Card>
|
||||
<div className="card-btns" onClick={projectData.follow || inFollowPage ? this.del : this.add}>
|
||||
<Tooltip placement="rightTop" title={projectData.follow || inFollowPage ? '取消关注' : '添加关注'}>
|
||||
<Icon type={projectData.follow || inFollowPage ? 'star' : 'star-o'} className={'icon ' + (projectData.follow || inFollowPage ? 'active' : '')}/>
|
||||
</Card>
|
||||
<div
|
||||
className="card-btns"
|
||||
onClick={projectData.follow || inFollowPage ? this.del : this.add}
|
||||
>
|
||||
<Tooltip
|
||||
placement="rightTop"
|
||||
title={projectData.follow || inFollowPage ? '取消关注' : '添加关注'}
|
||||
>
|
||||
<Icon
|
||||
type={projectData.follow || inFollowPage ? 'star' : 'star-o'}
|
||||
className={'icon ' + (projectData.follow || inFollowPage ? 'active' : '')}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
{isShow && (
|
||||
<div className="copy-btns" onClick={this.showConfirm}>
|
||||
<Tooltip placement="rightTop" title="复制项目">
|
||||
<Icon type="copy" className="icon" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ProjectCard
|
||||
export default ProjectCard;
|
||||
|
@ -8,22 +8,26 @@
|
||||
transition: all .2s;
|
||||
}
|
||||
&:hover {
|
||||
.m-card, .card-btns {
|
||||
.m-card, .card-btns , .copy-btns {
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
.m-card .ant-card-body {
|
||||
background-color: $color-bg-gray;
|
||||
box-shadow: 0 4px 8px rgba(50, 50, 93, 0.11), 0 4px 6px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
.card-btns .icon {
|
||||
.card-btns .icon {
|
||||
color: rgba(39, 56, 72, 0.85);
|
||||
}
|
||||
.card-btns .icon.active {
|
||||
|
||||
.copy-btns .icon {
|
||||
color: #2395f1
|
||||
}
|
||||
.card-btns .icon.active , .copy-btns .icon.active {
|
||||
color: #fac200;
|
||||
}
|
||||
}
|
||||
&:active {
|
||||
.m-card, .card-btns {
|
||||
.m-card, .card-btns, .copy-btns {
|
||||
transform: translateY(4px);
|
||||
}
|
||||
}
|
||||
@ -52,6 +56,31 @@
|
||||
.icon.active {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 卡片昨上角按钮
|
||||
.copy-btns {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: .48rem;
|
||||
height: .48rem;
|
||||
// background: linear-gradient(225deg, #ccc, #ccc 50%, transparent 0);
|
||||
border-top-right-radius: 4px;
|
||||
.icon {
|
||||
cursor: pointer;
|
||||
font-size: .16rem;
|
||||
padding: .06rem;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 3px;
|
||||
color: #fff;
|
||||
}
|
||||
.icon.active {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
.m-card {
|
||||
|
@ -43,6 +43,7 @@ export default class Group extends Component {
|
||||
// // }
|
||||
// }
|
||||
render() {
|
||||
|
||||
const GroupContent = (
|
||||
<Layout style={{ minHeight: 'calc(100vh - 100px)', marginLeft: '24px', marginTop: '24px' }}>
|
||||
<Sider style={{ height: '100%' }} width={300}>
|
||||
|
@ -2,10 +2,16 @@ import React, { PureComponent as Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { Table, Select, Button, Modal, Row, Col, message, Popconfirm } from 'antd';
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Link } from 'react-router-dom';
|
||||
import './MemberList.scss';
|
||||
import { autobind } from 'core-decorators';
|
||||
import { fetchGroupMemberList, fetchGroupMsg, addMember, delMember, changeMemberRole } from '../../../reducer/modules/group.js'
|
||||
import {
|
||||
fetchGroupMemberList,
|
||||
fetchGroupMsg,
|
||||
addMember,
|
||||
delMember,
|
||||
changeMemberRole
|
||||
} from '../../../reducer/modules/group.js';
|
||||
import ErrMsg from '../../../components/ErrMsg/ErrMsg.js';
|
||||
import UsernameAutoComplete from '../../../components/UsernameAutoComplete/UsernameAutoComplete.js';
|
||||
const Option = Select.Option;
|
||||
@ -15,7 +21,7 @@ function arrayAddKey(arr) {
|
||||
return {
|
||||
...item,
|
||||
key: index
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@ -25,7 +31,7 @@ function arrayAddKey(arr) {
|
||||
currGroup: state.group.currGroup,
|
||||
uid: state.user.uid,
|
||||
role: state.group.role
|
||||
}
|
||||
};
|
||||
},
|
||||
{
|
||||
fetchGroupMemberList,
|
||||
@ -45,7 +51,7 @@ class MemberList extends Component {
|
||||
dataSource: [],
|
||||
inputUids: [],
|
||||
inputRole: 'dev'
|
||||
}
|
||||
};
|
||||
}
|
||||
static propTypes = {
|
||||
currGroup: PropTypes.object,
|
||||
@ -56,20 +62,18 @@ class MemberList extends Component {
|
||||
delMember: PropTypes.func,
|
||||
changeMemberRole: PropTypes.func,
|
||||
role: PropTypes.string
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@autobind
|
||||
showAddMemberModal() {
|
||||
|
||||
showAddMemberModal = () => {
|
||||
this.setState({
|
||||
visible: true
|
||||
});
|
||||
}
|
||||
|
||||
// 重新获取列表
|
||||
@autobind
|
||||
reFetchList() {
|
||||
this.props.fetchGroupMemberList(this.props.currGroup._id).then((res) => {
|
||||
reFetchList = () => {
|
||||
this.props.fetchGroupMemberList(this.props.currGroup._id).then(res => {
|
||||
this.setState({
|
||||
userInfo: arrayAddKey(res.payload.data.data),
|
||||
visible: false
|
||||
@ -78,55 +82,56 @@ class MemberList extends Component {
|
||||
}
|
||||
|
||||
// 增 - 添加成员
|
||||
@autobind
|
||||
handleOk() {
|
||||
this.props.addMember({
|
||||
id: this.props.currGroup._id,
|
||||
member_uids: this.state.inputUids,
|
||||
role: this.state.inputRole
|
||||
}).then((res) => {
|
||||
if (!res.payload.data.errcode) {
|
||||
const { add_members, exist_members } = res.payload.data.data;
|
||||
const addLength = add_members.length;
|
||||
const existLength = exist_members.length;
|
||||
this.setState({
|
||||
inputRole: 'dev',
|
||||
inputUids: []
|
||||
});
|
||||
message.success(`添加成功! 已成功添加 ${addLength} 人,其中 ${existLength} 人已存在`);
|
||||
this.reFetchList(); // 添加成功后重新获取分组成员列表
|
||||
}
|
||||
});
|
||||
|
||||
handleOk = () => {
|
||||
this.props
|
||||
.addMember({
|
||||
id: this.props.currGroup._id,
|
||||
member_uids: this.state.inputUids,
|
||||
role: this.state.inputRole
|
||||
})
|
||||
.then(res => {
|
||||
if (!res.payload.data.errcode) {
|
||||
const { add_members, exist_members } = res.payload.data.data;
|
||||
const addLength = add_members.length;
|
||||
const existLength = exist_members.length;
|
||||
this.setState({
|
||||
inputRole: 'dev',
|
||||
inputUids: []
|
||||
});
|
||||
message.success(`添加成功! 已成功添加 ${addLength} 人,其中 ${existLength} 人已存在`);
|
||||
this.reFetchList(); // 添加成功后重新获取分组成员列表
|
||||
}
|
||||
});
|
||||
}
|
||||
// 添加成员时 选择新增成员权限
|
||||
@autobind
|
||||
changeNewMemberRole(value) {
|
||||
|
||||
changeNewMemberRole = (value) => {
|
||||
this.setState({
|
||||
inputRole: value
|
||||
});
|
||||
}
|
||||
|
||||
// 删 - 删除分组成员
|
||||
@autobind
|
||||
deleteConfirm(member_uid) {
|
||||
|
||||
deleteConfirm = (member_uid) => {
|
||||
return () => {
|
||||
const id = this.props.currGroup._id;
|
||||
this.props.delMember({ id, member_uid }).then((res) => {
|
||||
this.props.delMember({ id, member_uid }).then(res => {
|
||||
if (!res.payload.data.errcode) {
|
||||
message.success(res.payload.data.errmsg);
|
||||
this.reFetchList(); // 添加成功后重新获取分组成员列表
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 改 - 修改成员权限
|
||||
@autobind
|
||||
changeUserRole(e) {
|
||||
changeUserRole = (e) => {
|
||||
const id = this.props.currGroup._id;
|
||||
const role = e.split('-')[0];
|
||||
const member_uid = e.split('-')[1];
|
||||
this.props.changeMemberRole({ id, member_uid, role }).then((res) => {
|
||||
this.props.changeMemberRole({ id, member_uid, role }).then(res => {
|
||||
if (!res.payload.data.errcode) {
|
||||
message.success(res.payload.data.errmsg);
|
||||
this.reFetchList(); // 添加成功后重新获取分组成员列表
|
||||
@ -135,40 +140,41 @@ class MemberList extends Component {
|
||||
}
|
||||
|
||||
// 关闭模态框
|
||||
@autobind
|
||||
handleCancel() {
|
||||
|
||||
handleCancel = () => {
|
||||
this.setState({
|
||||
visible: false
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
|
||||
if (this._groupId !== this._groupId) {
|
||||
return null;
|
||||
}
|
||||
if (this.props.currGroup !== nextProps.currGroup) {
|
||||
this.props.fetchGroupMemberList(nextProps.currGroup._id).then((res) => {
|
||||
if (this.props.currGroup._id !== nextProps.currGroup._id) {
|
||||
this.props.fetchGroupMemberList(nextProps.currGroup._id).then(res => {
|
||||
this.setState({
|
||||
userInfo: arrayAddKey(res.payload.data.data)
|
||||
});
|
||||
});
|
||||
this.props.fetchGroupMsg(nextProps.currGroup._id).then((res) => {
|
||||
this.props.fetchGroupMsg(nextProps.currGroup._id).then(res => {
|
||||
this.setState({
|
||||
role: res.payload.data.data.role
|
||||
});
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const currGroupId = this._groupId = this.props.currGroup._id;
|
||||
this.props.fetchGroupMsg(currGroupId).then((res) => {
|
||||
|
||||
const currGroupId = (this._groupId = this.props.currGroup._id);
|
||||
this.props.fetchGroupMsg(currGroupId).then(res => {
|
||||
this.setState({
|
||||
role: res.payload.data.data.role
|
||||
});
|
||||
})
|
||||
this.props.fetchGroupMemberList(currGroupId).then((res) => {
|
||||
});
|
||||
this.props.fetchGroupMemberList(currGroupId).then(res => {
|
||||
this.setState({
|
||||
userInfo: arrayAddKey(res.payload.data.data)
|
||||
});
|
||||
@ -179,101 +185,144 @@ class MemberList extends Component {
|
||||
onUserSelect(uids) {
|
||||
this.setState({
|
||||
inputUids: uids
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const columns = [{
|
||||
title: this.props.currGroup.group_name + ' 分组成员 (' + this.state.userInfo.length + ') 人',
|
||||
dataIndex: 'username',
|
||||
key: 'username',
|
||||
render: (text, record) => {
|
||||
return (<div className="m-user">
|
||||
<Link to={`/user/profile/${record.uid}`}>
|
||||
<img src={location.protocol + '//' + location.host + '/api/user/avatar?uid=' + record.uid} className="m-user-img" />
|
||||
</Link>
|
||||
<Link to={`/user/profile/${record.uid}`}>
|
||||
<p className="m-user-name">{text}</p>
|
||||
</Link>
|
||||
</div>);
|
||||
}
|
||||
}, {
|
||||
title: (this.state.role === 'owner' || this.state.role === 'admin') ? <div className="btn-container"><Button className="btn" type="primary" onClick={this.showAddMemberModal}>添加成员</Button></div> : '',
|
||||
key: 'action',
|
||||
className: 'member-opration',
|
||||
render: (text, record) => {
|
||||
if (this.state.role === 'owner' || this.state.role === 'admin') {
|
||||
const columns = [
|
||||
{
|
||||
title:
|
||||
this.props.currGroup.group_name + ' 分组成员 (' + this.state.userInfo.length + ') 人',
|
||||
dataIndex: 'username',
|
||||
key: 'username',
|
||||
render: (text, record) => {
|
||||
return (
|
||||
<div>
|
||||
<Select value={record.role + '-' + record.uid} className="select" onChange={this.changeUserRole}>
|
||||
<Option value={'owner-' + record.uid}>组长</Option>
|
||||
<Option value={'dev-' + record.uid}>开发者</Option>
|
||||
<Option value={'guest-' + record.uid}>访客</Option>
|
||||
</Select>
|
||||
<Popconfirm placement="topRight" title="你确定要删除吗? " onConfirm={this.deleteConfirm(record.uid)} okText="确定" cancelText="">
|
||||
<Button type="danger" icon="delete" className="btn-danger" />
|
||||
{/* <Icon type="delete" className="btn-danger"/> */}
|
||||
</Popconfirm>
|
||||
<div className="m-user">
|
||||
<Link to={`/user/profile/${record.uid}`}>
|
||||
<img
|
||||
src={
|
||||
location.protocol + '//' + location.host + '/api/user/avatar?uid=' + record.uid
|
||||
}
|
||||
className="m-user-img"
|
||||
/>
|
||||
</Link>
|
||||
<Link to={`/user/profile/${record.uid}`}>
|
||||
<p className="m-user-name">{text}</p>
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
// 非管理员可以看到权限 但无法修改
|
||||
if (record.role === 'owner') {
|
||||
return '组长';
|
||||
} else if (record.role === 'dev') {
|
||||
return '开发者';
|
||||
} else if (record.role === 'guest') {
|
||||
return '访客';
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title:
|
||||
this.state.role === 'owner' || this.state.role === 'admin' ? (
|
||||
<div className="btn-container">
|
||||
<Button className="btn" type="primary" onClick={this.showAddMemberModal}>
|
||||
添加成员
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
''
|
||||
),
|
||||
key: 'action',
|
||||
className: 'member-opration',
|
||||
render: (text, record) => {
|
||||
if (this.state.role === 'owner' || this.state.role === 'admin') {
|
||||
return (
|
||||
<div>
|
||||
<Select
|
||||
value={record.role + '-' + record.uid}
|
||||
className="select"
|
||||
onChange={this.changeUserRole}
|
||||
>
|
||||
<Option value={'owner-' + record.uid}>组长</Option>
|
||||
<Option value={'dev-' + record.uid}>开发者</Option>
|
||||
<Option value={'guest-' + record.uid}>访客</Option>
|
||||
</Select>
|
||||
<Popconfirm
|
||||
placement="topRight"
|
||||
title="你确定要删除吗? "
|
||||
onConfirm={this.deleteConfirm(record.uid)}
|
||||
okText="确定"
|
||||
cancelText=""
|
||||
>
|
||||
<Button type="danger" icon="delete" className="btn-danger" />
|
||||
{/* <Icon type="delete" className="btn-danger"/> */}
|
||||
</Popconfirm>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return '';
|
||||
// 非管理员可以看到权限 但无法修改
|
||||
if (record.role === 'owner') {
|
||||
return '组长';
|
||||
} else if (record.role === 'dev') {
|
||||
return '开发者';
|
||||
} else if (record.role === 'guest') {
|
||||
return '访客';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}];
|
||||
];
|
||||
let userinfo = this.state.userInfo;
|
||||
let ownerinfo = [];
|
||||
let devinfo = [];
|
||||
let guestinfo = [];
|
||||
for (let i = 0; i < userinfo.length; i++) {
|
||||
if (userinfo[i].role === "owner") {
|
||||
if (userinfo[i].role === 'owner') {
|
||||
ownerinfo.push(userinfo[i]);
|
||||
}
|
||||
if (userinfo[i].role === "dev") {
|
||||
if (userinfo[i].role === 'dev') {
|
||||
devinfo.push(userinfo[i]);
|
||||
}
|
||||
if (userinfo[i].role === "guest") {
|
||||
if (userinfo[i].role === 'guest') {
|
||||
guestinfo.push(userinfo[i]);
|
||||
}
|
||||
}
|
||||
userinfo = [...ownerinfo, ...devinfo, ...guestinfo];
|
||||
return (
|
||||
<div className="m-panel">
|
||||
{this.state.visible ? <Modal
|
||||
title="添加成员"
|
||||
visible={this.state.visible}
|
||||
onOk={this.handleOk}
|
||||
onCancel={this.handleCancel}
|
||||
okText="确认"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Row gutter={6} className="modal-input">
|
||||
<Col span="5"><div className="label usernamelabel">用户名: </div></Col>
|
||||
<Col span="15">
|
||||
<UsernameAutoComplete callbackState={this.onUserSelect} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row gutter={6} className="modal-input">
|
||||
<Col span="5"><div className="label usernameauth">权限: </div></Col>
|
||||
<Col span="15">
|
||||
<Select defaultValue="dev" className="select" onChange={this.changeNewMemberRole}>
|
||||
<Option value="owner">组长</Option>
|
||||
<Option value="dev">开发者</Option>
|
||||
<Option value="guest">访客</Option>
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
</Modal> : ""}
|
||||
<Table columns={columns} dataSource={userinfo} pagination={false} locale={{ emptyText: <ErrMsg type="noMemberInGroup" /> }} />
|
||||
{this.state.visible ? (
|
||||
<Modal
|
||||
title="添加成员"
|
||||
visible={this.state.visible}
|
||||
onOk={this.handleOk}
|
||||
onCancel={this.handleCancel}
|
||||
okText="确认"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Row gutter={6} className="modal-input">
|
||||
<Col span="5">
|
||||
<div className="label usernamelabel">用户名: </div>
|
||||
</Col>
|
||||
<Col span="15">
|
||||
<UsernameAutoComplete callbackState={this.onUserSelect} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row gutter={6} className="modal-input">
|
||||
<Col span="5">
|
||||
<div className="label usernameauth">权限: </div>
|
||||
</Col>
|
||||
<Col span="15">
|
||||
<Select defaultValue="dev" className="select" onChange={this.changeNewMemberRole}>
|
||||
<Option value="owner">组长</Option>
|
||||
<Option value="dev">开发者</Option>
|
||||
<Option value="guest">访客</Option>
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
</Modal>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={userinfo}
|
||||
pagination={false}
|
||||
locale={{ emptyText: <ErrMsg type="noMemberInGroup" /> }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -72,8 +72,8 @@ class ProjectList extends Component {
|
||||
}
|
||||
|
||||
// 获取 ProjectCard 组件的关注事件回调,收到后更新数据
|
||||
@autobind
|
||||
receiveRes() {
|
||||
|
||||
receiveRes = () => {
|
||||
this.props.fetchProjectList(this.props.currGroup._id, this.props.currPage);
|
||||
}
|
||||
|
||||
@ -119,6 +119,9 @@ class ProjectList extends Component {
|
||||
})
|
||||
projectData = [...followProject, ...noFollow]
|
||||
|
||||
|
||||
const isShow = /(admin)|(owner)|(dev)/.test(this.props.currGroup.role)
|
||||
|
||||
const Follow = () => {
|
||||
return followProject.length ? <Row>
|
||||
<h3 className="owner-type">我的关注</h3>
|
||||
@ -139,7 +142,7 @@ class ProjectList extends Component {
|
||||
noFollow.map((item, index) => {
|
||||
return (
|
||||
<Col xs={8} lg={6} xxl={4} key={index}>
|
||||
<ProjectCard projectData={item} callbackResult={this.receiveRes} />
|
||||
<ProjectCard projectData={item} callbackResult={this.receiveRes} isShow={isShow} />
|
||||
</Col>)
|
||||
})
|
||||
}
|
||||
@ -155,7 +158,7 @@ class ProjectList extends Component {
|
||||
: <ErrMsg type="noProject" />)
|
||||
}
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div style={{ paddingTop: '24px' }} className="m-panel card-panel card-panel-s project-list" >
|
||||
<Row className="project-list-header">
|
||||
@ -163,7 +166,7 @@ class ProjectList extends Component {
|
||||
{this.props.currGroup.group_name} 分组共 ({projectData.length}) 个项目
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
{/(admin)|(owner)|(dev)/.test(this.props.currGroup.role) ?
|
||||
{isShow?
|
||||
<Link to="/add-project"><Button type="primary">添加项目</Button></Link> :
|
||||
<Tooltip title="您没有权限,请联系该分组组长或管理员">
|
||||
<Button type="primary" disabled >添加项目</Button>
|
||||
@ -181,7 +184,7 @@ class ProjectList extends Component {
|
||||
this.props.currGroup.type === 'private' ? <OwnerSpace /> : projectData.length ? projectData.map((item, index) => {
|
||||
return (
|
||||
<Col xs={8} lg={6} xxl={4} key={index}>
|
||||
<ProjectCard projectData={item} callbackResult={this.receiveRes} />
|
||||
<ProjectCard projectData={item} callbackResult={this.receiveRes} isShow={isShow} />
|
||||
</Col>);
|
||||
}) : <ErrMsg type="noProject" />
|
||||
}
|
||||
|
@ -16,6 +16,9 @@ const DEL_PROJECT_MEMBER = 'yapi/project/DEL_PROJECT_MEMBER';
|
||||
const CHANGE_PROJECT_MEMBER = 'yapi/project/CHANGE_PROJECT_MEMBER';
|
||||
const GET_TOKEN = 'yapi/project/GET_TOKEN';
|
||||
const UPDATE_TOKEN = 'yapi/project/UPDATE_TOKEN';
|
||||
const CHECK_PROJECT_NAME = 'yapi/project/CHECK_PROJECT_NAME';
|
||||
const COPY_PROJECT_MSG = 'yapi/project/COPY_PROJECT_MSG';
|
||||
|
||||
|
||||
// Reducer
|
||||
const initialState = {
|
||||
@ -70,6 +73,18 @@ export default (state = initialState, action) => {
|
||||
token: action.payload.data.data.token
|
||||
}
|
||||
}
|
||||
|
||||
case CHECK_PROJECT_NAME: {
|
||||
return{
|
||||
...state
|
||||
|
||||
}
|
||||
}
|
||||
case COPY_PROJECT_MSG: {
|
||||
return {
|
||||
...state
|
||||
}
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
@ -89,15 +104,13 @@ export function fetchProjectList(id, pageNum) {
|
||||
};
|
||||
}
|
||||
|
||||
// // 获取项目信息
|
||||
// export function getProjectMsg(id) {
|
||||
// return {
|
||||
// type: GET_PROJECT_MSG,
|
||||
// payload: axios.get('/api/project/get', {
|
||||
// params: { id }
|
||||
// })
|
||||
// };
|
||||
// }
|
||||
// 复制项目
|
||||
export function copyProjectMsg(params) {
|
||||
return {
|
||||
type: COPY_PROJECT_MSG,
|
||||
payload: axios.post('/api/project/copy', params)
|
||||
};
|
||||
}
|
||||
|
||||
// 添加项目成员
|
||||
export function addMember(param) {
|
||||
@ -245,3 +258,12 @@ export async function updateToken(project_id){
|
||||
}
|
||||
}
|
||||
|
||||
export async function checkProjectName(name, group_id){
|
||||
return {
|
||||
type: CHECK_PROJECT_NAME,
|
||||
payload: axios.get('/api/project/check_project_name', {
|
||||
params: { name, group_id }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,7 +191,7 @@ class baseController {
|
||||
*/
|
||||
async checkAuth(id, type, action) {
|
||||
let role = await this.getProjectRole(id, type);
|
||||
console.log(role);
|
||||
|
||||
if (action === 'danger') {
|
||||
if (role === 'admin' || role === 'owner') {
|
||||
return true;
|
||||
|
@ -1,6 +1,6 @@
|
||||
const projectModel = require('../models/project.js');
|
||||
const yapi = require('../yapi.js');
|
||||
const _ = require("underscore");
|
||||
const _ = require('underscore');
|
||||
const baseController = require('./base.js');
|
||||
const interfaceModel = require('../models/interface.js');
|
||||
const interfaceColModel = require('../models/interfaceCol.js');
|
||||
@ -12,11 +12,10 @@ const userModel = require('../models/user.js');
|
||||
const logModel = require('../models/log.js');
|
||||
const followModel = require('../models/follow.js');
|
||||
const tokenModel = require('../models/token.js');
|
||||
|
||||
const sha = require('sha.js');
|
||||
|
||||
|
||||
class projectController extends baseController {
|
||||
|
||||
constructor(ctx) {
|
||||
super(ctx);
|
||||
this.Model = yapi.getInst(projectModel);
|
||||
@ -24,6 +23,7 @@ class projectController extends baseController {
|
||||
this.logModel = yapi.getInst(logModel);
|
||||
this.followModel = yapi.getInst(followModel);
|
||||
this.tokenModel = yapi.getInst(tokenModel);
|
||||
this.interfaceModel = yapi.getInst(interfaceModel);
|
||||
|
||||
const id = 'number';
|
||||
const member_uid = ['number'];
|
||||
@ -32,73 +32,89 @@ class projectController extends baseController {
|
||||
minLength: 1
|
||||
};
|
||||
const role = {
|
||||
type: "string",
|
||||
enum: ["owner", "dev", "guest"]
|
||||
}
|
||||
type: 'string',
|
||||
enum: ['owner', 'dev', 'guest']
|
||||
};
|
||||
const basepath = {
|
||||
type: 'string',
|
||||
default: ''
|
||||
};
|
||||
const group_id = 'number';
|
||||
const group_name = 'string'
|
||||
const group_name = 'string';
|
||||
const project_type = {
|
||||
type: 'string',
|
||||
enum: ['private', 'public'],
|
||||
default: 'private'
|
||||
}
|
||||
const desc = 'string'
|
||||
const icon = 'string'
|
||||
const color = 'string'
|
||||
};
|
||||
const desc = 'string';
|
||||
const icon = 'string';
|
||||
const color = 'string';
|
||||
const env = 'array';
|
||||
|
||||
const cat ='array';
|
||||
this.schemaMap = {
|
||||
add: {
|
||||
"*name": name,
|
||||
"basepath": basepath,
|
||||
"*group_id": group_id,
|
||||
'*name': name,
|
||||
basepath: basepath,
|
||||
'*group_id': group_id,
|
||||
group_name,
|
||||
desc: desc,
|
||||
color,
|
||||
icon,
|
||||
project_type
|
||||
},
|
||||
copy: {
|
||||
'*name': name,
|
||||
'preName': name,
|
||||
basepath: basepath,
|
||||
'*group_id': group_id,
|
||||
_id: id,
|
||||
cat,
|
||||
env,
|
||||
group_name,
|
||||
desc,
|
||||
color,
|
||||
icon,
|
||||
project_type
|
||||
},
|
||||
addMember: {
|
||||
"*id": id,
|
||||
"*member_uids": member_uid,
|
||||
"role": role
|
||||
'*id': id,
|
||||
'*member_uids': member_uid,
|
||||
role: role
|
||||
},
|
||||
delMember: {
|
||||
"*id": id,
|
||||
"*member_uid": id
|
||||
'*id': id,
|
||||
'*member_uid': id
|
||||
},
|
||||
getMemberList: {
|
||||
"*id": id
|
||||
'*id': id
|
||||
},
|
||||
get: {
|
||||
"*id": id
|
||||
'*id': id
|
||||
},
|
||||
list: {
|
||||
"*group_id": group_id
|
||||
'*group_id': group_id
|
||||
},
|
||||
del: {
|
||||
"*id": id
|
||||
'*id': id
|
||||
},
|
||||
changeMemberRole: {
|
||||
"*id": id,
|
||||
"*member_uid": id,
|
||||
'*id': id,
|
||||
'*member_uid': id,
|
||||
role
|
||||
},
|
||||
token: {
|
||||
'*project_id':id
|
||||
'*project_id': id
|
||||
},
|
||||
updateToken: {
|
||||
'*project_id':id
|
||||
'*project_id': id
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
handleBasepath(basepath) {
|
||||
if (!basepath) return "";
|
||||
if (basepath === '/') return "";
|
||||
if (!basepath) return '';
|
||||
if (basepath === '/') return '';
|
||||
if (basepath[0] !== '/') basepath = '/' + basepath;
|
||||
if (basepath[basepath.length - 1] === '/') basepath = basepath.substr(0, basepath.length - 1);
|
||||
if (!/^\/[a-zA-Z0-9\-\/_]+$/.test(basepath)) {
|
||||
@ -115,7 +131,27 @@ class projectController extends baseController {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断分组名称是否重复
|
||||
* @interface /project/check_project_name
|
||||
* @method get
|
||||
*/
|
||||
|
||||
async checkProjectName(ctx) {
|
||||
let name = ctx.request.query.name;
|
||||
let group_id = ctx.request.query.group_id;
|
||||
console.log(ctx.request.query);
|
||||
if (!name) {
|
||||
return (ctx.body = yapi.commons.resReturn(null, 401, '项目名不能为空'));
|
||||
}
|
||||
let checkRepeat = await this.Model.checkNameRepeat(name, group_id);
|
||||
|
||||
if (checkRepeat > 0) {
|
||||
return (ctx.body = yapi.commons.resReturn(null, 401, '已存在的项目名'));
|
||||
}
|
||||
|
||||
ctx.body = yapi.commons.resReturn({});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加项目分组
|
||||
@ -135,21 +171,20 @@ class projectController extends baseController {
|
||||
async add(ctx) {
|
||||
let params = ctx.params;
|
||||
|
||||
if (await this.checkAuth(params.group_id, 'group', 'edit') !== true) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
|
||||
if ((await this.checkAuth(params.group_id, 'group', 'edit')) !== true) {
|
||||
return (ctx.body = yapi.commons.resReturn(null, 405, '没有权限'));
|
||||
}
|
||||
|
||||
|
||||
let checkRepeat = await this.Model.checkNameRepeat(params.name, params.group_id);
|
||||
|
||||
if (checkRepeat > 0) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 401, '已存在的项目名');
|
||||
return (ctx.body = yapi.commons.resReturn(null, 401, '已存在的项目名'));
|
||||
}
|
||||
|
||||
params.basepath = params.basepath || '';
|
||||
|
||||
if ((params.basepath = this.handleBasepath(params.basepath)) === false) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 401, 'basepath格式有误');
|
||||
return (ctx.body = yapi.commons.resReturn(null, 401, 'basepath格式有误'));
|
||||
}
|
||||
|
||||
let data = {
|
||||
@ -179,7 +214,7 @@ class projectController extends baseController {
|
||||
uid: this.getUid(),
|
||||
add_time: yapi.commons.time(),
|
||||
up_time: yapi.commons.time()
|
||||
})
|
||||
});
|
||||
await catInst.save({
|
||||
name: '公共分类',
|
||||
project_id: result._id,
|
||||
@ -187,18 +222,19 @@ class projectController extends baseController {
|
||||
uid: this.getUid(),
|
||||
add_time: yapi.commons.time(),
|
||||
up_time: yapi.commons.time()
|
||||
})
|
||||
});
|
||||
}
|
||||
let uid = this.getUid();
|
||||
// 将项目添加者变成项目组长,除admin以外
|
||||
if (this.getRole() !== 'admin') {
|
||||
let userdata = await this.getUserdata(uid, 'owner')
|
||||
await this.Model.addMember(result._id, [userdata])
|
||||
|
||||
let userdata = await this.getUserdata(uid, 'owner');
|
||||
await this.Model.addMember(result._id, [userdata]);
|
||||
}
|
||||
let username = this.getUsername();
|
||||
yapi.commons.saveLog({
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 添加了项目 <a href="/project/${result._id}">${params.name}</a>`,
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 添加了项目 <a href="/project/${
|
||||
result._id
|
||||
}">${params.name}</a>`,
|
||||
type: 'project',
|
||||
uid,
|
||||
username: username,
|
||||
@ -207,49 +243,167 @@ class projectController extends baseController {
|
||||
ctx.body = yapi.commons.resReturn(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 拷贝项目分组
|
||||
* @interface /project/copy
|
||||
* @method POST
|
||||
* @category project
|
||||
* @foldnumber 10
|
||||
* @param {String} name 项目名称,不能为空
|
||||
* @param {String} basepath 项目基本路径,不能为空
|
||||
* @param {Number} group_id 项目分组id,不能为空
|
||||
* @param {Number} group_name 项目分组名称,不能为空
|
||||
* @param {String} project_type private public
|
||||
* @param {String} [desc] 项目描述
|
||||
* @returns {Object}
|
||||
* @example ./api/project/add.json
|
||||
*/
|
||||
async copy(ctx) {
|
||||
let params = ctx.params;
|
||||
|
||||
// 拷贝项目的ID
|
||||
let copyId = params._id;
|
||||
if ((await this.checkAuth(params.group_id, 'group', 'edit')) !== true) {
|
||||
return (ctx.body = yapi.commons.resReturn(null, 405, '没有权限'));
|
||||
}
|
||||
|
||||
params.basepath = params.basepath || '';
|
||||
|
||||
let data = {
|
||||
name: params.name,
|
||||
desc: params.desc,
|
||||
basepath: params.basepath,
|
||||
members: params.members || [],
|
||||
project_type: params.project_type || 'private',
|
||||
uid: this.getUid(),
|
||||
group_id: params.group_id,
|
||||
group_name: params.group_name,
|
||||
icon: params.icon,
|
||||
color: params.color,
|
||||
add_time: yapi.commons.time(),
|
||||
up_time: yapi.commons.time(),
|
||||
env: params.env || [{ name: 'local', domain: 'http://127.0.0.1' }]
|
||||
};
|
||||
|
||||
let result = await this.Model.save(data);
|
||||
let colInst = yapi.getInst(interfaceColModel);
|
||||
let catInst = yapi.getInst(interfaceCatModel);
|
||||
|
||||
// 增加集合
|
||||
if (result._id) {
|
||||
await colInst.save({
|
||||
name: '公共测试集',
|
||||
project_id: result._id,
|
||||
desc: '公共测试集',
|
||||
uid: this.getUid(),
|
||||
add_time: yapi.commons.time(),
|
||||
up_time: yapi.commons.time()
|
||||
});
|
||||
|
||||
// 拷贝接口列表
|
||||
let cat = params.cat;
|
||||
for (let i = 0; i < cat.length; i++) {
|
||||
let item = cat[i];
|
||||
let catDate = {
|
||||
name: item.name,
|
||||
project_id: result._id,
|
||||
desc: item.desc,
|
||||
uid: this.getUid(),
|
||||
add_time: yapi.commons.time(),
|
||||
up_time: yapi.commons.time()
|
||||
};
|
||||
let catResult = await catInst.save(catDate);
|
||||
|
||||
// 获取每个集合中的interface
|
||||
let interfaceData = await this.interfaceModel.listByInterStatus(item._id)
|
||||
|
||||
// 将interfaceData存到新的catID中
|
||||
for(let key =0 ; key < interfaceData.length ; key++){
|
||||
let interfaceItem = interfaceData[key].toObject();
|
||||
let data = Object.assign(interfaceItem, {
|
||||
uid: this.getUid(),
|
||||
catid: catResult._id,
|
||||
project_id: result._id,
|
||||
add_time: yapi.commons.time(),
|
||||
up_time: yapi.commons.time()
|
||||
});
|
||||
delete data._id;
|
||||
|
||||
await this.interfaceModel.save(data)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// 增加member
|
||||
let copyProject = await this.Model.get(copyId);
|
||||
let copyProjectMembers = copyProject.members;
|
||||
|
||||
let uid = this.getUid();
|
||||
// 将项目添加者变成项目组长,除admin以外
|
||||
if (this.getRole() !== 'admin') {
|
||||
let userdata = await this.getUserdata(uid, 'owner');
|
||||
copyProjectMembers.push(userdata)
|
||||
}
|
||||
await this.Model.addMember(result._id, copyProjectMembers);
|
||||
|
||||
// 在每个测试结合下添加interface
|
||||
|
||||
|
||||
let username = this.getUsername();
|
||||
yapi.commons.saveLog({
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 复制了项目 ${params.preName} 为 <a href="/project/${
|
||||
result._id
|
||||
}">${params.name}</a>`,
|
||||
type: 'project',
|
||||
uid,
|
||||
username: username,
|
||||
typeid: result._id
|
||||
});
|
||||
ctx.body = yapi.commons.resReturn(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加项目成员
|
||||
* @interface /project/add_member
|
||||
* @method POST
|
||||
* @category project
|
||||
* @foldnumber 10
|
||||
* @param {Number} id 项目id,不能为空
|
||||
* @param {Array} member_uid 项目成员uid,不能为空
|
||||
* @returns {Object}
|
||||
* @example ./api/project/add_member.json
|
||||
*/
|
||||
* 添加项目成员
|
||||
* @interface /project/add_member
|
||||
* @method POST
|
||||
* @category project
|
||||
* @foldnumber 10
|
||||
* @param {Number} id 项目id,不能为空
|
||||
* @param {Array} member_uid 项目成员uid,不能为空
|
||||
* @returns {Object}
|
||||
* @example ./api/project/add_member.json
|
||||
*/
|
||||
async addMember(ctx) {
|
||||
let params = ctx.params;
|
||||
if (await this.checkAuth(params.id, 'project', 'edit') !== true) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
|
||||
if ((await this.checkAuth(params.id, 'project', 'edit')) !== true) {
|
||||
return (ctx.body = yapi.commons.resReturn(null, 405, '没有权限'));
|
||||
}
|
||||
|
||||
params.role = ['owner', 'dev', 'guest'].find(v => v === params.role) || 'dev';
|
||||
let add_members = [];
|
||||
let exist_members = [];
|
||||
let no_members = []
|
||||
let no_members = [];
|
||||
for (let i = 0, len = params.member_uids.length; i < len; i++) {
|
||||
let id = params.member_uids[i]
|
||||
let id = params.member_uids[i];
|
||||
let check = await this.Model.checkMemberRepeat(params.id, id);
|
||||
let userdata = await this.getUserdata(id, params.role);
|
||||
if (check > 0) {
|
||||
exist_members.push(userdata)
|
||||
exist_members.push(userdata);
|
||||
} else if (!userdata) {
|
||||
no_members.push(id)
|
||||
no_members.push(id);
|
||||
} else {
|
||||
add_members.push(userdata)
|
||||
add_members.push(userdata);
|
||||
}
|
||||
}
|
||||
|
||||
let result = await this.Model.addMember(params.id, add_members);
|
||||
if (add_members.length) {
|
||||
let members = add_members.map((item) => {
|
||||
return `<a href = "/user/profile/${item.uid}">${item.username}</a>`
|
||||
})
|
||||
members = members.join("、");
|
||||
let members = add_members.map(item => {
|
||||
return `<a href = "/user/profile/${item.uid}">${item.username}</a>`;
|
||||
});
|
||||
members = members.join('、');
|
||||
let username = this.getUsername();
|
||||
yapi.commons.saveLog({
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 添加了项目成员 ${members}`,
|
||||
@ -265,48 +419,50 @@ class projectController extends baseController {
|
||||
exist_members,
|
||||
no_members
|
||||
});
|
||||
|
||||
}
|
||||
/**
|
||||
* 删除项目成员
|
||||
* @interface /project/del_member
|
||||
* @method POST
|
||||
* @category project
|
||||
* @foldnumber 10
|
||||
* @param {Number} id 项目id,不能为空
|
||||
* @param {member_uid} uid 项目成员uid,不能为空
|
||||
* @returns {Object}
|
||||
* @example ./api/project/del_member.json
|
||||
*/
|
||||
* 删除项目成员
|
||||
* @interface /project/del_member
|
||||
* @method POST
|
||||
* @category project
|
||||
* @foldnumber 10
|
||||
* @param {Number} id 项目id,不能为空
|
||||
* @param {member_uid} uid 项目成员uid,不能为空
|
||||
* @returns {Object}
|
||||
* @example ./api/project/del_member.json
|
||||
*/
|
||||
|
||||
async delMember(ctx) {
|
||||
let params = ctx.params;
|
||||
|
||||
var check = await this.Model.checkMemberRepeat(params.id, params.member_uid);
|
||||
if (check === 0) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 400, '项目成员不存在');
|
||||
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, '没有权限');
|
||||
if ((await this.checkAuth(params.id, 'project', 'danger')) !== true) {
|
||||
return (ctx.body = yapi.commons.resReturn(null, 405, '没有权限'));
|
||||
}
|
||||
|
||||
let result = await this.Model.delMember(params.id, params.member_uid);
|
||||
let username = this.getUsername();
|
||||
yapi.getInst(userModel).findById(params.member_uid).then((member) => {
|
||||
yapi.commons.saveLog({
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 删除了项目中的成员 <a href="/user/profile/${params.member_uid}">${member.username}</a>`,
|
||||
type: 'project',
|
||||
uid: this.getUid(),
|
||||
username: username,
|
||||
typeid: params.id
|
||||
yapi
|
||||
.getInst(userModel)
|
||||
.findById(params.member_uid)
|
||||
.then(member => {
|
||||
yapi.commons.saveLog({
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 删除了项目中的成员 <a href="/user/profile/${
|
||||
params.member_uid
|
||||
}">${member.username}</a>`,
|
||||
type: 'project',
|
||||
uid: this.getUid(),
|
||||
username: username,
|
||||
typeid: params.id
|
||||
});
|
||||
});
|
||||
});
|
||||
ctx.body = yapi.commons.resReturn(result);
|
||||
|
||||
}
|
||||
|
||||
|
||||
async getUserdata(uid, role) {
|
||||
role = role || 'dev';
|
||||
let userInst = yapi.getInst(userModel);
|
||||
@ -319,7 +475,7 @@ class projectController extends baseController {
|
||||
uid: userData._id,
|
||||
username: userData.username,
|
||||
email: userData.email
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -336,43 +492,42 @@ class projectController extends baseController {
|
||||
async getMemberList(ctx) {
|
||||
let params = ctx.params;
|
||||
if (!params.id) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
|
||||
return (ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空'));
|
||||
}
|
||||
|
||||
let project = await this.Model.get(params.id);
|
||||
ctx.body = yapi.commons.resReturn(project.members);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取项目信息
|
||||
* @interface /project/get
|
||||
* @method GET
|
||||
* @category project
|
||||
* @foldnumber 10
|
||||
* @param {Number} id 项目id,不能为空
|
||||
* @returns {Object}
|
||||
* @example ./api/project/get.json
|
||||
*/
|
||||
* 获取项目信息
|
||||
* @interface /project/get
|
||||
* @method GET
|
||||
* @category project
|
||||
* @foldnumber 10
|
||||
* @param {Number} id 项目id,不能为空
|
||||
* @returns {Object}
|
||||
* @example ./api/project/get.json
|
||||
*/
|
||||
|
||||
async get(ctx) {
|
||||
let params = ctx.params;
|
||||
let result = await this.Model.getBaseInfo(params.id);
|
||||
|
||||
if (!result) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 400, '不存在的项目');
|
||||
return (ctx.body = yapi.commons.resReturn(null, 400, '不存在的项目'));
|
||||
}
|
||||
if (result.project_type === 'private') {
|
||||
if (await this.checkAuth(result._id, 'project', 'view') !== true) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 406, '没有权限');
|
||||
if ((await this.checkAuth(result._id, 'project', 'view')) !== true) {
|
||||
return (ctx.body = yapi.commons.resReturn(null, 406, '没有权限'));
|
||||
}
|
||||
}
|
||||
result = result.toObject();
|
||||
let catInst = yapi.getInst(interfaceCatModel);
|
||||
let cat = await catInst.list(params.id);
|
||||
result.cat = cat;
|
||||
if(result.env.length === 0) {
|
||||
result.env.push({ name: 'local', domain: 'http://127.0.0.1' })
|
||||
if (result.env.length === 0) {
|
||||
result.env.push({ name: 'local', domain: 'http://127.0.0.1' });
|
||||
}
|
||||
result.role = await this.getProjectRole(params.id, 'project');
|
||||
|
||||
@ -392,14 +547,15 @@ class projectController extends baseController {
|
||||
*/
|
||||
|
||||
async list(ctx) {
|
||||
let group_id = ctx.params.group_id, project_list = [];
|
||||
let group_id = ctx.params.group_id,
|
||||
project_list = [];
|
||||
|
||||
let groupData = await this.groupModel.get(group_id);
|
||||
let isPrivateGroup = false;
|
||||
if (groupData.type === 'private' && this.getUid() === groupData.uid) {
|
||||
isPrivateGroup = true;
|
||||
}
|
||||
let auth = await this.checkAuth(group_id, 'group', 'view')
|
||||
let auth = await this.checkAuth(group_id, 'group', 'view');
|
||||
let result = await this.Model.list(group_id);
|
||||
let follow = await this.followModel.list(this.getUid());
|
||||
if (isPrivateGroup === false) {
|
||||
@ -412,9 +568,9 @@ class projectController extends baseController {
|
||||
}
|
||||
}
|
||||
|
||||
let f = _.find(follow, (fol) => {
|
||||
return fol.projectid === item._id
|
||||
})
|
||||
let f = _.find(follow, fol => {
|
||||
return fol.projectid === item._id;
|
||||
});
|
||||
// 排序:收藏的项目放前面
|
||||
if (f) {
|
||||
item.follow = true;
|
||||
@ -429,14 +585,13 @@ class projectController extends baseController {
|
||||
item = item.toObject();
|
||||
item.follow = true;
|
||||
return item;
|
||||
})
|
||||
project_list = _.uniq(follow.concat(result), item => item._id)
|
||||
});
|
||||
project_list = _.uniq(follow.concat(result), item => item._id);
|
||||
}
|
||||
|
||||
ctx.body = yapi.commons.resReturn({
|
||||
list: project_list
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -453,20 +608,19 @@ class projectController extends baseController {
|
||||
async del(ctx) {
|
||||
let id = ctx.params.id;
|
||||
|
||||
if (await this.checkAuth(id, 'project', 'danger') !== true) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
|
||||
if ((await this.checkAuth(id, 'project', 'danger')) !== true) {
|
||||
return (ctx.body = yapi.commons.resReturn(null, 405, '没有权限'));
|
||||
}
|
||||
|
||||
let interfaceInst = yapi.getInst(interfaceModel);
|
||||
let interfaceColInst = yapi.getInst(interfaceColModel);
|
||||
let interfaceCaseInst = yapi.getInst(interfaceCaseModel);
|
||||
await interfaceInst.delByProjectId(id)
|
||||
await interfaceCaseInst.delByProjectId(id)
|
||||
await interfaceColInst.delByProjectId(id)
|
||||
await interfaceInst.delByProjectId(id);
|
||||
await interfaceCaseInst.delByProjectId(id);
|
||||
await interfaceColInst.delByProjectId(id);
|
||||
yapi.emitHook('project_del', id).then();
|
||||
let result = await this.Model.del(id);
|
||||
ctx.body = yapi.commons.resReturn(result);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -487,33 +641,37 @@ class projectController extends baseController {
|
||||
|
||||
var check = await projectInst.checkMemberRepeat(params.id, params.member_uid);
|
||||
if (check === 0) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 400, '项目成员不存在');
|
||||
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, '没有权限');
|
||||
if ((await this.checkAuth(params.id, 'project', 'danger')) !== true) {
|
||||
return (ctx.body = yapi.commons.resReturn(null, 405, '没有权限'));
|
||||
}
|
||||
|
||||
params.role = ['owner', 'dev', 'guest'].find(v => v === params.role) || 'dev';
|
||||
let rolename = {
|
||||
'owner': '组长',
|
||||
'dev': '开发者',
|
||||
'guest': '访客'
|
||||
owner: '组长',
|
||||
dev: '开发者',
|
||||
guest: '访客'
|
||||
};
|
||||
|
||||
let result = await projectInst.changeMemberRole(params.id, params.member_uid, params.role);
|
||||
|
||||
let username = this.getUsername();
|
||||
yapi.getInst(userModel).findById(params.member_uid).then((member) => {
|
||||
yapi.commons.saveLog({
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 修改了项目中的成员 <a href="/user/profile/${params.member_uid}">${member.username}</a> 的角色为 "${rolename[params.role]}"`,
|
||||
type: 'project',
|
||||
uid: this.getUid(),
|
||||
username: username,
|
||||
typeid: params.id
|
||||
yapi
|
||||
.getInst(userModel)
|
||||
.findById(params.member_uid)
|
||||
.then(member => {
|
||||
yapi.commons.saveLog({
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 修改了项目中的成员 <a href="/user/profile/${
|
||||
params.member_uid
|
||||
}">${member.username}</a> 的角色为 "${rolename[params.role]}"`,
|
||||
type: 'project',
|
||||
uid: this.getUid(),
|
||||
username: username,
|
||||
typeid: params.id
|
||||
});
|
||||
});
|
||||
})
|
||||
ctx.body = yapi.commons.resReturn(result);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -531,13 +689,13 @@ class projectController extends baseController {
|
||||
async upSet(ctx) {
|
||||
let id = ctx.request.body.id;
|
||||
let data = {};
|
||||
if (await this.checkAuth(id, 'project', 'danger') !== true) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
|
||||
if ((await this.checkAuth(id, 'project', 'danger')) !== true) {
|
||||
return (ctx.body = yapi.commons.resReturn(null, 405, '没有权限'));
|
||||
}
|
||||
data.color = ctx.request.body.color;
|
||||
data.icon = ctx.request.body.icon;
|
||||
if (!id) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 405, '项目id不能为空');
|
||||
return (ctx.body = yapi.commons.resReturn(null, 405, '项目id不能为空'));
|
||||
}
|
||||
try {
|
||||
let result = await this.Model.up(id, data);
|
||||
@ -588,20 +746,19 @@ class projectController extends baseController {
|
||||
after_script: 'string'
|
||||
});
|
||||
|
||||
|
||||
if (!id) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 405, '项目id不能为空');
|
||||
return (ctx.body = yapi.commons.resReturn(null, 405, '项目id不能为空'));
|
||||
}
|
||||
|
||||
if (await this.checkAuth(id, 'project', 'danger') !== true) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
|
||||
if ((await this.checkAuth(id, 'project', 'danger')) !== true) {
|
||||
return (ctx.body = yapi.commons.resReturn(null, 405, '没有权限'));
|
||||
}
|
||||
|
||||
let projectData = await this.Model.get(id);
|
||||
|
||||
if (params.basepath) {
|
||||
if ((params.basepath = this.handleBasepath(params.basepath)) === false) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 401, 'basepath格式有误');
|
||||
return (ctx.body = yapi.commons.resReturn(null, 401, 'basepath格式有误'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -612,16 +769,15 @@ class projectController extends baseController {
|
||||
if (params.name) {
|
||||
let checkRepeat = await this.Model.checkNameRepeat(params.name, params.group_id);
|
||||
if (checkRepeat > 0) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 401, '已存在的项目名');
|
||||
return (ctx.body = yapi.commons.resReturn(null, 401, '已存在的项目名'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let data = {
|
||||
up_time: yapi.commons.time()
|
||||
};
|
||||
if (params.project_type) {
|
||||
data.project_type = params.project_type
|
||||
data.project_type = params.project_type;
|
||||
}
|
||||
|
||||
if (!_.isUndefined(params.name)) data.name = params.name;
|
||||
@ -633,11 +789,13 @@ class projectController extends baseController {
|
||||
if (!_.isUndefined(params.icon)) data.icon = params.icon;
|
||||
if (!_.isUndefined(params.pre_script)) data.pre_script = params.pre_script;
|
||||
if (!_.isUndefined(params.after_script)) data.after_script = params.after_script;
|
||||
|
||||
|
||||
let result = await this.Model.up(id, data);
|
||||
let username = this.getUsername();
|
||||
yapi.commons.saveLog({
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 更新了项目 <a href="/project/${id}/interface/api}">${projectData.name}</a>`,
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 更新了项目 <a href="/project/${id}/interface/api}">${
|
||||
projectData.name
|
||||
}</a>`,
|
||||
type: 'project',
|
||||
uid: this.getUid(),
|
||||
username: username,
|
||||
@ -649,7 +807,6 @@ class projectController extends baseController {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 编辑项目
|
||||
* @interface /project/up_env
|
||||
@ -662,22 +819,22 @@ class projectController extends baseController {
|
||||
* @param {String} [env[].domain] 环境域名
|
||||
* @param {Array} [env[].header] header
|
||||
* @returns {Object}
|
||||
* @example
|
||||
* @example
|
||||
*/
|
||||
async upEnv(ctx) {
|
||||
try {
|
||||
let id = ctx.request.body.id;
|
||||
let params = ctx.request.body;
|
||||
if (!id) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 405, '项目id不能为空');
|
||||
return (ctx.body = yapi.commons.resReturn(null, 405, '项目id不能为空'));
|
||||
}
|
||||
|
||||
if (await this.checkAuth(id, 'project', 'edit') !== true) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
|
||||
if ((await this.checkAuth(id, 'project', 'edit')) !== true) {
|
||||
return (ctx.body = yapi.commons.resReturn(null, 405, '没有权限'));
|
||||
}
|
||||
|
||||
if (!params.env || !Array.isArray(params.env)) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 405, 'env参数格式有误');
|
||||
return (ctx.body = yapi.commons.resReturn(null, 405, 'env参数格式有误'));
|
||||
}
|
||||
|
||||
let projectData = await this.Model.get(id);
|
||||
@ -688,12 +845,14 @@ class projectController extends baseController {
|
||||
data.env = params.env;
|
||||
let isRepeat = this.arrRepeat(data.env, 'name');
|
||||
if (isRepeat) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 405, '环境变量名重复');
|
||||
return (ctx.body = yapi.commons.resReturn(null, 405, '环境变量名重复'));
|
||||
}
|
||||
let result = await this.Model.up(id, data);
|
||||
let username = this.getUsername();
|
||||
yapi.commons.saveLog({
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 更新了项目 <a href="/project/${id}/interface/api">${projectData.name}</a> 的环境`,
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 更新了项目 <a href="/project/${id}/interface/api">${
|
||||
projectData.name
|
||||
}</a> 的环境`,
|
||||
type: 'project',
|
||||
uid: this.getUid(),
|
||||
username: username,
|
||||
@ -707,8 +866,8 @@ class projectController extends baseController {
|
||||
|
||||
arrRepeat(arr, key) {
|
||||
const s = new Set();
|
||||
arr.forEach(item => s.add(item[key]))
|
||||
return s.size !== arr.length
|
||||
arr.forEach(item => s.add(item[key]));
|
||||
return s.size !== arr.length;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -720,16 +879,19 @@ class projectController extends baseController {
|
||||
* @param {Number} id 项目id,不能为空
|
||||
* @param {String} q
|
||||
* @return {Object}
|
||||
*/
|
||||
*/
|
||||
async token(ctx) {
|
||||
try {
|
||||
let project_id = ctx.params.project_id ;
|
||||
try {
|
||||
let project_id = ctx.params.project_id;
|
||||
let data = await this.tokenModel.get(project_id);
|
||||
let token;
|
||||
if (!data ) {
|
||||
if (!data) {
|
||||
let passsalt = yapi.commons.randStr();
|
||||
token = sha('sha1').update(passsalt).digest('hex').substr(0, 20);
|
||||
await this.tokenModel.save({project_id, token})
|
||||
token = sha('sha1')
|
||||
.update(passsalt)
|
||||
.digest('hex')
|
||||
.substr(0, 20);
|
||||
await this.tokenModel.save({ project_id, token });
|
||||
} else {
|
||||
token = data.token;
|
||||
}
|
||||
@ -749,28 +911,29 @@ class projectController extends baseController {
|
||||
* @param {Number} id 项目id,不能为空
|
||||
* @param {String} q
|
||||
* @return {Object}
|
||||
*/
|
||||
*/
|
||||
async updateToken(ctx) {
|
||||
try {
|
||||
let project_id = ctx.params.project_id ;
|
||||
let data = await this.tokenModel.get(project_id);
|
||||
let token, result;
|
||||
if (data && data.token ) {
|
||||
let passsalt = yapi.commons.randStr();
|
||||
token = sha('sha1').update(passsalt).digest('hex').substr(0, 20);
|
||||
result = await this.tokenModel.up(project_id, token)
|
||||
result.token = token
|
||||
} else {
|
||||
ctx.body = yapi.commons.resReturn(null, 402, '没有查到token信息');
|
||||
}
|
||||
|
||||
ctx.body = yapi.commons.resReturn(result);
|
||||
} catch (err) {
|
||||
ctx.body = yapi.commons.resReturn(null, 402, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
let project_id = ctx.params.project_id;
|
||||
let data = await this.tokenModel.get(project_id);
|
||||
let token, result;
|
||||
if (data && data.token) {
|
||||
let passsalt = yapi.commons.randStr();
|
||||
token = sha('sha1')
|
||||
.update(passsalt)
|
||||
.digest('hex')
|
||||
.substr(0, 20);
|
||||
result = await this.tokenModel.up(project_id, token);
|
||||
result.token = token;
|
||||
} else {
|
||||
ctx.body = yapi.commons.resReturn(null, 402, '没有查到token信息');
|
||||
}
|
||||
|
||||
ctx.body = yapi.commons.resReturn(result);
|
||||
} catch (err) {
|
||||
ctx.body = yapi.commons.resReturn(null, 402, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 模糊搜索项目名称或者组名称
|
||||
@ -781,16 +944,16 @@ class projectController extends baseController {
|
||||
* @param {String} q
|
||||
* @return {Object}
|
||||
* @example ./api/project/search.json
|
||||
*/
|
||||
*/
|
||||
async search(ctx) {
|
||||
const { q } = ctx.request.query;
|
||||
|
||||
if (!q) {
|
||||
return ctx.body = yapi.commons.resReturn(void 0, 400, 'No keyword.');
|
||||
return (ctx.body = yapi.commons.resReturn(void 0, 400, 'No keyword.'));
|
||||
}
|
||||
|
||||
if (!yapi.commons.validateSearchKeyword(q)) {
|
||||
return ctx.body = yapi.commons.resReturn(void 0, 400, 'Bad query.');
|
||||
return (ctx.body = yapi.commons.resReturn(void 0, 400, 'Bad query.'));
|
||||
}
|
||||
|
||||
let projectList = await this.Model.search(q);
|
||||
@ -823,7 +986,7 @@ class projectController extends baseController {
|
||||
group: groupList
|
||||
};
|
||||
|
||||
return ctx.body = yapi.commons.resReturn(queryList, 0, 'ok');
|
||||
return (ctx.body = yapi.commons.resReturn(queryList, 0, 'ok'));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -249,6 +249,14 @@ let routerConfig = {
|
||||
"action": "updateToken",
|
||||
"path": "update_token",
|
||||
"method": "get"
|
||||
},{
|
||||
action: 'checkProjectName',
|
||||
path: 'check_project_name',
|
||||
method: 'get'
|
||||
},{
|
||||
action: 'copy',
|
||||
path: 'copy',
|
||||
method:'post'
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user