diff --git a/frontend/src/components/dialog/copy-dirent-dialog.js b/frontend/src/components/dialog/copy-dirent-dialog.js index 6d5865e9b1..d0a4313cc7 100644 --- a/frontend/src/components/dialog/copy-dirent-dialog.js +++ b/frontend/src/components/dialog/copy-dirent-dialog.js @@ -144,7 +144,7 @@ class CopyDirent extends React.Component { } else { title = gettext('Copy selected item(s) to:'); } - let mode = this.props.repoEncrypted ? 'only_current_library':'current_repo_and_other_repos'; + let mode = 'current_repo_and_other_repos'; return (
diff --git a/frontend/src/components/dialog/move-dirent-dialog.js b/frontend/src/components/dialog/move-dirent-dialog.js index 7cc0d8b0a9..1cdef90d5c 100644 --- a/frontend/src/components/dialog/move-dirent-dialog.js +++ b/frontend/src/components/dialog/move-dirent-dialog.js @@ -158,7 +158,7 @@ class MoveDirent extends React.Component { } else { title = gettext('Move selected item(s) to:'); } - let mode = this.props.repoEncrypted ? 'only_current_library':'current_repo_and_other_repos'; + let mode = 'current_repo_and_other_repos'; const { dirent, selectedDirentList } = this.props; const movedDirent = dirent ? dirent : selectedDirentList[0]; const { permission } = movedDirent; diff --git a/frontend/src/pages/lib-content-view/lib-content-view.js b/frontend/src/pages/lib-content-view/lib-content-view.js index 5a31cf54aa..5208ee335f 100644 --- a/frontend/src/pages/lib-content-view/lib-content-view.js +++ b/frontend/src/pages/lib-content-view/lib-content-view.js @@ -692,14 +692,6 @@ class LibContentView extends React.Component { onMoveItems = (destRepo, destDirentPath) => { let repoID = this.props.repoID; let selectedDirentList = this.state.selectedDirentList; - if (repoID !== destRepo.repo_id) { - this.setState(() => ({ - asyncOperatedFilesLength: selectedDirentList.length, - asyncOperationProgress: 0, - asyncOperationType: 'move', - isCopyMoveProgressDialogShow: true - })); - } let dirNames = this.getSelectedDirentNames(); let direntPaths = this.getSelectedDirentPaths(); @@ -707,6 +699,10 @@ class LibContentView extends React.Component { if (repoID !== destRepo.repo_id) { this.setState({ asyncCopyMoveTaskId: res.data.task_id, + asyncOperatedFilesLength: selectedDirentList.length, + asyncOperationProgress: 0, + asyncOperationType: 'move', + isCopyMoveProgressDialogShow: true }, () => { // After moving successfully, delete related files this.getAsyncCopyMoveProgress(); @@ -731,15 +727,19 @@ class LibContentView extends React.Component { } }).catch((error) => { - let errMessage = Utils.getErrorMsg(error); - if (errMessage === gettext('Error')) { - errMessage = Utils.getMoveFailedMessage(dirNames); + if (!error.response.data.lib_need_decrypt) { + let errMessage = Utils.getErrorMsg(error); + if (errMessage === gettext('Error')) { + errMessage = Utils.getCopyFailedMessage(dirNames); + } + toaster.danger(errMessage); + } else { + this.setState({ + libNeedDecryptWhenMove: true, + destRepoWhenCopyMove: destRepo, + destDirentPathWhenCopyMove: destDirentPath, + }); } - this.setState({ - asyncOperationProgress: 0, - isCopyMoveProgressDialogShow: false, - }); - toaster.danger(errMessage); }); }; @@ -747,20 +747,15 @@ class LibContentView extends React.Component { let repoID = this.props.repoID; let selectedDirentList = this.state.selectedDirentList; - if (repoID !== destRepo.repo_id) { - this.setState({ - asyncOperatedFilesLength: selectedDirentList.length, - asyncOperationProgress: 0, - asyncOperationType: 'copy', - isCopyMoveProgressDialogShow: true - }); - } - let dirNames = this.getSelectedDirentNames(); seafileAPI.copyDir(repoID, destRepo.repo_id, destDirentPath, this.state.path, dirNames).then(res => { if (repoID !== destRepo.repo_id) { this.setState({ asyncCopyMoveTaskId: res.data.task_id, + asyncOperatedFilesLength: selectedDirentList.length, + asyncOperationProgress: 0, + asyncOperationType: 'copy', + isCopyMoveProgressDialogShow: true }, () => { this.getAsyncCopyMoveProgress(); }); @@ -780,11 +775,19 @@ class LibContentView extends React.Component { toaster.success(message); } }).catch((error) => { - let errMessage = Utils.getErrorMsg(error); - if (errMessage === gettext('Error')) { - errMessage = Utils.getCopyFailedMessage(dirNames); + if (!error.response.data.lib_need_decrypt) { + let errMessage = Utils.getErrorMsg(error); + if (errMessage === gettext('Error')) { + errMessage = Utils.getCopyFailedMessage(dirNames); + } + toaster.danger(errMessage); + } else { + this.setState({ + libNeedDecryptWhenCopy: true, + destRepoWhenCopyMove: destRepo, + destDirentPathWhenCopyMove: destDirentPath, + }); } - toaster.danger(errMessage); }); }; @@ -1168,18 +1171,15 @@ class LibContentView extends React.Component { } let direntPath = Utils.joinPath(nodeParentPath, dirName); - if (repoID !== destRepo.repo_id) { - this.setState({ - asyncOperatedFilesLength: 1, - asyncOperationProgress: 0, - asyncOperationType: 'move', - isCopyMoveProgressDialogShow: true, - }); - } - seafileAPI.moveDir(repoID, destRepo.repo_id, moveToDirentPath, nodeParentPath, dirName).then(res => { if (repoID !== destRepo.repo_id) { - this.setState({asyncCopyMoveTaskId: res.data.task_id}, () => { + this.setState({ + asyncCopyMoveTaskId: res.data.task_id, + asyncOperatedFilesLength: 1, + asyncOperationProgress: 0, + asyncOperationType: 'move', + isCopyMoveProgressDialogShow: true, + }, () => { this.currentMoveItemName = dirName; this.currentMoveItemPath = direntPath; this.getAsyncCopyMoveProgress(dirName, direntPath); @@ -1205,12 +1205,23 @@ class LibContentView extends React.Component { toaster.success(message); } }).catch((error) => { - let errMessage = Utils.getErrorMsg(error); - if (errMessage === gettext('Error')) { - errMessage = gettext('Failed to move {name}.'); - errMessage = errMessage.replace('{name}', dirName); + if (!error.response.data.lib_need_decrypt) { + let errMessage = Utils.getErrorMsg(error); + if (errMessage === gettext('Error')) { + errMessage = gettext('Failed to move {name}.'); + errMessage = errMessage.replace('{name}', dirName); + } + toaster.danger(errMessage); + } else { + this.setState({ + libNeedDecryptWhenMove: true, + destRepoWhenCopyMove: destRepo, + destDirentPathWhenCopyMove: moveToDirentPath, + copyMoveSingleItem: true, + srcDirentWhenCopyMove: dirent, + srcNodeParentPathWhenCopyMove: nodeParentPath, + }); } - toaster.danger(errMessage); }); }; @@ -1222,20 +1233,15 @@ class LibContentView extends React.Component { nodeParentPath = this.state.path; } - if (repoID !== destRepo.repo_id) { - this.setState({ - asyncOperatedFilesLength: 1, - asyncOperationProgress: 0, - asyncOperationType: 'copy', - isCopyMoveProgressDialogShow: true - }); - } - seafileAPI.copyDir(repoID, destRepo.repo_id, copyToDirentPath, nodeParentPath, dirName).then(res => { if (repoID !== destRepo.repo_id) { this.setState({ asyncCopyMoveTaskId: res.data.task_id, + asyncOperatedFilesLength: 1, + asyncOperationProgress: 0, + asyncOperationType: 'copy', + isCopyMoveProgressDialogShow: true }, () => { this.getAsyncCopyMoveProgress(); }); @@ -1255,12 +1261,23 @@ class LibContentView extends React.Component { toaster.success(message); } }).catch((error) => { - let errMessage = Utils.getErrorMsg(error); - if (errMessage === gettext('Error')) { - errMessage = gettext('Failed to copy %(name)s'); - errMessage = errMessage.replace('%(name)s', dirName); + if (!error.response.data.lib_need_decrypt) { + let errMessage = Utils.getErrorMsg(error); + if (errMessage === gettext('Error')) { + errMessage = gettext('Failed to copy %(name)s'); + errMessage = errMessage.replace('%(name)s', dirName); + } + toaster.danger(errMessage); + } else { + this.setState({ + libNeedDecryptWhenCopy: true, + destRepoWhenCopyMove: destRepo, + destDirentPathWhenCopyMove: copyToDirentPath, + copyMoveSingleItem: true, + srcDirentWhenCopyMove: dirent, + srcNodeParentPathWhenCopyMove: nodeParentPath, + }); } - toaster.danger(errMessage); }); }; @@ -1861,6 +1878,39 @@ class LibContentView extends React.Component { this.loadDirData(this.state.path); }; + onLibDecryptWhenCopyMove = () => { + if (this.state.libNeedDecryptWhenCopy) { + if (this.state.copyMoveSingleItem) { + this.onCopyItem(this.state.destRepoWhenCopyMove, + this.state.srcDirentWhenCopyMove, + this.state.destDirentPathWhenCopyMove, + this.state.srcNodeParentPathWhenCopyMove) + } else { + this.onCopyItems(this.state.destRepoWhenCopyMove, + this.state.destDirentPathWhenCopyMove) + } + this.setState({ + libNeedDecryptWhenCopy: false, + copyMoveSingleItem: false, + }); + } + if (this.state.libNeedDecryptWhenMove) { + if (this.state.copyMoveSingleItem) { + this.onMoveItem(this.state.destRepoWhenCopyMove, + this.state.srcDirentWhenCopyMove, + this.state.destDirentPathWhenCopyMove, + this.state.srcNodeParentPathWhenCopyMove) + } else { + this.onMoveItems(this.state.destRepoWhenCopyMove, + this.state.destDirentPathWhenCopyMove) + } + this.setState({ + libNeedDecryptWhenMove: false, + copyMoveSingleItem: false, + }); + } + } + goDraftPage = () => { window.open(siteRoot + 'drafts/' + this.state.draftID + '/'); }; @@ -1951,6 +2001,17 @@ class LibContentView extends React.Component { ); } + if (this.state.libNeedDecryptWhenCopy || this.state.libNeedDecryptWhenMove) { + return ( + + + + ); + } + if (this.state.errorMsg) { return ( diff --git a/seahub/api2/endpoints/repos_batch.py b/seahub/api2/endpoints/repos_batch.py index 8a4beb8267..4012b77b57 100644 --- a/seahub/api2/endpoints/repos_batch.py +++ b/seahub/api2/endpoints/repos_batch.py @@ -1135,7 +1135,8 @@ class ReposAsyncBatchCopyItemView(APIView): error_msg = 'Folder %s not found.' % src_parent_dir return api_error(status.HTTP_404_NOT_FOUND, error_msg) - if not seafile_api.get_repo(dst_repo_id): + dst_repo = seafile_api.get_repo(dst_repo_id) + if not dst_repo: error_msg = 'Library %s not found.' % dst_repo_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) @@ -1155,6 +1156,12 @@ class ReposAsyncBatchCopyItemView(APIView): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) + # 3. if dst repo is encrypted, should decrypt it first + username = request.user.username + if dst_repo.encrypted and not seafile_api.is_password_set(dst_repo.id, username): + result = {'lib_need_decrypt': True} + return Response(result, status=status.HTTP_403_FORBIDDEN) + dirents_map = {} dst_dirents = [] for src_dirent in src_dirents: @@ -1255,7 +1262,8 @@ class ReposAsyncBatchMoveItemView(APIView): error_msg = 'Folder %s not found.' % src_parent_dir return api_error(status.HTTP_404_NOT_FOUND, error_msg) - if not seafile_api.get_repo(dst_repo_id): + dst_repo = seafile_api.get_repo(dst_repo_id) + if not dst_repo: error_msg = 'Library %s not found.' % dst_repo_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) @@ -1274,6 +1282,12 @@ class ReposAsyncBatchMoveItemView(APIView): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) + # 3. if dst repo is encrypted, should decrypt it first + username = request.user.username + if dst_repo.encrypted and not seafile_api.is_password_set(dst_repo.id, username): + result = {'lib_need_decrypt': True} + return Response(result, status=status.HTTP_403_FORBIDDEN) + # check locked files username = request.user.username locked_files = get_locked_files_by_dir(request, src_repo_id, src_parent_dir)