mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-09 19:01:42 +00:00
improve org admin manage department
This commit is contained in:
108
frontend/src/components/dialog/org-rename-department-dialog.js
Normal file
108
frontend/src/components/dialog/org-rename-department-dialog.js
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Button, Modal, ModalHeader, ModalBody, ModalFooter, Input, Form, FormGroup, Label } from 'reactstrap';
|
||||||
|
import { gettext } from '../../utils/constants';
|
||||||
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
|
import { Utils } from '../../utils/utils';
|
||||||
|
import toaster from '../toast';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
groupID: PropTypes.oneOfType([
|
||||||
|
PropTypes.string,
|
||||||
|
PropTypes.number
|
||||||
|
]).isRequired,
|
||||||
|
orgID: PropTypes.oneOfType([
|
||||||
|
PropTypes.string,
|
||||||
|
PropTypes.number
|
||||||
|
]).isRequired,
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
toggle: PropTypes.func.isRequired,
|
||||||
|
onDepartmentNameChanged: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
class RenameDepartmentDialog extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
departmentName: this.props.name,
|
||||||
|
errMessage: ''
|
||||||
|
};
|
||||||
|
this.newInput = React.createRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.newInput.select();
|
||||||
|
this.newInput.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSubmit = () => {
|
||||||
|
let isValid = this.validateName();
|
||||||
|
const { orgID, groupID } = this.props;
|
||||||
|
if (isValid) {
|
||||||
|
seafileAPI.orgAdminUpdateDepartGroup(orgID, groupID, this.state.departmentName.trim()).then((res) => {
|
||||||
|
this.props.toggle();
|
||||||
|
this.props.onDepartmentNameChanged(res.data);
|
||||||
|
toaster.success(gettext('Success'));
|
||||||
|
}).catch(error => {
|
||||||
|
let errorMsg = Utils.getErrorMsg(error);
|
||||||
|
this.setState({ errMessage: errorMsg });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validateName = () => {
|
||||||
|
let errMessage = '';
|
||||||
|
const name = this.state.departmentName.trim();
|
||||||
|
if (!name.length) {
|
||||||
|
errMessage = gettext('Name is required');
|
||||||
|
this.setState({ errMessage: errMessage });
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChange = (e) => {
|
||||||
|
this.setState({
|
||||||
|
departmentName: e.target.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleKeyPress = (e) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
this.handleSubmit();
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let header = gettext('Rename Department');
|
||||||
|
return (
|
||||||
|
<Modal isOpen={true} toggle={this.props.toggle}>
|
||||||
|
<ModalHeader toggle={this.props.toggle}>{header}</ModalHeader>
|
||||||
|
<ModalBody>
|
||||||
|
<Form>
|
||||||
|
<FormGroup>
|
||||||
|
<Label for="departmentName">{gettext('Name')}</Label>
|
||||||
|
<Input
|
||||||
|
id="departmentName"
|
||||||
|
onKeyPress={this.handleKeyPress}
|
||||||
|
value={this.state.departmentName}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
innerRef={input => {this.newInput = input;}}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</Form>
|
||||||
|
{this.state.errMessage && <p className="error">{this.state.errMessage}</p>}
|
||||||
|
</ModalBody>
|
||||||
|
<ModalFooter>
|
||||||
|
<Button color="primary" onClick={this.handleSubmit}>{gettext('Submit')}</Button>
|
||||||
|
</ModalFooter>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RenameDepartmentDialog.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default RenameDepartmentDialog;
|
@@ -15,6 +15,8 @@ import AddRepoDialog from '../../components/dialog/org-add-repo-dialog';
|
|||||||
import DeleteRepoDialog from '../../components/dialog/org-delete-repo-dialog';
|
import DeleteRepoDialog from '../../components/dialog/org-delete-repo-dialog';
|
||||||
import DeleteDepartDialog from '../../components/dialog/org-delete-department-dialog';
|
import DeleteDepartDialog from '../../components/dialog/org-delete-department-dialog';
|
||||||
import SetGroupQuotaDialog from '../../components/dialog/org-set-group-quota-dialog';
|
import SetGroupQuotaDialog from '../../components/dialog/org-set-group-quota-dialog';
|
||||||
|
import RenameDepartmentDialog from '../../components/dialog/org-rename-department-dialog';
|
||||||
|
import OpMenu from '../../components/dialog/op-menu';
|
||||||
import { serviceURL, siteRoot, gettext, orgID, lang } from '../../utils/constants';
|
import { serviceURL, siteRoot, gettext, orgID, lang } from '../../utils/constants';
|
||||||
import '../../css/org-department-item.css';
|
import '../../css/org-department-item.css';
|
||||||
|
|
||||||
@@ -27,6 +29,7 @@ class OrgDepartmentItem extends React.Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
groupName: '',
|
groupName: '',
|
||||||
isItemFreezed: false,
|
isItemFreezed: false,
|
||||||
|
isDepartFreezed: false,
|
||||||
ancestorGroups: [],
|
ancestorGroups: [],
|
||||||
members: [],
|
members: [],
|
||||||
deletedMember: {},
|
deletedMember: {},
|
||||||
@@ -99,6 +102,25 @@ class OrgDepartmentItem extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onFreezedDepart = () => {
|
||||||
|
this.setState({isDepartFreezed: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnfreezedDepart = () => {
|
||||||
|
this.setState({isDepartFreezed: false});
|
||||||
|
}
|
||||||
|
|
||||||
|
onDepartmentNameChanged = (dept) => {
|
||||||
|
this.setState({
|
||||||
|
groups: this.state.groups.map(item => {
|
||||||
|
if (item.id == dept.id) {
|
||||||
|
item.name = dept.name;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
onSubDepartChanged = () => {
|
onSubDepartChanged = () => {
|
||||||
this.listSubDepartGroups(this.props.groupID);
|
this.listSubDepartGroups(this.props.groupID);
|
||||||
}
|
}
|
||||||
@@ -237,6 +259,10 @@ class OrgDepartmentItem extends React.Component {
|
|||||||
<React.Fragment key={group.id}>
|
<React.Fragment key={group.id}>
|
||||||
<GroupItem
|
<GroupItem
|
||||||
group={group}
|
group={group}
|
||||||
|
isItemFreezed={this.state.isDepartFreezed}
|
||||||
|
onFreezedItem={this.onFreezedDepart}
|
||||||
|
onUnfreezedItem={this.onUnfreezedDepart}
|
||||||
|
onDepartmentNameChanged={this.onDepartmentNameChanged}
|
||||||
showDeleteDepartDialog={this.showDeleteDepartDialog}
|
showDeleteDepartDialog={this.showDeleteDepartDialog}
|
||||||
showSetGroupQuotaDialog={this.showSetGroupQuotaDialog}
|
showSetGroupQuotaDialog={this.showSetGroupQuotaDialog}
|
||||||
/>
|
/>
|
||||||
@@ -490,33 +516,108 @@ class GroupItem extends React.Component {
|
|||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
highlight: false,
|
highlight: false,
|
||||||
|
isOpIconShown: false,
|
||||||
|
isRenameDialogOpen: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseEnter = () => {
|
onMouseEnter = () => {
|
||||||
this.setState({ highlight: true });
|
if (!this.props.isItemFreezed) {
|
||||||
|
this.setState({
|
||||||
|
isOpIconShown: true,
|
||||||
|
highlight: true
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseLeave = () => {
|
onMouseLeave = () => {
|
||||||
this.setState({ highlight: false });
|
if (!this.props.isItemFreezed) {
|
||||||
|
this.setState({
|
||||||
|
isOpIconShown: false,
|
||||||
|
highlight: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
translateOperations = (item) => {
|
||||||
|
let translateResult = '';
|
||||||
|
switch(item) {
|
||||||
|
case 'Rename':
|
||||||
|
translateResult = gettext('Rename');
|
||||||
|
break;
|
||||||
|
case 'Delete':
|
||||||
|
translateResult = gettext('Delete');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return translateResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMenuItemClick = (operation) => {
|
||||||
|
const { group } = this.props;
|
||||||
|
switch(operation) {
|
||||||
|
case 'Rename':
|
||||||
|
this.toggleRenameDialog();
|
||||||
|
break;
|
||||||
|
case 'Delete':
|
||||||
|
this.props.showDeleteDepartDialog(group);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnfreezedItem = () => {
|
||||||
|
this.setState({
|
||||||
|
highlight: false,
|
||||||
|
isOpIconShow: false
|
||||||
|
});
|
||||||
|
this.props.onUnfreezedItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleRenameDialog = () => {
|
||||||
|
this.setState({
|
||||||
|
isRenameDialogOpen: !this.state.isRenameDialogOpen
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const group = this.props.group;
|
const group = this.props.group;
|
||||||
const highlight = this.state.highlight;
|
const { highlight, isOpIconShown, isRenameDialogOpen } = this.state;
|
||||||
const newHref = siteRoot+ 'org/departmentadmin/groups/' + group.id + '/';
|
const newHref = siteRoot+ 'org/departmentadmin/groups/' + group.id + '/';
|
||||||
return (
|
return (
|
||||||
<tr className={highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
|
<Fragment>
|
||||||
<td><Link to={newHref}>{group.name}</Link></td>
|
<tr className={highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
|
||||||
<td>{moment(group.created_at).fromNow()}</td>
|
<td><Link to={newHref}>{group.name}</Link></td>
|
||||||
<td onClick={this.props.showSetGroupQuotaDialog.bind(this, group.id)}>
|
<td>{moment(group.created_at).fromNow()}</td>
|
||||||
{Utils.bytesToSize(group.quota)}{' '}
|
<td onClick={this.props.showSetGroupQuotaDialog.bind(this, group.id)}>
|
||||||
<span title="Edit Quota" className={`fa fa-pencil-alt attr-action-icon ${highlight ? '' : 'vh'}`}></span>
|
{Utils.bytesToSize(group.quota)}{' '}
|
||||||
</td>
|
<span title="Edit Quota" className={`fa fa-pencil-alt attr-action-icon ${highlight ? '' : 'vh'}`}></span>
|
||||||
<td className="cursor-pointer text-center" onClick={this.props.showDeleteDepartDialog.bind(this, group)}>
|
</td>
|
||||||
<span className={`sf2-icon-delete action-icon ${highlight ? '' : 'vh'}`} title="Delete"></span>
|
<td>
|
||||||
</td>
|
{isOpIconShown &&
|
||||||
</tr>
|
<OpMenu
|
||||||
|
operations={['Rename', 'Delete']}
|
||||||
|
translateOperations={this.translateOperations}
|
||||||
|
onMenuItemClick={this.onMenuItemClick}
|
||||||
|
onFreezedItem={this.props.onFreezedItem}
|
||||||
|
onUnfreezedItem={this.onUnfreezedItem}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{isRenameDialogOpen && (
|
||||||
|
<RenameDepartmentDialog
|
||||||
|
orgID={orgID}
|
||||||
|
groupID={group.id}
|
||||||
|
name={group.name}
|
||||||
|
toggle={this.toggleRenameDialog}
|
||||||
|
onDepartmentNameChanged={this.props.onDepartmentNameChanged}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -524,6 +625,10 @@ class GroupItem extends React.Component {
|
|||||||
const GroupItemPropTypes = {
|
const GroupItemPropTypes = {
|
||||||
group: PropTypes.object.isRequired,
|
group: PropTypes.object.isRequired,
|
||||||
groupID: PropTypes.string,
|
groupID: PropTypes.string,
|
||||||
|
isItemFreezed: PropTypes.bool.isRequired,
|
||||||
|
onFreezedItem: PropTypes.func.isRequired,
|
||||||
|
onUnfreezedItem: PropTypes.func.isRequired,
|
||||||
|
onDepartmentNameChanged: PropTypes.func.isRequired,
|
||||||
showSetGroupQuotaDialog: PropTypes.func.isRequired,
|
showSetGroupQuotaDialog: PropTypes.func.isRequired,
|
||||||
showDeleteDepartDialog: PropTypes.func.isRequired,
|
showDeleteDepartDialog: PropTypes.func.isRequired,
|
||||||
isSubdepartChanged: PropTypes.bool,
|
isSubdepartChanged: PropTypes.bool,
|
||||||
|
@@ -9,6 +9,8 @@ import ModalPortal from '../../components/modal-portal';
|
|||||||
import AddDepartDialog from '../../components/dialog/org-add-department-dialog';
|
import AddDepartDialog from '../../components/dialog/org-add-department-dialog';
|
||||||
import DeleteDepartDialog from '../../components/dialog/org-delete-department-dialog';
|
import DeleteDepartDialog from '../../components/dialog/org-delete-department-dialog';
|
||||||
import SetGroupQuotaDialog from '../../components/dialog/org-set-group-quota-dialog';
|
import SetGroupQuotaDialog from '../../components/dialog/org-set-group-quota-dialog';
|
||||||
|
import RenameDepartmentDialog from '../../components/dialog/org-rename-department-dialog';
|
||||||
|
import OpMenu from '../../components/dialog/op-menu';
|
||||||
import { siteRoot, gettext, orgID, lang } from '../../utils/constants';
|
import { siteRoot, gettext, orgID, lang } from '../../utils/constants';
|
||||||
import '../../css/org-department-item.css';
|
import '../../css/org-department-item.css';
|
||||||
|
|
||||||
@@ -25,6 +27,7 @@ class OrgDepartmentsList extends React.Component {
|
|||||||
showDeleteDepartDialog: false,
|
showDeleteDepartDialog: false,
|
||||||
showSetGroupQuotaDialog: false,
|
showSetGroupQuotaDialog: false,
|
||||||
isShowAddDepartDialog: false,
|
isShowAddDepartDialog: false,
|
||||||
|
isItemFreezed: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,6 +41,25 @@ class OrgDepartmentsList extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onFreezedItem = () => {
|
||||||
|
this.setState({isItemFreezed: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnfreezedItem = () => {
|
||||||
|
this.setState({isItemFreezed: false});
|
||||||
|
}
|
||||||
|
|
||||||
|
onDepartmentNameChanged = (dept) => {
|
||||||
|
this.setState({
|
||||||
|
groups: this.state.groups.map(item => {
|
||||||
|
if (item.id == dept.id) {
|
||||||
|
item.name = dept.name;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
showDeleteDepartDialog = (group) => {
|
showDeleteDepartDialog = (group) => {
|
||||||
this.setState({ showDeleteDepartDialog: true, groupID: group.id, groupName: group.name });
|
this.setState({ showDeleteDepartDialog: true, groupID: group.id, groupName: group.name });
|
||||||
}
|
}
|
||||||
@@ -105,6 +127,10 @@ class OrgDepartmentsList extends React.Component {
|
|||||||
<React.Fragment key={group.id}>
|
<React.Fragment key={group.id}>
|
||||||
<GroupItem
|
<GroupItem
|
||||||
group={group}
|
group={group}
|
||||||
|
isItemFreezed={this.state.isItemFreezed}
|
||||||
|
onFreezedItem={this.onFreezedItem}
|
||||||
|
onUnfreezedItem={this.onUnfreezedItem}
|
||||||
|
onDepartmentNameChanged={this.onDepartmentNameChanged}
|
||||||
showDeleteDepartDialog={this.showDeleteDepartDialog}
|
showDeleteDepartDialog={this.showDeleteDepartDialog}
|
||||||
showSetGroupQuotaDialog={this.showSetGroupQuotaDialog}
|
showSetGroupQuotaDialog={this.showSetGroupQuotaDialog}
|
||||||
/>
|
/>
|
||||||
@@ -151,39 +177,118 @@ class GroupItem extends React.Component {
|
|||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
highlight: false,
|
highlight: false,
|
||||||
|
isOpIconShown: false,
|
||||||
|
isRenameDialogOpen: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseEnter = () => {
|
onMouseEnter = () => {
|
||||||
this.setState({ highlight: true });
|
if (!this.props.isItemFreezed) {
|
||||||
|
this.setState({
|
||||||
|
isOpIconShown: true,
|
||||||
|
highlight: true
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseLeave = () => {
|
onMouseLeave = () => {
|
||||||
this.setState({ highlight: false });
|
if (!this.props.isItemFreezed) {
|
||||||
|
this.setState({
|
||||||
|
isOpIconShown: false,
|
||||||
|
highlight: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
translateOperations = (item) => {
|
||||||
|
let translateResult = '';
|
||||||
|
switch(item) {
|
||||||
|
case 'Rename':
|
||||||
|
translateResult = gettext('Rename');
|
||||||
|
break;
|
||||||
|
case 'Delete':
|
||||||
|
translateResult = gettext('Delete');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return translateResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMenuItemClick = (operation) => {
|
||||||
|
const { group } = this.props;
|
||||||
|
switch(operation) {
|
||||||
|
case 'Rename':
|
||||||
|
this.toggleRenameDialog();
|
||||||
|
break;
|
||||||
|
case 'Delete':
|
||||||
|
this.props.showDeleteDepartDialog(group);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnfreezedItem = () => {
|
||||||
|
this.setState({
|
||||||
|
highlight: false,
|
||||||
|
isOpIconShow: false
|
||||||
|
});
|
||||||
|
this.props.onUnfreezedItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleRenameDialog = () => {
|
||||||
|
this.setState({
|
||||||
|
isRenameDialogOpen: !this.state.isRenameDialogOpen
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const group = this.props.group;
|
const group = this.props.group;
|
||||||
const highlight = this.state.highlight;
|
const { highlight, isOpIconShown, isRenameDialogOpen } = this.state;
|
||||||
const newHref = siteRoot+ 'org/departmentadmin/groups/' + group.id + '/';
|
const newHref = siteRoot+ 'org/departmentadmin/groups/' + group.id + '/';
|
||||||
return (
|
return (
|
||||||
<tr className={highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
|
<Fragment>
|
||||||
<td><Link to={newHref}>{group.name}</Link></td>
|
<tr className={highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
|
||||||
<td>{moment(group.created_at).fromNow()}</td>
|
<td><Link to={newHref}>{group.name}</Link></td>
|
||||||
<td onClick={this.props.showSetGroupQuotaDialog.bind(this, group.id)}>
|
<td>{moment(group.created_at).fromNow()}</td>
|
||||||
{Utils.bytesToSize(group.quota)}{' '}
|
<td onClick={this.props.showSetGroupQuotaDialog.bind(this, group.id)}>
|
||||||
<span title="Edit Quota" className={`fa fa-pencil-alt attr-action-icon ${highlight ? '' : 'vh'}`}></span>
|
{Utils.bytesToSize(group.quota)}{' '}
|
||||||
</td>
|
<span title="Edit Quota" className={`fa fa-pencil-alt attr-action-icon ${highlight ? '' : 'vh'}`}></span>
|
||||||
<td className="cursor-pointer text-center" onClick={this.props.showDeleteDepartDialog.bind(this, group)}>
|
</td>
|
||||||
<span className={`sf2-icon-delete action-icon ${highlight ? '' : 'vh'}`} title="Delete"></span>
|
<td>
|
||||||
</td>
|
{isOpIconShown &&
|
||||||
</tr>
|
<OpMenu
|
||||||
|
operations={['Rename', 'Delete']}
|
||||||
|
translateOperations={this.translateOperations}
|
||||||
|
onMenuItemClick={this.onMenuItemClick}
|
||||||
|
onFreezedItem={this.props.onFreezedItem}
|
||||||
|
onUnfreezedItem={this.onUnfreezedItem}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{isRenameDialogOpen && (
|
||||||
|
<RenameDepartmentDialog
|
||||||
|
orgID={orgID}
|
||||||
|
groupID={group.id}
|
||||||
|
name={group.name}
|
||||||
|
toggle={this.toggleRenameDialog}
|
||||||
|
onDepartmentNameChanged={this.props.onDepartmentNameChanged}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const GroupItemPropTypes = {
|
const GroupItemPropTypes = {
|
||||||
group: PropTypes.object.isRequired,
|
group: PropTypes.object.isRequired,
|
||||||
|
isItemFreezed: PropTypes.bool.isRequired,
|
||||||
|
onFreezedItem: PropTypes.func.isRequired,
|
||||||
|
onUnfreezedItem: PropTypes.func.isRequired,
|
||||||
|
onDepartmentNameChanged: PropTypes.func.isRequired,
|
||||||
showSetGroupQuotaDialog: PropTypes.func.isRequired,
|
showSetGroupQuotaDialog: PropTypes.func.isRequired,
|
||||||
showDeleteDepartDialog: PropTypes.func.isRequired,
|
showDeleteDepartDialog: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from rest_framework.authentication import SessionAuthentication
|
from rest_framework.authentication import SessionAuthentication
|
||||||
|
from rest_framework.response import Response
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
|
|
||||||
from seaserv import ccnet_api
|
from seaserv import ccnet_api, seafile_api
|
||||||
|
|
||||||
from seahub.api2.utils import api_error
|
from seahub.api2.utils import api_error
|
||||||
from seahub.organizations.views import get_org_id_by_group
|
from seahub.organizations.views import get_org_id_by_group
|
||||||
@@ -17,6 +18,10 @@ from seahub.api2.endpoints.admin.address_book.groups import (
|
|||||||
)
|
)
|
||||||
from seahub.organizations.api.permissions import IsOrgAdmin
|
from seahub.organizations.api.permissions import IsOrgAdmin
|
||||||
from seahub.organizations.api.utils import check_org_admin
|
from seahub.organizations.api.utils import check_org_admin
|
||||||
|
from seahub.utils import is_pro_version
|
||||||
|
from seahub.base.templatetags.seahub_tags import email2nickname
|
||||||
|
from seahub.utils.timeutils import timestamp_to_isoformat_timestr
|
||||||
|
from seahub.group.utils import validate_group_name, set_group_name_cache
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -83,3 +88,51 @@ class AdminAddressBookGroup(APIView):
|
|||||||
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||||
|
|
||||||
return SysAdminAddressBookGroup().delete(request, group_id)
|
return SysAdminAddressBookGroup().delete(request, group_id)
|
||||||
|
|
||||||
|
@check_org_admin
|
||||||
|
def put(self, request, org_id, group_id):
|
||||||
|
""" Update an org address book group.
|
||||||
|
"""
|
||||||
|
# resource check
|
||||||
|
org_id = int(org_id)
|
||||||
|
if not ccnet_api.get_org_by_id(org_id):
|
||||||
|
error_msg = 'Organization %s not found.' % org_id
|
||||||
|
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||||
|
|
||||||
|
# permission check
|
||||||
|
group_id = int(group_id)
|
||||||
|
if get_org_id_by_group(group_id) != org_id:
|
||||||
|
error_msg = 'Group %s not found.' % group_id
|
||||||
|
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||||
|
|
||||||
|
new_group_name = request.data.get('group_name', '').strip()
|
||||||
|
if not new_group_name:
|
||||||
|
error_msg = 'name %s invalid.' % new_group_name
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
|
# Check whether group name is validate.
|
||||||
|
if not validate_group_name(new_group_name):
|
||||||
|
error_msg = 'Group name can only contain letters, numbers, blank, hyphen, dot, single quote or underscore'
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
|
try:
|
||||||
|
ccnet_api.set_group_name(group_id, new_group_name)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
error_msg = 'Internal Server Error'
|
||||||
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||||
|
set_group_name_cache(group_id, new_group_name)
|
||||||
|
|
||||||
|
group = ccnet_api.get_group(group_id)
|
||||||
|
isoformat_timestr = timestamp_to_isoformat_timestr(group.timestamp)
|
||||||
|
group_info = {
|
||||||
|
"id": group.id,
|
||||||
|
"name": group.group_name,
|
||||||
|
"owner": group.creator_name,
|
||||||
|
"owner_name": email2nickname(group.creator_name),
|
||||||
|
"created_at": isoformat_timestr,
|
||||||
|
"quota": seafile_api.get_group_quota(group_id) if is_pro_version() else 0,
|
||||||
|
"parent_group_id": group.parent_group_id if is_pro_version() else 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response(group_info)
|
||||||
|
Reference in New Issue
Block a user