1
0
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:
lian 2023-04-22 08:03:58 +08:00 committed by GitHub
parent 7368ca84e8
commit b24c13dce5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 119 additions and 5 deletions

View File

@ -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);
}

View File

@ -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)

View File

@ -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)

View File

@ -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"),