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

[share] added permission check (#2900)

This commit is contained in:
llj
2019-01-29 10:06:26 +08:00
committed by Daniel Pan
parent 53f42e4283
commit d9a2f6ded9
12 changed files with 193 additions and 29 deletions

View File

@@ -1,7 +1,7 @@
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { Modal, ModalHeader, ModalBody, TabContent, TabPane, Nav, NavItem, NavLink } from 'reactstrap';
import { gettext } from '../../utils/constants';
import { gettext, canGenerateShareLink, canGenerateUploadLink } from '../../utils/constants';
import ShareToUser from './share-to-user';
import ShareToGroup from './share-to-group';
import GenerateShareLink from './generate-share-link';
@@ -21,10 +21,24 @@ class ShareDialog extends React.Component {
constructor(props) {
super(props);
this.state = {
activeTab: 'shareLink'
activeTab: this.getInitialActiveTab()
};
}
getInitialActiveTab = () => {
const {repoEncrypted, userPerm, enableDirPrivateShare} = this.props;
const enableShareLink = !repoEncrypted && canGenerateShareLink;
const enableUploadLink = !repoEncrypted && canGenerateUploadLink && userPerm == 'rw';
if (enableShareLink) {
return 'shareLink';
} else if (enableUploadLink) {
return 'uploadLink';
} else if (enableDirPrivateShare) {
return 'shareToUser';
}
}
toggle = (tab) => {
if (this.state.activeTab !== tab) {
this.setState({activeTab: tab});
@@ -33,20 +47,31 @@ class ShareDialog extends React.Component {
renderDirContent = () => {
let activeTab = this.state.activeTab;
const {repoEncrypted, userPerm, enableDirPrivateShare} = this.props;
const enableShareLink = !repoEncrypted && canGenerateShareLink;
const enableUploadLink = !repoEncrypted && canGenerateUploadLink && userPerm == 'rw';
return (
<Fragment>
<div className="share-dialog-side">
<Nav pills vertical>
{enableShareLink &&
<NavItem>
<NavLink className={activeTab === 'shareLink' ? 'active' : ''} onClick={this.toggle.bind(this, 'shareLink')}>
{gettext('Share Link')}
</NavLink>
</NavItem>
}
{enableUploadLink &&
<NavItem>
<NavLink className={activeTab === 'uploadLink' ? 'active' : ''} onClick={this.toggle.bind(this, 'uploadLink')}>
{gettext('Upload Link')}
</NavLink>
</NavItem>
}
{enableDirPrivateShare &&
<Fragment>
<NavItem>
<NavLink className={activeTab === 'shareToUser' ? 'active' : ''} onClick={this.toggle.bind(this, 'shareToUser')}>
{gettext('Share to user')}
@@ -57,10 +82,13 @@ class ShareDialog extends React.Component {
{gettext('Share to group')}
</NavLink>
</NavItem>
</Fragment>
}
</Nav>
</div>
<div className="share-dialog-main">
<TabContent activeTab={this.state.activeTab}>
{enableShareLink &&
<TabPane tabId="shareLink">
<GenerateShareLink
itemPath={this.props.itemPath}
@@ -68,6 +96,8 @@ class ShareDialog extends React.Component {
closeShareDialog={this.props.toggleDialog}
/>
</TabPane>
}
{enableUploadLink &&
<TabPane tabId="uploadLink">
<GenerateUploadLink
itemPath={this.props.itemPath}
@@ -75,12 +105,17 @@ class ShareDialog extends React.Component {
closeShareDialog={this.props.toggleDialog}
/>
</TabPane>
}
{enableDirPrivateShare &&
<Fragment>
<TabPane tabId="shareToUser">
<ShareToUser isGroupOwnedRepo={this.props.isGroupOwnedRepo} itemPath={this.props.itemPath} repoID={this.props.repoID} />
</TabPane>
<TabPane tabId="shareToGroup">
<ShareToGroup isGroupOwnedRepo={this.props.isGroupOwnedRepo} itemPath={this.props.itemPath} repoID={this.props.repoID} />
</TabPane>
</Fragment>
}
</TabContent>
</div>
</Fragment>
@@ -116,14 +151,15 @@ class ShareDialog extends React.Component {
}
render() {
let { itemType, itemName } = this.props;
const { itemType, itemName, repoEncrypted } = this.props;
const enableShareLink = !repoEncrypted && canGenerateShareLink;
return (
<div>
<Modal isOpen={true} style={{maxWidth: '720px'}} className="share-dialog">
<ModalHeader toggle={this.props.toggleDialog}>{gettext('Share')} <span className="sf-font" title={itemName}>{itemName}</span></ModalHeader>
<ModalBody className="dialog-list-container share-dialog-content">
{(itemType === 'library' || itemType === 'dir') && this.renderDirContent()}
{itemType === 'file' && this.renderFileContent()}
{(itemType === 'file' && enableShareLink) && this.renderFileContent()}
</ModalBody>
</Modal>
</div>

View File

@@ -23,6 +23,10 @@ const propTypes = {
repoName: PropTypes.string.isRequired,
repoEncrypted: PropTypes.bool.isRequired,
showShareBtn: PropTypes.bool.isRequired,
enableDirPrivateShare: PropTypes.bool.isRequired,
userPerm: PropTypes.string.isRequired,
isAdmin: PropTypes.bool.isRequired,
isGroupOwnedRepo: PropTypes.bool.isRequired,
pathExist: PropTypes.bool.isRequired,
permission: PropTypes.bool.isRequired,
isDirentListLoading: PropTypes.bool.isRequired,
@@ -66,16 +70,10 @@ class DirPanel extends React.Component {
currentDirent: null,
currentMode: 'list',
isDirentDetailShow: false,
isRepoOwner: false,
};
}
componentDidMount() {
let currentRepoInfo = this.props.currentRepoInfo;
if (currentRepoInfo) {
let isRepoOwner = currentRepoInfo.owner_email === username;
this.setState({isRepoOwner: isRepoOwner});
}
}
onPathClick = (path) => {
@@ -156,7 +154,13 @@ class DirPanel extends React.Component {
isViewFile={false}
path={this.props.path}
repoID={this.props.repoID}
repoName={this.props.repoName}
repoEncrypted={this.props.repoEncrypted}
showShareBtn={this.props.showShareBtn}
enableDirPrivateShare={this.props.enableDirPrivateShare}
userPerm={this.props.userPerm}
isAdmin={this.props.isAdmin}
isGroupOwnedRepo={this.props.isGroupOwnedRepo}
direntList={this.props.direntList}
onAddFile={this.props.onAddFile}
onAddFolder={this.props.onAddFolder}
@@ -213,6 +217,10 @@ class DirPanel extends React.Component {
path={this.props.path}
repoID={this.props.repoID}
repoEncrypted={this.props.repoEncrypted}
isRepoOwner={this.props.isRepoOwner}
isAdmin={this.props.isAdmin}
isGroupOwnedRepo={this.props.isGroupOwnedRepo}
enableDirPrivateShare={this.props.enableDirPrivateShare}
direntList={this.props.direntList}
sortBy={this.props.sortBy}
sortOrder={this.props.sortOrder}
@@ -220,7 +228,6 @@ class DirPanel extends React.Component {
currentRepoInfo={this.props.currentRepoInfo}
isDirentListLoading={this.props.isDirentListLoading}
isAllItemSelected={this.props.isAllDirentSelected}
isRepoOwner={this.state.isRepoOwner}
onAddFile={this.props.onAddFile}
onDirentClick={this.onDirentClick}
onItemDetails={this.onItemDetails}

View File

@@ -1,7 +1,7 @@
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';
import { siteRoot, canGenerateShareLink, canGenerateUploadLink, username } from '../../utils/constants';
import { isPro, siteRoot, canGenerateShareLink, canGenerateUploadLink, username } from '../../utils/constants';
import { seafileAPI } from '../../utils/seafile-api';
import { Utils } from '../../utils/utils';
import { gettext } from '../../utils/constants';
@@ -31,6 +31,7 @@ class DirView extends React.Component {
repoName: '',
repoID: '',
repoEncrypted: false,
isGroupOwnedRepo: false,
isAdmin: false,
ownerEmail: '',
userPerm: '',
@@ -91,12 +92,22 @@ class DirView extends React.Component {
repoID: repoInfo.repo_id,
repoName: repoInfo.repo_name,
repoEncrypted: repoInfo.encrypted,
isVirtual: repoInfo.is_virtual,
isAdmin: repoInfo.is_admin,
ownerEmail: repoInfo.owner_email,
permission: repoInfo.permission === 'rw',
libNeedDecrypt: res.data.lib_need_decrypt,
});
const ownerEmail = repoInfo.owner_email;
if (repoInfo.owner_email.indexOf('@seafile_group') != -1) {
const groupID = ownerEmail.substring(0, ownerEmail.indexOf('@'));
this.getGroupInfo(groupID);
this.setState({
isGroupOwnedRepo: true
});
}
let repoName = repoInfo.repo_name;
let repoID = repoInfo.repo_id;
let path = location.slice(location.indexOf(repoID) + repoID.length); // get the string after repoID
@@ -138,6 +149,16 @@ class DirView extends React.Component {
this.lastModifyTime = new Date();
}
getGroupInfo = (groupID) => {
seafileAPI.getGroup(groupID).then(res => {
if (res.data.admins.indexOf(username) != -1) {
this.setState({
isDepartmentAdmin: true
});
}
});
}
onRepoUpdateEvent = () => {
let currentTime = new Date();
if ((parseFloat(currentTime - this.lastModifyTime)/1000) <= 5) {
@@ -669,14 +690,18 @@ class DirView extends React.Component {
}
render() {
let showShareBtn = false;
const { repoEncrypted, isAdmin, ownerEmail, userPerm } = this.state;
let showShareBtn = false,
enableDirPrivateShare = false;
const { repoEncrypted, isAdmin, ownerEmail, userPerm, isVirtual, isDepartmentAdmin } = this.state;
const isRepoOwner = ownerEmail == username;
if (!repoEncrypted && (
canGenerateShareLink || canGenerateUploadLink ||
isRepoOwner || isAdmin) && (
userPerm == 'rw' || userPerm == 'r')) {
showShareBtn = true;
if (!isVirtual && (isRepoOwner || isAdmin || isDepartmentAdmin)) {
enableDirPrivateShare = true;
}
}
return (
@@ -694,6 +719,11 @@ class DirView extends React.Component {
isDirentSelected={this.state.isDirentSelected}
isAllDirentSelected={this.state.isAllDirentSelected}
showShareBtn={showShareBtn}
enableDirPrivateShare={enableDirPrivateShare}
userPerm={userPerm}
isRepoOwner={isRepoOwner}
isAdmin={isAdmin}
isGroupOwnedRepo={this.state.isGroupOwnedRepo}
direntList={this.state.direntList}
sortBy={this.state.sortBy}
sortOrder={this.state.sortOrder}

View File

@@ -2,7 +2,7 @@ import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import MD5 from 'MD5';
import { UncontrolledTooltip } from 'reactstrap';
import { gettext, siteRoot, mediaUrl } from '../../utils/constants';
import { gettext, siteRoot, mediaUrl, canGenerateShareLink, canGenerateUploadLink } from '../../utils/constants';
import { Utils } from '../../utils/utils';
import { seafileAPI } from '../../utils/seafile-api';
import URLDecorator from '../../utils/url-decorator';
@@ -365,6 +365,14 @@ class DirentListItem extends React.Component {
iconUrl = Utils.getFolderIconUrl({isReadOnly, size});
}
const {repoEncrypted, isRepoOwner, isAdmin} = this.props;
let showShare = false;
if (!repoEncrypted &&
(dirent.permission == 'rw' || dirent.permission == 'r')) {
showShare = dirent.type == 'file' ? canGenerateShareLink :
(canGenerateShareLink || canGenerateUploadLink || (isRepoOwner || isAdmin));
}
return (
<Fragment>
<tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseOver={this.onMouseOver} onMouseLeave={this.onMouseLeave} onClick={this.onDirentClick}>
@@ -415,9 +423,11 @@ class DirentListItem extends React.Component {
<li className="operation-group-item">
<i className="op-icon sf2-icon-download" title={gettext('Download')} onClick={this.onItemDownload}></i>
</li>
{showShare &&
<li className="operation-group-item">
<i className="op-icon sf2-icon-share" title={gettext('Share')} onClick={this.onItemShare}></i>
</li>
}
<li className="operation-group-item">
<i className="op-icon sf2-icon-delete" title={gettext('Delete')} onClick={this.onItemDelete}></i>
</li>
@@ -476,7 +486,12 @@ class DirentListItem extends React.Component {
itemType={dirent.type}
itemName={dirent.name}
itemPath={direntPath}
userPerm={dirent.permission}
repoID={this.props.repoID}
repoEncrypted={false}
enableDirPrivateShare={this.props.enableDirPrivateShare}
isAdmin={this.props.isAdmin}
isGroupOwnedRepo={this.props.isGroupOwnedRepo}
toggleDialog={this.closeSharedDialog}
/>
</ModalPortal>

View File

@@ -267,6 +267,10 @@ class DirentListView extends React.Component {
onDirentClick={this.props.onDirentClick}
onItemDetails={this.onItemDetails}
showImagePopup={this.showImagePopup}
repoEncrypted={this.props.repoEncrypted}
enableDirPrivateShare={this.props.enableDirPrivateShare}
isAdmin={this.props.isAdmin}
isGroupOwnedRepo={this.props.isGroupOwnedRepo}
/>
);
})

View File

@@ -313,6 +313,8 @@ class SharedRepoListItem extends React.Component {
renderPCUI = () => {
let { iconUrl, iconTitle, libPath } = this.getRepoComputeParams();
let { repo } = this.props;
// TODO: enableDirPrivateShare, isGroupOwnedRepo
let isGroupOwnedRepo = repo.owner_email.indexOf('@seafile_group') > -1;
return (
<Fragment>
@@ -331,6 +333,10 @@ class SharedRepoListItem extends React.Component {
itemName={repo.repo_name}
itemPath={'/'}
repoID={repo.repo_id}
repoEncrypted={repo.encrypted}
enableDirPrivateShare={true}
userPerm={repo.permission}
isAdmin={repo.is_admin}
isGroupOwnedRepo={isGroupOwnedRepo}
toggleDialog={this.toggleShareDialog}
/>
@@ -363,6 +369,10 @@ class SharedRepoListItem extends React.Component {
itemName={repo.repo_name}
itemPath={'/'}
repoID={repo.repo_id}
repoEncrypted={repo.encrypted}
enableDirPrivateShare={true}
userPerm={repo.permission}
isAdmin={repo.is_admin}
isGroupOwnedRepo={isGroupOwnedRepo}
toggleDialog={this.toggleShareDialog}
/>

View File

@@ -177,9 +177,9 @@ class DirOperationToolbar extends React.Component {
}
render() {
let { path, isViewFile } = this.props;
let { path, isViewFile, repoName } = this.props;
let itemType = isViewFile ? 'file' : 'dir';
let itemName = isViewFile ? Utils.getFileName(path) : Utils.getFolderName(path);
let itemName = isViewFile ? Utils.getFileName(path) : (path == '/' ? repoName : Utils.getFolderName(path));
return (
<Fragment>
<div className="operation">
@@ -251,6 +251,11 @@ class DirOperationToolbar extends React.Component {
itemName={itemName}
itemPath={this.props.path}
repoID={this.props.repoID}
repoEncrypted={this.props.repoEncrypted}
enableDirPrivateShare={this.props.enableDirPrivateShare}
userPerm={this.props.userPerm}
isAdmin={this.props.isAdmin}
isGroupOwnedRepo={this.props.isGroupOwnedRepo}
toggleDialog={this.onShareClick}
/>
</ModalPortal>

View File

@@ -15,6 +15,9 @@ class Repo {
this.modifier_email = object.modifier_email;
this.modifier_name = object.modifier_name;
this.type = object.type;
if (object.is_admin != undefined) {
this.is_admin = object.is_admin;
}
}
}

View File

@@ -270,6 +270,9 @@ class Item extends Component {
itemName={data.repo_name}
itemPath={'/'}
repoID={data.repo_id}
repoEncrypted={data.encrypted}
enableDirPrivateShare={true}
userPerm={data.permission}
toggleDialog={this.toggleShareDialog}
/>
</ModalPotal>
@@ -298,6 +301,9 @@ class Item extends Component {
itemName={data.repo_name}
itemPath={'/'}
repoID={data.repo_id}
repoEncrypted={data.encrypted}
enableDirPrivateShare={true}
userPerm={data.permission}
toggleDialog={this.toggleShareDialog}
/>
</ModalPotal>

View File

@@ -23,8 +23,13 @@ const propTypes = {
permission: PropTypes.string,
hash: PropTypes.string,
path: PropTypes.string.isRequired,
repoName: PropTypes.string.isRequired,
repoEncrypted: PropTypes.bool.isRequired,
showShareBtn: PropTypes.bool.isRequired,
enableDirPrivateShare: PropTypes.bool.isRequired,
userPerm: PropTypes.string.isRequired,
isAdmin: PropTypes.bool.isRequired,
isGroupOwnedRepo: PropTypes.bool.isRequired,
// whether the file or dir corresponding to the path exist
pathExist: PropTypes.bool.isRequired,
isFileLoading: PropTypes.bool.isRequired,
@@ -78,20 +83,14 @@ class MainPanel extends Component {
currentDirent: null,
direntPath: '',
currentRepoInfo: null,
isRepoOwner: false,
};
}
componentDidMount() {
seafileAPI.getRepoInfo(repoID).then(res => {
let repoInfo = new RepoInfo(res.data);
seafileAPI.getAccountInfo().then(res => {
let user_email = res.data.email;
let isRepoOwner = repoInfo.owner_email === user_email;
this.setState({
currentRepoInfo: repoInfo,
isRepoOwner: isRepoOwner,
});
});
});
if (this.props.hash) {
@@ -185,12 +184,18 @@ class MainPanel extends Component {
<DirOperationToolBar
path={this.props.path}
repoID={repoID}
repoName={this.props.repoName}
repoEncrypted={this.props.repoEncrypted}
isDraft={this.props.isDraft}
hasDraft={this.props.hasDraft}
direntList={this.props.direntList}
permission={this.props.permission}
isViewFile={this.props.isViewFile}
showShareBtn={this.props.showShareBtn}
enableDirPrivateShare={this.props.enableDirPrivateShare}
userPerm={this.props.userPerm}
isAdmin={this.props.isAdmin}
isGroupOwnedRepo={this.props.isGroupOwnedRepo}
onAddFile={this.props.onAddFile}
onAddFolder={this.props.onAddFolder}
onUploadFile={this.onUploadFile}
@@ -262,6 +267,10 @@ class MainPanel extends Component {
path={this.props.path}
repoID={repoID}
repoEncrypted={this.props.repoEncrypted}
isRepoOwner={this.props.isRepoOwner}
isAdmin={this.props.isAdmin}
isGroupOwnedRepo={this.props.isGroupOwnedRepo}
enableDirPrivateShare={this.props.enableDirPrivateShare}
direntList={this.props.direntList}
sortBy={this.props.sortBy}
sortOrder={this.props.sortOrder}
@@ -277,7 +286,6 @@ class MainPanel extends Component {
isDirentListLoading={this.props.isDirentListLoading}
updateDirent={this.props.updateDirent}
currentRepoInfo={this.state.currentRepoInfo}
isRepoOwner={this.state.isRepoOwner}
isAllItemSelected={this.props.isAllDirentSelected}
onAllItemSelected={this.props.onAllDirentSelected}
onItemSelected={this.props.onItemSelected}

View File

@@ -177,7 +177,6 @@ class Item extends Component {
}
render() {
if (this.state.unshared) {
return null;
}
@@ -227,6 +226,10 @@ class Item extends Component {
itemName={data.repo_name}
itemPath={'/'}
repoID={data.repo_id}
repoEncrypted={data.encrypted}
enableDirPrivateShare={true}
userPerm={data.permission}
isAdmin={true}
toggleDialog={this.toggleShareDialog}
/>
</ModalPotal>
@@ -258,6 +261,10 @@ class Item extends Component {
itemName={data.repo_name}
itemPath={'/'}
repoID={data.repo_id}
repoEncrypted={data.encrypted}
enableDirPrivateShare={true}
userPerm={data.permission}
isAdmin={true}
toggleDialog={this.toggleShareDialog}
/>
</ModalPotal>

View File

@@ -30,7 +30,9 @@ class Wiki extends Component {
constructor(props) {
super(props);
this.state = {
repoName: '',
repoEncrypted: false,
isGroupOwnedRepo: false,
isAdmin: false,
ownerEmail: '',
userPerm: '',
@@ -83,11 +85,22 @@ class Wiki extends Component {
let repoInfo = new RepoInfo(res.data);
this.setState({
libNeedDecrypt: res.data.lib_need_decrypt,
repoName: repoInfo.repo_name,
repoEncrypted: repoInfo.encrypted,
isVirtual: repoInfo.is_virtual,
isAdmin: repoInfo.is_admin,
ownerEmail: repoInfo.owner_email
});
const ownerEmail = repoInfo.owner_email;
if (repoInfo.owner_email.indexOf('@seafile_group') != -1) {
const groupID = ownerEmail.substring(0, ownerEmail.indexOf('@'));
this.getGroupInfo(groupID);
this.setState({
isGroupOwnedRepo: true
});
}
if (!res.data.lib_need_decrypt) {
this.loadWikiData();
}
@@ -102,6 +115,16 @@ class Wiki extends Component {
this.lastModifyTime = new Date();
}
getGroupInfo = (groupID) => {
seafileAPI.getGroup(groupID).then(res => {
if (res.data.admins.indexOf(username) != -1) {
this.setState({
isDepartmentAdmin: true
});
}
});
}
onRepoUpdateEvent = () => {
let currentTime = new Date();
if ((parseFloat(currentTime - this.lastModifyTime)/1000) <= 5) {
@@ -1018,14 +1041,18 @@ class Wiki extends Component {
)
}
let showShareBtn = false;
const { repoEncrypted, isAdmin, ownerEmail, userPerm } = this.state;
let showShareBtn = false,
enableDirPrivateShare = false;
const { repoEncrypted, isAdmin, ownerEmail, userPerm, isVirtual, isDepartmentAdmin } = this.state;
const isRepoOwner = ownerEmail == username;
if (!repoEncrypted && (
canGenerateShareLink || canGenerateUploadLink ||
isRepoOwner || isAdmin) && (
userPerm == 'rw' || userPerm == 'r')) {
showShareBtn = true;
if (!isVirtual && (isRepoOwner || isAdmin || isDepartmentAdmin)) {
enableDirPrivateShare = true;
}
}
return (
@@ -1047,6 +1074,7 @@ class Wiki extends Component {
/>
<MainPanel
path={this.state.path}
repoName={this.state.repoName}
repoEncrypted={this.state.repoEncrypted}
isViewFile={this.state.isViewFile}
pathExist={this.state.pathExist}
@@ -1057,6 +1085,11 @@ class Wiki extends Component {
lastModified={this.state.lastModified}
latestContributor={this.state.latestContributor}
showShareBtn={showShareBtn}
enableDirPrivateShare={enableDirPrivateShare}
userPerm={userPerm}
isRepoOwner={isRepoOwner}
isAdmin={isAdmin}
isGroupOwnedRepo={this.state.isGroupOwnedRepo}
direntList={this.state.direntList}
sortBy={this.state.sortBy}
sortOrder={this.state.sortOrder}