From d1fb67c78f098cfb2dce1a331c1f058e42f74232 Mon Sep 17 00:00:00 2001 From: lian Date: Wed, 21 Jan 2015 11:14:34 +0800 Subject: [PATCH] [repo-setting] Set folder perm --- media/css/seahub.css | 25 + media/js/base.js | 52 ++ seahub/api2/views.py | 102 ++-- seahub/share/views.py | 9 +- seahub/templates/repo.html | 26 +- seahub/templates/repo_basic_info.html | 125 +++++ seahub/templates/repo_change_password.html | 116 ++++ seahub/templates/repo_folder_perm.html | 393 ++++++++++++++ seahub/templates/repo_setting_extra_js.html | 58 ++ seahub/templates/repo_settings.html | 359 ------------- seahub/templates/repo_share_manage.html | 239 +++++++++ seahub/templates/repo_shared_link.html | 130 +++++ seahub/templates/repo_transfer_owner.html | 85 +++ seahub/urls.py | 19 +- seahub/utils/repo.py | 60 ++- seahub/views/__init__.py | 349 ++++++------ seahub/views/ajax.py | 561 +++++++++++++++++--- seahub/views/file.py | 8 +- 18 files changed, 2056 insertions(+), 660 deletions(-) create mode 100644 seahub/templates/repo_basic_info.html create mode 100644 seahub/templates/repo_change_password.html create mode 100644 seahub/templates/repo_folder_perm.html create mode 100644 seahub/templates/repo_setting_extra_js.html delete mode 100644 seahub/templates/repo_settings.html create mode 100644 seahub/templates/repo_share_manage.html create mode 100644 seahub/templates/repo_shared_link.html create mode 100644 seahub/templates/repo_transfer_owner.html diff --git a/media/css/seahub.css b/media/css/seahub.css index da75b1b467..308221bf7f 100644 --- a/media/css/seahub.css +++ b/media/css/seahub.css @@ -2786,6 +2786,8 @@ textarea:-moz-placeholder {/* for FF */ .view-link-alert p { display: inline-block; } +.perm-add-perm, +.perm-toggle-select, .share-permission-select, .user-role-select, .user-status-select { @@ -3343,3 +3345,26 @@ textarea:-moz-placeholder {/* for FF */ background:#fff; z-index:100; } + +/* repo setting */ +.user-perm-add-perm, +.group-perm-add-perm, +.perm-toggle-select, +.share-permission-select { + position:relative;/*for long text in other lang in 'share admin'*/ + padding:3px 2px; + background:#fff; + border:1px solid #ddd; + border-radius:2px; +} +.perm-add-select-folder { + position:relative; + right:18px; + cursor:pointer; +} +.perm-add-jstree-select { + margin-top:8px; +} +#perm-add-jstree-wrap { + background:#fcfcfc; +} diff --git a/media/js/base.js b/media/js/base.js index c9468c57e4..428114986a 100644 --- a/media/js/base.js +++ b/media/js/base.js @@ -713,6 +713,58 @@ FileTree.prototype.renderDirTree = function(container, form, repo_data) { }); } +// list dir by repo +FileTree.prototype.renderDirTreeByRepo = function(container, repo_data) { + container + .bind('select_node.jstree', function(e, data) { + var select_path_array = data.inst.get_path(data.rslt.obj); + container.next().on("click", { path_array: select_path_array }, selectClickHandler); + }) + .jstree({ + 'json_data': { + 'data': repo_data, + 'ajax': { + 'url': function(data) { + var path = this.get_path(data), + root = path.shift(), + path = root + path.join('/'), + site_root = container.data('site_root'), + repo_id = container.data('repo_id'); + + return site_root + 'ajax/repo/' + repo_id + '/dirents/?path=' + e(path) + '&dir_only=true'; + }, + 'success': function(data) { + var items = [], o, item; + for (var i = 0, len = data.length; i < len; i++) { + o = data[i]; + if (o.has_subdir) { + item = { + 'data': o.name, + 'attr': { 'type': o.type }, + 'state': 'closed' + }; + } else { + item = { + 'data': o.name, + 'attr': {'type': o.type } + }; + } + items.push(item); + } + return items; + } + } + }, + 'plugins': ['themes', 'json_data', 'ui'], + 'core': { + 'animation': 100 + }, + 'ui': { + 'select_limit': 1 + } + }); +} + function trimFilename(name, n) { var len = name.length; var ext = ''; diff --git a/seahub/api2/views.py b/seahub/api2/views.py index 7c8111dea0..aa87650e66 100644 --- a/seahub/api2/views.py +++ b/seahub/api2/views.py @@ -63,7 +63,7 @@ from seahub.utils.star import star_file, unstar_file from seahub.utils.file_types import IMAGE, DOCUMENT from seahub.views import validate_owner, is_registered_user, \ group_events_data, get_diff, create_default_library, get_owned_repo_list, \ - list_inner_pub_repos, get_virtual_repos_by_owner + list_inner_pub_repos, get_virtual_repos_by_owner, check_folder_permission from seahub.views.ajax import get_share_in_repo_list, get_groups_by_user, \ get_group_repos from seahub.views.file import get_file_view_path_and_perm, send_file_download_msg @@ -822,8 +822,13 @@ class UploadLinkView(APIView): throttle_classes = (UserRateThrottle, ) def get(self, request, repo_id, format=None): - if check_permission(repo_id, request.user.username) != 'rw': - return api_error(status.HTTP_403_FORBIDDEN, "Can not access repo") + parent_dir = request.GET.get('p', None) + if parent_dir is None: + return api_error(status.HTTP_400_BAD_REQUEST, + 'Missing argument.') + + if check_folder_permission(repo_id, parent_dir, request.user.username) != 'rw': + return api_error(status.HTTP_403_FORBIDDEN, 'Forbid to access this folder.') if check_quota(repo_id) < 0: return api_error(HTTP_520_OPERATION_FAILED, 'Above quota') @@ -839,8 +844,13 @@ class UpdateLinkView(APIView): throttle_classes = (UserRateThrottle, ) def get(self, request, repo_id, format=None): - if check_permission(repo_id, request.user.username) != 'rw': - return api_error(status.HTTP_403_FORBIDDEN, "Can not access repo") + parent_dir = request.GET.get('p', None) + if parent_dir is None: + return api_error(status.HTTP_400_BAD_REQUEST, + 'Missing argument.') + + if check_folder_permission(repo_id, parent_dir, request.user.username) != 'rw': + return api_error(status.HTTP_403_FORBIDDEN, 'Forbid to access this folder.') if check_quota(repo_id) < 0: return api_error(HTTP_520_OPERATION_FAILED, 'Above quota') @@ -856,8 +866,13 @@ class UploadBlksLinkView(APIView): throttle_classes = (UserRateThrottle, ) def get(self, request, repo_id, format=None): - if check_permission(repo_id, request.user.username) != 'rw': - return api_error(status.HTTP_403_FORBIDDEN, "Can not access repo") + parent_dir = request.GET.get('p', None) + if parent_dir is None: + return api_error(status.HTTP_400_BAD_REQUEST, + 'Missing argument.') + + if check_folder_permission(repo_id, parent_dir, request.user.username) != 'rw': + return api_error(status.HTTP_403_FORBIDDEN, 'Forbid to access this folder.') if check_quota(repo_id) < 0: return api_error(HTTP_520_OPERATION_FAILED, 'Above quota') @@ -873,8 +888,13 @@ class UpdateBlksLinkView(APIView): throttle_classes = (UserRateThrottle, ) def get(self, request, repo_id, format=None): - if check_permission(repo_id, request.user.username) != 'rw': - return api_error(status.HTTP_403_FORBIDDEN, "Can not access repo") + parent_dir = request.GET.get('p', None) + if parent_dir is None: + return api_error(status.HTTP_400_BAD_REQUEST, + 'Missing argument.') + + if check_folder_permission(repo_id, parent_dir, request.user.username) != 'rw': + return api_error(status.HTTP_403_FORBIDDEN, 'Forbid to access this folder.') if check_quota(repo_id) < 0: return api_error(HTTP_520_OPERATION_FAILED, 'Above quota') @@ -1127,9 +1147,17 @@ class OpCopyView(APIView): return api_error(status.HTTP_403_FORBIDDEN, 'You do not have permission to delete file.') - resp = check_repo_access_permission(request, repo) - if resp: - return resp + parent_dir = request.GET.get('p', None) + dst_repo = request.POST.get('dst_repo', None) + dst_dir = request.POST.get('dst_dir', None) + file_names = request.POST.get("file_names", None) + + if not parent_dir or not file_names or not dst_repo or not dst_dir: + return api_error(status.HTTP_400_BAD_REQUEST, + 'Missing argument.') + + if check_folder_permission(repo_id, parent_dir, username) != 'rw': + return api_error(status.HTTP_403_FORBIDDEN, 'Forbid to access this folder.') parent_dir = request.GET.get('p', None) dst_repo = request.POST.get('dst_repo', None) @@ -1254,16 +1282,16 @@ class FileView(APIView): if not repo: return api_error(status.HTTP_404_NOT_FOUND, 'Repo not found.') - resp = check_repo_access_permission(request, repo) - if resp: - return resp - path = request.GET.get('p', '') + username = request.user.username + parent_dir = os.path.dirname(path) + if check_folder_permission(repo_id, parent_dir, username) != 'rw': + return api_error(status.HTTP_403_FORBIDDEN, 'Forbid to access this folder.') + if not path or path[0] != '/': return api_error(status.HTTP_400_BAD_REQUEST, 'Path is missing or invalid.') - username = request.user.username operation = request.POST.get('operation', '') if operation.lower() == 'rename': if not is_repo_writable(repo.id, username): @@ -1404,14 +1432,14 @@ class FileView(APIView): return api_error(status.HTTP_403_FORBIDDEN, 'You do not have permission to delete file.') - resp = check_repo_access_permission(request, repo) - if resp: - return resp - path = request.GET.get('p', None) if not path: return api_error(status.HTTP_400_BAD_REQUEST, 'Path is missing.') + parent_dir = os.path.dirname(path) + if check_folder_permission(repo_id, parent_dir, username) != 'rw': + return api_error(status.HTTP_403_FORBIDDEN, 'Forbid to access this folder.') + parent_dir_utf8 = os.path.dirname(path).encode('utf-8') file_name_utf8 = os.path.basename(path).encode('utf-8') @@ -1481,12 +1509,17 @@ class FileRevert(APIView): throttle_classes = (UserRateThrottle, ) def put(self, request, repo_id, format=None): - path = unquote(request.DATA.get('p', '').encode('utf-8')) + path = request.DATA.get('p', '') if not path: return api_error(status.HTTP_400_BAD_REQUEST, 'Path is missing.') + + parent_dir = os.path.dirname(path) + username = request.uset.username + if check_folder_permission(repo_id, parent_dir, username) != 'rw': + return api_error(status.HTTP_403_FORBIDDEN, 'Forbid to access this folder.') + + path = unquote(path.encode('utf-8')) commit_id = unquote(request.DATA.get('commit_id', '').encode('utf-8')) - if not path: - return api_error(status.HTTP_400_BAD_REQUEST, 'Path is missing.') try: ret = seafserv_threaded_rpc.revert_file (repo_id, commit_id, path, request.user.username) @@ -1636,11 +1669,8 @@ class DirView(APIView): if not repo: return api_error(status.HTTP_404_NOT_FOUND, 'Repo not found.') - resp = check_repo_access_permission(request, repo) - if resp: - return resp - path = request.GET.get('p', '') + if not path or path[0] != '/': return api_error(status.HTTP_400_BAD_REQUEST, "Path is missing.") if path == '/': # Can not make or rename root dir. @@ -1650,13 +1680,16 @@ class DirView(APIView): username = request.user.username operation = request.POST.get('operation', '') - + if operation.lower() == 'mkdir': if not is_repo_writable(repo.id, username): return api_error(status.HTTP_403_FORBIDDEN, 'You do not have permission to create folder.') parent_dir = os.path.dirname(path) + if check_folder_permission(repo_id, parent_dir, username) != 'rw': + return api_error(status.HTTP_403_FORBIDDEN, 'Forbid to access this folder.') + parent_dir_utf8 = parent_dir.encode('utf-8') new_dir_name = os.path.basename(path) new_dir_name_utf8 = check_filename_with_rename_utf8(repo_id, @@ -1679,11 +1712,13 @@ class DirView(APIView): quote(new_dir_name_utf8) return resp elif operation.lower() == 'rename': + if check_folder_permission(repo.id, path, username) != 'rw': + return api_error(status.HTTP_403_FORBIDDEN, 'Forbid to access this folder.') + if not is_repo_writable(repo.id, username): return api_error(status.HTTP_403_FORBIDDEN, 'You do not have permission to rename a folder.') - parent_dir = os.path.dirname(path) old_dir_name = os.path.basename(path) newname = request.POST.get('newname', '') @@ -1722,14 +1757,13 @@ class DirView(APIView): return api_error(status.HTTP_403_FORBIDDEN, 'You do not have permission to delete folder.') - resp = check_repo_access_permission(request, repo) - if resp: - return resp - path = request.GET.get('p', None) if not path: return api_error(status.HTTP_400_BAD_REQUEST, 'Path is missing.') + if check_folder_permission(repo_id, path, username) != 'rw': + return api_error(status.HTTP_403_FORBIDDEN, 'Forbid to access this folder.') + if path == '/': # Can not delete root path. return api_error(status.HTTP_400_BAD_REQUEST, 'Path is invalid.') diff --git a/seahub/share/views.py b/seahub/share/views.py index 3d51b1f97b..0799e6b167 100644 --- a/seahub/share/views.py +++ b/seahub/share/views.py @@ -35,7 +35,8 @@ from seahub.base.decorators import user_mods_check from seahub.contacts.models import Contact from seahub.contacts.signals import mail_sended from seahub.signals import share_file_to_user_successful -from seahub.views import is_registered_user, check_repo_access_permission +from seahub.views import is_registered_user, check_repo_access_permission, \ + check_folder_permission from seahub.utils import render_permission_error, string2list, render_error, \ gen_token, gen_shared_link, gen_shared_upload_link, gen_dir_share_link, \ gen_file_share_link, IS_EMAIL_CONFIGURED, check_filename_with_rename, \ @@ -1104,7 +1105,11 @@ def get_shared_upload_link(request): path += '/' repo = seaserv.get_repo(repo_id) - user_perm = check_repo_access_permission(repo.id, request.user) + if not repo: + messages.error(request, _(u'Library does not exist')) + return HttpResponse(status=400, content_type=content_type) + + user_perm = check_folder_permission(repo.id, path, request.user.username) if user_perm == 'r': messages.error(request, _(u'Permission denied')) diff --git a/seahub/templates/repo.html b/seahub/templates/repo.html index 4c98d5447f..29a67e5122 100644 --- a/seahub/templates/repo.html +++ b/seahub/templates/repo.html @@ -27,7 +27,7 @@ {% trans "Download" %} {% endif %} {% if show_repo_settings %} - {% trans "Settings" %} + {% trans "Settings" %} {% endif %} {% if user_perm == 'rw' %} {% trans "Trash"%} @@ -343,8 +343,12 @@ $(function() { // get url(token) for every file if (!file.error) { $.ajax({ - url: '{% url 'get_file_op_url' repo.id %}?op_type=upload', + url: '{% url 'get_file_op_url' repo.id %}', cache: false, + data: { + 'op_type': 'upload', + 'path': cur_path + }, dataType: 'json', success: function(ret) { {% if enable_upload_folder %} @@ -1221,8 +1225,12 @@ $('#upload-file').click(function () { $.modal.close(); $.ajax({ - url: '{% url 'get_file_op_url' repo.id %}?op_type=' + e('upload-blks'), + url: '{% url 'get_file_op_url' repo.id %}', cache: false, + data: { + 'op_type': 'upload-blks', + 'path': cur_path + }, dataType: 'json', success: function(data) { encAndSubmitFile(file, fd, data['url']); @@ -1745,8 +1753,12 @@ $('.file-update', context).click(function() { $.modal.close(); $.ajax({ - url: '{% url 'get_file_op_url' repo.id %}?op_type=' + e('update-blks'), + url: '{% url 'get_file_op_url' repo.id %}', cache: false, + data: { + 'op_type': 'update-blks', + 'path': cur_path + }, dataType: 'json', success: function(data) { var sb_url = data['url'] + '?head=' + $('#repo-latest-commit .commit-msg').data('cmtid'); @@ -1781,8 +1793,12 @@ $('.file-update', context).click(function() { hd.html(hd.html().replace('%(file_name)s', '' + file_name + '')); $.ajax({ - url: '{% url 'get_file_op_url' repo.id %}?op_type=' + e('update'), + url: '{% url 'get_file_op_url' repo.id %}', cache: false, + data: { + 'op_type': 'update', + 'path': cur_path + }, dataType: 'json', success: function(data) { // Initialize the jQuery File Upload widget: diff --git a/seahub/templates/repo_basic_info.html b/seahub/templates/repo_basic_info.html new file mode 100644 index 0000000000..4d0f7691ac --- /dev/null +++ b/seahub/templates/repo_basic_info.html @@ -0,0 +1,125 @@ +{% extends "myhome_base.html" %} + +{% load i18n avatar_tags seahub_tags %} + +{% block sub_title %}{{repo.name}} - {% endblock %} + +{% block extra_style %} + +{% endblock %} + +{% block left_panel %} + +
+ +
+{% endblock %} + +{% block right_panel %} +
+

{% trans "Library Settings" %}

+
+

{% trans "Basic Info" %}

+
{% csrf_token %} +
+
+
+
+ + {% if not ENABLE_SUB_LIBRARY or not repo.is_virtual %} +
+ {% trans "Keep full history" %}
+ {% trans "Don't keep history" %}
+ {% trans "Only keep a period of history:" %} + {% trans "days" %}
+ {% endif %} + +

+ +
+
+
+{% endblock %} + +{% block extra_script %} + +{% endblock %} diff --git a/seahub/templates/repo_change_password.html b/seahub/templates/repo_change_password.html new file mode 100644 index 0000000000..e281db9268 --- /dev/null +++ b/seahub/templates/repo_change_password.html @@ -0,0 +1,116 @@ +{% extends "myhome_base.html" %} + +{% load i18n avatar_tags seahub_tags %} + +{% block sub_title %}{{repo.name}} - {% endblock %} + +{% block extra_style %} + +{% endblock %} + +{% block left_panel %} + +
+ +
+{% endblock %} + +{% block right_panel %} +
+

{% trans "Library Settings" %}

+
+

{% trans "Change Password" %}

+
{% csrf_token %} +

{% trans "Change the password of this library:" %}

+
+
+
+
+
+
+

+ +
+
+
+{% endblock %} + +{% block extra_script %} + +{% endblock %} diff --git a/seahub/templates/repo_folder_perm.html b/seahub/templates/repo_folder_perm.html new file mode 100644 index 0000000000..bc0dd47b7b --- /dev/null +++ b/seahub/templates/repo_folder_perm.html @@ -0,0 +1,393 @@ +{% extends "myhome_base.html" %} + +{% load i18n avatar_tags seahub_tags %} + +{% block sub_title %}{{repo.name}} - {% endblock %} + +{% block extra_style %} + +{% endblock %} + +{% block left_panel %} + +
+ +
+{% endblock %} + +{% block right_panel %} +
+

{% trans "Library Settings" %}

+

{% trans "Folder Permission" %}

+

{% trans "View and manage all the folder permissions in this library." %}

+
+
+ +
+ +
+
+ +
+ + + + + + + + + + + + + + {% if user_folder_perms %} + {% for perm in user_folder_perms %} + + + + + + + {% endfor %} + {% endif %} +
{% trans "User" %}{% trans "Folder" %}{% trans "Permission" %}
+ + + + + + +
{{ perm.user }}{{ perm.folder_name }} +
+ {% if perm.permission == 'rw' %} + {% trans "Read-Write" %} + {% else %} + {% trans "Read-Only" %} + {% endif %} + {% trans +
+ +
+ +
+
+ +
+ + + + + + + + + + + + + + {% if group_folder_perms %} + {% for perm in group_folder_perms %} + + + + + + + {% endfor %} + {% endif %} +
{% trans "Group" %}{% trans "Folder" %}{% trans "Permission" %}
+ + + + + + + + + +
{{ perm.group_name }} + {{ perm.folder_name }} + +
+ {% if perm.permission == 'rw' %} + {% trans "Read-Write" %} + {% else %} + {% trans "Read-Only" %} + {% endif %} + {% trans +
+ +
+ +
+
+
+
+

{% trans "Please selecte a directory" %}

+ +
+ +
+ +
+
+{% endblock %} + +{% block extra_script %} + +{% endblock %} diff --git a/seahub/templates/repo_setting_extra_js.html b/seahub/templates/repo_setting_extra_js.html new file mode 100644 index 0000000000..1f6b7f8536 --- /dev/null +++ b/seahub/templates/repo_setting_extra_js.html @@ -0,0 +1,58 @@ +{% load i18n %} + +var cur_tab = $('.ui-tabs-selected .a'); +if (cur_tab.attr('id') == 'user-tab') { + var is_user_tab = new Boolean(true); +} else { + var is_user_tab = new Boolean(false); +} +$('#user-tab').click(function() { + is_user_tab = new Boolean(true); +}); +$('#group-tab').click(function() { + is_user_tab = new Boolean(false); +}); + +$('.perm-item').on({ + mouseenter: function() { + var perm_item = $(this); + perm_item.find('.perm-edit-icon').removeClass('vh'); + perm_item.find('.perm-delete-btn').removeClass('vh'); + }, + mouseleave: function() { + var perm_item = $(this); + perm_item.find('.perm-edit-icon').addClass('vh'); + perm_item.find('.perm-delete-btn').addClass('vh'); + } +}); +$('.perm-edit-icon').on('click', function() { + $(this).parent().addClass('hide') + .next().removeClass('hide'); +}); + +function perm_toggle(select, data, url) { + $.ajax({ + url: url, + type: 'POST', + dataType: 'json', + cache: false, + beforeSend: prepareCSRFToken, + data: data, + success: function(data) { + select.addClass('hide') + .prev().removeClass('hide') + .children('span') + .html(select.children('option[value="' + select.val() + '"]').text()); + feedback("{% trans "Success" %}", 'success'); + }, + error: ajaxErrorHandler + }); +} + +$(document).on('click', function(e) { + var target = e.target || event.srcElement; + if (!$('.perm-edit-icon, .perm-toggle-select').is(target)) { + $('.perm-change').removeClass('hide'); + $('.perm-toggle-select').addClass('hide'); + } +}); diff --git a/seahub/templates/repo_settings.html b/seahub/templates/repo_settings.html deleted file mode 100644 index 714e826464..0000000000 --- a/seahub/templates/repo_settings.html +++ /dev/null @@ -1,359 +0,0 @@ -{% extends "myhome_base.html" %} - -{% load i18n avatar_tags seahub_tags %} - -{% block sub_title %}{{repo.name}} - {% endblock %} - -{% block extra_style %} - -{% endblock %} - -{% block left_panel %} - -
- -
-{% endblock %} - -{% block right_panel %} -
-

{% trans "Library Settings" %}

- -
-

{% trans "Basic Info" %}

-
{% csrf_token %} -
-
-
-
- - {% if not ENABLE_SUB_LIBRARY or not repo.is_virtual %} -
- {% trans "Keep full history" %}
- {% trans "Don't keep history" %}
- {% trans "Only keep a period of history:" %} - {% trans "days" %}
- {% endif %} - -

- -
-
- -
-

{% trans "Transfer Ownership" %}

-
{% csrf_token %} -

{% trans "Transfer this library to another user:" %}

-
-

- -
-
- - {% if repo.encrypted and repo.enc_version == 2 %} -
-

{% trans "Change Password" %}

-
{% csrf_token %} -

{% trans "Change the password of this library:" %}

-
-
-
-
-
-
-

- -
-
- {% endif %} - - {% if not repo.encrypted %} - - {% endif %} - -
-{% endblock %} - -{% block extra_script %} - -{% endblock %} diff --git a/seahub/templates/repo_share_manage.html b/seahub/templates/repo_share_manage.html new file mode 100644 index 0000000000..76ec1f0a21 --- /dev/null +++ b/seahub/templates/repo_share_manage.html @@ -0,0 +1,239 @@ +{% extends "myhome_base.html" %} + +{% load i18n avatar_tags group_avatar_tags seahub_tags %} + +{% block sub_title %}{{repo.name}} - {% endblock %} + +{% block extra_style %} + +{% endblock %} + +{% block left_panel %} + +
+ +
+{% endblock %} + +{% block right_panel %} +
+

{% trans "Library Settings" %}

+

{% trans "Sharing Management" %}

+

{% trans "View and manage all the share of this library." %}

+ +
+
+ +
+ +
+
+ +
+ + + + + + + {% if repo_share_user %} + {% for share in repo_share_user %} + + + + + + {% endfor %} + {% endif %} +
{% trans "Share To"%}{% trans "Permission"%}{% trans "Operations"%}
{{ share.user }} +
+ {% if share.permission == 'rw' %} + + {% else %} + + {% endif %} + {% trans +
+ +
+ +
+
+
+ + + + + + + {% if repo_share_group %} + {% for share in repo_share_group %} + + + + + + {% endfor %} + {% endif %} +
{% trans "Share To"%}{% trans "Permission"%}{% trans "Operations"%}
{{ share.group_name }} +
+ {% if share.permission == 'rw' %} + {% trans "Read-Write" %} + {% else %} + {% trans "Read-Only" %} + {% endif %} + {% trans +
+ +
+ +
+
+
+
+ +{% url 'share_repo' as repo_share_url %} +{% with post_url=repo_share_url %} +{% include "snippets/repo_share_form.html" %} +{% endwith %} + +{% endblock %} + +{% block extra_script %} + +{% endblock %} diff --git a/seahub/templates/repo_shared_link.html b/seahub/templates/repo_shared_link.html new file mode 100644 index 0000000000..959f908bce --- /dev/null +++ b/seahub/templates/repo_shared_link.html @@ -0,0 +1,130 @@ +{% extends "myhome_base.html" %} + +{% load i18n avatar_tags seahub_tags %} + +{% block sub_title %}{{repo.name}} - {% endblock %} + +{% block extra_style %} + +{% endblock %} + +{% block left_panel %} + +
+ +
+{% endblock %} + +{% block right_panel %} +
+

{% trans "Library Settings" %}

+ +
+{% endblock %} + +{% block extra_script %} + +{% endblock %} diff --git a/seahub/templates/repo_transfer_owner.html b/seahub/templates/repo_transfer_owner.html new file mode 100644 index 0000000000..dfad1c46f2 --- /dev/null +++ b/seahub/templates/repo_transfer_owner.html @@ -0,0 +1,85 @@ +{% extends "myhome_base.html" %} + +{% load i18n avatar_tags seahub_tags %} + +{% block sub_title %}{{repo.name}} - {% endblock %} + +{% block extra_style %} + +{% endblock %} + +{% block left_panel %} + +
+ +
+{% endblock %} + +{% block right_panel %} +
+

{% trans "Library Settings" %}

+
+

{% trans "Transfer Ownership" %}

+
{% csrf_token %} +

{% trans "Transfer this library to another user:" %}

+
+

+ +
+
+
+{% endblock %} + +{% block extra_script %} + +{% endblock %} diff --git a/seahub/urls.py b/seahub/urls.py index 43c4ff405a..cac251c0a9 100644 --- a/seahub/urls.py +++ b/seahub/urls.py @@ -83,10 +83,12 @@ urlpatterns = patterns('', url(r'^repo/(?P[-0-9a-f]{36})/privshare/$', gen_private_file_share, name='gen_private_file_share'), url(r'^repo/(?P[-0-9a-f]{36})/(?P[0-9a-f]{40})/$', repo_access_file, name='repo_access_file'), url(r'^repo/(?P[-0-9a-f]{36})/(?P[0-9a-f]{40})/download/$', download_file, name='download_file'), - url(r'^repo/(?P[-0-9a-f]{36})/settings/$', repo_settings, name='repo_settings'), - url(r'^repo/(?P[-0-9a-f]{36})/basic_info/$', repo_change_basic_info, name='repo_change_basic_info'), - url(r'^repo/(?P[-0-9a-f]{36})/owner/$', repo_transfer_owner, name='repo_transfer_owner'), - url(r'^repo/(?P[-0-9a-f]{36})/passwd/$', repo_change_passwd, name='repo_change_passwd'), + url(r'^repo/(?P[-0-9a-f]{36})/setting/basic-info/$', repo_basic_info, name='repo_basic_info'), + url(r'^repo/(?P[-0-9a-f]{36})/setting/transfer-owner/$', repo_transfer_owner, name='repo_transfer_owner'), + url(r'^repo/(?P[-0-9a-f]{36})/setting/change-password/$', repo_change_password, name='repo_change_password'), + url(r'^repo/(?P[-0-9a-f]{36})/setting/shared-link/$', repo_shared_link, name='repo_shared_link'), + url(r'^repo/(?P[-0-9a-f]{36})/setting/share-manage/$', repo_share_manage, name='repo_share_manage'), + url(r'^repo/(?P[-0-9a-f]{36})/setting/folder-perm/$', repo_folder_perm, name='repo_folder_perm'), ### share file/dir, upload link ### url(r'^s/f/(?P[a-f0-9]{10})/$', view_priv_shared_file, name="view_priv_shared_file"), @@ -155,6 +157,15 @@ urlpatterns = patterns('', url(r'^ajax/space_and_traffic/$', space_and_traffic, name='space_and_traffic'), url(r'^ajax/my-shared-and-group-repos/$', my_shared_and_group_repos, name='my_shared_and_group_repos'), url(r'^ajax/events/$', events, name="events"), + url(r'^ajax/repo/(?P[-0-9a-f]{36})/setting/change-basic-info/$', ajax_repo_change_basic_info, name='ajax_repo_change_basic_info'), + url(r'^ajax/repo/(?P[-0-9a-f]{36})/setting/transfer-owner/$', ajax_repo_transfer_owner, name='ajax_repo_transfer_owner'), + url(r'^ajax/repo/(?P[-0-9a-f]{36})/setting/change-passwd/$', ajax_repo_change_passwd, name='ajax_repo_change_passwd'), + url(r'^ajax/repo/(?P[-0-9a-f]{36})/setting/user-folder-permission/add/$', add_user_folder_permission, name='add_user_folder_permission'), + url(r'^ajax/repo/(?P[-0-9a-f]{36})/setting/user-folder-permission/remove/$', remove_user_folder_permission, name='remove_user_folder_permission'), + url(r'^ajax/repo/(?P[-0-9a-f]{36})/setting/user-folder-permission/toggle/$', toggle_user_folder_permission, name='toggle_user_folder_permission'), + url(r'^ajax/repo/(?P[-0-9a-f]{36})/setting/group-folder-permission/add/$', add_group_folder_permission, name='add_group_folder_permission'), + url(r'^ajax/repo/(?P[-0-9a-f]{36})/setting/group-folder-permission/remove/$', remove_group_folder_permission, name='remove_group_folder_permission'), + url(r'^ajax/repo/(?P[-0-9a-f]{36})/setting/group-folder-permission/toggle/$', toggle_group_folder_permission, name='toggle_group_folder_permission'), ### Organizaion ### url(r'^pubinfo/libraries/$', pubrepo, name='pubrepo'), diff --git a/seahub/utils/repo.py b/seahub/utils/repo.py index cb29771194..169171a118 100644 --- a/seahub/utils/repo.py +++ b/seahub/utils/repo.py @@ -1,10 +1,66 @@ # -*- coding: utf-8 -*- +from django.utils.translation import ugettext as _ + +import seaserv from seaserv import seafile_api -from seahub.utils import EMPTY_SHA1 + +from seahub.utils import EMPTY_SHA1, is_valid_username +from seahub.views import check_repo_access_permission def list_dir_by_path(cmmt, path): if cmmt.root_id == EMPTY_SHA1: return [] else: return seafile_api.list_dir_by_commit_and_path(cmmt.repo_id, cmmt.id, path) - + +def check_user_folder_perm_args(request_user, repo_id, path, user, perm = None): + if not seafile_api.get_repo(repo_id): + return {'error': _(u'Library does not exist.'), 'status': 400} + + if check_repo_access_permission(repo_id, request_user) != 'rw': + return {'error': _('Permission denied'), 'status': 403} + + if perm is not None: + # add or toggle folder perm + if seafile_api.get_dir_id_by_path(repo_id, path) is None: + return {'error': _('Invalid path'), 'status': 400} + + if perm != 'r' and perm != 'rw': + return {'error': _('Invalid folder permission'), 'status': 400} + + if not path.startswith('/'): + return {'error': _('Path should start with "/"'), 'status': 400} + + if path != '/' and path.endswith('/'): + return {'error': _('Path should NOT ends with "/"'), 'status': 400} + + if user and not is_valid_username(user): + return {'error': _('Invalid username'), 'status': 400} + + return {'success': True} + +def check_group_folder_perm_args(request_user, repo_id, path, group_id, perm = None): + if not seafile_api.get_repo(repo_id): + return {'error': _(u'Library does not exist.'), 'status': 400} + + if check_repo_access_permission(repo_id, request_user) != 'rw': + return {'error': _('Permission denied'), 'status': 403} + + if perm is not None: + # add or toggle folder perm + if seafile_api.get_dir_id_by_path(repo_id, path) is None: + return {'error': _('Invalid path'), 'status': 400} + + if perm != 'r' and perm != 'rw': + return {'error': _('Invalid folder permission'), 'status': 400} + + if not path.startswith('/'): + return {'error': _('Path should start with "/"'), 'status': 400} + + if path != '/' and path.endswith('/'): + return {'error': _('Path should NOT ends with "/"'), 'status': 400} + + if group_id and not seaserv.get_group(group_id): + return {'error': _('Invalid group'), 'status': 400} + + return {'success': True} diff --git a/seahub/views/__init__.py b/seahub/views/__init__.py index 7053671f3c..20f2aba0a3 100644 --- a/seahub/views/__init__.py +++ b/seahub/views/__init__.py @@ -24,9 +24,9 @@ from django.views.decorators.http import condition import seaserv from seaserv import get_repo, get_commits, is_valid_filename, \ seafserv_threaded_rpc, seafserv_rpc, is_repo_owner, check_permission, \ - is_passwd_set, get_file_size, edit_repo, \ - get_session_info, set_repo_history_limit, get_commit, \ - MAX_DOWNLOAD_DIR_SIZE, send_message, ccnet_threaded_rpc + is_passwd_set, get_file_size, get_group, get_session_info, get_commit, \ + MAX_DOWNLOAD_DIR_SIZE, send_message, ccnet_threaded_rpc, \ + get_personal_groups_by_user from seaserv import seafile_api from pysearpc import SearpcError @@ -42,18 +42,17 @@ from seahub.options.models import UserOptions, CryptoOptionNotSetError from seahub.profile.models import Profile from seahub.share.models import FileShare, PrivateFileDirShare, \ UploadLinkShare -from seahub.forms import RepoPassowrdForm, RepoSettingForm +from seahub.forms import RepoPassowrdForm from seahub.utils import render_permission_error, render_error, list_to_string, \ - get_fileserver_root, gen_shared_upload_link, \ + get_fileserver_root, gen_shared_upload_link, is_org_context, \ gen_dir_share_link, gen_file_share_link, get_repo_last_modify, \ calculate_repos_last_modify, get_file_type_and_ext, get_user_repos, \ - EMPTY_SHA1, normalize_file_path, is_valid_username, \ + EMPTY_SHA1, normalize_file_path, gen_file_upload_url, \ get_file_revision_id_size, get_ccnet_server_addr_port, \ gen_file_get_url, string2list, MAX_INT, IS_EMAIL_CONFIGURED, \ - gen_file_upload_url, \ EVENTS_ENABLED, get_user_events, get_org_user_events, show_delete_days, \ TRAFFIC_STATS_ENABLED, get_user_traffic_stat, new_merge_with_no_conflict, \ - user_traffic_over_limit, is_org_context + user_traffic_over_limit from seahub.utils.paginator import get_page_range from seahub.utils.star import get_dir_starred_files from seahub.views.modules import MOD_PERSONAL_WIKI, enable_mod_for_user, \ @@ -96,6 +95,16 @@ def get_system_default_repo_id(): logger.error(e) return None +def check_folder_permission(repo_id, path, username): + repo_owner = seafile_api.get_repo_owner(repo_id) + if username == repo_owner: + return 'rw' + + if path != '/' and path.endswith('/'): + path = path.rstrip('/') + + return seafile_api.check_permission_by_path(repo_id, path, username) + def check_repo_access_permission(repo_id, user): """Check repo access permission of a user, always return 'rw' when repo is system repo and user is admin. @@ -409,27 +418,34 @@ def repo_online_gc(request, repo_id): return HttpResponseRedirect(next) -@login_required -def repo_settings(request, repo_id): - """List and change library settings. - """ - username = request.user.username - +def can_access_repo_setting(request, repo_id, username): repo = seafile_api.get_repo(repo_id) if not repo: - raise Http404 + return (False, None) # no settings for virtual repo if ENABLE_SUB_LIBRARY and repo.is_virtual: - raise Http404 + return (False, None) # check permission if is_org_context(request): - repo_owner = seafile_api.get_org_repo_owner(repo.id) + repo_owner = seafile_api.get_org_repo_owner(repo_id) else: - repo_owner = seafile_api.get_repo_owner(repo.id) + repo_owner = seafile_api.get_repo_owner(repo_id) is_owner = True if username == repo_owner else False if not is_owner: + return (False, None) + + return (True, repo) + +@login_required +def repo_basic_info(request, repo_id): + """List and change library basic info. + """ + username = request.user.username + can_access, repo = can_access_repo_setting(request, repo_id, username) + + if not can_access: raise Http404 history_limit = seaserv.get_repo_history_limit(repo.id) @@ -450,6 +466,57 @@ def repo_settings(request, repo_id): if history_limit <= 0: days_enabled = False + return render_to_response('repo_basic_info.html', { + 'repo': repo, + 'history_limit': history_limit if history_limit > 0 else '', + 'full_history_checked': full_history_checked, + 'no_history_checked': no_history_checked, + 'partial_history_checked': partial_history_checked, + 'full_history_enabled': full_history_enabled, + 'no_history_enabled': no_history_enabled, + 'partial_history_enabled': partial_history_enabled, + 'days_enabled': days_enabled, + }, context_instance=RequestContext(request)) + +@login_required +def repo_transfer_owner(request, repo_id): + """Transfer repo owner. + """ + username = request.user.username + can_access, repo = can_access_repo_setting(request, repo_id, username) + + if not can_access: + raise Http404 + + return render_to_response('repo_transfer_owner.html', { + 'repo': repo, + }, context_instance=RequestContext(request)) + +@login_required +def repo_change_password(request, repo_id): + """Change library password. + """ + username = request.user.username + can_access, repo = can_access_repo_setting(request, repo_id, username) + + if not can_access: + raise Http404 + + return render_to_response('repo_change_password.html', { + 'repo': repo, + 'repo_password_min_length': REPO_PASSWORD_MIN_LENGTH, + }, context_instance=RequestContext(request)) + +@login_required +def repo_shared_link(request, repo_id): + """List and change library shared links. + """ + username = request.user.username + can_access, repo = can_access_repo_setting(request, repo_id, username) + + if not can_access: + raise Http404 + # download links fileshares = FileShare.objects.filter(repo_id=repo_id) p_fileshares = [] @@ -493,178 +560,88 @@ def repo_settings(request, repo_id): link.shared_link = gen_shared_upload_link(link.token) p_uploadlinks.append(link) - return render_to_response('repo_settings.html', { + return render_to_response('repo_shared_link.html', { 'repo': repo, - 'repo_owner': repo_owner, - 'history_limit': history_limit if history_limit > 0 else '', - 'full_history_checked': full_history_checked, - 'no_history_checked': no_history_checked, - 'partial_history_checked': partial_history_checked, - 'full_history_enabled': full_history_enabled, - 'no_history_enabled': no_history_enabled, - 'partial_history_enabled': partial_history_enabled, - 'days_enabled': days_enabled, - 'repo_password_min_length': REPO_PASSWORD_MIN_LENGTH, 'fileshares': p_fileshares, 'uploadlinks': p_uploadlinks, }, context_instance=RequestContext(request)) -@login_required_ajax -def repo_change_basic_info(request, repo_id): - """Handle post request to change library basic info. +@login_required +def repo_share_manage(request, repo_id): + """Manage share of this library. """ - if request.method != 'POST': - raise Http404 - - content_type = 'application/json; charset=utf-8' username = request.user.username + can_access, repo = can_access_repo_setting(request, repo_id, username) - repo = seafile_api.get_repo(repo_id) - if not repo: + if not can_access: raise Http404 - # no settings for virtual repo - if ENABLE_SUB_LIBRARY and repo.is_virtual: - raise Http404 - - # check permission - if is_org_context(request): - repo_owner = seafile_api.get_org_repo_owner(repo.id) - else: - repo_owner = seafile_api.get_repo_owner(repo.id) - is_owner = True if username == repo_owner else False - if not is_owner: - raise Http404 - - form = RepoSettingForm(request.POST) - if not form.is_valid(): - return HttpResponse(json.dumps({ - 'error': str(form.errors.values()[0]) - }), status=400, content_type=content_type) - - repo_name = form.cleaned_data['repo_name'] - repo_desc = form.cleaned_data['repo_desc'] - days = form.cleaned_data['days'] - - # Edit library info (name, descryption). - if repo.name != repo_name or repo.desc != repo_desc: - if not edit_repo(repo_id, repo_name, repo_desc, username): - err_msg = _(u'Failed to edit library information.') - return HttpResponse(json.dumps({'error': err_msg}), - status=500, content_type=content_type) - - # set library history - if days is not None and ENABLE_REPO_HISTORY_SETTING: - res = set_repo_history_limit(repo_id, days) - if res != 0: - return HttpResponse(json.dumps({ - 'error': _(u'Failed to save settings on server') - }), status=400, content_type=content_type) - - messages.success(request, _(u'Settings saved.')) - return HttpResponse(json.dumps({'success': True}), - content_type=content_type) - -@login_required_ajax -def repo_transfer_owner(request, repo_id): - """Handle post request to transfer library owner. - """ - if request.method != 'POST': - raise Http404 - - content_type = 'application/json; charset=utf-8' - username = request.user.username - - repo = seafile_api.get_repo(repo_id) - if not repo: - raise Http404 - - # check permission - if is_org_context(request): - repo_owner = seafile_api.get_org_repo_owner(repo.id) - else: - repo_owner = seafile_api.get_repo_owner(repo.id) - is_owner = True if username == repo_owner else False - if not is_owner: - raise Http404 - - # check POST arg - repo_owner = request.POST.get('repo_owner', '').lower() - if not is_valid_username(repo_owner): - return HttpResponse(json.dumps({ - 'error': _('Username %s is not valid.') % repo_owner, - }), status=400, content_type=content_type) - - try: - User.objects.get(email=repo_owner) - except User.DoesNotExist: - return HttpResponse(json.dumps({ - 'error': _('User %s is not found.') % repo_owner, - }), status=400, content_type=content_type) + # sharing management + repo_share_user = [] + repo_share_group = [] if is_org_context(request): org_id = request.user.org.org_id - if not seaserv.ccnet_threaded_rpc.org_user_exists(org_id, repo_owner): - return HttpResponse(json.dumps({ - 'error': _('User %s is not in current organization.') % - repo_owner,}), status=400, content_type=content_type) - - if repo_owner and repo_owner != username: - if is_org_context(request): - org_id = request.user.org.org_id - seafile_api.set_org_repo_owner(org_id, repo_id, repo_owner) - else: - if ccnet_threaded_rpc.get_orgs_by_user(repo_owner): - return HttpResponse(json.dumps({ - 'error': _('Can not transfer library to organization user %s.') % repo_owner, - }), status=400, content_type=content_type) - else: - seafile_api.set_repo_owner(repo_id, repo_owner) - - messages.success(request, - _(u'Library %(repo_name)s has been transfered to %(new_owner)s.') % - {'repo_name': repo.name, 'new_owner': repo_owner}) - return HttpResponse(json.dumps({'success': True}), - content_type=content_type) - -@login_required_ajax -def repo_change_passwd(request, repo_id): - """Handle ajax post request to change library password. - """ - if request.method != 'POST': - raise Http404 - - content_type = 'application/json; charset=utf-8' - username = request.user.username - - repo = seafile_api.get_repo(repo_id) - if not repo: - raise Http404 - - # check permission - if is_org_context(request): - repo_owner = seafile_api.get_org_repo_owner(repo.id) + repo_share_user = seafile_api.get_org_share_out_repo_list(org_id, username, -1, -1) + repo_share_group = seafserv_threaded_rpc.get_org_group_repos_by_owner(org_id, username) else: - repo_owner = seafile_api.get_repo_owner(repo.id) - is_owner = True if username == repo_owner else False - if not is_owner: - return HttpResponse(json.dumps({ - 'error': _('Faied to change password, you are not owner.')}), - status=400, content_type=content_type) + repo_share_user = seafile_api.get_share_out_repo_list(username, -1, -1) + repo_share_group = seaserv.get_group_repos_by_owner(username) - old_passwd = request.POST.get('old_passwd', '') - new_passwd = request.POST.get('new_passwd', '') - try: - seafile_api.change_repo_passwd(repo_id, old_passwd, new_passwd, username) - except SearpcError, e: - return HttpResponse(json.dumps({ - 'error': e.msg, - }), status=400, content_type=content_type) + repo_share_user = filter(lambda i: i.repo_id == repo_id, repo_share_user) + repo_share_group = filter(lambda i: i.repo_id == repo_id, repo_share_group) + for share in repo_share_group: + share.group_name = get_group(share.group_id).group_name - messages.success(request, _(u'Successfully updated the password of Library %(repo_name)s.') % - {'repo_name': repo.name}) - return HttpResponse(json.dumps({'success': True}), - content_type=content_type) + return render_to_response('repo_share_manage.html', { + 'repo': repo, + 'repo_share_user': repo_share_user, + 'repo_share_group': repo_share_group, + }, context_instance=RequestContext(request)) + +@login_required +def repo_folder_perm(request, repo_id): + """Manage folder permmission of this library. + """ + username = request.user.username + can_access, repo = can_access_repo_setting(request, repo_id, username) + + if not can_access: + raise Http404 + + # for user folder permission + user_folder_perms = seafile_api.list_folder_user_perm_by_repo(repo_id) + user_folder_perms.reverse() + + for folder_perm in user_folder_perms: + folder_path = folder_perm.path + folder_perm.folder_link = reverse('repo', args=[repo_id]) + '?p=' + urlquote(folder_path) + if folder_path == '/': + folder_perm.folder_name = _(u'Root Directory') + else: + folder_perm.folder_name = os.path.basename(folder_path) + + # for group folder permission + group_folder_perms = seafile_api.list_folder_group_perm_by_repo(repo_id) + group_folder_perms.reverse() + + for folder_perm in group_folder_perms: + folder_path = folder_perm.path + folder_perm.folder_link = reverse('repo', args=[repo_id]) + '?p=' + urlquote(folder_path) + if folder_path == '/': + folder_perm.folder_name = _(u'Root Directory') + else: + folder_perm.folder_name = os.path.basename(folder_path) + folder_perm.group_name = get_group(folder_perm.group_id).group_name + + contacts = Contact.objects.get_contacts_by_user(username) + + return render_to_response('repo_folder_perm.html', { + 'repo': repo, + 'user_folder_perms': user_folder_perms, + 'group_folder_perms': group_folder_perms, + 'contacts': contacts, + }, context_instance=RequestContext(request)) def upload_error_msg (code): err_msg = _(u'Internal Server Error') @@ -1359,10 +1336,6 @@ def repo_revert_file (request, repo_id): if not repo: raise Http404 - # perm check - if check_repo_access_permission(repo.id, request.user) is None: - raise Http404 - commit_id = request.GET.get('commit') path = request.GET.get('p') from_page = request.GET.get('from') @@ -1370,6 +1343,14 @@ def repo_revert_file (request, repo_id): if not (commit_id and path and from_page): return render_error(request, _(u"Invalid arguments")) + # perm check + if check_folder_permission(repo.id, path, request.user.username) != 'rw': + next = request.META.get('HTTP_REFERER', None) + if not next: + next = settings.SITE_ROOT + messages.error(request, _("Permission denied")) + return HttpResponseRedirect(next) + try: ret = seafserv_threaded_rpc.revert_file (repo_id, commit_id, path.encode('utf-8'), request.user.username) @@ -1403,16 +1384,20 @@ def repo_revert_dir (request, repo_id): if not repo: raise Http404 - # perm check - if check_repo_access_permission(repo.id, request.user) is None: - raise Http404 - commit_id = request.GET.get('commit') path = request.GET.get('p') if not (commit_id and path): return render_error(request, _(u"Invalid arguments")) + # perm check + if check_folder_permission(repo.id, path, request.user.username) != 'rw': + next = request.META.get('HTTP_REFERER', None) + if not next: + next = settings.SITE_ROOT + messages.error(request, _("Permission denied")) + return HttpResponseRedirect(next) + try: ret = seafserv_threaded_rpc.revert_dir (repo_id, commit_id, path.encode('utf-8'), request.user.username) diff --git a/seahub/views/ajax.py b/seahub/views/ajax.py index e428727e8d..ee6b7c1101 100644 --- a/seahub/views/ajax.py +++ b/seahub/views/ajax.py @@ -10,18 +10,20 @@ from django.template import RequestContext from django.template.loader import render_to_string from django.utils.http import urlquote from django.utils.translation import ugettext as _ +from django.contrib import messages import seaserv from seaserv import seafile_api, seafserv_rpc, is_passwd_set, \ get_related_users_by_repo, get_related_users_by_org_repo, \ CALC_SHARE_USAGE, seafserv_threaded_rpc, ccnet_threaded_rpc, \ - get_user_quota_usage, get_user_share_usage + get_user_quota_usage, get_user_share_usage, edit_repo, \ + set_repo_history_limit from pysearpc import SearpcError from seahub.auth.decorators import login_required_ajax from seahub.contacts.models import Contact from seahub.forms import RepoNewDirentForm, RepoRenameDirentForm, \ - RepoCreateForm, SharedRepoCreateForm + RepoCreateForm, SharedRepoCreateForm, RepoSettingForm from seahub.options.models import UserOptions, CryptoOptionNotSetError from seahub.notifications.models import UserNotification from seahub.notifications.views import add_notice_from_info @@ -31,18 +33,20 @@ from seahub.signals import upload_file_successful, repo_created, repo_deleted from seahub.views import get_repo_dirents, validate_owner, \ check_repo_access_permission, get_unencry_rw_repos_by_user, \ get_system_default_repo_id, get_diff, group_events_data, \ - get_owned_repo_list - + get_owned_repo_list, check_folder_permission from seahub.views.repo import get_nav_path, get_fileshare, get_dir_share_link, \ get_uploadlink, get_dir_shared_upload_link import seahub.settings as settings from seahub.settings import ENABLE_THUMBNAIL, THUMBNAIL_ROOT, \ - THUMBNAIL_DEFAULT_SIZE + THUMBNAIL_DEFAULT_SIZE, ENABLE_SUB_LIBRARY, ENABLE_REPO_HISTORY_SETTING from seahub.utils import check_filename_with_rename, EMPTY_SHA1, \ gen_block_get_url, TRAFFIC_STATS_ENABLED, get_user_traffic_stat,\ new_merge_with_no_conflict, get_commit_before_new_merge, \ get_repo_last_modify, gen_file_upload_url, is_org_context, \ - get_org_user_events, get_user_events, get_file_type_and_ext + get_org_user_events, get_user_events, get_file_type_and_ext, \ + is_valid_username +from seahub.utils.repo import check_group_folder_perm_args, \ + check_user_folder_perm_args from seahub.utils.star import star_file, unstar_file from seahub.base.accounts import User from seahub.utils.file_types import IMAGE @@ -301,7 +305,7 @@ def list_dir(request, repo_id): 'file_list': file_list, 'dirent_more': dirent_more, 'more_start': more_start, - 'ENABLE_SUB_LIBRARY': settings.ENABLE_SUB_LIBRARY, + 'ENABLE_SUB_LIBRARY': ENABLE_SUB_LIBRARY, 'sub_lib_enabled': sub_lib_enabled, 'enable_upload_folder': settings.ENABLE_UPLOAD_FOLDER, 'current_commit': head_commit, @@ -384,7 +388,7 @@ def list_dir_more(request, repo_id): 'server_crypto': server_crypto, 'dir_list': dir_list, 'file_list': file_list, - 'ENABLE_SUB_LIBRARY': settings.ENABLE_SUB_LIBRARY, + 'ENABLE_SUB_LIBRARY': ENABLE_SUB_LIBRARY, 'sub_lib_enabled': sub_lib_enabled, 'ENABLE_THUMBNAIL': ENABLE_THUMBNAIL, } @@ -393,7 +397,6 @@ def list_dir_more(request, repo_id): return HttpResponse(json.dumps({'html': html, 'dirent_more': dirent_more, 'more_start': more_start}), content_type=content_type) - def new_dirent_common(func): """Decorator for common logic in creating directory and file. """ @@ -410,9 +413,16 @@ def new_dirent_common(func): return HttpResponse(json.dumps(result), status=400, content_type=content_type) + # arguments checking + parent_dir = request.GET.get('parent_dir', None) + if not parent_dir: + result['error'] = _('Argument missing') + return HttpResponse(json.dumps(result), status=400, + content_type=content_type) + # permission checking username = request.user.username - if check_repo_access_permission(repo.id, request.user) != 'rw': + if check_folder_permission(repo.id, parent_dir, username) != 'rw': result['error'] = _('Permission denied') return HttpResponse(json.dumps(result), status=403, content_type=content_type) @@ -426,13 +436,6 @@ def new_dirent_common(func): return HttpResponse(json.dumps(result), status=400, content_type=content_type) - # arguments checking - parent_dir = request.GET.get('parent_dir', None) - if not parent_dir: - result['error'] = _('Argument missing') - return HttpResponse(json.dumps(result), status=400, - content_type=content_type) - # rename duplicate name dirent_name = check_filename_with_rename(repo.id, parent_dir, dirent_name) @@ -497,10 +500,11 @@ def rename_dirent(request, repo_id): return HttpResponse(json.dumps(result), status=400, content_type=content_type) - # permission checking - if check_repo_access_permission(repo.id, request.user) != 'rw': - result['error'] = _('Permission denied') - return HttpResponse(json.dumps(result), status=403, + # argument checking + parent_dir = request.GET.get('parent_dir', None) + if not parent_dir: + result['error'] = _('Argument missing') + return HttpResponse(json.dumps(result), status=400, content_type=content_type) # form validation @@ -513,17 +517,25 @@ def rename_dirent(request, repo_id): return HttpResponse(json.dumps(result), status=400, content_type=content_type) + full_path = os.path.join(parent_dir, oldname) + if seafile_api.get_dir_id_by_path(repo.id, full_path) is not None: + # when dirent is a dir, check current dir perm + if check_folder_permission(repo.id, full_path, username) != 'rw': + err_msg = _('Permission denied') + return HttpResponse(json.dumps({'error': err_msg}), status=403, + content_type=content_type) + + if seafile_api.get_file_id_by_path(repo.id, full_path) is not None: + # when dirent is a file, check parent dir perm + if check_folder_permission(repo.id, parent_dir, username) != 'rw': + err_msg = _('Permission denied') + return HttpResponse(json.dumps({'error': err_msg}), status=403, + content_type=content_type) + if newname == oldname: return HttpResponse(json.dumps({'success': True}), content_type=content_type) - # argument checking - parent_dir = request.GET.get('parent_dir', None) - if not parent_dir: - result['error'] = _('Argument missing') - return HttpResponse(json.dumps(result), status=400, - content_type=content_type) - # rename duplicate name newname = check_filename_with_rename(repo_id, parent_dir, newname) @@ -551,13 +563,6 @@ def delete_dirent(request, repo_id): return HttpResponse(json.dumps({'error': err_msg}), status=400, content_type=content_type) - # permission checking - username = request.user.username - if check_repo_access_permission(repo.id, request.user) != 'rw': - err_msg = _(u'Permission denied.') - return HttpResponse(json.dumps({'error': err_msg}), - status=403, content_type=content_type) - # argument checking parent_dir = request.GET.get("parent_dir", None) dirent_name = request.GET.get("name", None) @@ -566,6 +571,23 @@ def delete_dirent(request, repo_id): return HttpResponse(json.dumps({'error': err_msg}), status=400, content_type=content_type) + full_path = os.path.join(parent_dir, dirent_name) + username = request.user.username + + if seafile_api.get_dir_id_by_path(repo.id, full_path) is not None: + # when dirent is a dir, check current dir perm + if check_folder_permission(repo.id, full_path, username) != 'rw': + err_msg = _('Permission denied') + return HttpResponse(json.dumps({'error': err_msg}), status=403, + content_type=content_type) + + if seafile_api.get_file_id_by_path(repo.id, full_path) is not None: + # when dirent is a file, check parent dir perm + if check_folder_permission(repo.id, parent_dir, username) != 'rw': + err_msg = _('Permission denied') + return HttpResponse(json.dumps({'error': err_msg}), status=403, + content_type=content_type) + # delete file/dir try: seafile_api.del_file(repo_id, parent_dir, dirent_name, username) @@ -590,13 +612,6 @@ def delete_dirents(request, repo_id): return HttpResponse(json.dumps({'error': err_msg}), status=400, content_type=content_type) - # permission checking - username = request.user.username - if check_repo_access_permission(repo.id, request.user) != 'rw': - err_msg = _(u'Permission denied.') - return HttpResponse(json.dumps({'error': err_msg}), - status=403, content_type=content_type) - # argument checking parent_dir = request.GET.get("parent_dir") dirents_names = request.POST.getlist('dirents_names') @@ -605,6 +620,13 @@ def delete_dirents(request, repo_id): return HttpResponse(json.dumps({'error': err_msg}), status=400, content_type=content_type) + # permission checking + username = request.user.username + if check_folder_permission(repo.id, parent_dir, username) != 'rw': + err_msg = _(u'Permission denied.') + return HttpResponse(json.dumps({'error': err_msg}), + status=403, content_type=content_type) + deleted = [] undeleted = [] for dirent_name in dirents_names: @@ -634,14 +656,6 @@ def copy_move_common(func): return HttpResponse(json.dumps(result), status=400, content_type=content_type) - # permission checking - username = request.user.username - if check_repo_access_permission(repo.id, request.user) != 'rw': - result['error'] = _('Permission denied') - return HttpResponse(json.dumps(result), status=403, - content_type=content_type) - - # arguments validation path = request.GET.get('path') obj_name = request.GET.get('obj_name') @@ -653,6 +667,13 @@ def copy_move_common(func): return HttpResponse(json.dumps(result), status=400, content_type=content_type) + # permission checking + username = request.user.username + if check_folder_permission(repo.id, path, username) != 'rw': + result['error'] = _('Permission denied') + return HttpResponse(json.dumps(result), status=403, + content_type=content_type) + # check file path if len(dst_path+obj_name) > settings.MAX_PATH: result['error'] = _('Destination path is too long.') @@ -737,8 +758,17 @@ def cp_file(src_repo_id, src_path, dst_repo_id, dst_path, obj_name, username): def mv_dir(src_repo_id, src_path, dst_repo_id, dst_path, obj_name, username): result = {} content_type = 'application/json; charset=utf-8' - + src_dir = os.path.join(src_path, obj_name) + + # permission checking + dst_repo_owner = seafile_api.get_repo_owner(dst_repo_id) + if check_folder_permission(src_repo_id, src_dir, username) != 'rw' or \ + check_folder_permission(dst_repo_id, dst_path, dst_repo_owner) != 'rw': + result['error'] = _('Permission denied') + return HttpResponse(json.dumps(result), status=403, + content_type=content_type) + if dst_path.startswith(src_dir + '/'): error_msg = _(u'Can not move directory %(src)s to its subdirectory %(des)s') \ % {'src': src_dir, 'des': dst_path} @@ -775,6 +805,14 @@ def cp_dir(src_repo_id, src_path, dst_repo_id, dst_path, obj_name, username): result = {} content_type = 'application/json; charset=utf-8' + # permission checking + dst_repo_owner = seafile_api.get_repo_owner(dst_repo_id) + if check_folder_permission(src_repo_id, src_path, username) != 'rw' or \ + check_folder_permission(dst_repo_id, dst_path, dst_repo_owner) != 'rw': + result['error'] = _('Permission denied') + return HttpResponse(json.dumps(result), status=403, + content_type=content_type) + src_dir = os.path.join(src_path, obj_name) if dst_path.startswith(src_dir): error_msg = _(u'Can not copy directory %(src)s to its subdirectory %(des)s') \ @@ -825,13 +863,6 @@ def dirents_copy_move_common(func): return HttpResponse(json.dumps(result), status=400, content_type=content_type) - # permission checking - username = request.user.username - if check_repo_access_permission(repo.id, request.user) != 'rw': - result['error'] = _('Permission denied') - return HttpResponse(json.dumps(result), status=403, - content_type=content_type) - # arguments validation parent_dir = request.GET.get('parent_dir') obj_file_names = request.POST.getlist('file_names') @@ -844,6 +875,13 @@ def dirents_copy_move_common(func): return HttpResponse(json.dumps(result), status=400, content_type=content_type) + # permission checking + username = request.user.username + if check_folder_permission(repo.id, parent_dir, username) != 'rw': + result['error'] = _('Permission denied') + return HttpResponse(json.dumps(result), status=403, + content_type=content_type) + # check file path for obj_name in obj_file_names + obj_dir_names: if len(dst_path+obj_name) > settings.MAX_PATH: @@ -870,6 +908,9 @@ def dirents_copy_move_common(func): def mv_dirents(src_repo_id, src_path, dst_repo_id, dst_path, obj_file_names, obj_dir_names, username): result = {} content_type = 'application/json; charset=utf-8' + failed = [] + allowed_dirs = [] + dst_repo_owner = seafile_api.get_repo_owner(dst_repo_id) for obj_name in obj_dir_names: src_dir = os.path.join(src_path, obj_name) @@ -878,11 +919,18 @@ def mv_dirents(src_repo_id, src_path, dst_repo_id, dst_path, obj_file_names, obj % {'src': src_dir, 'des': dst_path} result['error'] = error_msg return HttpResponse(json.dumps(result), status=400, content_type=content_type) - + + # permission checking + if check_folder_permission(src_repo_id, obj_name, username) != 'rw' or \ + check_folder_permission(dst_repo_id, dst_path, dst_repo_owner) != 'rw': + failed.append(obj_name) + else: + allowed_dirs.append(obj_name) + success = [] - failed = [] url = None - for obj_name in obj_file_names + obj_dir_names: + + for obj_name in obj_file_names + allowed_dirs: new_obj_name = check_filename_with_rename(dst_repo_id, dst_path, obj_name) try: res = seafile_api.move_file(src_repo_id, src_path, obj_name, @@ -907,6 +955,10 @@ def cp_dirents(src_repo_id, src_path, dst_repo_id, dst_path, obj_file_names, obj result = {} content_type = 'application/json; charset=utf-8' + failed = [] + allowed_dirs = [] + dst_repo_owner = seafile_api.get_repo_owner(dst_repo_id) + for obj_name in obj_dir_names: src_dir = os.path.join(src_path, obj_name) if dst_path.startswith(src_dir): @@ -914,11 +966,18 @@ def cp_dirents(src_repo_id, src_path, dst_repo_id, dst_path, obj_file_names, obj % {'src': src_dir, 'des': dst_path} result['error'] = error_msg return HttpResponse(json.dumps(result), status=400, content_type=content_type) - + + # permission checking + if check_folder_permission(src_repo_id, obj_name, username) != 'rw' or \ + check_folder_permission(dst_repo_id, dst_path, dst_repo_owner) != 'rw': + failed.append(obj_name) + else: + allowed_dirs.append(obj_name) + success = [] - failed = [] url = None - for obj_name in obj_file_names + obj_dir_names: + + for obj_name in obj_file_names + allowed_dirs: new_obj_name = check_filename_with_rename(dst_repo_id, dst_path, obj_name) try: res = seafile_api.copy_file(src_repo_id, src_path, obj_name, @@ -1596,17 +1655,29 @@ def get_file_op_url(request, repo_id): content_type = 'application/json; charset=utf-8' op_type = request.GET.get('op_type') # value can be 'upload', 'update', 'upload-blks', 'update-blks' - if not op_type: + path = request.GET.get('path') + if not (op_type and path): err_msg = _(u'Argument missing') return HttpResponse(json.dumps({"error": err_msg}), status=400, content_type=content_type) + repo = get_repo(repo_id) + if not repo: + err_msg = _(u'Library does not exist') + return HttpResponse(json.dumps({"error": err_msg}), status=400, + content_type=content_type) + username = request.user.username + # permission checking + if check_folder_permission(repo.id, path, username) != 'rw': + err_msg = _(u'Permission denied') + return HttpResponse(json.dumps({"error": err_msg}), status=403, + content_type=content_type) + url = '' - if check_repo_access_permission(repo_id, request.user) == 'rw': - token = seafile_api.get_fileserver_access_token(repo_id, 'dummy', - op_type, username) - url = gen_file_upload_url(token, op_type + '-aj') + token = seafile_api.get_fileserver_access_token(repo_id, 'dummy', + op_type, username) + url = gen_file_upload_url(token, op_type + '-aj') return HttpResponse(json.dumps({"url": url}), content_type=content_type) @@ -1859,3 +1930,355 @@ def events(request): 'events_more': events_more, 'new_start': start}), content_type='application/json; charset=utf-8') + +@login_required_ajax +def ajax_repo_change_basic_info(request, repo_id): + """Handle post request to change library basic info. + """ + if request.method != 'POST': + raise Http404 + + content_type = 'application/json; charset=utf-8' + username = request.user.username + + repo = seafile_api.get_repo(repo_id) + if not repo: + raise Http404 + + # no settings for virtual repo + if ENABLE_SUB_LIBRARY and repo.is_virtual: + raise Http404 + + # check permission + if is_org_context(request): + repo_owner = seafile_api.get_org_repo_owner(repo.id) + else: + repo_owner = seafile_api.get_repo_owner(repo.id) + is_owner = True if username == repo_owner else False + if not is_owner: + raise Http404 + + form = RepoSettingForm(request.POST) + if not form.is_valid(): + return HttpResponse(json.dumps({ + 'error': str(form.errors.values()[0]) + }), status=400, content_type=content_type) + + repo_name = form.cleaned_data['repo_name'] + repo_desc = form.cleaned_data['repo_desc'] + days = form.cleaned_data['days'] + + # Edit library info (name, descryption). + if repo.name != repo_name or repo.desc != repo_desc: + if not edit_repo(repo_id, repo_name, repo_desc, username): + err_msg = _(u'Failed to edit library information.') + return HttpResponse(json.dumps({'error': err_msg}), + status=500, content_type=content_type) + + # set library history + if days is not None and ENABLE_REPO_HISTORY_SETTING: + res = set_repo_history_limit(repo_id, days) + if res != 0: + return HttpResponse(json.dumps({ + 'error': _(u'Failed to save settings on server') + }), status=400, content_type=content_type) + + messages.success(request, _(u'Settings saved.')) + return HttpResponse(json.dumps({'success': True}), + content_type=content_type) + +@login_required_ajax +def ajax_repo_transfer_owner(request, repo_id): + """Handle post request to transfer library owner. + """ + if request.method != 'POST': + raise Http404 + + content_type = 'application/json; charset=utf-8' + username = request.user.username + + repo = seafile_api.get_repo(repo_id) + if not repo: + raise Http404 + + # check permission + if is_org_context(request): + repo_owner = seafile_api.get_org_repo_owner(repo.id) + else: + repo_owner = seafile_api.get_repo_owner(repo.id) + is_owner = True if username == repo_owner else False + if not is_owner: + raise Http404 + + # check POST arg + repo_owner = request.POST.get('repo_owner', '').lower() + if not is_valid_username(repo_owner): + return HttpResponse(json.dumps({ + 'error': _('Username %s is not valid.') % repo_owner, + }), status=400, content_type=content_type) + + try: + User.objects.get(email=repo_owner) + except User.DoesNotExist: + return HttpResponse(json.dumps({ + 'error': _('User %s is not found.') % repo_owner, + }), status=400, content_type=content_type) + + if is_org_context(request): + org_id = request.user.org.org_id + if not seaserv.ccnet_threaded_rpc.org_user_exists(org_id, repo_owner): + return HttpResponse(json.dumps({ + 'error': _('User %s is not in current organization.') % + repo_owner,}), status=400, content_type=content_type) + + if repo_owner and repo_owner != username: + if is_org_context(request): + org_id = request.user.org.org_id + seafile_api.set_org_repo_owner(org_id, repo_id, repo_owner) + else: + if ccnet_threaded_rpc.get_orgs_by_user(repo_owner): + return HttpResponse(json.dumps({ + 'error': _('Can not transfer library to organization user %s.') % repo_owner, + }), status=400, content_type=content_type) + else: + seafile_api.set_repo_owner(repo_id, repo_owner) + + messages.success(request, + _(u'Library %(repo_name)s has been transfered to %(new_owner)s.') % + {'repo_name': repo.name, 'new_owner': repo_owner}) + return HttpResponse(json.dumps({'success': True}), + content_type=content_type) + +@login_required_ajax +def ajax_repo_change_passwd(request, repo_id): + """Handle ajax post request to change library password. + """ + if request.method != 'POST': + raise Http404 + + content_type = 'application/json; charset=utf-8' + username = request.user.username + + repo = seafile_api.get_repo(repo_id) + if not repo: + raise Http404 + + # check permission + if is_org_context(request): + repo_owner = seafile_api.get_org_repo_owner(repo.id) + else: + repo_owner = seafile_api.get_repo_owner(repo.id) + is_owner = True if username == repo_owner else False + if not is_owner: + return HttpResponse(json.dumps({ + 'error': _('Faied to change password, you are not owner.')}), + status=400, content_type=content_type) + + old_passwd = request.POST.get('old_passwd', '') + new_passwd = request.POST.get('new_passwd', '') + try: + seafile_api.change_repo_passwd(repo_id, old_passwd, new_passwd, username) + except SearpcError, e: + return HttpResponse(json.dumps({ + 'error': e.msg, + }), status=400, content_type=content_type) + + messages.success(request, _(u'Successfully updated the password of Library %(repo_name)s.') % + {'repo_name': repo.name}) + return HttpResponse(json.dumps({'success': True}), + content_type=content_type) + +@login_required_ajax +def add_user_folder_permission(request, repo_id): + """ + Add folder permission to a user + """ + if request.method != 'POST': + raise Http404 + + result = {} + content_type = 'application/json; charset=utf-8' + + user = request.POST.get('user', None) + path = request.POST.get('path', None) + perm = request.POST.get('perm', None) + + if not user or not path or not perm: + return HttpResponse(json.dumps({"error": _('Argument missing')}), + status=400, + content_type=content_type) + + result = check_user_folder_perm_args(request.user, repo_id, path, user, perm) + if 'error' in result: + return HttpResponse(json.dumps(result), status=result['status'], + content_type=content_type) + + try: + seafile_api.add_folder_user_perm(repo_id, path, perm, user) + except SearpcError, e: + return HttpResponse(json.dumps({"error": e.msg}), status=500, + content_type=content_type) + + messages.success(request, _(u'Success')) + return HttpResponse(json.dumps({'success': True}), + content_type=content_type) + +@login_required_ajax +def remove_user_folder_permission(request, repo_id): + """ + Remove folder permission of a user + """ + result = {} + content_type = 'application/json; charset=utf-8' + + user = request.GET.get('user', None) + path = request.GET.get('path', None) + + if not user or not path: + return HttpResponse(json.dumps({"error": _('Argument missing')}), + status=400, + content_type=content_type) + + result = check_user_folder_perm_args(request.user, repo_id, path, user) + if 'error' in result: + return HttpResponse(json.dumps(result), status=result['status'], + content_type=content_type) + + try: + seafile_api.rm_folder_user_perm(repo_id, path, user) + return HttpResponse(json.dumps({'success': True}), + content_type=content_type) + except SearpcError, e: + return HttpResponse(json.dumps({"error": e.msg}), status=500, + content_type=content_type) + +@login_required_ajax +def toggle_user_folder_permission(request, repo_id): + """ + Change folder permission of a user + """ + if request.method != 'POST': + raise Http404 + + result = {} + content_type = 'application/json; charset=utf-8' + + user = request.POST.get('user', None) + path = request.POST.get('path', None) + perm = request.POST.get('perm', None) + + print user, path, perm + if not user or not path or not perm: + return HttpResponse(json.dumps({"error": _('Argument missing')}), + status=400, + content_type=content_type) + + result = check_user_folder_perm_args(request.user, repo_id, path, user, perm) + if 'error' in result: + return HttpResponse(json.dumps(result), status=result['status'], + content_type=content_type) + + try: + seafile_api.set_folder_user_perm(repo_id, path, perm, user) + return HttpResponse(json.dumps({'success': True}), + content_type=content_type) + except SearpcError, e: + return HttpResponse(json.dumps({"error": e.msg}), status=500, + content_type=content_type) + +@login_required_ajax +def add_group_folder_permission(request, repo_id): + """ + Add folder permission to a group + """ + if request.method != 'POST': + raise Http404 + + result = {} + content_type = 'application/json; charset=utf-8' + + group_id = request.POST.get('group_id', None) + path = request.POST.get('path', None) + perm = request.POST.get('perm', None) + + if not group_id or not path or not perm: + return HttpResponse(json.dumps({"error": _('Argument missing')}), + status=400, + content_type=content_type) + group_id = int(group_id) + result = check_group_folder_perm_args(request.user, repo_id, path, group_id, perm) + if 'error' in result: + return HttpResponse(json.dumps(result), status=result['status'], + content_type=content_type) + + try: + seafile_api.add_folder_group_perm(repo_id, path, perm, group_id) + except SearpcError, e: + return HttpResponse(json.dumps({"error": e.msg}), status=500, + content_type=content_type) + + messages.success(request, _(u'Success')) + return HttpResponse(json.dumps({'success': True}), + content_type=content_type) + +@login_required_ajax +def remove_group_folder_permission(request, repo_id): + """ + Remove folder permission of a group + """ + result = {} + content_type = 'application/json; charset=utf-8' + + group_id = int(request.GET.get('group_id', None)) + path = request.GET.get('path', None) + + if not group_id or not path: + return HttpResponse(json.dumps({"error": _('Argument missing')}), + status=400, + content_type=content_type) + + result = check_group_folder_perm_args(request.user, repo_id, path, group_id) + if 'error' in result: + return HttpResponse(json.dumps(result), status=result['status'], + content_type=content_type) + + try: + seafile_api.rm_folder_group_perm(repo_id, path, group_id) + return HttpResponse(json.dumps({'success': True}), + content_type=content_type) + except SearpcError, e: + return HttpResponse(json.dumps({"error": e.msg}), status=500, + content_type=content_type) + +@login_required_ajax +def toggle_group_folder_permission(request, repo_id): + """ + Change folder permission of a group + """ + if request.method != 'POST': + raise Http404 + + result = {} + content_type = 'application/json; charset=utf-8' + + group_id = int(request.POST.get('group_id', None)) + path = request.POST.get('path', None) + perm = request.POST.get('perm', None) + + if not group_id or not path or not perm: + return HttpResponse(json.dumps({"error": _('Argument missing')}), + status=400, + content_type=content_type) + + result = check_group_folder_perm_args(request.user, repo_id, path, group_id, perm) + if 'error' in result: + return HttpResponse(json.dumps(result), status=result['status'], + content_type=content_type) + + try: + seafile_api.set_folder_group_perm(repo_id, path, perm, group_id) + return HttpResponse(json.dumps({'success': True}), + content_type=content_type) + except SearpcError, e: + return HttpResponse(json.dumps({"error": e.msg}), status=500, + content_type=content_type) diff --git a/seahub/views/file.py b/seahub/views/file.py index 9c738b905d..503dafb854 100644 --- a/seahub/views/file.py +++ b/seahub/views/file.py @@ -58,6 +58,7 @@ from seahub.utils.file_types import (IMAGE, PDF, DOCUMENT, SPREADSHEET, MARKDOWN, TEXT, SF, OPENDOCUMENT) from seahub.utils.star import is_file_starred from seahub.utils import HAS_OFFICE_CONVERTER, FILEEXT_TYPE_MAP +from seahub.views import check_folder_permission if HAS_OFFICE_CONVERTER: from seahub.utils import ( @@ -957,14 +958,15 @@ def file_edit(request, repo_id): if request.method == 'POST': return file_edit_submit(request, repo_id) - if check_repo_access_permission(repo_id, request.user) != 'rw': - return render_permission_error(request, _(u'Unable to edit file')) - path = request.GET.get('p', '/') if path[-1] == '/': path = path[:-1] u_filename = os.path.basename(path) filename = urllib2.quote(u_filename.encode('utf-8')) + parent_dir = os.path.dirname(path) + + if check_folder_permission(repo.id, parent_dir, request.user.username) != 'rw': + return render_permission_error(request, _(u'Unable to edit file')) head_id = repo.head_cmmt_id