1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-20 02:48:51 +00:00

custom share permission (#4967)

* custom share permission

* remove path field

* add permission manager ui

* optimize custom permission manager style

* add permission setting

* add normalize_custom_permission_name

* optimize repo custom permission

* delete useless code

* optimize code

* optimize code

* optimize markdown file page

* fix a few bugs

* add permission control

* repair modify permission

* optimize style

* optimize copyright

* add try-except

* optimize code

* move file&folder

* batch operation item

* repair batch move item

* update copyright

* optimize move permission control

* optimize code

* optimize code

* optimize code & fix code wranning

* optimize code

* delete unsupport permission

* optimize code

* repair code bug

* add pro limit

* optimize code

* add permission handle for permission editor

* repair new file&folder bug

* optimize file uploader code

* custom permission user can not visit custom permission module

* optimize code

* forbid comment&detail module

* optimize code

* optimize modify/preview permission

* optimize custom permission share perm

* optimize view file module: file-toolbar

* optimize custom drag move operation

* repair column view bug

* optimize drag operation code

* repair code bug

* optimize code

Co-authored-by: shanshuirenjia <978987373@qq.com>
This commit is contained in:
王健辉
2021-09-13 10:37:07 +08:00
committed by GitHub
parent 1f68680257
commit 07df610e43
60 changed files with 1965 additions and 287 deletions

View File

@@ -0,0 +1,30 @@
import React from 'react';
import PropTypes from 'prop-types';
import CustomPermissionEditor from './custom-permission-editor';
const propTypes = {
onChangeMode: PropTypes.func.isRequired,
addCustomPermission: PropTypes.func.isRequired,
};
class AddCustomPermission extends React.Component {
onUpdateCustomPermission = (permission_name, permission_desc, permission) => {
this.props.addCustomPermission(permission_name, permission_desc, permission)
}
render() {
return (
<CustomPermissionEditor
mode={'add'}
onChangeMode={this.props.onChangeMode}
onUpdateCustomPermission={this.onUpdateCustomPermission}
/>
);
}
}
AddCustomPermission.propTypes = propTypes;
export default AddCustomPermission;

View File

@@ -0,0 +1,208 @@
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { Alert, FormGroup, Input, Label, Tooltip } from 'reactstrap';
import { gettext } from '../../../utils/constants';
import Loading from '../../loading';
const propTypes = {
mode: PropTypes.string,
permission: PropTypes.object,
onChangeMode: PropTypes.func.isRequired,
onUpdateCustomPermission: PropTypes.func.isRequired,
};
class CustomPermissionEditor extends React.Component {
static defaultProps = {
mode: 'add'
}
constructor(props) {
super(props);
this.state = {
isLoading: true,
permission_name: '',
permission_desc: '',
permission: {
upload: false,
download: false,
modify: false,
copy: false,
delete: false,
preview: false,
download_external_link: false,
},
errMessage: '',
tooltipOpen: false,
};
}
componentDidMount() {
const { permission } = this.props;
if (permission) {
this.setState({
permission_name: permission.name,
permission_desc: permission.description,
permission: permission.permission,
isLoading: false
});
} else {
this.setState({isLoading: false});
}
}
onChangePermissionName = (evt) => {
const { permission_name } = this.state;
const newName = evt.target.value;
if (newName === permission_name) return;
this.setState({permission_name: newName});
}
onChangePermissionDescription = (evt) => {
const { permission_desc } = this.state;
const newDescription = evt.target.value;
if (newDescription === permission_desc) return;
this.setState({permission_desc: newDescription});
}
onChangePermission = (type) => {
return () => {
const { permission } = this.state;
const value = !permission[type];
const newPermission = Object.assign({}, permission, {[type]: value});
this.setState({permission: newPermission});
}
}
validParams = () => {
const { permission_name, permission_desc } = this.state;
let isValid = false;
let errMessage = '';
if (!permission_name || !permission_name.trim()) {
errMessage = gettext('Name is required');
return { isValid, errMessage };
}
if (!permission_desc || !permission_desc.trim()) {
errMessage = gettext('Description is required');
return { isValid, errMessage };
}
isValid = true;
return { isValid };
}
onUpdateCustomPermission = () => {
const { permission_name, permission_desc, permission } = this.state;
const { isValid, errMessage } = this.validParams();
if (!isValid) {
this.setState({errMessage});
return;
}
this.props.onUpdateCustomPermission(permission_name, permission_desc, permission);
}
toggle = () => {
this.setState({tooltipOpen: !this.state.tooltipOpen});
}
render() {
const { mode } = this.props;
const title = mode === 'add' ? gettext('Add permission') : gettext('Edit permission');
const { isLoading, permission_name, permission_desc, permission, errMessage } = this.state;
return (
<div className="custom-permission">
<div className="permission-header">
<div className="title">
<div onClick={this.props.onChangeMode}>
<i className="fa fa-arrow-left"></i>
</div>
<div>{title}</div>
</div>
<div className="operation">
<button type="button" className="btn btn-outline-primary" onClick={this.onUpdateCustomPermission}>{gettext('Submit')}</button>
</div>
</div>
<div className="permission-main mt-4">
{isLoading && <Loading />}
{!isLoading && (
<Fragment>
<div className="permission-name-desc d-flex">
<FormGroup className="permission-name">
<Label>{gettext('Permission name')}</Label>
<Input value={permission_name || ''} onChange={this.onChangePermissionName} />
</FormGroup>
<FormGroup className="permission-desc">
<Label>{gettext('Description')}</Label>
<Input value={permission_desc || ''} onChange={this.onChangePermissionDescription} />
</FormGroup>
</div>
{errMessage && <Alert color="danger">{errMessage}</Alert>}
<div className="permission-options">
<FormGroup check>
<Label check>
<Input type="checkbox" onChange={this.onChangePermission('upload')} checked={permission.upload}/>
<span>{gettext('Upload')}</span>
</Label>
</FormGroup>
<FormGroup check>
<Label check>
<Input type="checkbox" onChange={this.onChangePermission('download')} checked={permission.download}/>
<span>{gettext('Download')}</span>
</Label>
</FormGroup>
<FormGroup check>
<Label check>
<Input type="checkbox" onChange={this.onChangePermission('modify')} checked={permission.modify}/>
<span>{gettext('Modify')}</span>
<span id="modify-tip" className="fa fa-question-circle ml-2" style={{color: '#999'}}></span>
<Tooltip
toggle={this.toggle}
delay={{show: 0, hide: 0}}
target={'modify-tip'}
placement='bottom'
isOpen={this.state.tooltipOpen}>
({gettext('Modify includes modify file, create file and folder, move/rename file and folder')})
</Tooltip>
</Label>
</FormGroup>
<FormGroup check>
<Label check>
<Input type="checkbox" onChange={this.onChangePermission('copy')} checked={permission.copy}/>
<span>{gettext('Copy')}</span>
</Label>
</FormGroup>
<FormGroup check>
<Label check>
<Input type="checkbox" onChange={this.onChangePermission('delete')} checked={permission.delete}/>
<span>{gettext('Delete')}</span>
</Label>
</FormGroup>
<FormGroup check>
<Label check>
<Input type="checkbox" onChange={this.onChangePermission('preview')} checked={permission.preview}/>
<span>{gettext('Preview online')}</span>
</Label>
</FormGroup>
<FormGroup check>
<Label check>
<Input type="checkbox" onChange={this.onChangePermission('download_external_link')} checked={permission.download_external_link}/>
<span>{gettext('Generate share link')}</span>
</Label>
</FormGroup>
</div>
</Fragment>
)}
</div>
</div>
);
}
}
CustomPermissionEditor.propTypes = propTypes;
export default CustomPermissionEditor;

View File

@@ -0,0 +1,67 @@
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
const propTypes = {
permission: PropTypes.object.isRequired,
onEditCustomPermission: PropTypes.func.isRequired,
onDeleteCustomPermission: PropTypes.func.isRequired,
};
class CustomPermissionItem extends React.Component {
constructor(props) {
super(props);
this.state = {
isShowOperations: false
};
}
onMouseEnter = () => {
this.setState({isShowOperations: true});
}
onMouseOver = () => {
this.setState({isShowOperations: true});
}
onMouseLeave = () => {
this.setState({isShowOperations: false});
}
onEditCustomPermission = () => {
const { permission } = this.props;
this.props.onEditCustomPermission(permission)
}
onDeleteCustomPermission = () => {
const { permission } = this.props;
this.props.onDeleteCustomPermission(permission)
}
render() {
const { permission } = this.props;
const { id, name, description } = permission;
return (
<tr key={id} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave} onMouseOver={this.onMouseOver}>
<td width='22%' className="text-truncate" title={name}>{name}</td>
<td width='56%' className="text-truncate">{description}</td>
<td width='22%'>
{this.state.isShowOperations && (
<Fragment>
<span className="permission-operation-btn edit" onClick={this.onEditCustomPermission}>
<i className="fa fa-pencil-alt attr-action-icon"></i>
</span>
<span className="permission-operation-btn delete" onClick={this.onDeleteCustomPermission}>
<i className="fa fa-trash attr-action-icon"></i>
</span>
</Fragment>
)}
</td>
</tr>
);
}
}
CustomPermissionItem.propTypes = propTypes;
export default CustomPermissionItem;

