diff --git a/seahub/api2/endpoints/query_zip_progress.py b/seahub/api2/endpoints/query_zip_progress.py new file mode 100644 index 0000000000..af63340581 --- /dev/null +++ b/seahub/api2/endpoints/query_zip_progress.py @@ -0,0 +1,37 @@ +import logging +import json + +from rest_framework.response import Response +from rest_framework.views import APIView +from rest_framework import status + +from seahub.api2.throttling import UserRateThrottle +from seahub.api2.utils import api_error + +from seaserv import seafile_api + +logger = logging.getLogger(__name__) + +class QueryZipProgressView(APIView): + + throttle_classes = (UserRateThrottle, ) + + def get(self, request, format=None): + """ check progress when download dir/multi. + + Permission checking: + """ + + token = request.GET.get('token', None) + if not token: + error_msg = 'token invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + try: + progress = seafile_api.query_zip_progress(token) + except Exception as e: + logger.error(e) + error_msg = 'Internal Server Error' + return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) + + return Response(json.loads(progress)) diff --git a/seahub/api2/endpoints/share_link_zip_task.py b/seahub/api2/endpoints/share_link_zip_task.py new file mode 100644 index 0000000000..be11d9666e --- /dev/null +++ b/seahub/api2/endpoints/share_link_zip_task.py @@ -0,0 +1,120 @@ +import logging +import os +import json +import posixpath + +from rest_framework.response import Response +from rest_framework.views import APIView +from rest_framework import status + +from django.conf import settings + +from seahub.api2.throttling import UserRateThrottle +from seahub.api2.utils import api_error + +from seahub.views.file import send_file_access_msg +from seahub.share.models import FileShare +from seahub.utils import is_windows_operating_system, \ + is_pro_version + +import seaserv +from seaserv import seafile_api + +logger = logging.getLogger(__name__) + +class ShareLinkZipTaskView(APIView): + + throttle_classes = (UserRateThrottle,) + + def get(self, request, format=None): + """ Only used for download dir when view dir share link from web. + + + Permission checking: + 1. authenticated user OR anonymous user has passed email code check(if necessary); + """ + + # permission check + if is_pro_version() and settings.ENABLE_SHARE_LINK_AUDIT: + if not request.user.is_authenticated() and \ + not request.session.get('anonymous_email'): + # if anonymous user has passed email code check, + # then his/her email info will be in session. + + error_msg = 'Permission denied.' + return api_error(status.HTTP_403_FORBIDDEN, error_msg) + + # argument check + share_link_token = request.GET.get('share_link_token', None) + if not share_link_token: + error_msg = 'share_link_token invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + req_path = request.GET.get('path', None) + if not req_path: + error_msg = 'path invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + # recourse check + fileshare = FileShare.objects.get_valid_dir_link_by_token(share_link_token) + if not fileshare: + error_msg = 'share_link_token %s not found.' % share_link_token + return api_error(status.HTTP_404_NOT_FOUND, error_msg) + + if req_path[-1] != '/': + req_path += '/' + + if req_path == '/': + real_path = fileshare.path + else: + real_path = posixpath.join(fileshare.path, req_path.lstrip('/')) + + if real_path[-1] != '/': + real_path += '/' + + repo_id = fileshare.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) + + dir_id = seafile_api.get_dir_id_by_path(repo_id, real_path) + if not dir_id: + error_msg = 'Folder %s not found.' % real_path + return api_error(status.HTTP_404_NOT_FOUND, error_msg) + + # get file server access token + dir_name = repo.name if real_path == '/' else \ + os.path.basename(real_path.rstrip('/')) + + dir_size = seafile_api.get_dir_size( + repo.store_id, repo.version, dir_id) + if dir_size > seaserv.MAX_DOWNLOAD_DIR_SIZE: + error_msg = 'Unable to download directory "%s": size is too large.' % dir_name + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + is_windows = 0 + if is_windows_operating_system(request): + is_windows = 1 + + fake_obj_id = { + 'obj_id': dir_id, + 'dir_name': dir_name, + 'is_windows': is_windows + } + + username = request.user.username + try: + zip_token = seafile_api.get_fileserver_access_token( + repo_id, json.dumps(fake_obj_id), 'download-dir', 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 request.session.get('anonymous_email'): + request.user.username = request.session.get('anonymous_email') + + send_file_access_msg(request, repo, real_path, 'share-link') + + return Response({'zip_token': zip_token}) diff --git a/seahub/api2/endpoints/zip_task.py b/seahub/api2/endpoints/zip_task.py new file mode 100644 index 0000000000..17115f259d --- /dev/null +++ b/seahub/api2/endpoints/zip_task.py @@ -0,0 +1,144 @@ +import logging +import json +import stat +import posixpath + +from rest_framework.authentication import SessionAuthentication +from rest_framework.permissions import IsAuthenticated +from rest_framework.response import Response +from rest_framework.views import APIView +from rest_framework import status +from django.utils.translation import ugettext as _ + +from seahub.api2.throttling import UserRateThrottle +from seahub.api2.authentication import TokenAuthentication +from seahub.api2.utils import api_error + +from seahub.views import check_folder_permission +from seahub.views.file import send_file_access_msg +from seahub.utils import is_windows_operating_system + +import seaserv +from seaserv import seafile_api + +logger = logging.getLogger(__name__) + +class ZipTaskView(APIView): + + authentication_classes = (TokenAuthentication, SessionAuthentication) + permission_classes = (IsAuthenticated,) + throttle_classes = (UserRateThrottle,) + + def get(self, request, repo_id, format=None): + """ Get file server token for download-dir and download-multi. + + Permission checking: + 1. user with 'r' or 'rw' permission; + """ + + # argument check + parent_dir = request.GET.get('parent_dir', None) + if not parent_dir: + error_msg = 'parent_dir invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + dirent_name_list = request.GET.getlist('dirents', None) + if not dirent_name_list: + error_msg = 'dirents invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + if len(dirent_name_list) == 1: + download_type = 'download-dir' + elif len(dirent_name_list) > 1: + download_type = 'download-multi' + else: + error_msg = 'dirents invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + # recourse 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) + + if not seafile_api.get_dir_id_by_path(repo_id, parent_dir): + error_msg = 'Folder %s not found.' % parent_dir + return api_error(status.HTTP_404_NOT_FOUND, error_msg) + + # permission check + if not check_folder_permission(request, repo_id, parent_dir): + error_msg = 'Permission denied.' + return api_error(status.HTTP_403_FORBIDDEN, error_msg) + + # get file server access token + is_windows = 0 + if is_windows_operating_system(request): + is_windows = 1 + + if download_type == 'download-dir': + dir_name = dirent_name_list[0].strip('/') + full_dir_path = posixpath.join(parent_dir, dir_name) + + dir_id = seafile_api.get_dir_id_by_path(repo_id, full_dir_path) + if not dir_id: + error_msg = 'Folder %s not found.' % full_dir_path + return api_error(status.HTTP_404_NOT_FOUND, error_msg) + + dir_size = seafile_api.get_dir_size( + repo.store_id, repo.version, dir_id) + + if dir_size > seaserv.MAX_DOWNLOAD_DIR_SIZE: + error_msg = 'Unable to download directory "%s": size is too large.' % dir_name + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + fake_obj_id = { + 'obj_id': dir_id, + 'dir_name': dir_name, + 'is_windows': is_windows + } + + if download_type == 'download-multi': + dirent_list = [] + total_size = 0 + for dirent_name in dirent_name_list: + dirent_name = dirent_name.strip('/') + dirent_list.append(dirent_name) + + full_dirent_path = posixpath.join(parent_dir, dirent_name) + current_dirent = seafile_api.get_dirent_by_path(repo_id, full_dirent_path) + if not current_dirent: + continue + + if stat.S_ISDIR(current_dirent.mode): + total_size += seafile_api.get_dir_size(repo.store_id, + repo.version, current_dirent.obj_id) + else: + total_size += current_dirent.size + + if total_size > seaserv.MAX_DOWNLOAD_DIR_SIZE: + error_msg = _('Total size exceeds limit.') + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + fake_obj_id = { + 'parent_dir': parent_dir, + 'file_list': dirent_list, + 'is_windows': is_windows + } + + username = request.user.username + try: + zip_token = seafile_api.get_fileserver_access_token( + repo_id, json.dumps(fake_obj_id), download_type, 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 len(dirent_name_list) > 10: + send_file_access_msg(request, repo, parent_dir, 'web') + else: + for dirent_name in dirent_name_list: + full_dirent_path = posixpath.join(parent_dir, dirent_name) + send_file_access_msg(request, repo, full_dirent_path, 'web') + + return Response({'zip_token': zip_token}) diff --git a/seahub/base/context_processors.py b/seahub/base/context_processors.py index 98aeee6994..f4650bc866 100644 --- a/seahub/base/context_processors.py +++ b/seahub/base/context_processors.py @@ -61,6 +61,9 @@ def base(request): repo_id_patt = r".*/([a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12})/.*" m = re.match(repo_id_patt, request.get_full_path()) search_repo_id = m.group(1) if m is not None else None + file_server_root = config.FILE_SERVER_ROOT + if not file_server_root.endswith('/'): + file_server_root += '/' return { 'seafile_version': SEAFILE_VERSION, @@ -90,4 +93,5 @@ def base(request): 'search_repo_id': search_repo_id, 'SITE_ROOT': SITE_ROOT, 'constance_enabled': dj_settings.CONSTANCE_ENABLED, + 'FILE_SERVER_ROOT': file_server_root, } diff --git a/seahub/templates/base_for_backbone.html b/seahub/templates/base_for_backbone.html index d73257736a..0f6de3cbc3 100644 --- a/seahub/templates/base_for_backbone.html +++ b/seahub/templates/base_for_backbone.html @@ -112,7 +112,8 @@ var app = { config: { mediaUrl: '{{ MEDIA_URL }}', - siteRoot: '{{ SITE_ROOT }}' + siteRoot: '{{ SITE_ROOT }}', + fileServerRoot: '{{ FILE_SERVER_ROOT }}' } }; diff --git a/seahub/templates/js/templates.html b/seahub/templates/js/templates.html index 45a5b2dd33..eccf355a30 100644 --- a/seahub/templates/js/templates.html +++ b/seahub/templates/js/templates.html @@ -105,6 +105,7 @@ <% if (!encrypted && user_perm == 'r') { %>