From 419645fdc20dd21dbee6d714c44b2993b95e3b6f Mon Sep 17 00:00:00 2001 From: lian Date: Thu, 28 Apr 2016 15:16:58 +0800 Subject: [PATCH] add download multi dirents api --- .../api2/endpoints/dirents_download_link.py | 88 +++++++++++++++++++ seahub/templates/js/templates.html | 1 + seahub/urls.py | 6 +- static/scripts/app/views/dir.js | 25 ++++++ static/scripts/common.js | 1 + .../endpoints/test_dirents_download_link.py | 66 ++++++++++++++ 6 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 seahub/api2/endpoints/dirents_download_link.py create mode 100644 tests/api/endpoints/test_dirents_download_link.py diff --git a/seahub/api2/endpoints/dirents_download_link.py b/seahub/api2/endpoints/dirents_download_link.py new file mode 100644 index 0000000000..f1ff619b30 --- /dev/null +++ b/seahub/api2/endpoints/dirents_download_link.py @@ -0,0 +1,88 @@ +import logging +import json +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 seahub.api2.throttling import UserRateThrottle +from seahub.api2.authentication import TokenAuthentication +from seahub.api2.utils import api_error + +from seahub.utils import string2list, get_fileserver_root +from seahub.views import check_folder_permission +from seahub.views.file import send_file_access_msg + +from seaserv import seafile_api +from pysearpc import SearpcError + +logger = logging.getLogger(__name__) + +class DirentsDownloadLinkView(APIView): + """ + Download multi files/dirs. + """ + + authentication_classes = (TokenAuthentication, SessionAuthentication) + permission_classes = (IsAuthenticated, ) + throttle_classes = (UserRateThrottle, ) + + def get(self, request, repo_id, format=None): + + 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) + + # argument checking + parent_dir = request.GET.get('parent_dir', None) + dirent_name_string = request.GET.get('dirents', None) + + if not parent_dir: + error_msg = 'parent_dir invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + if not dirent_name_string: + error_msg = 'dirents invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + # folder exist checking + 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 checking + if check_folder_permission(request, repo_id, parent_dir) is None: + error_msg = 'Permission denied.' + return api_error(status.HTTP_403_FORBIDDEN, error_msg) + + dirent_name_list = string2list(dirent_name_string) + dirent_list = [] + for dirent_name in dirent_name_list: + dirent_list.append(dirent_name.strip('/')) + + fake_obj_id = {} + fake_obj_id['file_list'] = dirent_list + fake_obj_id['parent_dir'] = parent_dir + + username = request.user.username + try: + token = seafile_api.get_fileserver_access_token(repo_id, + json.dumps(fake_obj_id), 'download-multi', username, False) + except SearpcError as e: + logger.error(e) + error_msg = 'Internal Server Error' + return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) + + if len(dirent_list) > 10: + send_file_access_msg(request, repo, parent_dir, 'web') + else: + for dirent_name in dirent_list: + full_dirent_path = posixpath.join(parent_dir, dirent_name) + send_file_access_msg(request, repo, full_dirent_path, 'web') + + download_url = '%s/files/%s' % (get_fileserver_root(), token) + return Response({'url': download_url}) diff --git a/seahub/templates/js/templates.html b/seahub/templates/js/templates.html index 3d7c5ef9b4..fee286c830 100644 --- a/seahub/templates/js/templates.html +++ b/seahub/templates/js/templates.html @@ -99,6 +99,7 @@ +
diff --git a/seahub/urls.py b/seahub/urls.py index ef461f0e65..d295f1022c 100644 --- a/seahub/urls.py +++ b/seahub/urls.py @@ -24,6 +24,7 @@ from seahub.api2.endpoints.upload_links import UploadLinks, UploadLink from seahub.api2.endpoints.file import FileView from seahub.api2.endpoints.dir import DirView from seahub.api2.endpoints.repo_set_password import RepoSetPassword +from seahub.api2.endpoints.dirents_download_link import DirentsDownloadLinkView from seahub.api2.endpoints.admin.login import Login from seahub.api2.endpoints.admin.file_audit import FileAudit from seahub.api2.endpoints.admin.file_update import FileUpdate @@ -189,8 +190,9 @@ urlpatterns = patterns( url(r'^api/v2.1/share-link/(?P[a-f0-9]{10})/$', ShareLink.as_view(), name='api-v2.1-share-link'), url(r'^api/v2.1/upload-links/$', UploadLinks.as_view(), name='api-v2.1-upload-links'), url(r'^api/v2.1/upload-link/(?P[a-f0-9]{10})/$', UploadLink.as_view(), name='api-v2.1-upload-link'), - url(r'^api/v2.1/repos/(?P[-0-9-a-f]{36})/file/$', FileView.as_view(), name='api-v2.1-file-view'), - url(r'^api/v2.1/repos/(?P[-0-9-a-f]{36})/dir/$', DirView.as_view(), name='api-v2.1-dir-view'), + url(r'^api/v2.1/repos/(?P[-0-9a-f]{36})/file/$', FileView.as_view(), name='api-v2.1-file-view'), + url(r'^api/v2.1/repos/(?P[-0-9a-f]{36})/dirents/download-link/$', DirentsDownloadLinkView.as_view(), name='api-v2.1-dirents-download-link-view'), + url(r'^api/v2.1/repos/(?P[-0-9a-f]{36})/dir/$', DirView.as_view(), name='api-v2.1-dir-view'), url(r'^api/v2.1/repos/(?P[-0-9a-f]{36})/set-password/$', RepoSetPassword.as_view(), name="api-v2.1-repo-set-password"), url(r'^api/v2.1/admin/sysinfo/$', SysInfo.as_view(), name='api-v2.1-sysinfo'), url(r'^api/v2.1/admin/devices/$', AdminDevices.as_view(), name='api-v2.1-admin-devices'), diff --git a/static/scripts/app/views/dir.js b/static/scripts/app/views/dir.js index f9304366a6..24dd0016c6 100644 --- a/static/scripts/app/views/dir.js +++ b/static/scripts/app/views/dir.js @@ -466,6 +466,7 @@ define([ 'click #mv-dirents': 'mv', 'click #cp-dirents': 'cp', 'click #del-dirents': 'del', + 'click #download-dirents': 'download', 'click .by-name': 'sortByName', 'click .by-time': 'sortByTime', 'click .basic-upload-btn': 'uploadFile', @@ -799,6 +800,30 @@ define([ } }, + download: function () { + var dirents = this.dir, + selected_dirents = dirents.where({'selected':true}), + selected_names = ''; + + $(selected_dirents).each(function() { + selected_names += this.get('obj_name') + ','; + }); + + $.ajax({ + url: Common.getUrl({ + name: 'download_dirents', + repo_id: dirents.repo_id + }) + '?parent_dir=' + encodeURIComponent(dirents.path) + '&dirents=' + encodeURIComponent(selected_names), + dataType: 'json', + success: function(data) { + location.href = data['url']; + }, + error: function (xhr) { + Common.ajaxErrorHandler(xhr); + } + }); + }, + del: function () { var dirents = this.dir; var _this = this; diff --git a/static/scripts/common.js b/static/scripts/common.js index 9a0429c910..25610e08cd 100644 --- a/static/scripts/common.js +++ b/static/scripts/common.js @@ -80,6 +80,7 @@ define([ case 'unstar_file': return siteRoot + 'ajax/repo/' + options.repo_id + '/file/unstar/'; case 'del_dir': return siteRoot + 'api2/repos/' + options.repo_id + '/dir/'; case 'del_file': return siteRoot + 'api/v2.1/repos/' + options.repo_id + '/file/'; + case 'download_dirents': return siteRoot + 'api/v2.1/repos/' + options.repo_id + '/dirents/download-link/'; case 'rename_dir': return siteRoot + 'api2/repos/' + options.repo_id + '/dir/'; case 'rename_file': return siteRoot + 'api/v2.1/repos/' + options.repo_id + '/file/'; case 'mv_dir': return siteRoot + 'ajax/repo/' + options.repo_id + '/dir/mv/'; diff --git a/tests/api/endpoints/test_dirents_download_link.py b/tests/api/endpoints/test_dirents_download_link.py new file mode 100644 index 0000000000..f69a9b77a7 --- /dev/null +++ b/tests/api/endpoints/test_dirents_download_link.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- +import os +import json + +from django.core.urlresolvers import reverse + +from seahub.test_utils import BaseTestCase + +try: + from seahub.settings import LOCAL_PRO_DEV_ENV +except ImportError: + LOCAL_PRO_DEV_ENV = False + + +class DirentsDownloadLinkViewTest(BaseTestCase): + + def setUp(self): + self.repo_id = self.repo.id + + self.file_path = self.file + self.file_name = os.path.basename(self.file_path) + + self.folder_path = self.folder + self.folder_name = os.path.basename(self.folder_path) + + self.url = reverse('api-v2.1-dirents-download-link-view', args=[self.repo_id]) + + def tearDown(self): + self.remove_repo() + + def test_can_get_download_url(self): + self.login_as(self.user) + parent_dir = '/' + dirents = self.file_name + ',' + self.folder_name + url = self.url + '?parent_dir=%s&dirents=%s' % (parent_dir, dirents) + + resp = self.client.get(url) + self.assertEqual(200, resp.status_code) + json_resp = json.loads(resp.content) + assert '8082' in json_resp['url'] + + def test_args_invalid(self): + self.login_as(self.user) + parent_dir = '/' + dirents = self.file_name + ',' + self.folder_name + + url = self.url + '?prent_dir=%s&dirents=%s' % (parent_dir, dirents) + resp = self.client.get(url) + self.assertEqual(400, resp.status_code) + + url = self.url + '?parent_dir=%s&dirent=%s' % (parent_dir, dirents) + resp = self.client.get(url) + self.assertEqual(400, resp.status_code) + + url = self.url + '?parent_dir=%s&dirents=%s' % (parent_dir+'invalid', dirents) + resp = self.client.get(url) + self.assertEqual(404, resp.status_code) + + def test_permission_invalid(self): + self.login_as(self.admin) + parent_dir = '/' + dirents = self.file_name + ',' + self.folder_name + + url = self.url + '?parent_dir=%s&dirents=%s' % (parent_dir, dirents) + resp = self.client.get(url) + self.assertEqual(403, resp.status_code)