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

corrent logic for check generate share link, and share link permissions (#4121)

This commit is contained in:
Leo
2019-10-12 14:54:25 +08:00
committed by Daniel Pan
parent 821d6afbaa
commit 5b789c4300
9 changed files with 140 additions and 65 deletions

View File

@@ -25,11 +25,6 @@ class GenerateShareLink extends React.Component {
this.isExpireDaysNoLimit = (parseInt(shareLinkExpireDaysMin) === 0 && parseInt(shareLinkExpireDaysMax) === 0 && shareLinkExpireDaysDefault == 0); this.isExpireDaysNoLimit = (parseInt(shareLinkExpireDaysMin) === 0 && parseInt(shareLinkExpireDaysMax) === 0 && shareLinkExpireDaysDefault == 0);
this.defaultExpireDays = this.isExpireDaysNoLimit ? '' : shareLinkExpireDaysDefault; this.defaultExpireDays = this.isExpireDaysNoLimit ? '' : shareLinkExpireDaysDefault;
if (isPro) {
this.editOption = 'edit_download';
this.permissionOptions = ['preview_download', 'preview_only'];
}
this.state = { this.state = {
isValidate: false, isValidate: false,
isShowPasswordInput: false, isShowPasswordInput: false,
@@ -42,7 +37,8 @@ class GenerateShareLink extends React.Component {
sharedLinkInfo: null, sharedLinkInfo: null,
isNoticeMessageShow: false, isNoticeMessageShow: false,
isLoading: true, isLoading: true,
currentPermission: isPro ? this.permissionOptions[0] : '', permissionOptions: [],
currentPermission: '',
isSendLinkShown: false isSendLinkShown: false
}; };
} }
@@ -65,17 +61,34 @@ class GenerateShareLink extends React.Component {
toaster.danger(errMessage); toaster.danger(errMessage);
}); });
if (isPro && Utils.isEditableOfficeFile(path)) { if (isPro) {
seafileAPI.getFileInfo(repoID, path).then((res) => { if (this.props.itemType === 'library') {
if (res.data.can_edit) { let permissionOptions = Utils.getShareLinkPermissionList(this.props.itemType, '', path);
this.permissionOptions.push(this.editOption); this.setState({
permissionOptions: permissionOptions,
currentPermission: permissionOptions[0],
});
} else {
let getDirentInfoAPI;
if (this.props.itemType === 'file') {
getDirentInfoAPI = seafileAPI.getFileInfo(repoID, path);
} else if (this.props.itemType === 'dir') {
getDirentInfoAPI = seafileAPI.getDirInfo(repoID, path);
} }
getDirentInfoAPI.then((res) => {
let permission = res.data.permission;
let permissionOptions = Utils.getShareLinkPermissionList(this.props.itemType, permission, path);
this.setState({
permissionOptions: permissionOptions,
currentPermission: permissionOptions[0],
});
}).catch(error => { }).catch(error => {
let errMessage = Utils.getErrorMsg(error); let errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage); toaster.danger(errMessage);
}); });
} }
} }
}
onPasswordInputChecked = () => { onPasswordInputChecked = () => {
this.setState({ this.setState({
@@ -260,7 +273,6 @@ class GenerateShareLink extends React.Component {
} }
render() { render() {
if (this.state.isLoading) { if (this.state.isLoading) {
return <Loading />; return <Loading />;
} }
@@ -394,7 +406,7 @@ class GenerateShareLink extends React.Component {
<span>{gettext('Set permission')}</span> <span>{gettext('Set permission')}</span>
</Label> </Label>
</FormGroup> </FormGroup>
{this.permissionOptions.map((item, index) => { {this.state.permissionOptions.map((item, index) => {
return ( return (
<FormGroup check className="permission" key={index}> <FormGroup check className="permission" key={index}>
<Label className="form-check-label"> <Label className="form-check-label">

View File

@@ -129,6 +129,7 @@ class ShareDialog extends React.Component {
itemPath={this.props.itemPath} itemPath={this.props.itemPath}
repoID={this.props.repoID} repoID={this.props.repoID}
closeShareDialog={this.props.toggleDialog} closeShareDialog={this.props.toggleDialog}
itemType={itemType}
/> />
</TabPane> </TabPane>
} }
@@ -166,6 +167,7 @@ class ShareDialog extends React.Component {
renderFileContent = () => { renderFileContent = () => {
let activeTab = this.state.activeTab; let activeTab = this.state.activeTab;
const { itemType } = this.props;
return ( return (
<Fragment> <Fragment>
@@ -190,6 +192,7 @@ class ShareDialog extends React.Component {
itemPath={this.props.itemPath} itemPath={this.props.itemPath}
repoID={this.props.repoID} repoID={this.props.repoID}
closeShareDialog={this.props.toggleDialog} closeShareDialog={this.props.toggleDialog}
itemType={itemType}
/> />
</TabPane> </TabPane>
{activeTab === 'internalLink' && {activeTab === 'internalLink' &&

View File

@@ -494,11 +494,13 @@ class DirentListItem extends React.Component {
} }
renderItemOperation = () => { renderItemOperation = () => {
let { dirent, selectedDirentList, currentRepoInfo } = this.props; let { dirent, selectedDirentList } = this.props;
if (currentRepoInfo.permission === 'cloud-edit' || currentRepoInfo.permission === 'preview') {
return ''; // no need to check whether show shareBtn or not.
} // according to specification below, shareBtn aways show.
let showShareBtn = Utils.isHasPermissionToShare(currentRepoInfo, dirent.permission, dirent); // check for "generate uploadlink" or other tabs should put inside the shareDialog.
// https://dev.seafile.com/seahub/lib/d6f300e7-bb2b-4722-b83e-cf45e370bfbc/file/seaf-server%20%E5%8A%9F%E8%83%BD%E8%AE%BE%E8%AE%A1/%E6%9D%83%E9%99%90%E7%9B%B8%E5%85%B3/%E8%B5%84%E6%96%99%E5%BA%93%E6%9D%83%E9%99%90%E8%A7%84%E8%8C%83.md
// let showShareBtn = Utils.isHasPermissionToShare(currentRepoInfo, dirent.permission, dirent);
return ( return (
<Fragment> <Fragment>
@@ -512,11 +514,9 @@ class DirentListItem extends React.Component {
<i className="op-icon sf2-icon-download" title={gettext('Download')} onClick={this.onItemDownload}></i> <i className="op-icon sf2-icon-download" title={gettext('Download')} onClick={this.onItemDownload}></i>
</li> </li>
)} )}
{showShareBtn && (
<li className="operation-group-item"> <li className="operation-group-item">
<i className="op-icon sf2-icon-share" title={gettext('Share')} onClick={this.onItemShare}></i> <i className="op-icon sf2-icon-share" title={gettext('Share')} onClick={this.onItemShare}></i>
</li> </li>
)}
{dirent.permission === 'rw' && ( {dirent.permission === 'rw' && (
<li className="operation-group-item"> <li className="operation-group-item">
<i className="op-icon sf2-icon-delete" title={gettext('Delete')} onClick={this.onItemDelete}></i> <i className="op-icon sf2-icon-delete" title={gettext('Delete')} onClick={this.onItemDelete}></i>
@@ -546,7 +546,7 @@ class DirentListItem extends React.Component {
<i className="op-icon sf2-icon-download" title={gettext('Download')} onClick={this.onItemDownload}></i> <i className="op-icon sf2-icon-download" title={gettext('Download')} onClick={this.onItemDownload}></i>
</li> </li>
)} )}
{showShareBtn && ( {(
<li className="operation-group-item"> <li className="operation-group-item">
<i className="op-icon sf2-icon-share" title={gettext('Share')} onClick={this.onItemShare}></i> <i className="op-icon sf2-icon-share" title={gettext('Share')} onClick={this.onItemShare}></i>
</li> </li>

View File

@@ -46,6 +46,10 @@ class SelectEditor extends React.Component {
}); });
} }
componentWillReceiveProps() {
this.setOptions();
}
componentWillUnmount() { componentWillUnmount() {
document.removeEventListener('click', this.onHideSelect); document.removeEventListener('click', this.onHideSelect);
} }

View File

@@ -91,56 +91,60 @@ class Item extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
const item = this.props.item;
if (isPro) {
this.editOption = 'edit_download';
this.permissionOptions = ['preview_download', 'preview_only'];
this.updatePermissionOptions();
}
this.state = { this.state = {
currentPermission: isPro ? this.getCurrentPermission() : '',
isOpIconShown: false, isOpIconShown: false,
isOpMenuOpen: false, // for mobile isOpMenuOpen: false, // for mobile
isPermSelectDialogOpen: false, // for mobile isPermSelectDialogOpen: false, // for mobile
isLinkDialogOpen: false isLinkDialogOpen: false,
permissionOptions: [],
currentPermission: '',
}; };
} }
componentDidMount() {
if (isPro) {
this.updatePermissionOptions();
}
}
updatePermissionOptions = () => { updatePermissionOptions = () => {
const item = this.props.item; const item = this.props.item;
let options = this.permissionOptions; if (item.is_dir && item.path === '/') {
let permissionOptions = Utils.getShareLinkPermissionList('library', '', item.path);
if (!Utils.isEditableOfficeFile(item.obj_name)) { this.setState({
return ; permissionOptions: permissionOptions,
} });
} else {
if (item.permissions.can_edit) { let { repo_id, path } = item;
options.push(this.editOption); let getDirentInfoAPI = item.is_dir ? seafileAPI.getDirInfo(repo_id, path) : seafileAPI.getFileInfo(repo_id, path);
return ; getDirentInfoAPI.then((res) => {
} let itemType = item.is_dir ? 'dir' : 'file';
let permission = res.data.permission;
seafileAPI.getFileInfo(item.repo_id, item.path).then((res) => { let permissionOptions = Utils.getShareLinkPermissionList(itemType, permission, item.path);
if (res.data.can_edit) { this.setState({
options.push(this.editOption); permissionOptions: permissionOptions,
return ; });
}
}).catch(error => { }).catch(error => {
return ; let errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage);
});
}
this.setState({
currentPermission: this.getCurrentPermission(),
}); });
} }
getCurrentPermission = () => { getCurrentPermission = () => {
const options = this.permissionOptions;
const { can_edit, can_download } = this.props.item.permissions; const { can_edit, can_download } = this.props.item.permissions;
switch (`${can_edit} ${can_download}`) { switch (`${can_edit} ${can_download}`) {
case 'false true': case 'false true':
return options[0]; return 'preview_download';
case 'false false': case 'false false':
return options[1]; return 'preview_only';
case 'true true': case 'true true':
return this.editOption; return 'edit_download';
case 'true false':
return 'cloud_edit';
} }
} }
@@ -214,7 +218,7 @@ class Item extends Component {
render() { render() {
const item = this.props.item; const item = this.props.item;
const { currentPermission, isOpIconShown, isPermSelectDialogOpen, isLinkDialogOpen } = this.state; const { currentPermission, permissionOptions , isOpIconShown, isPermSelectDialogOpen, isLinkDialogOpen } = this.state;
let iconUrl, objUrl; let iconUrl, objUrl;
if (item.is_dir) { if (item.is_dir) {
@@ -242,7 +246,7 @@ class Item extends Component {
isTextMode={true} isTextMode={true}
isEditIconShow={isOpIconShown && !item.is_expired} isEditIconShow={isOpIconShown && !item.is_expired}
currentPermission={currentPermission} currentPermission={currentPermission}
permissionOptions={this.permissionOptions} permissionOptions={permissionOptions}
onPermissionChanged={this.changePerm} onPermissionChanged={this.changePerm}
/> />
</td> </td>
@@ -294,7 +298,7 @@ class Item extends Component {
{isPermSelectDialogOpen && {isPermSelectDialogOpen &&
<ShareLinkPermissionSelect <ShareLinkPermissionSelect
currentPerm={currentPermission} currentPerm={currentPermission}
permissions={this.permissionOptions} permissions={permissionOptions}
changePerm={this.changePerm} changePerm={this.changePerm}
toggleDialog={this.togglePermSelectDialog} toggleDialog={this.togglePermSelectDialog}
/> />

View File

@@ -109,6 +109,39 @@ export const Utils = {
} }
}, },
getShareLinkPermissionList: function(itemType, permission, path) {
// itemType: library, dir, file
// permission: rw, r, admin, cloud-edit, preview
// if item is library, can preview and download, no need to check
// if item is dir, check can download
// if item is file, check can download and check can edit
let editDownloadOption = 'edit_download';
let editOnly = 'cloud_edit';
let downloadOption = 'preview_download';
let permissionOptions = ['preview_only'];
if (itemType === 'library') {
permissionOptions.push(downloadOption);
} else if (itemType === 'dir') {
if (permission == 'rw' || permission == 'admin' || permission == 'r') {
permissionOptions.push(downloadOption);
}
} else if (itemType === 'file') {
if (permission == 'rw' || permission == 'admin' || permission == 'r') {
permissionOptions.push(downloadOption);
}
if (this.isEditableOfficeFile(path) && (permission == 'rw' || permission == 'admin')) {
permissionOptions.push(editDownloadOption);
}
if (this.isEditableOfficeFile(path) && (permission == 'cloud-edit')) {
permissionOptions.push(editOnly);
}
}
return permissionOptions;
},
isEditableOfficeFile: function(filename) { isEditableOfficeFile: function(filename) {
// no file ext // no file ext
if (filename.lastIndexOf('.') == -1) { if (filename.lastIndexOf('.') == -1) {
@@ -562,7 +595,19 @@ export const Utils = {
"can_download": true "can_download": true
} }
}; };
case 'cloud_edit':
return {
value: permission,
text: gettext('Edit on cloud'),
permissionDetails: {
'can_edit': true,
"can_download": false
} }
};
}
return {
text: '',
};
}, },
formatSize: function(options) { formatSize: function(options) {

View File

@@ -563,7 +563,8 @@ class DirDetailView(APIView):
return api_error(status.HTTP_404_NOT_FOUND, error_msg) return api_error(status.HTTP_404_NOT_FOUND, error_msg)
# permission check # permission check
if not check_folder_permission(request, repo_id, path): permission = check_folder_permission(request, repo_id, path)
if not permission:
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)
@@ -579,6 +580,7 @@ class DirDetailView(APIView):
'path': path, 'path': path,
'name': dir_obj.obj_name, 'name': dir_obj.obj_name,
'mtime': timestamp_to_isoformat_timestr(dir_obj.mtime), 'mtime': timestamp_to_isoformat_timestr(dir_obj.mtime),
'permission': permission,
} }
return Response(dir_info) return Response(dir_info)

View File

@@ -29,7 +29,6 @@ from seahub.utils import gen_shared_link, is_org_context, normalize_file_path, \
normalize_dir_path, is_pro_version, get_file_type_and_ext normalize_dir_path, is_pro_version, get_file_type_and_ext
from seahub.utils.file_op import if_locked_by_online_office from seahub.utils.file_op import if_locked_by_online_office
from seahub.utils.file_types import IMAGE, VIDEO, XMIND from seahub.utils.file_types import IMAGE, VIDEO, XMIND
from seahub.views import check_folder_permission
from seahub.utils.timeutils import datetime_to_isoformat_timestr, \ from seahub.utils.timeutils import datetime_to_isoformat_timestr, \
timestamp_to_isoformat_timestr timestamp_to_isoformat_timestr
from seahub.utils.repo import parse_repo_perm from seahub.utils.repo import parse_repo_perm
@@ -288,11 +287,12 @@ class ShareLinks(APIView):
return api_error(status.HTTP_404_NOT_FOUND, error_msg) return api_error(status.HTTP_404_NOT_FOUND, error_msg)
if parse_repo_perm(check_folder_permission(request, repo_id, path)).can_download is False: username = request.user.username
permission_by_path = seafile_api.check_permission_by_path(repo_id, path, username)
if parse_repo_perm(permission_by_path).can_generate_share_link is False:
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)
username = request.user.username
org_id = request.user.org.org_id if is_org_context(request) else None org_id = request.user.org.org_id if is_org_context(request) else None
if s_type == 'f': if s_type == 'f':
fs = FileShare.objects.get_file_link_by_path(username, repo_id, path) fs = FileShare.objects.get_file_link_by_path(username, repo_id, path)

View File

@@ -54,6 +54,7 @@ def parse_repo_perm(perm):
'can_edit_on_web', # edit files on web 'can_edit_on_web', # edit files on web
'can_copy', # copy files/folders on web 'can_copy', # copy files/folders on web
'can_preview', # preview files on web 'can_preview', # preview files on web
'can_generate_share_link', # generate share link
]) ])
RP.can_download = True if perm in [ RP.can_download = True if perm in [
@@ -70,6 +71,10 @@ def parse_repo_perm(perm):
PERMISSION_READ, PERMISSION_READ_WRITE, PERMISSION_ADMIN, PERMISSION_READ, PERMISSION_READ_WRITE, PERMISSION_ADMIN,
PERMISSION_PREVIEW, PERMISSION_PREVIEW_EDIT PERMISSION_PREVIEW, PERMISSION_PREVIEW_EDIT
] else False ] else False
RP.can_generate_share_link = True if perm in [
PERMISSION_READ_WRITE, PERMISSION_READ, PERMISSION_ADMIN,
PERMISSION_PREVIEW, PERMISSION_PREVIEW_EDIT
] else False
return RP return RP
def list_dir_by_path(cmmt, path): def list_dir_by_path(cmmt, path):