mirror of
https://github.com/haiwen/seahub.git
synced 2025-08-02 07:47:32 +00:00
add batch copy/move item api
This commit is contained in:
parent
25aa891bcd
commit
bed4bb9bd7
@ -22,7 +22,8 @@ from seahub.base.accounts import User
|
||||
from seahub.share.signals import share_repo_to_user_successful, \
|
||||
share_repo_to_group_successful
|
||||
from seahub.utils import is_org_context, send_perm_audit_msg, \
|
||||
normalize_dir_path, get_folder_permission_recursively
|
||||
normalize_dir_path, get_folder_permission_recursively, \
|
||||
normalize_file_path, check_filename_with_rename
|
||||
from seahub.views import check_folder_permission
|
||||
from seahub.settings import MAX_PATH
|
||||
|
||||
@ -596,3 +597,348 @@ class ReposBatchCreateDirView(APIView):
|
||||
result['success'].append(common_dict)
|
||||
|
||||
return Response(result)
|
||||
|
||||
|
||||
class ReposBatchCopyItemView(APIView):
|
||||
|
||||
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
||||
permission_classes = (IsAuthenticated, )
|
||||
throttle_classes = (UserRateThrottle, )
|
||||
|
||||
def post(self, request):
|
||||
""" Multi copy files/folders.
|
||||
Permission checking:
|
||||
1. User must has `r/rw` permission for src folder.
|
||||
2. User must has `rw` permission for dst folder.
|
||||
Parameter:
|
||||
{
|
||||
"src_repo_id":"7460f7ac-a0ff-4585-8906-bb5a57d2e118",
|
||||
"dst_repo_id":"a3fa768d-0f00-4343-8b8d-07b4077881db",
|
||||
"paths":[
|
||||
{"src_path":"/1/2/3/","dst_path":"/4/5/6/"},
|
||||
{"src_path":"/a/b/c/","dst_path":"/d/e/f/"},
|
||||
]
|
||||
}
|
||||
"""
|
||||
|
||||
# argument check
|
||||
path_list = request.data.get('paths', None)
|
||||
if not path_list:
|
||||
error_msg = 'paths invalid.'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
src_repo_id = request.data.get('src_repo_id', None)
|
||||
if not src_repo_id:
|
||||
error_msg = 'src_repo_id invalid.'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
dst_repo_id = request.data.get('dst_repo_id', None)
|
||||
if not dst_repo_id:
|
||||
error_msg = 'dst_repo_id invalid.'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
# resource check
|
||||
src_repo = seafile_api.get_repo(src_repo_id)
|
||||
if not src_repo:
|
||||
error_msg = 'Library %s not found.' % src_repo_id
|
||||
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||
|
||||
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)
|
||||
|
||||
# permission check
|
||||
if check_folder_permission(request, src_repo_id, '/') is None:
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
if check_folder_permission(request, dst_repo_id, '/') is None:
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
result = {}
|
||||
result['failed'] = []
|
||||
result['success'] = []
|
||||
username = request.user.username
|
||||
|
||||
for path_item in path_list:
|
||||
|
||||
src_path = path_item['src_path']
|
||||
src_path = normalize_dir_path(src_path)
|
||||
src_parent_dir = os.path.dirname(src_path.rstrip('/'))
|
||||
src_parent_dir = normalize_dir_path(src_parent_dir)
|
||||
src_obj_name = os.path.basename(src_path.rstrip('/'))
|
||||
|
||||
dst_path = path_item['dst_path']
|
||||
dst_path = normalize_dir_path(dst_path)
|
||||
dst_parent_dir = dst_path
|
||||
dst_obj_name = src_obj_name
|
||||
|
||||
common_dict = {
|
||||
'src_repo_id': src_repo_id,
|
||||
'src_path': src_path,
|
||||
'dst_repo_id': dst_repo_id,
|
||||
'dst_path': dst_path,
|
||||
}
|
||||
|
||||
# src/dst parameter check
|
||||
if src_repo_id == dst_repo_id and \
|
||||
dst_path.startswith(src_path):
|
||||
error_dict = {
|
||||
'error_msg': "The destination directory is the same as the source, or is it's subfolder."
|
||||
}
|
||||
common_dict.update(error_dict)
|
||||
result['failed'].append(common_dict)
|
||||
continue
|
||||
|
||||
if src_path == '/':
|
||||
error_dict = {
|
||||
'error_msg': "The source path can not be '/'."
|
||||
}
|
||||
common_dict.update(error_dict)
|
||||
result['failed'].append(common_dict)
|
||||
continue
|
||||
|
||||
if len(dst_parent_dir + dst_obj_name) > MAX_PATH:
|
||||
error_dict = {
|
||||
'error_msg': "'Destination path is too long."
|
||||
}
|
||||
common_dict.update(error_dict)
|
||||
result['failed'].append(common_dict)
|
||||
continue
|
||||
|
||||
# src resource check
|
||||
## as we don't know if `src_path` stands for a file or a folder,
|
||||
## so we check both
|
||||
src_dir_id = seafile_api.get_dir_id_by_path(src_repo_id, src_path)
|
||||
src_file_id = seafile_api.get_file_id_by_path(src_repo_id,
|
||||
normalize_file_path(src_path))
|
||||
|
||||
if not src_dir_id and not src_file_id:
|
||||
error_dict = {
|
||||
'error_msg': '%s not found.' % src_path
|
||||
}
|
||||
common_dict.update(error_dict)
|
||||
result['failed'].append(common_dict)
|
||||
continue
|
||||
|
||||
# dst resource check
|
||||
if not seafile_api.get_dir_id_by_path(dst_repo_id, dst_path):
|
||||
error_dict = {
|
||||
'error_msg': 'Folder %s not found.' % dst_path
|
||||
}
|
||||
common_dict.update(error_dict)
|
||||
result['failed'].append(common_dict)
|
||||
continue
|
||||
|
||||
# src path permission check, user must has `r/rw` permission for src folder.
|
||||
if check_folder_permission(request, src_repo_id, src_parent_dir) is None:
|
||||
error_dict = {
|
||||
'error_msg': 'Permission denied.'
|
||||
}
|
||||
common_dict.update(error_dict)
|
||||
result['failed'].append(common_dict)
|
||||
continue
|
||||
|
||||
# dst path permission check, user must has `rw` permission for dst folder.
|
||||
if check_folder_permission(request, dst_repo_id, dst_path) != 'rw':
|
||||
error_dict = {
|
||||
'error_msg': 'Permission denied.'
|
||||
}
|
||||
common_dict.update(error_dict)
|
||||
result['failed'].append(common_dict)
|
||||
continue
|
||||
|
||||
try:
|
||||
dst_obj_name = check_filename_with_rename(dst_repo_id,
|
||||
dst_parent_dir, dst_obj_name)
|
||||
# need_progress=0, synchronous=1
|
||||
seafile_api.copy_file(src_repo_id, src_parent_dir, src_obj_name,
|
||||
dst_repo_id, dst_parent_dir, dst_obj_name, username, 0, 1)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
error_dict = {
|
||||
'error_msg': 'Internal Server Error'
|
||||
}
|
||||
common_dict.update(error_dict)
|
||||
result['failed'].append(common_dict)
|
||||
continue
|
||||
|
||||
common_dict['dst_obj_name'] = dst_obj_name
|
||||
result['success'].append(common_dict)
|
||||
|
||||
return Response(result)
|
||||
|
||||
|
||||
class ReposBatchMoveItemView(APIView):
|
||||
|
||||
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
||||
permission_classes = (IsAuthenticated, )
|
||||
throttle_classes = (UserRateThrottle, )
|
||||
|
||||
def post(self, request):
|
||||
""" Multi move files/folders.
|
||||
Permission checking:
|
||||
1. User must has `rw` permission for src folder.
|
||||
2. User must has `rw` permission for dst folder.
|
||||
Parameter:
|
||||
{
|
||||
"src_repo_id":"7460f7ac-a0ff-4585-8906-bb5a57d2e118",
|
||||
"dst_repo_id":"a3fa768d-0f00-4343-8b8d-07b4077881db",
|
||||
"paths":[
|
||||
{"src_path":"/1/2/3/","dst_path":"/4/5/6/"},
|
||||
{"src_path":"/a/b/c/","dst_path":"/d/e/f/"},
|
||||
]
|
||||
}
|
||||
"""
|
||||
|
||||
# argument check
|
||||
path_list = request.data.get('paths', None)
|
||||
if not path_list:
|
||||
error_msg = 'paths invalid.'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
src_repo_id = request.data.get('src_repo_id', None)
|
||||
if not src_repo_id:
|
||||
error_msg = 'src_repo_id invalid.'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
dst_repo_id = request.data.get('dst_repo_id', None)
|
||||
if not dst_repo_id:
|
||||
error_msg = 'dst_repo_id invalid.'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
# resource check
|
||||
src_repo = seafile_api.get_repo(src_repo_id)
|
||||
if not src_repo:
|
||||
error_msg = 'Library %s not found.' % src_repo_id
|
||||
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||
|
||||
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)
|
||||
|
||||
# permission check
|
||||
if check_folder_permission(request, src_repo_id, '/') is None:
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
if check_folder_permission(request, dst_repo_id, '/') is None:
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
result = {}
|
||||
result['failed'] = []
|
||||
result['success'] = []
|
||||
username = request.user.username
|
||||
|
||||
for path_item in path_list:
|
||||
|
||||
src_path = path_item['src_path']
|
||||
src_path = normalize_dir_path(src_path)
|
||||
src_parent_dir = os.path.dirname(src_path.rstrip('/'))
|
||||
src_parent_dir = normalize_dir_path(src_parent_dir)
|
||||
src_obj_name = os.path.basename(src_path.rstrip('/'))
|
||||
|
||||
dst_path = path_item['dst_path']
|
||||
dst_path = normalize_dir_path(dst_path)
|
||||
dst_parent_dir = dst_path
|
||||
dst_obj_name = src_obj_name
|
||||
|
||||
common_dict = {
|
||||
'src_repo_id': src_repo_id,
|
||||
'src_path': src_path,
|
||||
'dst_repo_id': dst_repo_id,
|
||||
'dst_path': dst_path,
|
||||
}
|
||||
|
||||
# src/dst parameter check
|
||||
if src_repo_id == dst_repo_id and \
|
||||
dst_path.startswith(src_path):
|
||||
error_dict = {
|
||||
'error_msg': "The destination directory is the same as the source, or is it's subfolder."
|
||||
}
|
||||
common_dict.update(error_dict)
|
||||
result['failed'].append(common_dict)
|
||||
continue
|
||||
|
||||
if src_path == '/':
|
||||
error_dict = {
|
||||
'error_msg': "The source path can not be '/'."
|
||||
}
|
||||
common_dict.update(error_dict)
|
||||
result['failed'].append(common_dict)
|
||||
continue
|
||||
|
||||
if len(dst_parent_dir + dst_obj_name) > MAX_PATH:
|
||||
error_dict = {
|
||||
'error_msg': "'Destination path is too long."
|
||||
}
|
||||
common_dict.update(error_dict)
|
||||
result['failed'].append(common_dict)
|
||||
continue
|
||||
|
||||
# src resource check
|
||||
## as we don't know if `src_path` stands for a file or a folder,
|
||||
## so we check both
|
||||
src_dir_id = seafile_api.get_dir_id_by_path(src_repo_id, src_path)
|
||||
src_file_id = seafile_api.get_file_id_by_path(src_repo_id,
|
||||
normalize_file_path(src_path))
|
||||
|
||||
if not src_dir_id and not src_file_id:
|
||||
error_dict = {
|
||||
'error_msg': '%s not found.' % src_path
|
||||
}
|
||||
common_dict.update(error_dict)
|
||||
result['failed'].append(common_dict)
|
||||
continue
|
||||
|
||||
# dst resource check
|
||||
if not seafile_api.get_dir_id_by_path(dst_repo_id, dst_path):
|
||||
error_dict = {
|
||||
'error_msg': 'Folder %s not found.' % dst_path
|
||||
}
|
||||
common_dict.update(error_dict)
|
||||
result['failed'].append(common_dict)
|
||||
continue
|
||||
|
||||
# src path permission check, user must has `rw` permission for src folder.
|
||||
if check_folder_permission(request, src_repo_id, src_parent_dir) != 'rw':
|
||||
error_dict = {
|
||||
'error_msg': 'Permission denied.'
|
||||
}
|
||||
common_dict.update(error_dict)
|
||||
result['failed'].append(common_dict)
|
||||
continue
|
||||
|
||||
# dst path permission check, user must has `rw` permission for dst folder.
|
||||
if check_folder_permission(request, dst_repo_id, dst_path) != 'rw':
|
||||
error_dict = {
|
||||
'error_msg': 'Permission denied.'
|
||||
}
|
||||
common_dict.update(error_dict)
|
||||
result['failed'].append(common_dict)
|
||||
continue
|
||||
|
||||
try:
|
||||
dst_obj_name = check_filename_with_rename(dst_repo_id,
|
||||
dst_parent_dir, dst_obj_name)
|
||||
# replace=False, username=username, need_progress=0, synchronous=1
|
||||
seafile_api.move_file(src_repo_id, src_parent_dir, src_obj_name,
|
||||
dst_repo_id, dst_parent_dir, dst_obj_name,
|
||||
False, username, 0, 1)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
error_dict = {
|
||||
'error_msg': 'Internal Server Error'
|
||||
}
|
||||
common_dict.update(error_dict)
|
||||
result['failed'].append(common_dict)
|
||||
continue
|
||||
|
||||
common_dict['dst_obj_name'] = dst_obj_name
|
||||
result['success'].append(common_dict)
|
||||
|
||||
return Response(result)
|
||||
|
@ -30,7 +30,8 @@ from seahub.api2.endpoints.shared_repos import SharedRepos, SharedRepo
|
||||
from seahub.api2.endpoints.upload_links import UploadLinks, UploadLink, \
|
||||
UploadLinkUpload
|
||||
from seahub.api2.endpoints.repos_batch import ReposBatchView, \
|
||||
ReposBatchCopyDirView, ReposBatchCreateDirView
|
||||
ReposBatchCopyDirView, ReposBatchCreateDirView, \
|
||||
ReposBatchCopyItemView, ReposBatchMoveItemView
|
||||
from seahub.api2.endpoints.repos import RepoView
|
||||
from seahub.api2.endpoints.file import FileView
|
||||
from seahub.api2.endpoints.file_history import FileHistoryView
|
||||
@ -247,6 +248,8 @@ urlpatterns = patterns(
|
||||
url(r'^api/v2.1/repos/batch/$', ReposBatchView.as_view(), name='api-v2.1-repos-batch'),
|
||||
url(r'^api/v2.1/repos/batch-copy-dir/$', ReposBatchCopyDirView.as_view(), name='api-v2.1-repos-batch-copy-dir'),
|
||||
url(r'^api/v2.1/repos/batch-create-dir/$', ReposBatchCreateDirView.as_view(), name='api-v2.1-repos-batch-create-dir'),
|
||||
url(r'^api/v2.1/repos/batch-copy-item/$', ReposBatchCopyItemView.as_view(), name='api-v2.1-repos-batch-copy-item'),
|
||||
url(r'^api/v2.1/repos/batch-move-item/$', ReposBatchMoveItemView.as_view(), name='api-v2.1-repos-batch-move-item'),
|
||||
|
||||
## user::deleted repos
|
||||
url(r'^api/v2.1/deleted-repos/$', DeletedRepos.as_view(), name='api2-v2.1-deleted-repos'),
|
||||
|
Loading…
Reference in New Issue
Block a user