View File

@@ -0,0 +1,159 @@
import React from 'react';
import PropTypes from 'prop-types';
import ListCustomPermission from './list-custom-permissions';
import AddCustomPermission from './add-custom-permission';
import EditCustomPermission from './edit-custom-permission';
import Loading from '../../loading';
import { seafileAPI } from '../../../utils/seafile-api';
import toaster from '../../toast';
import { Utils } from '../../../utils/utils';
import CustomPermission from '../../../models/custom-permission';
const propTypes = {
repoID: PropTypes.string.isRequired
};
const MANAGER_STATE = {
LIST: 'list',
ADD: 'add',
EDIT: 'edit',
};
class CustomPermissionManager extends React.Component {
constructor(props) {
super(props);
this.state = {
currentMode: MANAGER_STATE.LIST,
isLoading: true,
permissions: [],
currentPermission: null,
};
}
componentDidMount() {
this.listCustomPermissions();
}
listCustomPermissions = () => {
const { repoID } = this.props;
seafileAPI.listCustomPermissions(repoID).then(res => {
const permissions = res.data.permission_list.map(item => new CustomPermission(item));
this.setState({
isLoading: false,
permissions: permissions
});
}).catch(error => {
let errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage);
this.setState({isLoading: false});
});
}
addCustomPermission = (permission_name, permission_desc, permission) => {
const { repoID } = this.props;
seafileAPI.createCustomPermission(repoID, permission_name, permission_desc, permission).then(res => {
const { permissions } = this.state;
const customPermission = new CustomPermission(res.data.permission);
permissions.unshift(customPermission)
this.setState({
permissions,
currentMode: MANAGER_STATE.LIST
});
}).catch(error => {
let errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage);
});
}
editCustomPermission = (newPermission) => {
const { repoID } = this.props;
seafileAPI.updateCustomPermission(repoID, newPermission).then(res => {
const customPermission = new CustomPermission(res.data.permission);
const { permissions } = this.state;
const newPermissions = permissions.map(item => {
if (item.id === customPermission.id) {
return customPermission;
}
return item;
});
this.setState({
permissions: newPermissions,
currentMode: MANAGER_STATE.LIST
});
}).catch(error => {
let errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage);
});
}
deleteCustomPermission = (permission) => {
const { repoID } = this.props;
const { id: permissionID } = permission;
seafileAPI.deleteCustomPermission(repoID, permissionID).then(res => {
const { permissions } = this.state;
const newPermissions = permissions.filter(permission => permission.id !== permissionID);
this.setState({permissions: newPermissions});
}).catch(error => {
let errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage);
});
}
onChangeMode = () => {
this.setState({currentMode: MANAGER_STATE.LIST});
}
onAddCustomPermission = () => {
this.setState({currentMode: MANAGER_STATE.ADD});
}
onEditCustomPermission = (permission) => {
this.setState({
currentMode: MANAGER_STATE.EDIT,
currentPermission: permission
});
}
onDeleteCustomPermission = (permission) => {
this.deleteCustomPermission(permission);
}
render() {
if (this.state.isLoading) {
return <Loading />
}
const { currentMode, permissions, currentPermission } = this.state;
return (
<div className="custom-permission-manager">
{currentMode === MANAGER_STATE.LIST && (
<ListCustomPermission
permissions={permissions}
onAddCustomPermission={this.onAddCustomPermission}
onEditCustomPermission={this.onEditCustomPermission}
onDeleteCustomPermission={this.onDeleteCustomPermission}
/>
)}
{currentMode === MANAGER_STATE.ADD && (
<AddCustomPermission
onChangeMode={this.onChangeMode}
addCustomPermission={this.addCustomPermission}
/>
)}
{currentMode === MANAGER_STATE.EDIT && (
<EditCustomPermission
permission={currentPermission}
onChangeMode={this.onChangeMode}
editCustomPermission={this.editCustomPermission}
/>
)}
</div>
);
}
}
CustomPermissionManager.propTypes = propTypes;
export default CustomPermissionManager;

