mirror of
https://github.com/haiwen/seahub.git
synced 2025-08-10 11:22:09 +00:00
wikis permission set (#2799)
This commit is contained in:
parent
c6cd6bb2c4
commit
1c4f48eef3
6
frontend/package-lock.json
generated
6
frontend/package-lock.json
generated
@ -10793,9 +10793,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"seafile-js": {
|
"seafile-js": {
|
||||||
"version": "0.2.55",
|
"version": "0.2.56",
|
||||||
"resolved": "https://registry.npmjs.org/seafile-js/-/seafile-js-0.2.55.tgz",
|
"resolved": "https://registry.npmjs.org/seafile-js/-/seafile-js-0.2.56.tgz",
|
||||||
"integrity": "sha512-Q9qE/RE0rg3wmXlYENO8mcEhu+OHC3emK9/+Fq3k3u38z6iy/Kc/1ntJjNpHYI5VS4oipum/Lc8gIvPL/FZQAQ==",
|
"integrity": "sha512-Stm5Xa3OmXZ8beNVftS2OPU5nZlGGSIL7JazD2R4KrOtxQElfUWA5XsGsFnfbuAFv25mUxABzteWpYsMPVtOqg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"axios": "^0.18.0",
|
"axios": "^0.18.0",
|
||||||
"form-data": "^2.3.2",
|
"form-data": "^2.3.2",
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
"react-moment": "^0.7.9",
|
"react-moment": "^0.7.9",
|
||||||
"react-select": "^2.1.1",
|
"react-select": "^2.1.1",
|
||||||
"reactstrap": "^6.4.0",
|
"reactstrap": "^6.4.0",
|
||||||
"seafile-js": "^0.2.55",
|
"seafile-js": "^0.2.56",
|
||||||
"seafile-ui": "^0.1.10",
|
"seafile-ui": "^0.1.10",
|
||||||
"socket.io-client": "^2.2.0",
|
"socket.io-client": "^2.2.0",
|
||||||
"sw-precache-webpack-plugin": "0.11.4",
|
"sw-precache-webpack-plugin": "0.11.4",
|
||||||
|
@ -5,7 +5,7 @@ import Select from 'react-select';
|
|||||||
import makeAnimated from 'react-select/lib/animated';
|
import makeAnimated from 'react-select/lib/animated';
|
||||||
import { gettext } from '../../utils/constants';
|
import { gettext } from '../../utils/constants';
|
||||||
import { seafileAPI } from '../../utils/seafile-api.js';
|
import { seafileAPI } from '../../utils/seafile-api.js';
|
||||||
import PermissionEditor from '../select-editor/permission-editor';
|
import SharePermissionEditor from '../select-editor/share-permission-editor';
|
||||||
|
|
||||||
class GroupItem extends React.Component {
|
class GroupItem extends React.Component {
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ class GroupItem extends React.Component {
|
|||||||
<tr onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
|
<tr onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
|
||||||
<td className='name'>{item.group_info.name}</td>
|
<td className='name'>{item.group_info.name}</td>
|
||||||
<td>
|
<td>
|
||||||
<PermissionEditor
|
<SharePermissionEditor
|
||||||
isTextMode={true}
|
isTextMode={true}
|
||||||
isEditIconShow={this.state.isOperationShow}
|
isEditIconShow={this.state.isOperationShow}
|
||||||
currentPermission={item.permission}
|
currentPermission={item.permission}
|
||||||
@ -270,7 +270,7 @@ class ShareToGroup extends React.Component {
|
|||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<PermissionEditor
|
<SharePermissionEditor
|
||||||
isTextMode={false}
|
isTextMode={false}
|
||||||
isEditIconShow={false}
|
isEditIconShow={false}
|
||||||
currentPermission={this.state.permission}
|
currentPermission={this.state.permission}
|
||||||
|
@ -4,7 +4,7 @@ import AsyncSelect from 'react-select/lib/Async';
|
|||||||
import { gettext } from '../../utils/constants';
|
import { gettext } from '../../utils/constants';
|
||||||
import { Button } from 'reactstrap';
|
import { Button } from 'reactstrap';
|
||||||
import { seafileAPI } from '../../utils/seafile-api.js';
|
import { seafileAPI } from '../../utils/seafile-api.js';
|
||||||
import PermissionEditor from '../select-editor/permission-editor';
|
import SharePermissionEditor from '../select-editor/share-permission-editor';
|
||||||
|
|
||||||
class UserItem extends React.Component {
|
class UserItem extends React.Component {
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ class UserItem extends React.Component {
|
|||||||
<tr onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
|
<tr onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
|
||||||
<td className="name">{item.user_info.nickname}</td>
|
<td className="name">{item.user_info.nickname}</td>
|
||||||
<td>
|
<td>
|
||||||
<PermissionEditor
|
<SharePermissionEditor
|
||||||
isTextMode={true}
|
isTextMode={true}
|
||||||
isEditIconShow={this.state.isOperationShow}
|
isEditIconShow={this.state.isOperationShow}
|
||||||
currentPermission={currentPermission}
|
currentPermission={currentPermission}
|
||||||
@ -292,7 +292,7 @@ class ShareToUser extends React.Component {
|
|||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<PermissionEditor
|
<SharePermissionEditor
|
||||||
isTextMode={false}
|
isTextMode={false}
|
||||||
isEditIconShow={false}
|
isEditIconShow={false}
|
||||||
currentPermission={this.state.permission}
|
currentPermission={this.state.permission}
|
||||||
|
@ -11,7 +11,7 @@ const propTypes = {
|
|||||||
onPermissionChangedHandler: PropTypes.func.isRequired
|
onPermissionChangedHandler: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
class PermissionEditor extends React.Component {
|
class SharePermissionEditor extends React.Component {
|
||||||
|
|
||||||
translatePermission = (permission) => {
|
translatePermission = (permission) => {
|
||||||
return Utils.sharePerms(permission);
|
return Utils.sharePerms(permission);
|
||||||
@ -31,6 +31,6 @@ class PermissionEditor extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PermissionEditor.propTypes = propTypes;
|
SharePermissionEditor.propTypes = propTypes;
|
||||||
|
|
||||||
export default PermissionEditor;
|
export default SharePermissionEditor;
|
@ -0,0 +1,43 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { gettext } from '../../utils/constants';
|
||||||
|
import SelectEditor from './select-editor';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
isTextMode: PropTypes.bool.isRequired,
|
||||||
|
isEditIconShow: PropTypes.bool.isRequired,
|
||||||
|
permissions: PropTypes.array.isRequired,
|
||||||
|
currentPermission: PropTypes.string.isRequired,
|
||||||
|
onPermissionChangedHandler: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
class WikiPermissionEditor extends React.Component {
|
||||||
|
|
||||||
|
translatePermission = (permission) => {
|
||||||
|
if (permission === 'private') {
|
||||||
|
return gettext('Private');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (permission === 'public') {
|
||||||
|
return gettext('Public');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<SelectEditor
|
||||||
|
isTextMode={this.props.isTextMode}
|
||||||
|
isEditIconShow={this.props.isEditIconShow}
|
||||||
|
options={this.props.permissions}
|
||||||
|
currentOption={this.props.currentPermission}
|
||||||
|
onOptionChangedHandler={this.props.onPermissionChangedHandler}
|
||||||
|
translateOption={this.translatePermission}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
WikiPermissionEditor.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default WikiPermissionEditor;
|
@ -3,6 +3,8 @@ import PropTypes from 'prop-types';
|
|||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';
|
import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';
|
||||||
import { gettext, siteRoot } from '../../utils/constants';
|
import { gettext, siteRoot } from '../../utils/constants';
|
||||||
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
|
import WikiPermissionEditor from '../select-editor/wiki-permission-editor.js';
|
||||||
import Toast from '../toast';
|
import Toast from '../toast';
|
||||||
import ModalPortal from '../modal-portal';
|
import ModalPortal from '../modal-portal';
|
||||||
import WikiDeleteDialog from '../dialog/wiki-delete-dialog';
|
import WikiDeleteDialog from '../dialog/wiki-delete-dialog';
|
||||||
@ -26,7 +28,10 @@ class WikiListItem extends Component {
|
|||||||
isShowMenuControl: false,
|
isShowMenuControl: false,
|
||||||
isRenameing: false,
|
isRenameing: false,
|
||||||
highlight: false,
|
highlight: false,
|
||||||
|
permission: this.props.wiki.permission,
|
||||||
|
showOpIcon: false,
|
||||||
};
|
};
|
||||||
|
this.permissions = ['private', 'public'];
|
||||||
}
|
}
|
||||||
|
|
||||||
clickMenuToggle = (e) => {
|
clickMenuToggle = (e) => {
|
||||||
@ -58,6 +63,7 @@ class WikiListItem extends Component {
|
|||||||
this.setState({
|
this.setState({
|
||||||
isShowMenuControl: true,
|
isShowMenuControl: true,
|
||||||
highlight: true,
|
highlight: true,
|
||||||
|
showOpIcon: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -67,10 +73,23 @@ class WikiListItem extends Component {
|
|||||||
this.setState({
|
this.setState({
|
||||||
isShowMenuControl: false,
|
isShowMenuControl: false,
|
||||||
highlight: false,
|
highlight: false,
|
||||||
|
showOpIcon: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
changePerm = (permission) => {
|
||||||
|
let wiki = this.props.wiki;
|
||||||
|
seafileAPI.updateWikiPermission(wiki.slug, permission).then(() => {
|
||||||
|
this.setState({permission: permission});
|
||||||
|
}).catch((error) => {
|
||||||
|
if(error.response) {
|
||||||
|
let errorMsg = error.response.data.error_msg;
|
||||||
|
Toast.danger(errorMsg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
onRenameToggle = (e) => {
|
onRenameToggle = (e) => {
|
||||||
this.props.onFreezedItem();
|
this.props.onFreezedItem();
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -150,6 +169,15 @@ class WikiListItem extends Component {
|
|||||||
</td>
|
</td>
|
||||||
<td><a href={userProfileURL} target='_blank'>{gettext(wiki.owner_nickname)}</a></td>
|
<td><a href={userProfileURL} target='_blank'>{gettext(wiki.owner_nickname)}</a></td>
|
||||||
<td>{moment(wiki.updated_at).fromNow()}</td>
|
<td>{moment(wiki.updated_at).fromNow()}</td>
|
||||||
|
<td>
|
||||||
|
<WikiPermissionEditor
|
||||||
|
isTextMode={true}
|
||||||
|
isEditIconShow={this.state.showOpIcon}
|
||||||
|
currentPermission={this.state.permission}
|
||||||
|
permissions={this.permissions}
|
||||||
|
onPermissionChangedHandler={this.changePerm}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
<td className="text-center cursor-pointer">
|
<td className="text-center cursor-pointer">
|
||||||
{this.state.isShowMenuControl && (
|
{this.state.isShowMenuControl && (
|
||||||
<Dropdown isOpen={this.state.isShowWikiMenu} toggle={this.onMenuToggle}>
|
<Dropdown isOpen={this.state.isShowWikiMenu} toggle={this.onMenuToggle}>
|
||||||
|
@ -38,9 +38,10 @@ class WikiListView extends Component {
|
|||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th width="50%">{gettext('Name')}</th>
|
<th width="40%">{gettext('Name')}</th>
|
||||||
<th width="20%">{gettext('Owner')}</th>
|
<th width="20%">{gettext('Owner')}</th>
|
||||||
<th width="20%">{gettext('Last Update')}</th>
|
<th width="20%">{gettext('Last Update')}</th>
|
||||||
|
<th width="10%">{gettext('Permission')}</th>
|
||||||
<th width="10%">{/* operation */}</th>
|
<th width="10%">{/* operation */}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
@ -3,7 +3,7 @@ import { Link } from '@reach/router';
|
|||||||
import { seafileAPI } from '../../utils/seafile-api';
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
import { gettext, siteRoot, loginUrl, isPro } from '../../utils/constants';
|
import { gettext, siteRoot, loginUrl, isPro } from '../../utils/constants';
|
||||||
import PermissionEditor from '../../components/select-editor/permission-editor';
|
import SharePermissionEditor from '../../components/select-editor/share-permission-editor';
|
||||||
import SharedFolderInfo from '../../models/shared-folder-info';
|
import SharedFolderInfo from '../../models/shared-folder-info';
|
||||||
|
|
||||||
class Content extends Component {
|
class Content extends Component {
|
||||||
@ -153,7 +153,7 @@ class Item extends Component {
|
|||||||
<td><Link to={folderUrl}>{item.folder_name}</Link></td>
|
<td><Link to={folderUrl}>{item.folder_name}</Link></td>
|
||||||
{shareTo}
|
{shareTo}
|
||||||
<td>
|
<td>
|
||||||
<PermissionEditor
|
<SharePermissionEditor
|
||||||
isTextMode={true}
|
isTextMode={true}
|
||||||
isEditIconShow={this.state.showOpIcon}
|
isEditIconShow={this.state.showOpIcon}
|
||||||
currentPermission={this.state.share_permission}
|
currentPermission={this.state.share_permission}
|
||||||
|
@ -3,7 +3,7 @@ import { Link } from '@reach/router';
|
|||||||
import { seafileAPI } from '../../utils/seafile-api';
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
import { gettext, siteRoot, loginUrl, isPro } from '../../utils/constants';
|
import { gettext, siteRoot, loginUrl, isPro } from '../../utils/constants';
|
||||||
import PermissionEditor from '../../components/select-editor/permission-editor';
|
import SharePermissionEditor from '../../components/select-editor/share-permission-editor';
|
||||||
import SharedRepoInfo from '../../models/shared-repo-info';
|
import SharedRepoInfo from '../../models/shared-repo-info';
|
||||||
|
|
||||||
class Content extends Component {
|
class Content extends Component {
|
||||||
@ -173,7 +173,7 @@ class Item extends Component {
|
|||||||
<td><Link to={repoUrl}>{item.repo_name}</Link></td>
|
<td><Link to={repoUrl}>{item.repo_name}</Link></td>
|
||||||
{shareTo}
|
{shareTo}
|
||||||
<td>
|
<td>
|
||||||
<PermissionEditor
|
<SharePermissionEditor
|
||||||
isTextMode={true}
|
isTextMode={true}
|
||||||
isEditIconShow={this.state.showOpIcon}
|
isEditIconShow={this.state.showOpIcon}
|
||||||
currentPermission={share_permission}
|
currentPermission={share_permission}
|
||||||
|
@ -5,6 +5,7 @@ import CommonToolbar from '../../components/toolbar/common-toolbar';
|
|||||||
import MarkdownViewer from '../../components/markdown-viewer';
|
import MarkdownViewer from '../../components/markdown-viewer';
|
||||||
import TreeDirView from '../../components/tree-dir-view/tree-dir-view';
|
import TreeDirView from '../../components/tree-dir-view/tree-dir-view';
|
||||||
|
|
||||||
|
let loginUser = window.app.pageOptions.username;
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
content: PropTypes.string,
|
content: PropTypes.string,
|
||||||
lastModified: PropTypes.string,
|
lastModified: PropTypes.string,
|
||||||
@ -88,11 +89,13 @@ class MainPanel extends Component {
|
|||||||
<button className="btn btn-secondary operation-item" title="Edit File" onClick={this.onEditClick}>{gettext('Edit Page')}</button>
|
<button className="btn btn-secondary operation-item" title="Edit File" onClick={this.onEditClick}>{gettext('Edit Page')}</button>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<CommonToolbar
|
{loginUser &&
|
||||||
repoID={repoID}
|
<CommonToolbar
|
||||||
onSearchedClick={this.props.onSearchedClick}
|
repoID={repoID}
|
||||||
searchPlaceholder={gettext('Search files in this library')}
|
onSearchedClick={this.props.onSearchedClick}
|
||||||
/>
|
searchPlaceholder={gettext('Search files in this library')}
|
||||||
|
/>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<div className="cur-view-container">
|
<div className="cur-view-container">
|
||||||
<div className="cur-view-path">
|
<div className="cur-view-path">
|
||||||
|
@ -225,7 +225,7 @@ class WikiPagesDirView(APIView):
|
|||||||
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||||
|
|
||||||
# perm check
|
# perm check
|
||||||
if not wiki.check_access_wiki(request):
|
if not wiki.has_read_perm(request.user):
|
||||||
error_msg = "Permission denied"
|
error_msg = "Permission denied"
|
||||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||||
|
|
||||||
@ -266,7 +266,7 @@ class WikiPageContentView(APIView):
|
|||||||
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||||
|
|
||||||
# perm check
|
# perm check
|
||||||
if not wiki.check_access_wiki(request):
|
if not wiki.has_read_perm(request.user):
|
||||||
error_msg = 'Permission denied.'
|
error_msg = 'Permission denied.'
|
||||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||||
|
|
||||||
|
@ -54,11 +54,11 @@ def slug(request, slug, file_path="home.md"):
|
|||||||
# perm check
|
# perm check
|
||||||
req_user = request.user.username
|
req_user = request.user.username
|
||||||
|
|
||||||
if not req_user:
|
if not req_user and not wiki.has_read_perm(request.user):
|
||||||
return redirect('auth_login')
|
return redirect('auth_login')
|
||||||
|
else:
|
||||||
if not wiki.check_access_wiki(request):
|
if not wiki.has_read_perm(request.user):
|
||||||
return render_permission_error(request, _(u'Permission denied.'))
|
return render_permission_error(request, _(u'Unable to view Wiki'))
|
||||||
|
|
||||||
file_type, ext = get_file_type_and_ext(posixpath.basename(file_path))
|
file_type, ext = get_file_type_and_ext(posixpath.basename(file_path))
|
||||||
if file_type == IMAGE:
|
if file_type == IMAGE:
|
||||||
|
Loading…
Reference in New Issue
Block a user