mirror of
https://github.com/haiwen/seahub.git
synced 2025-08-01 23:38:37 +00:00
delete dirents undo (#5422)
* delete dirents undo * update message * update * update * [dir view] fixup & improvements for 'restore deleted dirents'(refactored it) --------- Co-authored-by: llj <lingjun.li1@gmail.com>
This commit is contained in:
parent
7368ca84e8
commit
b24c13dce5
@ -760,6 +760,53 @@ class LibContentView extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
restoreDeletedDirents = (commitID, paths, e) => {
|
||||
const { repoID } = this.props;
|
||||
e.preventDefault();
|
||||
toaster.closeAll();
|
||||
seafileAPI.restoreDirents(repoID, commitID, paths).then(res => {
|
||||
const { success, failed } = res.data;
|
||||
success.forEach(dirent => {
|
||||
let name = Utils.getFileName(dirent.path);
|
||||
let parentPath = Utils.getDirName(dirent.path);
|
||||
if (!dirent.is_dir) {
|
||||
if (this.state.currentMode === 'column') {
|
||||
this.addNodeToTree(name, parentPath, 'file');
|
||||
}
|
||||
if (parentPath === this.state.path && !this.state.isViewFile) {
|
||||
this.addDirent(name, 'file');
|
||||
}
|
||||
} else {
|
||||
if (this.state.currentMode === 'column') {
|
||||
this.addNodeToTree(name, parentPath, 'dir');
|
||||
}
|
||||
if (parentPath === this.state.path && !this.state.isViewFile) {
|
||||
this.addDirent(name, 'dir');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (success.length) {
|
||||
let msg = success.length > 1 ? gettext('Restored {name} and {n} other items') :
|
||||
gettext('Restored {name}');
|
||||
msg = msg.replace('{name}', success[0].path.split('/').pop())
|
||||
.replace('{n}', success.length - 1);
|
||||
toaster.success(msg);
|
||||
}
|
||||
|
||||
if (failed.length) {
|
||||
let msg = failed.length > 1 ? gettext('Failed to restore {name} and {n} other items') :
|
||||
gettext('Failed to restore {name}');
|
||||
msg = msg.replace('{name}', failed[0].path.split('/').pop())
|
||||
.replace('{n}', failed.length - 1);
|
||||
toaster.danger(msg);
|
||||
}
|
||||
}).catch((error) => {
|
||||
let errMessage = Utils.getErrorMsg(error);
|
||||
toaster.danger(errMessage);
|
||||
});
|
||||
}
|
||||
|
||||
onDeleteItems = () => {
|
||||
let repoID = this.props.repoID;
|
||||
let direntPaths = this.getSelectedDirentPaths();
|
||||
@ -775,18 +822,24 @@ class LibContentView extends React.Component {
|
||||
|
||||
let msg = '';
|
||||
if (direntPaths.length > 1) {
|
||||
msg = gettext('Successfully deleted {name} and other {n} items.');
|
||||
msg = gettext('Successfully deleted {name} and {n} other items.');
|
||||
msg = msg.replace('{name}', dirNames[0]);
|
||||
msg = msg.replace('{n}', dirNames.length - 1);
|
||||
} else {
|
||||
msg = gettext('Successfully deleted {name}.');
|
||||
msg = msg.replace('{name}', dirNames[0]);
|
||||
}
|
||||
toaster.success(msg);
|
||||
const successTipWithUndo = (
|
||||
<>
|
||||
<span>{msg}</span>
|
||||
<a className="action-link p-0 ml-1" href="#" onClick={this.restoreDeletedDirents.bind(this, res.data.commit_id, direntPaths)}>{gettext('Undo')}</a>
|
||||
</>
|
||||
);
|
||||
toaster.success(successTipWithUndo, {duration: 5});
|
||||
}).catch((error) => {
|
||||
let errMessage = Utils.getErrorMsg(error);
|
||||
if (errMessage === gettext('Error')) {
|
||||
errMessage = gettext('Failed to delete {name} and other {n} items.');
|
||||
errMessage = gettext('Failed to delete {name} and {n} other items.');
|
||||
errMessage = errMessage.replace('{name}', dirNames[0]);
|
||||
errMessage = errMessage.replace('{n}', dirNames.length - 1);
|
||||
}
|
||||
|
@ -251,3 +251,61 @@ class RepoTrash(APIView):
|
||||
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||
|
||||
return Response({'success': True})
|
||||
|
||||
|
||||
class RepoTrashRevertDirents(APIView):
|
||||
|
||||
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
||||
permission_classes = (IsAuthenticated, )
|
||||
throttle_classes = (UserRateThrottle, )
|
||||
|
||||
def post(self, request, repo_id):
|
||||
""" Revert deleted files/dirs.
|
||||
"""
|
||||
|
||||
# argument check
|
||||
path_list = request.data.getlist('path', [])
|
||||
if not path_list:
|
||||
error_msg = 'path invalid.'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
commit_id = request.data.get('commit_id', '')
|
||||
if not commit_id:
|
||||
error_msg = 'commit_id invalid.'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
# resource check
|
||||
repo = seafile_api.get_repo(repo_id)
|
||||
if not repo:
|
||||
error_msg = 'Library %s not found.' % repo_id
|
||||
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||
|
||||
# permission check
|
||||
if check_folder_permission(request, repo_id, '/') != 'rw':
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
result = {}
|
||||
result['failed'] = []
|
||||
result['success'] = []
|
||||
username = request.user.username
|
||||
for path in path_list:
|
||||
try:
|
||||
if seafile_api.get_dir_id_by_commit_and_path(repo_id, commit_id, path):
|
||||
seafile_api.revert_dir(repo_id, commit_id, path, username)
|
||||
result['success'].append({'path': path, 'is_dir': True})
|
||||
elif seafile_api.get_file_id_by_commit_and_path(repo_id, commit_id, path):
|
||||
seafile_api.revert_file(repo_id, commit_id, path, username)
|
||||
result['success'].append({'path': path, 'is_dir': False})
|
||||
else:
|
||||
result['failed'].append({
|
||||
'path': path,
|
||||
'error_msg': f'Dirent {path} not found.'
|
||||
})
|
||||
except Exception as e:
|
||||
result['failed'].append({
|
||||
'path': path,
|
||||
'error_msg': str(e)
|
||||
})
|
||||
|
||||
return Response(result)
|
||||
|
@ -1535,7 +1535,8 @@ class ReposBatchDeleteItemView(APIView):
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
# resource check
|
||||
if not seafile_api.get_repo(repo_id):
|
||||
repo = seafile_api.get_repo(repo_id)
|
||||
if not repo:
|
||||
error_msg = 'Library %s not found.' % repo_id
|
||||
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||
|
||||
@ -1580,4 +1581,5 @@ class ReposBatchDeleteItemView(APIView):
|
||||
|
||||
result = {}
|
||||
result['success'] = True
|
||||
result['commit_id'] = repo.head_cmmt_id
|
||||
return Response(result)
|
||||
|
@ -61,7 +61,7 @@ from seahub.api2.endpoints.file_history import FileHistoryView, NewFileHistoryVi
|
||||
from seahub.api2.endpoints.dir import DirView, DirDetailView
|
||||
from seahub.api2.endpoints.file_tag import FileTagView
|
||||
from seahub.api2.endpoints.file_tag import FileTagsView
|
||||
from seahub.api2.endpoints.repo_trash import RepoTrash
|
||||
from seahub.api2.endpoints.repo_trash import RepoTrash, RepoTrashRevertDirents
|
||||
from seahub.api2.endpoints.repo_commit import RepoCommitView
|
||||
from seahub.api2.endpoints.repo_commit_dir import RepoCommitDirView
|
||||
from seahub.api2.endpoints.repo_commit_revert import RepoCommitRevertView
|
||||
@ -401,6 +401,7 @@ urlpatterns = [
|
||||
url(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/commits/(?P<commit_id>[0-9a-f]{40})/revert/$', RepoCommitRevertView.as_view(), name='api-v2.1-repo-commit-revert'),
|
||||
url(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/dir/detail/$', DirDetailView.as_view(), name='api-v2.1-dir-detail-view'),
|
||||
url(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/trash/$', RepoTrash.as_view(), name='api-v2.1-repo-trash'),
|
||||
url(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/trash/revert-dirents/$', RepoTrashRevertDirents.as_view(), name='api-v2.1-repo-trash-revert-dirents'),
|
||||
url(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/history/$', RepoHistory.as_view(), name='api-v2.1-repo-history'),
|
||||
url(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/set-password/$', RepoSetPassword.as_view(), name="api-v2.1-repo-set-password"),
|
||||
url(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/send-new-password/$', RepoSendNewPassword.as_view(), name="api-v2.1-repo-send-new-password"),
|
||||
|
Loading…
Reference in New Issue
Block a user