View File

@@ -0,0 +1,37 @@
import React from 'react';
import PropTypes from 'prop-types';
import CustomPermissionEditor from './custom-permission-editor';
const propTypes = {
permission: PropTypes.object.isRequired,
onChangeMode: PropTypes.func.isRequired,
editCustomPermission: PropTypes.func.isRequired
};
class EditCustomPermission extends React.Component {
onUpdateCustomPermission = (permission_name, permission_desc, permission) => {
const { permission: editPermission } = this.props;
const newPermission = Object.assign({}, editPermission, {
name: permission_name,
description: permission_desc,
permission: permission
});
this.props.editCustomPermission(newPermission);
}
render() {
return (
<CustomPermissionEditor
mode={'edit'}
permission={this.props.permission}
onChangeMode={this.props.onChangeMode}
onUpdateCustomPermission={this.onUpdateCustomPermission}
/>
);
}
}
EditCustomPermission.propTypes = propTypes;
export default EditCustomPermission;

View File

@@ -0,0 +1,60 @@
import React from 'react';
import PropTypes from 'prop-types';
import CustomPermissionItem from './custom-permission-item';
import { gettext } from '../../../utils/constants';
const propTypes = {
permissions: PropTypes.array.isRequired,
onAddCustomPermission: PropTypes.func.isRequired,
onEditCustomPermission: PropTypes.func.isRequired,
onDeleteCustomPermission: PropTypes.func.isRequired,
};
class ListCustomPermissions extends React.Component {
render() {
const { permissions } = this.props;
return (
<div className="custom-permission">
<div className="permission-header">
<div className="title">{gettext('Permission')}</div>
<div className="operation">
<button type="button" className="btn btn-outline-primary" onClick={this.props.onAddCustomPermission}>{gettext('Add permission')}</button>
</div>
</div>
<div className="permission-main mt-4">
<table className="permissions-list-header">
<thead>
<tr>
<th width='22%'>{gettext('Permission name')}</th>
<th width='56%'>{gettext('Description')}</th>
<th width='22%'></th>
</tr>
</thead>
</table>
<div className="permissions-list-body">
<table>
<tbody>
{permissions.map(permission => {
return (
<CustomPermissionItem
key={permission.id}
permission={permission}
onEditCustomPermission={this.props.onEditCustomPermission}
onDeleteCustomPermission={this.props.onDeleteCustomPermission}
/>
);
})}
</tbody>
</table>
</div>
</div>
</div>
);
}
}
ListCustomPermissions.propTypes = propTypes;
export default ListCustomPermissions;