diff --git a/seahub/api2/endpoints/copy_move_task.py b/seahub/api2/endpoints/copy_move_task.py index cf5201ba7b..299e60c78d 100644 --- a/seahub/api2/endpoints/copy_move_task.py +++ b/seahub/api2/endpoints/copy_move_task.py @@ -17,6 +17,7 @@ from seahub.signals import rename_dirent_successful from seahub.views import check_folder_permission from seahub.utils import check_filename_with_rename +from seahub.utils.file_op import check_file_lock from seahub.settings import MAX_PATH from seaserv import seafile_api @@ -118,10 +119,15 @@ class CopyMoveTaskView(APIView): return api_error(status.HTTP_403_FORBIDDEN, error_msg) new_dirent_name = check_filename_with_rename(dst_repo_id, - dst_parent_dir, src_dirent_name) + dst_parent_dir, src_dirent_name) username = request.user.username if operation == 'move': + # permission check for src parent dir + if check_folder_permission(request, src_repo_id, src_parent_dir) != 'rw': + error_msg = 'Permission denied.' + return api_error(status.HTTP_403_FORBIDDEN, error_msg) + if dirent_type == 'dir' and src_repo_id == dst_repo_id and \ dst_parent_dir.startswith(src_dirent_path + '/'): @@ -129,10 +135,19 @@ class CopyMoveTaskView(APIView): % {'src': escape(src_dirent_path), 'des': escape(dst_parent_dir)} return api_error(status.HTTP_400_BAD_REQUEST, error_msg) - # permission check for src parent dir - if check_folder_permission(request, src_repo_id, src_parent_dir) != 'rw': - error_msg = 'Permission denied.' - return api_error(status.HTTP_403_FORBIDDEN, error_msg) + if dirent_type == 'file': + # check file lock + try: + is_locked, locked_by_me = check_file_lock(src_repo_id, + src_dirent_path, username) + except Exception as e: + logger.error(e) + error_msg = 'Internal Server Error' + return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) + + if is_locked and not locked_by_me: + error_msg = _("File is locked") + return api_error(status.HTTP_403_FORBIDDEN, error_msg) try: res = seafile_api.move_file(src_repo_id, src_parent_dir, diff --git a/seahub/api2/endpoints/file.py b/seahub/api2/endpoints/file.py index fa1af6fc8b..321f25f3a2 100644 --- a/seahub/api2/endpoints/file.py +++ b/seahub/api2/endpoints/file.py @@ -18,9 +18,11 @@ from seahub.api2.utils import api_error from seahub.signals import rename_dirent_successful from seahub.utils import check_filename_with_rename, is_pro_version, \ - gen_file_upload_url, is_valid_dirent_name + gen_file_upload_url, is_valid_dirent_name, normalize_file_path, \ + normalize_dir_path from seahub.utils.timeutils import timestamp_to_isoformat_timestr -from seahub.views import check_folder_permission, check_file_lock +from seahub.views import check_folder_permission +from seahub.utils.file_op import check_file_lock from seahub.settings import MAX_UPLOAD_FILE_NAME_LEN, \ FILE_LOCK_EXPIRATION_DAYS, OFFICE_TEMPLATE_ROOT @@ -44,7 +46,13 @@ class FileView(APIView): def get_file_info(self, username, repo_id, file_path): file_obj = seafile_api.get_dirent_by_path(repo_id, file_path) - is_locked, locked_by_me = check_file_lock(repo_id, file_path, username) + + try: + is_locked, locked_by_me = check_file_lock(repo_id, file_path, username) + except Exception as e: + logger.error(e) + is_locked = False + file_info = { 'type': 'file', 'repo_id': repo_id, @@ -110,10 +118,12 @@ class FileView(APIView): # argument check path = request.GET.get('p', None) - if not path or path[0] != '/': + if not path: error_msg = 'p invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + path = normalize_file_path(path) + operation = request.data.get('operation', None) if not operation: error_msg = 'operation invalid.' @@ -240,6 +250,18 @@ class FileView(APIView): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) + # check file lock + try: + is_locked, locked_by_me = check_file_lock(repo_id, path, username) + except Exception as e: + logger.error(e) + error_msg = 'Internal Server Error' + return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) + + if is_locked and not locked_by_me: + error_msg = _("File is locked") + return api_error(status.HTTP_403_FORBIDDEN, error_msg) + # rename file new_file_name = check_filename_with_rename(repo_id, parent_dir, new_file_name) @@ -271,6 +293,8 @@ class FileView(APIView): error_msg = 'dst_dir invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + dst_dir = normalize_dir_path(dst_dir) + # resource check for source file try: file_id = seafile_api.get_file_id_by_path(repo_id, path) @@ -306,10 +330,19 @@ class FileView(APIView): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) - # move file - if dst_dir[-1] != '/': # Append '/' to the end of directory if necessary - dst_dir += '/' + # check file lock + try: + is_locked, locked_by_me = check_file_lock(repo_id, path, username) + except Exception as e: + logger.error(e) + error_msg = 'Internal Server Error' + return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) + if is_locked and not locked_by_me: + error_msg = _("File is locked") + return api_error(status.HTTP_403_FORBIDDEN, error_msg) + + # move file if src_repo_id == dst_repo_id and src_dir == dst_dir: file_info = self.get_file_info(username, repo_id, path) return Response(file_info) @@ -345,6 +378,8 @@ class FileView(APIView): error_msg = 'dst_dir invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + dst_dir = normalize_dir_path(dst_dir) + # resource check for source file try: file_id = seafile_api.get_file_id_by_path(repo_id, path) @@ -381,9 +416,6 @@ class FileView(APIView): return api_error(status.HTTP_403_FORBIDDEN, error_msg) # copy file - if dst_dir[-1] != '/': # Append '/' to the end of directory if necessary - dst_dir += '/' - if src_repo_id == dst_repo_id and src_dir == dst_dir: file_info = self.get_file_info(username, repo_id, path) return Response(file_info) @@ -414,9 +446,12 @@ class FileView(APIView): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) - is_locked, locked_by_me = check_file_lock(repo_id, path, username) - if (is_locked, locked_by_me) == (None, None): - error_msg = _("Check file lock error") + # check file lock + try: + is_locked, locked_by_me = check_file_lock(repo_id, path, username) + except Exception as e: + logger.error(e) + error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) if is_locked and not locked_by_me: @@ -454,6 +489,7 @@ class FileView(APIView): if not path: error_msg = 'p invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + path = normalize_file_path(path) operation = request.data.get('operation', None) if not operation: @@ -483,7 +519,13 @@ class FileView(APIView): return api_error(status.HTTP_403_FORBIDDEN, error_msg) username = request.user.username - is_locked, locked_by_me = check_file_lock(repo_id, path, username) + try: + is_locked, locked_by_me = check_file_lock(repo_id, path, username) + except Exception as e: + logger.error(e) + error_msg = 'Internal Server Error' + return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) + if operation == 'lock': if not is_locked: # lock file @@ -494,6 +536,10 @@ class FileView(APIView): logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) + else: + if not locked_by_me: + error_msg = _("File is locked") + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) if operation == 'unlock': if is_locked: @@ -525,6 +571,8 @@ class FileView(APIView): error_msg = 'p invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + path = normalize_file_path(path) + # resource check repo = seafile_api.get_repo(repo_id) if not repo: @@ -537,10 +585,24 @@ class FileView(APIView): # permission check parent_dir = os.path.dirname(path) + + username = request.user.username if check_folder_permission(request, repo_id, parent_dir) != 'rw': error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) + # check file lock + try: + is_locked, locked_by_me = check_file_lock(repo_id, path, username) + except Exception as e: + logger.error(e) + error_msg = 'Internal Server Error' + return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) + + if is_locked and not locked_by_me: + error_msg = _("File is locked") + return api_error(status.HTTP_403_FORBIDDEN, error_msg) + # delete file file_name = os.path.basename(path) try: diff --git a/seahub/api2/views.py b/seahub/api2/views.py index d3b6f43145..1283aa7d9a 100644 --- a/seahub/api2/views.py +++ b/seahub/api2/views.py @@ -73,14 +73,15 @@ from seahub.utils import gen_file_get_url, gen_token, gen_file_upload_url, \ from seahub.utils.file_revisions import get_file_revisions_after_renamed from seahub.utils.devices import do_unlink_device -from seahub.utils.repo import get_repo_owner, get_library_storages +from seahub.utils.repo import get_repo_owner, get_library_storages, \ + get_locked_files_by_dir from seahub.utils.star import star_file, unstar_file from seahub.utils.file_types import DOCUMENT from seahub.utils.file_size import get_file_size_unit +from seahub.utils.file_op import check_file_lock from seahub.utils.timeutils import utc_to_local, datetime_to_isoformat_timestr -from seahub.views import is_registered_user, check_file_lock, \ - group_events_data, get_diff, create_default_library, \ - list_inner_pub_repos, check_folder_permission +from seahub.views import is_registered_user, check_folder_permission, \ + create_default_library, list_inner_pub_repos from seahub.views.ajax import get_groups_by_user, get_group_repos from seahub.views.file import get_file_view_path_and_perm, send_file_access_msg if HAS_FILE_SEARCH: @@ -1817,27 +1818,34 @@ class OpDeleteView(APIView): permission_classes = (IsAuthenticated, ) def post(self, request, repo_id, format=None): + + parent_dir = request.GET.get('p') + file_names = request.POST.get("file_names") + if not parent_dir or not file_names: + return api_error(status.HTTP_404_NOT_FOUND, + 'File or directory not found.') + repo = get_repo(repo_id) if not repo: return api_error(status.HTTP_404_NOT_FOUND, 'Library not found.') username = request.user.username - if check_folder_permission(request, repo_id, '/') != 'rw': + if check_folder_permission(request, repo_id, parent_dir) != 'rw': return api_error(status.HTTP_403_FORBIDDEN, 'You do not have permission to delete this file.') - if not check_folder_permission(request, repo_id, '/'): - return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') - - parent_dir = request.GET.get('p') - file_names = request.POST.get("file_names") - - if not parent_dir or not file_names: - return api_error(status.HTTP_404_NOT_FOUND, - 'File or directory not found.') + allowed_file_names = [] + locked_files = get_locked_files_by_dir(request, repo_id, parent_dir) + for file_name in file_names.split(':'): + if file_name not in locked_files.keys(): + # file is not locked + allowed_file_names.append(file_name) + elif locked_files[file_name] == username: + # file is locked by current user + allowed_file_names.append(file_name) try: - multi_files = "\t".join(file_names.split(':')) + multi_files = "\t".join(allowed_file_names) seafile_api.del_file(repo_id, parent_dir, multi_files, username) except SearpcError as e: @@ -1899,8 +1907,18 @@ class OpMoveView(APIView): return api_error(status.HTTP_403_FORBIDDEN, 'You do not have permission to move file to destination folder.') + allowed_obj_names = [] + locked_files = get_locked_files_by_dir(request, repo_id, parent_dir) + for file_name in obj_names.split(':'): + if file_name not in locked_files.keys(): + # file is not locked + allowed_obj_names.append(file_name) + elif locked_files[file_name] == username: + # file is locked by current user + allowed_obj_names.append(file_name) + # check if all file/dir existes - obj_names = obj_names.strip(':').split(':') + obj_names = allowed_obj_names dirents = seafile_api.list_dir_by_path(repo_id, parent_dir) exist_obj_names = [dirent.obj_name for dirent in dirents] if not set(obj_names).issubset(exist_obj_names): @@ -2481,10 +2499,16 @@ class FileView(APIView): if check_folder_permission(request, repo_id, parent_dir) != 'rw': return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') + # check file lock + try: + is_locked, locked_by_me = check_file_lock(repo_id, path, username) + except Exception as e: + logger.error(e) + error_msg = 'Internal Server Error' + return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) + operation = request.data.get('operation', '') if operation.lower() == 'lock': - - is_locked, locked_by_me = check_file_lock(repo_id, path, username) if is_locked: return api_error(status.HTTP_403_FORBIDDEN, 'File is already locked') @@ -2498,7 +2522,6 @@ class FileView(APIView): return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, 'Internal error') if operation.lower() == 'unlock': - is_locked, locked_by_me = check_file_lock(repo_id, path, username) if not is_locked: return api_error(status.HTTP_403_FORBIDDEN, 'File is not locked') if not locked_by_me: diff --git a/seahub/templates/js/templates.html b/seahub/templates/js/templates.html index cca557039d..d28a834074 100644 --- a/seahub/templates/js/templates.html +++ b/seahub/templates/js/templates.html @@ -604,16 +604,20 @@ <% } %> <% if (dirent.perm == 'rw') { %> + <% if (!dirent.is_locked || (dirent.is_locked && dirent.locked_by_me)) { %> <% } %> + <% } %> <% if (dirent.perm == 'rw') { %>