diff --git a/seahub/api2/urls.py b/seahub/api2/urls.py index 186520bb76..51d6298b07 100644 --- a/seahub/api2/urls.py +++ b/seahub/api2/urls.py @@ -55,7 +55,7 @@ urlpatterns = patterns('', url(r'^repos/(?P[-0-9-a-f]{36})/file/revert/$', FileRevert.as_view(), name='api2-file-revert'), url(r'^repos/(?P[-0-9-a-f]{36})/file/shared-link/$', FileSharedLinkView.as_view()), url(r'^repos/(?P[-0-9-a-f]{36})/dir/$', DirView.as_view(), name='DirView'), - url(r'^repos/(?P[-0-9-a-f]{36})/dir/sub_repo/$', DirSubRepoView.as_view()), + url(r'^repos/(?P[-0-9-a-f]{36})/dir/sub_repo/$', DirSubRepoView.as_view(), name="api2-dir-sub-repo"), url(r'^repos/(?P[-0-9-a-f]{36})/dir/shared_items/$', DirSharedItemsEndpoint.as_view(), name="api2-dir-shared-items"), url(r'^repos/(?P[-0-9-a-f]{36})/dir/download/$', DirDownloadView.as_view(), name='api2-dir-download'), url(r'^repos/(?P[-0-9-a-f]{36})/dir/revert/$', DirRevert.as_view(), name='api2-dir-revert'), diff --git a/seahub/api2/views.py b/seahub/api2/views.py index abb91be3c0..990afc43b0 100644 --- a/seahub/api2/views.py +++ b/seahub/api2/views.py @@ -2660,67 +2660,94 @@ class DirRevert(APIView): class DirSubRepoView(APIView): - authentication_classes = (TokenAuthentication, ) + authentication_classes = (TokenAuthentication, SessionAuthentication) permission_classes = (IsAuthenticated,) - throttle_classes = (UserRateThrottle, ) + throttle_classes = (UserRateThrottle,) - # from seahub.views.ajax.py::sub_repo def get(self, request, repo_id, format=None): - ''' - check if a dir has a corresponding sub_repo - if it does not have, create one - ''' + """ Create sub-repo for folder - result = {} + Permission checking: + 1. user with `r` or `rw` permission. + 2. password correct for encrypted repo. + """ - path = request.GET.get('p') - name = request.GET.get('name') - password = request.GET.get('password', None) + # argument check + path = request.GET.get('p', None) + if not path: + error_msg = 'p invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + name = request.GET.get('name', None) + if not name: + error_msg = 'name invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + # recourse check repo = get_repo(repo_id) if not repo: - result['error'] = 'Library not found.' - return HttpResponse(json.dumps(result), status=404, content_type=json_content_type) + error_msg = 'Library %s not found.' % repo_id + return api_error(status.HTTP_404_NOT_FOUND, error_msg) - if not (path and name): - result['error'] = 'Argument missing' - return HttpResponse(json.dumps(result), status=400, content_type=json_content_type) + # permission check + if not check_folder_permission(request, repo_id, path) or \ + not request.user.permissions.can_add_repo(): + error_msg = 'Permission denied.' + return api_error(status.HTTP_403_FORBIDDEN, error_msg) username = request.user.username - - # check if the sub-lib exist - try: - sub_repo = seafile_api.get_virtual_repo(repo_id, path, username) - except SearpcError, e: - result['error'] = e.msg - return HttpResponse(json.dumps(result), status=500, content_type=json_content_type) - - if sub_repo: - result['sub_repo_id'] = sub_repo.id - else: - if not request.user.permissions.can_add_repo(): - return api_error(status.HTTP_403_FORBIDDEN, - 'You do not have permission to create library.') - - # create a sub-lib - try: - # use name as 'repo_name' & 'repo_desc' for sub_repo - if repo.encrypted: - if password: - sub_repo_id = seafile_api.create_virtual_repo(repo_id, - path, name, name, username, password) + password = request.GET.get('password', '') + if repo.encrypted: + # check password for encrypted repo + if not password: + error_msg = 'password invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + else: + try: + seafile_api.set_passwd(repo_id, username, password) + except SearpcError as e: + if e.msg == 'Bad arguments': + error_msg = 'Bad arguments' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + elif e.msg == 'Incorrect password': + error_msg = _(u'Wrong password') + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + elif e.msg == 'Internal server error': + error_msg = _(u'Internal server error') + return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) else: - result['error'] = 'Password Required.' - return HttpResponse(json.dumps(result), status=403, content_type=json_content_type) + error_msg = _(u'Decrypt library error') + return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) + + # create sub-lib for encrypted repo + try: + if is_org_context(request): + org_id = request.user.org.org_id + sub_repo_id = seafile_api.create_org_virtual_repo( + org_id, repo_id, path, name, name, username, password) else: - sub_repo_id = seafile_api.create_virtual_repo(repo_id, path, name, name, username) + sub_repo_id = seafile_api.create_virtual_repo( + repo_id, path, name, name, username, password) + except SearpcError as e: + logger.error(e) + error_msg = 'Internal Server Error' + return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) + else: + # create sub-lib for common repo + try: + if is_org_context(request): + org_id = request.user.org.org_id + sub_repo_id = seafile_api.create_org_virtual_repo( + org_id, repo_id, path, name, name, username) + else: + sub_repo_id = seafile_api.create_virtual_repo( + repo_id, path, name, name, username) + except SearpcError as e: + logger.error(e) + error_msg = 'Internal Server Error' + return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) - result['sub_repo_id'] = sub_repo_id - except SearpcError, e: - result['error'] = e.msg - return HttpResponse(json.dumps(result), status=500, content_type=json_content_type) - - return HttpResponse(json.dumps(result), content_type=json_content_type) + return Response({'sub_repo_id': sub_repo_id}) ########## Sharing class SharedRepos(APIView): diff --git a/tests/api/test_dir_sub_repo.py b/tests/api/test_dir_sub_repo.py new file mode 100644 index 0000000000..5efb02e410 --- /dev/null +++ b/tests/api/test_dir_sub_repo.py @@ -0,0 +1,118 @@ +import os +import json +from django.core.urlresolvers import reverse + +from seaserv import seafile_api +from seahub.test_utils import BaseTestCase +from tests.common.utils import randstring + +try: + from seahub.settings import LOCAL_PRO_DEV_ENV +except ImportError: + LOCAL_PRO_DEV_ENV = False + +class DirSubRepoViewTest(BaseTestCase): + + def setUp(self): + self.user_name = self.user.username + self.user_repo_id = self.repo.id + self.user_folder_path = self.folder + self.user_folder_name = os.path.basename(self.folder.rstrip('/')) + + self.admin_name = self.admin.username + + self.url = reverse("api2-dir-sub-repo", args=[self.user_repo_id]) + + def tearDown(self): + self.remove_repo() + + def test_can_create_dir_sub_repo(self): + self.login_as(self.user) + + args = "?p=%s&name=%s" % (self.user_folder_path, self.user_folder_name) + resp = self.client.get(self.url + args) + json_resp = json.loads(resp.content) + assert len(json_resp['sub_repo_id']) == 36 + + def test_can_create_in_encrypted_lib(self): + + password = randstring(8) + encrypted_repo_id = seafile_api.create_repo( + 'encrypted_repo_name', '', self.user_name, password) + + dirname = randstring(8) + seafile_api.post_dir(repo_id=encrypted_repo_id, + parent_dir='/', dirname=dirname, username=self.user_name) + + self.login_as(self.user) + + url = reverse("api2-dir-sub-repo", args=[encrypted_repo_id]) + args = "?p=/%s&name=%s&password=%s" % (dirname, dirname, password) + resp = self.client.get(url + args) + json_resp = json.loads(resp.content) + assert len(json_resp['sub_repo_id']) == 36 + + self.remove_repo(encrypted_repo_id) + + def test_create_in_encrypted_lib_with_invalid_password(self): + + password = randstring(8) + encrypted_repo_id = seafile_api.create_repo( + 'encrypted_repo_name', '', self.user_name, password) + + dirname = randstring(8) + seafile_api.post_dir(repo_id=encrypted_repo_id, + parent_dir='/', dirname=dirname, username=self.user_name) + + self.login_as(self.user) + + url = reverse("api2-dir-sub-repo", args=[encrypted_repo_id]) + + # test invalid password argument + args = "?p=/%s&name=%s&invalid_password=%s" % (dirname, dirname, password) + resp = self.client.get(url + args) + self.assertEqual(400, resp.status_code) + + # test wrong password + args = "?p=/%s&name=%s&password=%s" % (dirname, dirname, 'invalid_password') + resp = self.client.get(url + args) + self.assertEqual(400, resp.status_code) + json_resp = json.loads(resp.content) + assert json_resp['error_msg'] == 'Wrong password' + + self.remove_repo(encrypted_repo_id) + + def test_create_with_invalid_repo_permission(self): + self.login_as(self.admin) + + args = "?p=%s&name=%s" % (self.user_folder_path, self.user_folder_name) + resp = self.client.get(self.url + args) + self.assertEqual(403, resp.status_code) + + def test_create_with_r_permission_folder(self): + + if not LOCAL_PRO_DEV_ENV: + return + + self.set_user_folder_r_permission_to_admin() + + self.login_as(self.admin) + + args = "?p=%s&name=%s" % (self.user_folder_path, self.user_folder_name) + resp = self.client.get(self.url + args) + json_resp = json.loads(resp.content) + assert len(json_resp['sub_repo_id']) == 36 + + def test_create_with_rw_permission_folder(self): + + if not LOCAL_PRO_DEV_ENV: + return + + self.set_user_folder_r_permission_to_admin() + + self.login_as(self.admin) + + args = "?p=%s&name=%s" % (self.user_folder_path, self.user_folder_name) + resp = self.client.get(self.url + args) + json_resp = json.loads(resp.content) + assert len(json_resp['sub_repo_id']) == 36