mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-02 07:27:04 +00:00
User perm check (#2876)
* added 'user permission check' * added 'can add repo' check * [dir view, repo wiki mode] added condition check for 'share current dir' * [dir view, repo wiki mode] modified var name
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import React, { Component } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Router, navigate } from '@reach/router';
|
||||
import { siteRoot } from './utils/constants';
|
||||
import { siteRoot, canAddRepo } from './utils/constants';
|
||||
import { Utils } from './utils/utils';
|
||||
import SidePanel from './components/side-panel';
|
||||
import MainPanel from './components/main-panel';
|
||||
@@ -176,12 +176,17 @@ class App extends Component {
|
||||
|
||||
render() {
|
||||
let { currentTab } = this.state;
|
||||
|
||||
const home = canAddRepo ?
|
||||
<MyLibraries path={ siteRoot } onShowSidePanel={this.onShowSidePanel} onSearchedClick={this.onSearchedClick} /> :
|
||||
<SharedLibrariesWrapper path={ siteRoot } onShowSidePanel={this.onShowSidePanel} onSearchedClick={this.onSearchedClick} />;
|
||||
|
||||
return (
|
||||
<div id="main">
|
||||
<SidePanel isSidePanelClosed={this.state.isSidePanelClosed} onCloseSidePanel={this.onCloseSidePanel} currentTab={currentTab} tabItemClick={this.tabItemClick} draftCounts={this.state.draftCounts} />
|
||||
<MainPanel>
|
||||
<Router>
|
||||
<MyLibraries path={ siteRoot } onShowSidePanel={this.onShowSidePanel} onSearchedClick={this.onSearchedClick} />
|
||||
{home}
|
||||
<FilesActivitiesWrapper path={siteRoot + 'dashboard'} onShowSidePanel={this.onShowSidePanel} onSearchedClick={this.onSearchedClick} />
|
||||
<DraftsViewWrapper path={siteRoot + 'drafts'}
|
||||
currentTab={currentTab}
|
||||
|
@@ -21,6 +21,8 @@ const propTypes = {
|
||||
errorMsg: PropTypes.string.isRequired,
|
||||
repoID: PropTypes.string.isRequired,
|
||||
repoName: PropTypes.string.isRequired,
|
||||
repoEncrypted: PropTypes.bool.isRequired,
|
||||
showShareBtn: PropTypes.bool.isRequired,
|
||||
pathExist: PropTypes.bool.isRequired,
|
||||
permission: PropTypes.bool.isRequired,
|
||||
isDirentListLoading: PropTypes.bool.isRequired,
|
||||
@@ -154,6 +156,7 @@ class DirPanel extends React.Component {
|
||||
isViewFile={false}
|
||||
path={this.props.path}
|
||||
repoID={this.props.repoID}
|
||||
showShareBtn={this.props.showShareBtn}
|
||||
onAddFile={this.props.onAddFile}
|
||||
onAddFolder={this.props.onAddFolder}
|
||||
onUploadFile={this.onUploadFile}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import moment from 'moment';
|
||||
import { siteRoot } from '../../utils/constants';
|
||||
import { siteRoot, canGenerateShareLink, canGenerateUploadLink, username } from '../../utils/constants';
|
||||
import { seafileAPI } from '../../utils/seafile-api';
|
||||
import { Utils } from '../../utils/utils';
|
||||
import { gettext } from '../../utils/constants';
|
||||
@@ -27,9 +27,14 @@ class DirView extends React.Component {
|
||||
this.state = {
|
||||
path: '/',
|
||||
pathExist: true,
|
||||
|
||||
repoName: '',
|
||||
repoID: '',
|
||||
repoEncrypted: false,
|
||||
isAdmin: false,
|
||||
ownerEmail: '',
|
||||
userPerm: '',
|
||||
|
||||
permission: true,
|
||||
libNeedDecrypt: false,
|
||||
isDirentSelected: false,
|
||||
@@ -86,6 +91,8 @@ class DirView extends React.Component {
|
||||
repoID: repoInfo.repo_id,
|
||||
repoName: repoInfo.repo_name,
|
||||
repoEncrypted: repoInfo.encrypted,
|
||||
isAdmin: repoInfo.is_admin,
|
||||
ownerEmail: repoInfo.owner_email,
|
||||
permission: repoInfo.permission === 'rw',
|
||||
libNeedDecrypt: res.data.lib_need_decrypt,
|
||||
});
|
||||
@@ -181,6 +188,7 @@ class DirView extends React.Component {
|
||||
this.setState({
|
||||
isDirentListLoading: false,
|
||||
pathExist: true,
|
||||
userPerm: res.data.user_perm,
|
||||
direntList: Utils.sortDirents(direntList, this.state.sortBy, this.state.sortOrder),
|
||||
dirID: res.headers.oid,
|
||||
});
|
||||
@@ -661,6 +669,16 @@ class DirView extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
let showShareBtn = false;
|
||||
const { repoEncrypted, isAdmin, ownerEmail, userPerm } = this.state;
|
||||
const isRepoOwner = ownerEmail == username;
|
||||
if (!repoEncrypted && (
|
||||
canGenerateShareLink || canGenerateUploadLink ||
|
||||
isRepoOwner || isAdmin) && (
|
||||
userPerm == 'rw' || userPerm == 'r')) {
|
||||
showShareBtn = true;
|
||||
}
|
||||
|
||||
return (
|
||||
<DirPanel
|
||||
pathPrefix={this.props.pathPrefix}
|
||||
@@ -675,6 +693,7 @@ class DirView extends React.Component {
|
||||
isDirentListLoading={this.state.isDirentListLoading}
|
||||
isDirentSelected={this.state.isDirentSelected}
|
||||
isAllDirentSelected={this.state.isAllDirentSelected}
|
||||
showShareBtn={showShareBtn}
|
||||
direntList={this.state.direntList}
|
||||
sortBy={this.state.sortBy}
|
||||
sortOrder={this.state.sortOrder}
|
||||
|
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link } from '@reach/router';
|
||||
import Group from '../models/group';
|
||||
import { gettext, siteRoot, enableWiki } from '../utils/constants';
|
||||
import { gettext, siteRoot, enableWiki, canAddRepo, canGenerateShareLink, canGenerateUploadLink } from '../utils/constants';
|
||||
import { seafileAPI } from '../utils/seafile-api';
|
||||
import { Badge } from 'reactstrap';
|
||||
|
||||
@@ -101,26 +101,44 @@ class MainSideNav extends React.Component {
|
||||
height = this.adminHeight;
|
||||
}
|
||||
let style = {height: height};
|
||||
|
||||
let linksNavItem = null;
|
||||
if (canGenerateShareLink) {
|
||||
linksNavItem = (
|
||||
<li className="nav-item">
|
||||
<Link to={siteRoot + 'share-admin-share-links/'} className={`nav-link ellipsis ${this.getActiveClass('share-admin-share-links')}`} title={gettext('Links')} onClick={() => this.tabItemClick('share-admin-share-links')}>
|
||||
<span aria-hidden="true" className="sharp">#</span>
|
||||
<span className="nav-text">{gettext('Links')}</span>
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
} else if (canGenerateUploadLink) {
|
||||
linksNavItem = (
|
||||
<li className="nav-item">
|
||||
<Link to={siteRoot + 'share-admin-upload-links/'} className={`nav-link ellipsis ${this.getActiveClass('share-admin-upload-links')}`} title={gettext('Links')} onClick={() => this.tabItemClick('share-admin-upload-links')}>
|
||||
<span aria-hidden="true" className="sharp">#</span>
|
||||
<span className="nav-text">{gettext('Links')}</span>
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<ul className={`nav sub-nav nav-pills flex-column ${this.state.sharedExtended ? 'side-panel-slide' : 'side-panel-slide-up'}`} style={style} >
|
||||
{canAddRepo && (
|
||||
<li className="nav-item">
|
||||
<Link to={siteRoot + 'share-admin-libs/'} className={`nav-link ellipsis ${this.getActiveClass('share-admin-libs')}`} title={gettext('Libraries')} onClick={() => this.tabItemClick('share-admin-libs')}>
|
||||
<span aria-hidden="true" className="sharp">#</span>
|
||||
<span className="nav-text">{gettext('Libraries')}</span>
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
<li className="nav-item">
|
||||
<Link to={siteRoot + 'share-admin-folders/'} className={`nav-link ellipsis ${this.getActiveClass('share-admin-folders')}`} title={gettext('Folders')} onClick={() => this.tabItemClick('share-admin-folders')}>
|
||||
<span aria-hidden="true" className="sharp">#</span>
|
||||
<span className="nav-text">{gettext('Folders')}</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<Link to={siteRoot + 'share-admin-share-links/'} className={`nav-link ellipsis ${this.getActiveClass('share-admin-share-links') || this.getActiveClass('share-admin-upload-links')}`} title={gettext('Links')} onClick={() => this.tabItemClick('share-admin-share-links')}>
|
||||
<span aria-hidden="true" className="sharp">#</span>
|
||||
<span className="nav-text">{gettext('Links')}</span>
|
||||
</Link>
|
||||
</li>
|
||||
{linksNavItem}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
@@ -131,12 +149,14 @@ class MainSideNav extends React.Component {
|
||||
<div className="side-nav-con">
|
||||
<h3 className="sf-heading">{gettext('Files')}</h3>
|
||||
<ul className="nav nav-pills flex-column nav-container">
|
||||
{canAddRepo && (
|
||||
<li className="nav-item">
|
||||
<Link to={ siteRoot + 'my-libs/' } className={`nav-link ellipsis ${this.getActiveClass('my-libs') || this.getActiveClass('deleted') }`} title={gettext('My Libraries')} onClick={() => this.tabItemClick('my-libs')}>
|
||||
<span className="sf2-icon-user" aria-hidden="true"></span>
|
||||
<span className="nav-text">{gettext('My Libraries')}</span>
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
<li className="nav-item">
|
||||
<Link to={siteRoot + 'shared-libs/'} className={`nav-link ellipsis ${this.getActiveClass('shared-libs')}`} title={gettext('Shared with me')} onClick={() => this.tabItemClick('shared-libs')}>
|
||||
<span className="sf2-icon-share" aria-hidden="true"></span>
|
||||
|
@@ -13,6 +13,7 @@ const propTypes = {
|
||||
permission: PropTypes.string, //just for view file, and premission is file permission
|
||||
path: PropTypes.string.isRequired,
|
||||
repoID: PropTypes.string.isRequired,
|
||||
showShareBtn: PropTypes.bool.isRequired,
|
||||
onAddFile: PropTypes.func.isRequired,
|
||||
onAddFolder: PropTypes.func.isRequired,
|
||||
onUploadFile: PropTypes.func.isRequired,
|
||||
@@ -192,7 +193,9 @@ class DirOperationToolbar extends React.Component {
|
||||
<button className="btn btn-secondary operation-item" title={gettext('New')} onClick={this.onCreateClick}>{gettext('New')}</button>
|
||||
</Fragment>
|
||||
)}
|
||||
{this.props.showShareBtn &&
|
||||
<button className="btn btn-secondary operation-item" title={gettext('Share')} onClick={this.onShareClick}>{gettext('Share')}</button>
|
||||
}
|
||||
</div>
|
||||
{this.state.isUploadMenuShow && (
|
||||
<ul className="menu dropdown-menu" style={this.state.operationMenuStyle}>
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React,{ Fragment } from 'react';
|
||||
import { Popover } from 'reactstrap';
|
||||
import PropTypes from 'prop-types';
|
||||
import { gettext, siteRoot, username, loginUrl } from '../../utils/constants';
|
||||
import { gettext, siteRoot, username, loginUrl, canAddRepo } from '../../utils/constants';
|
||||
import { Link } from '@reach/router';
|
||||
import { seafileAPI } from '../../utils/seafile-api';
|
||||
import { Utils } from '../../utils/utils';
|
||||
@@ -331,9 +331,11 @@ class GroupView extends React.Component {
|
||||
<div className="cur-view-toolbar border-left-show">
|
||||
<span className="sf2-icon-menu side-nav-toggle hidden-md-up d-md-none" title="Side Nav Menu" onClick={this.props.onShowSidePanel}></span>
|
||||
<div className="operation">
|
||||
{canAddRepo && (
|
||||
<button className="btn btn-secondary operation-item" title={gettext('New Library')} onClick={this.onCreateRepoToggle}>
|
||||
<i className="fas fa-plus-square text-secondary mr-1"></i>{gettext('New Library')}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<CommonToolbar onSearchedClick={this.props.onSearchedClick} />
|
||||
|
@@ -1,10 +1,9 @@
|
||||
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import moment from 'moment';
|
||||
import { Link } from '@reach/router';
|
||||
import { Dropdown, DropdownMenu, DropdownToggle, DropdownItem } from 'reactstrap';
|
||||
import { gettext, siteRoot, storages, canGenerateShareLink, canGenerateUploadLink, folderPermEnabled, enableRepoSnapshotLabel } from '../../utils/constants';
|
||||
import { gettext, siteRoot, storages, folderPermEnabled, enableRepoSnapshotLabel } from '../../utils/constants';
|
||||
import { Utils } from '../../utils/utils';
|
||||
import { seafileAPI } from '../../utils/seafile-api';
|
||||
import RenameInput from '../../components/rename-input';
|
||||
@@ -144,9 +143,6 @@ class Item extends Component {
|
||||
changePassword = () => {
|
||||
}
|
||||
|
||||
showLinks = () => {
|
||||
}
|
||||
|
||||
folderPerm = () => {
|
||||
}
|
||||
|
||||
@@ -194,8 +190,6 @@ class Item extends Component {
|
||||
operationMenuToggleIconClassName += iconVisibility;
|
||||
}
|
||||
|
||||
// const showShareLinks = !data.encrypted && (canGenerateShareLink || canGenerateUploadLink);
|
||||
|
||||
const commonToggle = (
|
||||
<DropdownToggle
|
||||
tag="i"
|
||||
@@ -212,7 +206,6 @@ class Item extends Component {
|
||||
<DropdownItem onClick={this.transfer}>{gettext('Transfer')}</DropdownItem>
|
||||
<DropdownItem onClick={this.historySetting}>{gettext('History Setting')}</DropdownItem>
|
||||
{data.encrypted ? <DropdownItem onClick={this.changePassword}>{gettext('Change Password')}</DropdownItem> : ''}
|
||||
{/* {showShareLinks ? <DropdownItem onClick={this.showLinks}>{gettext('Share Links')}</DropdownItem> : ''} */}
|
||||
{folderPermEnabled ? <DropdownItem onClick={this.folderPerm}>{gettext('Folder Permission')}</DropdownItem> : ''}
|
||||
<DropdownItem onClick={this.showDetails}>{gettext('Details')}</DropdownItem>
|
||||
</React.Fragment>
|
||||
|
@@ -24,6 +24,7 @@ const propTypes = {
|
||||
hash: PropTypes.string,
|
||||
path: PropTypes.string.isRequired,
|
||||
repoEncrypted: PropTypes.bool.isRequired,
|
||||
showShareBtn: PropTypes.bool.isRequired,
|
||||
// whether the file or dir corresponding to the path exist
|
||||
pathExist: PropTypes.bool.isRequired,
|
||||
isFileLoading: PropTypes.bool.isRequired,
|
||||
@@ -188,6 +189,7 @@ class MainPanel extends Component {
|
||||
hasDraft={this.props.hasDraft}
|
||||
permission={this.props.permission}
|
||||
isViewFile={this.props.isViewFile}
|
||||
showShareBtn={this.props.showShareBtn}
|
||||
onAddFile={this.props.onAddFile}
|
||||
onAddFolder={this.props.onAddFolder}
|
||||
onUploadFile={this.onUploadFile}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React, { Component } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import moment from 'moment';
|
||||
import { gettext, repoID, siteRoot, initialPath, isDir, slug } from './utils/constants';
|
||||
import { gettext, repoID, siteRoot, initialPath, isDir, slug , canGenerateShareLink, canGenerateUploadLink, username } from './utils/constants';
|
||||
import { seafileAPI } from './utils/seafile-api';
|
||||
import { Utils } from './utils/utils';
|
||||
import collabServer from './utils/collab-server';
|
||||
@@ -15,6 +15,8 @@ import ModalPortal from './components/modal-portal';
|
||||
import Dirent from './models/dirent';
|
||||
import FileTag from './models/file-tag';
|
||||
import RepoTag from './models/repo-tag';
|
||||
import RepoInfo from './models/repo-info';
|
||||
|
||||
import './assets/css/fa-solid.css';
|
||||
import './assets/css/fa-regular.css';
|
||||
import './assets/css/fontawesome.css';
|
||||
@@ -29,6 +31,10 @@ class Wiki extends Component {
|
||||
super(props);
|
||||
this.state = {
|
||||
repoEncrypted: false,
|
||||
isAdmin: false,
|
||||
ownerEmail: '',
|
||||
userPerm: '',
|
||||
|
||||
path: '',
|
||||
pathExist: true,
|
||||
treeData: treeHelper.buildTree(),
|
||||
@@ -74,9 +80,12 @@ class Wiki extends Component {
|
||||
|
||||
componentDidMount() {
|
||||
seafileAPI.getRepoInfo(repoID).then(res => {
|
||||
let repoInfo = new RepoInfo(res.data);
|
||||
this.setState({
|
||||
libNeedDecrypt: res.data.lib_need_decrypt,
|
||||
repoEncrypted: res.data.encrypted
|
||||
repoEncrypted: repoInfo.encrypted,
|
||||
isAdmin: repoInfo.is_admin,
|
||||
ownerEmail: repoInfo.owner_email
|
||||
});
|
||||
|
||||
if (!res.data.lib_need_decrypt) {
|
||||
@@ -236,6 +245,7 @@ class Wiki extends Component {
|
||||
});
|
||||
|
||||
this.setState({
|
||||
userPerm: res.data.user_perm,
|
||||
direntList: Utils.sortDirents(direntList, this.state.sortBy, this.state.sortOrder),
|
||||
isDirentListLoading: false,
|
||||
dirID: res.headers.oid,
|
||||
@@ -1001,6 +1011,16 @@ class Wiki extends Component {
|
||||
)
|
||||
}
|
||||
|
||||
let showShareBtn = false;
|
||||
const { repoEncrypted, isAdmin, ownerEmail, userPerm } = this.state;
|
||||
const isRepoOwner = ownerEmail == username;
|
||||
if (!repoEncrypted && (
|
||||
canGenerateShareLink || canGenerateUploadLink ||
|
||||
isRepoOwner || isAdmin) && (
|
||||
userPerm == 'rw' || userPerm == 'r')) {
|
||||
showShareBtn = true;
|
||||
}
|
||||
|
||||
return (
|
||||
<div id="main" className="wiki-main">
|
||||
<SidePanel
|
||||
@@ -1029,6 +1049,7 @@ class Wiki extends Component {
|
||||
content={this.state.content}
|
||||
lastModified={this.state.lastModified}
|
||||
latestContributor={this.state.latestContributor}
|
||||
showShareBtn={showShareBtn}
|
||||
direntList={this.state.direntList}
|
||||
sortBy={this.state.sortBy}
|
||||
sortOrder={this.state.sortOrder}
|
||||
|
@@ -19,8 +19,9 @@ export const seafileCollabServer = window.app.pageOptions.seafileCollabServer;
|
||||
export const name = window.app.pageOptions.name;
|
||||
export const contactEmail = window.app.pageOptions.contactEmail;
|
||||
export const username = window.app.pageOptions.username;
|
||||
export const canGenerateShareLink = window.app.pageOptions.canGenerateShareLink === 'True';
|
||||
export const canGenerateUploadLink = window.app.pageOptions.canGenerateUploadLink === 'True';
|
||||
export const canAddRepo = window.app.pageOptions.canAddRepo;
|
||||
export const canGenerateShareLink = window.app.pageOptions.canGenerateShareLink;
|
||||
export const canGenerateUploadLink = window.app.pageOptions.canGenerateUploadLink;
|
||||
export const canViewOrg = window.app.pageOptions.canViewOrg === 'True';
|
||||
export const fileAuditEnabled = window.app.pageOptions.fileAuditEnabled ? true : false;
|
||||
export const enableFileComment = window.app.pageOptions.enableFileComment ? true : false;
|
||||
|
@@ -42,8 +42,9 @@
|
||||
name: "{{request.user.username|email2nickname|escapejs}}",
|
||||
contactEmail: "{{request.user.username|email2contact_email|escapejs}}",
|
||||
username: "{{request.user.username|escapejs}}",
|
||||
canGenerateShareLink: '{{ user.permissions.can_generate_share_link }}',
|
||||
canGenerateUploadLink: '{{ user.permissions.can_generate_upload_link }}',
|
||||
canAddRepo: {% if user.permissions.can_add_repo %} true {% else %} false {% endif %},
|
||||
canGenerateShareLink: {% if user.permissions.can_generate_share_link %} true {% else %} false {% endif %},
|
||||
canGenerateUploadLink: {% if user.permissions.can_generate_upload_link %} true {% else %} false {% endif %},
|
||||
canViewOrg:'{{ user.permissions.can_view_org }}',
|
||||
fileAuditEnabled: '{{ file_audit_enabled }}',
|
||||
enableFileComment: '{{ enable_file_comment }}',
|
||||
@@ -66,7 +67,7 @@
|
||||
shareLinkExpireDaysMin: "{{ share_link_expire_days_min }}",
|
||||
shareLinkExpireDaysMax: "{{ share_link_expire_days_max }}",
|
||||
maxFileName: "{{ max_file_name }}",
|
||||
enableWiki: {% if enable_wiki %} true {% else %} false {% endif %},
|
||||
enableWiki: {% if user.permissions.can_use_wiki %} true {% else %} false {% endif %},
|
||||
enableEncryptedLibrary: '{{ enable_encrypted_library }}',
|
||||
enableRepoHistorySetting: '{{ enable_repo_history_setting }}',
|
||||
isSystemStaff: {% if request.user.is_staff %} true {% else %} false {% endif %},
|
||||
|
@@ -1220,7 +1220,6 @@ def react_fake_view(request, **kwargs):
|
||||
return render(request, "react_app.html", {
|
||||
'seafile_collab_server': SEAFILE_COLLAB_SERVER,
|
||||
'storages': get_library_storages(request),
|
||||
'enable_wiki': request.user.permissions.can_use_wiki(),
|
||||
'enable_repo_snapshot_label': settings.ENABLE_REPO_SNAPSHOT_LABEL,
|
||||
'share_link_expire_days_min': SHARE_LINK_EXPIRE_DAYS_MIN,
|
||||
'share_link_expire_days_max': SHARE_LINK_EXPIRE_DAYS_MAX,
|
||||
|
Reference in New Issue
Block a user