1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-08-01 07:10:55 +00:00

[repo-setting] Set folder perm

This commit is contained in:
lian 2015-01-21 11:14:34 +08:00
parent 579eb91da6
commit d1fb67c78f
18 changed files with 2056 additions and 660 deletions

View File

@ -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;
}

View File

@ -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 = '';

View File

@ -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.')

View File

@ -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'))

View File

@ -27,7 +27,7 @@
<a href="{{ SITE_ROOT }}seafile_access_check/?repo_id={{repo.props.id}}" target="_blank">{% trans "Download" %}</a>
{% endif %}
{% if show_repo_settings %}
<a id="repo-setting-btn" href="{% url 'repo_settings' repo.id %}" class="normal"><img class="link-icon vam" src="{{ MEDIA_URL }}img/setting.png" alt="" /><span class="vam">{% trans "Settings" %}</span></a>
<a id="repo-setting-btn" href="{% url 'repo_basic_info' repo.id %}" class="normal"><img class="link-icon vam" src="{{ MEDIA_URL }}img/setting.png" alt="" /><span class="vam">{% trans "Settings" %}</span></a>
{% endif %}
{% if user_perm == 'rw' %}
<a id="recycle-btn" href="{% url 'repo_recycle_view' repo.id %}" class="normal"><img class="link-icon vam" src="{{ MEDIA_URL }}img/lib_trash.png" alt="" /><span class="vam">{% trans "Trash"%}</span></a>
@ -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', '<span class="op-target">' + file_name + '</span>'));
$.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:

View File

@ -0,0 +1,125 @@
{% extends "myhome_base.html" %}
{% load i18n avatar_tags seahub_tags %}
{% block sub_title %}{{repo.name}} - {% endblock %}
{% block extra_style %}
<style type="text/css">
#left-panel { position: relative; }
.go-back { top:0; }
</style>
{% endblock %}
{% block left_panel %}
<a class="go-back" title="{% trans "Back to Library" %}" href="{% url 'repo' repo.id %}"><span class="icon-chevron-left"></span></a>
<div class="side-textnav">
<ul class="side-textnav-tabs">
<li class="tab tab-cur"><a href="{% url 'repo_basic_info' repo.id %}">{% trans "Basic Info" %}</a></li>
<li class="tab"><a href="{% url 'repo_transfer_owner' repo.id %}">{% trans "Transfer Ownership" %}</a></li>
{% if repo.encrypted and repo.enc_version == 2 %}
<li class="tab"><a href="{% url 'repo_change_password' repo.id %}">{% trans "Change Password" %}</a></li>
{% endif %}
{% if not repo.encrypted %}
<li class="tab"><a href="{% url 'repo_shared_link' repo.id %}">{% trans "Shared Links" %}</a></li>
{% endif %}
<li class="tab"><a href="{% url 'repo_share_manage' repo.id %}">{% trans "Sharing Management" %}</a></li>
<li class="tab"><a href="{% url 'repo_folder_perm' repo.id %}">{% trans "SubFolder Permission" %}</a></li>
</ul>
</div>
{% endblock %}
{% block right_panel %}
<div class="lib-setting">
<h2>{% trans "Library Settings" %}</h2>
<div id="basic-info" class="setting-item">
<h3>{% trans "Basic Info" %}</h3>
<form id="repo-basic-info-form" action="" method="post" class="form">{% csrf_token %}
<label>{% trans "Name" %}</label><br />
<input type="text" name="repo_name" value="{{ repo.name }}" class="input" /><br />
<label>{% trans "Description" %}</label></br />
<textarea name="repo_desc" class="textarea">{{ repo.desc }}</textarea><br />
{% if not ENABLE_SUB_LIBRARY or not repo.is_virtual %}
<label>{% trans "History" %}</label><br />
<input type="radio" name="history" value="full_history" {% if full_history_checked %}checked="checked"{% endif %} class="vam" {% if not full_history_enabled %}disabled="disabled"{% endif %} /> <span class="vam">{% trans "Keep full history" %}</span><br />
<input type="radio" name="history" value="no_history" {% if no_history_checked %}checked="checked"{% endif %} class="vam" {% if not full_history_enabled %}disabled="disabled"{% endif %} /> <span class="vam">{% trans "Don't keep history" %}</span><br />
<input type="radio" name="history" value="partial_history" {% if partial_history_checked %}checked="checked"{% endif %} class="vam" {% if not full_history_enabled %}disabled="disabled"{% endif %} /> <span calss="vam">{% trans "Only keep a period of history:" %}
<input type="text" name="days" size="4" {% if not days_enabled %} disabled="disabled" class="input-disabled"{% endif %} value="{{history_limit}}" /> {% trans "days" %}</span><br />
{% endif %}
<p class="error hide"></p>
<input type="submit" value="{% trans "Submit" %}" class="submit" />
</form>
</div>
</div>
{% endblock %}
{% block extra_script %}
<script type="text/javascript">
$('#repo-basic-info-form input[name="history"]').change(function() {
var value = $(this).attr('value'),
days_input = $('#repo-basic-info-form input[name="days"]');
if (value == 'full_history' || value == 'no_history') {
days_input.attr('disabled', true).addClass('input-disabled');
} else {
days_input.attr('disabled', false).removeClass('input-disabled');
}
});
$('#repo-basic-info-form').submit(function() {
var form = $(this),
form_id = form.attr('id');
var repo_name = $('[name="repo_name"]', form).val(),
repo_desc = $('[name="repo_desc"]', form).val();
if (!$.trim(repo_name)) {
apply_form_error(form_id, "{% trans "Name is required." %}");
return false;
}
if (!$.trim(repo_desc)) {
apply_form_error(form_id, "{% trans "Description is required." %}");
return false;
}
var days;
var value = $(this).find('input[name="history"]:checked').val();
if (value == 'partial_history') {
days = $(this).find('input[name="days"]').val();
} else if (value == 'full_history') {
days = -1;
} else {
days = 0;
}
var submit_btn = $(this).children('input[type="submit"]');
disable(submit_btn);
$.ajax({
url: '{% url 'ajax_repo_change_basic_info' repo.id %}',
type: 'POST',
dataType: 'json',
beforeSend: prepareCSRFToken,
data: {
'repo_name': repo_name,
'repo_desc': repo_desc,
'days': days
},
success: function(data) {
if (data['success']) {
location.reload(true);
}
},
error: function(jqXHR, textStatus, errorThrown) {
if (jqXHR.responseText) {
apply_form_error(form_id, $.parseJSON(jqXHR.responseText).error);
} else {
apply_form_error(form_id, "{% trans "Failed. Please check the network." %}");
}
enable(submit_btn);
}
});
return false;
});
</script>
{% endblock %}

View File

@ -0,0 +1,116 @@
{% extends "myhome_base.html" %}
{% load i18n avatar_tags seahub_tags %}
{% block sub_title %}{{repo.name}} - {% endblock %}
{% block extra_style %}
<style type="text/css">
#left-panel { position: relative; }
.go-back { top:0; }
</style>
{% endblock %}
{% block left_panel %}
<a class="go-back" title="{% trans "Back to Library" %}" href="{% url 'repo' repo.id %}"><span class="icon-chevron-left"></span></a>
<div class="side-textnav">
<ul class="side-textnav-tabs">
<li class="tab"><a href="{% url 'repo_basic_info' repo.id %}">{% trans "Basic Info" %}</a></li>
<li class="tab"><a href="{% url 'repo_transfer_owner' repo.id %}">{% trans "Transfer Ownership" %}</a></li>
{% if repo.encrypted and repo.enc_version == 2 %}
<li class="tab tab-cur"><a href="{% url 'repo_change_password' repo.id %}">{% trans "Change Password" %}</a></li>
{% endif %}
{% if not repo.encrypted %}
<li class="tab"><a href="{% url 'repo_shared_link' repo.id %}">{% trans "Shared Links" %}</a></li>
{% endif %}
<li class="tab"><a href="{% url 'repo_share_manage' repo.id %}">{% trans "Sharing Management" %}</a></li>
<li class="tab"><a href="{% url 'repo_folder_perm' repo.id %}">{% trans "SubFolder Permission" %}</a></li>
</ul>
</div>
{% endblock %}
{% block right_panel %}
<div class="lib-setting">
<h2>{% trans "Library Settings" %}</h2>
<div id="change-password" class="setting-item">
<h3>{% trans "Change Password" %}</h3>
<form id="repo-change-passwd-form" action="" method="post" class="form">{% csrf_token %}
<p>{% trans "Change the password of this library:" %}</p>
<label>{% trans "Old Password" %}</label><br />
<input type="password" name="old_passwd" class="input" /><br />
<label>{% blocktrans %}New Password(at least {{repo_password_min_length}} characters){% endblocktrans %}</label><br />
<input type="password" name="new_passwd" class="input" /><br />
<label>{% trans "New Password Again" %}</label><br />
<input type="password" name="new_passwd_again" class="input" /><br />
<p class="error hide"></p>
<input type="submit" value="{% trans "Submit" %}" class="submit" />
</form>
</div>
</div>
{% endblock %}
{% block extra_script %}
<script type="text/javascript">
{% if repo.encrypted and repo.enc_version == 2 %}
$('#repo-change-passwd-form').submit(function() {
var form = $(this),
form_id = form.attr('id'),
old_passwd, new_passwd, new_passwd_again;
old_passwd = $('input[name="old_passwd"]', form).val();
new_passwd = $('input[name="new_passwd"]', form).val();
new_passwd_again = $('input[name="new_passwd_again"]', form).val();
if (!$.trim(old_passwd)) {
apply_form_error(form_id, "{% trans "Please enter the old password" %}");
return false;
}
if (!$.trim(new_passwd)) {
apply_form_error(form_id, "{% trans "Please enter the new password" %}");
return false;
}
if ($.trim(new_passwd).length < {{repo_password_min_length}}) {
apply_form_error(form_id, "{% trans "New password is too short" %}");
return false;
}
if (!$.trim(new_passwd_again)) {
apply_form_error(form_id, "{% trans "Please enter the new password again" %}");
return false;
}
if ($.trim(new_passwd) != $.trim(new_passwd_again)) {
apply_form_error(form_id, "{% trans "New passwords don't match" %}");
return false;
}
var submit_btn = $(this).children('input[type="submit"]');
disable(submit_btn);
$.ajax({
url: '{% url 'ajax_repo_change_passwd' repo.id %}',
type: 'POST',
dataType: 'json',
beforeSend: prepareCSRFToken,
data: {
'old_passwd': old_passwd,
'new_passwd': new_passwd,
'new_passwd_again': new_passwd_again
},
success: function(data) {
if (data['success']) {
location.reload(true);
}
},
error: function(jqXHR, textStatus, errorThrown) {
if (jqXHR.responseText) {
apply_form_error(form_id, $.parseJSON(jqXHR.responseText).error);
} else {
apply_form_error(form_id, "{% trans "Failed. Please check the network." %}");
}
enable(submit_btn);
}
});
return false;
});
{% endif %}
</script>
{% endblock %}

View File

@ -0,0 +1,393 @@
{% extends "myhome_base.html" %}
{% load i18n avatar_tags seahub_tags %}
{% block sub_title %}{{repo.name}} - {% endblock %}
{% block extra_style %}
<style type="text/css">
#left-panel { position: relative; }
.go-back { top:0; }
</style>
{% endblock %}
{% block left_panel %}
<a class="go-back" title="{% trans "Back to Library" %}" href="{% url 'repo' repo.id %}"><span class="icon-chevron-left"></span></a>
<div class="side-textnav">
<ul class="side-textnav-tabs">
<li class="tab"><a href="{% url 'repo_basic_info' repo.id %}">{% trans "Basic Info" %}</a></li>
<li class="tab"><a href="{% url 'repo_transfer_owner' repo.id %}">{% trans "Transfer Ownership" %}</a></li>
{% if repo.encrypted and repo.enc_version == 2 %}
<li class="tab"><a href="{% url 'repo_change_password' repo.id %}">{% trans "Change Password" %}</a></li>
{% endif %}
{% if not repo.encrypted %}
<li class="tab"><a href="{% url 'repo_shared_link' repo.id %}">{% trans "Shared Links" %}</a></li>
{% endif %}
<li class="tab"><a href="{% url 'repo_share_manage' repo.id %}">{% trans "Sharing Management" %}</a></li>
<li class="tab tab-cur"><a href="{% url 'repo_folder_perm' repo.id %}">{% trans "SubFolder Permission" %}</a></li>
</ul>
</div>
{% endblock %}
{% block right_panel %}
<div class="lib-setting">
<h2>{% trans "Library Settings" %}</h2>
<h3>{% trans "Folder Permission" %}</h3>
<p>{% trans "View and manage all the folder permissions in this library." %}</p>
<div id="tabs" class="tab-tabs">
<div class="hd ovhd">
<ul class="tab-tabs-nav fleft">
<li class="tab"><a href="#user-tab" class="a" id="user-tab">{% trans "User Permission" %}</a></li>
<li class="tab"><a href="#group-tab" class="a" id="group-tab">{% trans "Group permission" %}</a></li>
</ul>
<div class="fright">
<button id="folder-perm-add-btn"><img src="{{ MEDIA_URL }}img/add.png" alt="" class="add vam" /><span class="vam">{% trans "Add Permission" %}</span></button>
</div>
</div>
<div id="user-tab">
<table>
<tr>
<th width="30%">{% trans "User" %}</th>
<th width="30%">{% trans "Folder" %}</th>
<th width="30%">{% trans "Permission" %}</th>
<th width="10%"></th>
</tr>
<tr class="user-perm-add-tr hide">
<td><input id="perm-add-user" placeholder=" {% trans "Email"%}"></input></td>
<td>
<input class="user-perm-add-folder-name" placeholder=" {% trans "Select a folder"%}"></input><img src="{{ MEDIA_URL }}img/add.png" alt="" title="Select Folder" class="perm-add-select-folder add vam" />
<input class="user-perm-add-folder-path" type="hidden"></input>
</td>
<td>
<select name="permission" class="user-perm-add-perm">
<option value="rw" selected="selected">{% trans "Read-Write"%}</option>
<option value="r">{% trans "Read-Only"%}</option>
</select>
</td>
<td>
<button class="perm-add-submit">{% trans "Submit" %}</button>
</td>
</tr>
{% if user_folder_perms %}
{% for perm in user_folder_perms %}
<tr class="perm-item" data-user="{{ perm.user }}" data-path="{{ perm.path }}">
<td><a href="{% url 'user_profile' perm.user %}">{{ perm.user }}</a></td>
<td><span><a href="{{ perm.folder_link }}">{{ perm.folder_name }}</a></span></td>
<td>
<div class="perm-change">
{% if perm.permission == 'rw' %}
<span class="perm-cur-value">{% trans "Read-Write" %}</span>
{% else %}
<span class="perm-cur-value">{% trans "Read-Only" %}</span>
{% endif %}
<img src="{{MEDIA_URL}}img/edit_12.png" alt="{% trans "Edit"%}" title="{% trans "Edit"%}" class="perm-edit-icon cspt vh" />
</div>
<select class="perm-toggle-select hide">
<option value="rw" {%if perm.permission == 'rw' %}selected="selected"{% endif %}>{% trans "Read-Write" %}</option>
<option value="r" {%if not perm.permission == 'rw' %}selected="selected"{% endif %}>{% trans "Read-Only"%}</option>
</select>
</td>
<td>
<img src="{{MEDIA_URL}}img/rm.png" class="perm-delete-btn op-icon vh" title="{% trans "Delete" %}" />
</td>
</tr>
{% endfor %}
{% endif %}
</table>
</div>
<div id="group-tab" class="hide">
<table>
<tr>
<th width="30%">{% trans "Group" %}</th>
<th width="30%">{% trans "Folder" %}</th>
<th width="30%">{% trans "Permission" %}</th>
<th width="10%"></th>
</tr>
<tr class="group-perm-add-tr hide">
<td>
<input id="perm-add-grp-name" placeholder=" {% trans "Group"%}"></input>
<input id="perm-add-grp-id" type="hidden"></input>
</td>
<td>
<input class="group-perm-add-folder-name" placeholder=" {% trans "Select a folder"%}"></input><img src="{{ MEDIA_URL }}img/add.png" alt="" title="Select Folder" class="perm-add-select-folder add vam" />
<input class="group-perm-add-folder-path" type="hidden"></input>
</td>
<td>
<select name="permission" class="group-perm-add-perm">
<option value="rw" selected="selected">{% trans "Read-Write"%}</option>
<option value="r">{% trans "Read-Only"%}</option>
</select>
</td>
<td>
<button class="perm-add-submit">{% trans "Submit" %}</button>
</td>
</tr>
{% if group_folder_perms %}
{% for perm in group_folder_perms %}
<tr class="perm-item" data-group_id="{{ perm.group_id }}" data-path="{{ perm.path }}">
<td><a href="{% url 'group_info' perm.group_id %}">{{ perm.group_name }}</a></td>
<td>
<span><a href="{{ perm.folder_link }}">{{ perm.folder_name }}</a></span>
</td>
<td>
<div class="perm-change">
{% if perm.permission == 'rw' %}
<span class="perm-cur-value">{% trans "Read-Write" %}</span>
{% else %}
<span class="perm-cur-value">{% trans "Read-Only" %}</span>
{% endif %}
<img src="{{MEDIA_URL}}img/edit_12.png" alt="{% trans "Edit"%}" title="{% trans "Edit"%}" class="perm-edit-icon cspt vh" />
</div>
<select class="perm-toggle-select hide">
<option value="rw" {%if perm.permission == 'rw' %}selected="selected"{% endif %}>{% trans "Read-Write" %}</option>
<option value="r" {%if not perm.permission == 'rw' %}selected="selected"{% endif %}>{% trans "Read-Only"%}</option>
</select>
</td>
<td>
<img src="{{MEDIA_URL}}img/rm.png" class="perm-delete-btn op-icon vh" title="{% trans "Delete" %}" />
</td>
</tr>
{% endfor %}
{% endif %}
</table>
</div>
</div>
<div id="perm-add-jstree-wrap" class="hide">
<h3>{% trans "Please selecte a directory" %}</h3>
<img src="{{MEDIA_URL}}img/loading-icon.gif" alt="" class="loading-tip" />
<div id="perm-add-jstree" data-repo_id="{{repo.id}}"></div>
<button class="perm-add-jstree-select">{% trans "Select" %}</button>
<button class="simplemodal-close">{% trans "Cancel"%}</button><br />
<span class="error hide"></span>
</div>
</div>
{% endblock %}
{% block extra_script %}
<script type="text/javascript">
{% include "repo_setting_extra_js.html" %}
var user_perm_add_tr = $('.user-perm-add-tr'),
group_perm_add_tr = $('.group-perm-add-tr');
$('#user-tab').click(function() {
group_perm_add_tr.addClass('hide');
});
$('#group-tab').click(function() {
user_perm_add_tr.addClass('hide');
});
var user_list = [], contact,
group_list = [], group_name, group_id,
user_input = $('#perm-add-user'),
group_input = $('#perm-add-grp-name');
{% for contact in contacts %}
contact = '{{ contact }}';
user_list.push({value:contact, label:contact});
{% endfor %}
{% for group in request.user.joined_groups %}
group_name = '{{ group.group_name }}';
group_id = '{{ group.id }}';
group_list.push({value:group_id, label:group_name});
{% endfor %}
user_input.bind('autocompleteopen', function(e, ui) {
var widget = user_input.autocomplete('widget');
widget.css({'max-width':user_input.width() - 2 * parseInt(widget.css('padding')), 'max-height':$(window).height() + $(window).scrollTop() - user_input.offset().top - user_input.outerHeight()});
})
.autocomplete({
source: user_list
});
group_input.bind('autocompleteopen', function(e, ui) {
var widget = group_input.autocomplete('widget');
widget.css({'max-width':group_input.width() - 2 * parseInt(widget.css('padding')), 'max-height':$(window).height() + $(window).scrollTop() - group_input.offset().top - group_input.outerHeight()});
})
.autocomplete({
source: group_list,
select: function(event, ui) {
// prevent autocomplete from updating the textbox
event.preventDefault();
// manually update the textbox and hidden field
group_input.val(ui.item.label);
$('#perm-add-grp-id').val(ui.item.value);
}
});
$('#folder-perm-add-btn').click(function() {
if (is_user_tab == true) {
user_perm_add_tr.removeClass('hide');
$('.user-perm-add-folder-name').val('');
user_input.focus().val('');
} else {
group_perm_add_tr.removeClass('hide');
$('.group-perm-add-folder-name').val('');
group_input.focus().val('');
}
});
$('.perm-toggle-select').on('change', function() {
var select = $(this),
perm_item = select.parents('.perm-item'),
path = perm_item.attr('data-path'),
perm = select.val();
if (is_user_tab == true) {
var user = perm_item.attr('data-user'),
data = { 'user': user, 'path': path, 'perm': perm },
url = '{% url 'toggle_user_folder_permission' repo.id %}';
} else {
var group_id = perm_item.attr('data-group_id'),
data = { 'group_id': group_id, 'path': path, 'perm': perm },
url = '{% url 'toggle_group_folder_permission' repo.id %}';
}
perm_toggle(select, data, url)
});
$('.perm-delete-btn').on('click', function() {
var perm_item = $(this).parents('.perm-item'),
path = perm_item.attr('data-path');
if (is_user_tab == true) {
var user = perm_item.attr('data-user'),
data = { 'user': user, 'path': path },
url = '{% url 'remove_user_folder_permission' repo.id %}';
} else {
var group_id = perm_item.attr('data-group_id'),
data = { 'group_id': group_id, 'path': path },
url = '{% url 'remove_group_folder_permission' repo.id %}';
}
$.ajax({
url: url,
dataType: 'json',
data: data,
success: function() {
perm_item.remove();
feedback("{% trans "Delete succeeded" %}", 'success');
},
error: ajaxErrorHandler
});
});
$('.perm-add-submit').click(function() {
if (is_user_tab == true) {
var path = $('.user-perm-add-folder-path').val();
if (!$.trim(path)) {
path = $('.user-perm-add-folder-name').val();
}
var user = user_input.val(),
perm = $('.user-perm-add-perm').val(),
data = { 'user': user, 'path': path, 'perm': perm },
url = '{% url 'add_user_folder_permission' repo.id %}';
} else {
var path = $('.group-perm-add-folder-path').val();
if (!$.trim(path)) {
path = $('.group-perm-add-folder-name').val();
}
var group_id = $('#perm-add-grp-id').val(),
perm = $('.group-perm-add-perm').val(),
data = { 'group_id': group_id, 'path': path, 'perm': perm },
url = '{% url 'add_group_folder_permission' repo.id %}';
}
$.ajax({
url: url,
type: 'POST',
cache: false,
dataType: 'json',
beforeSend: prepareCSRFToken,
data: data,
success: function() {
location.reload();
},
error: ajaxErrorHandler
});
});
$('.perm-add-select-folder').click(function() {
$('#perm-add-jstree-wrap').modal({appendTo:'#main', autoResize:true, focus:false});
$('#simplemodal-container').css({'width':'auto', 'height':'auto'});
render_jstree($('#perm-add-jstree'))
});
function selectClickHandler(event) {
var path, folder_name, folder_path,
path_array = event.data.path_array;
if (is_user_tab == true) {
folder_name = $('.user-perm-add-folder-name');
folder_path = $('.user-perm-add-folder-path');
} else {
folder_name = $('.group-perm-add-folder-name');
folder_path = $('.group-perm-add-folder-path');
}
if (path_array.length == 1) {
path = path_array.shift();
folder_name.val('Root Directory');
} else {
var root = path_array.shift(),
path = root + path_array.join('/'),
name = path.split('/');
folder_name.val(name.pop());
}
folder_path.val(path);
$.modal.close();
};
function render_jstree(container) {
var base_path = '/', loading_tip = $('.loading-tip'),
file_tree = new FileTree();
container.data('site_root', '{{SITE_ROOT}}');
container.data('repo_id', '{{repo.id}}');
$.ajax({
url: '{% url 'get_dirents' repo.id %}?path=' + e(base_path) + '&dir_only=true&all_dir=true',
cache: false,
dataType: 'json',
success: function(data) {
var json_data = [], children = [],
repo_data = {'data': base_path, 'attr': {'root_node': true}, 'state': 'open'};
for (var i = 0, len = data[0].length; i < len; i++) {
children.push({ 'data': data[0][i], 'state': 'closed' });
}
if (children.length > 0) {
$.extend(repo_data, {'children': children});
}
json_data.push(repo_data);
loading_tip.hide();
file_tree.renderDirTreeByRepo(container, json_data, selectClickHandler);
container.removeClass('hide');
},
error: function() {
var cur_repo = [{
'data': base_path,
'attr': {'root_node': true},
'state': 'open'
}];
loading_tip.hide();
renderDirTree(container, json_data);
container.removeClass('hide');
}
});
}
$('.perm-add-jstree-select').click(function() {
if($("#perm-add-jstree:has('.jstree-clicked')").length == 0) {
$('#perm-add-jstree-wrap').find('.error')
.removeClass('hide')
.html('Please select a folder');
}
});
</script>
{% endblock %}

View File

@ -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');
}
});

View File

@ -1,359 +0,0 @@
{% extends "myhome_base.html" %}
{% load i18n avatar_tags seahub_tags %}
{% block sub_title %}{{repo.name}} - {% endblock %}
{% block extra_style %}
<style type="text/css">
#left-panel { position: relative; }
.go-back { top:0; }
</style>
{% endblock %}
{% block left_panel %}
<a class="go-back" title="{% trans "Back to Library" %}" href="{% url 'repo' repo.id %}"><span class="icon-chevron-left"></span></a>
<div class="side-textnav">
<ul class="side-textnav-tabs">
<li class="tab tab-cur"><a href="#basic-info">{% trans "Basic Info" %}</a></li>
<li class="tab"><a href="#transfer-ownership">{% trans "Transfer Ownership" %}</a></li>
{% if repo.encrypted and repo.enc_version == 2 %}
<li class="tab"><a href="#change-password">{% trans "Change Password" %}</a></li>
{% endif %}
{% if not repo.encrypted %}
<li class="tab"><a href="#shared-links">{% trans "Shared Links" %}</a></li>
{% endif %}
</ul>
</div>
{% endblock %}
{% block right_panel %}
<div class="lib-setting">
<h2>{% trans "Library Settings" %}</h2>
<div id="basic-info" class="setting-item">
<h3>{% trans "Basic Info" %}</h3>
<form id="repo-basic-info-form" action="" method="post" class="form">{% csrf_token %}
<label>{% trans "Name" %}</label><br />
<input type="text" name="repo_name" value="{{ repo.name }}" class="input" /><br />
<label>{% trans "Description" %}</label></br />
<textarea name="repo_desc" class="textarea">{{ repo.desc }}</textarea><br />
{% if not ENABLE_SUB_LIBRARY or not repo.is_virtual %}
<label>{% trans "History" %}</label><br />
<input type="radio" name="history" value="full_history" {% if full_history_checked %}checked="checked"{% endif %} class="vam" {% if not full_history_enabled %}disabled="disabled"{% endif %} /> <span class="vam">{% trans "Keep full history" %}</span><br />
<input type="radio" name="history" value="no_history" {% if no_history_checked %}checked="checked"{% endif %} class="vam" {% if not full_history_enabled %}disabled="disabled"{% endif %} /> <span class="vam">{% trans "Don't keep history" %}</span><br />
<input type="radio" name="history" value="partial_history" {% if partial_history_checked %}checked="checked"{% endif %} class="vam" {% if not full_history_enabled %}disabled="disabled"{% endif %} /> <span calss="vam">{% trans "Only keep a period of history:" %}
<input type="text" name="days" size="4" {% if not days_enabled %} disabled="disabled" class="input-disabled"{% endif %} value="{{history_limit}}" /> {% trans "days" %}</span><br />
{% endif %}
<p class="error hide"></p>
<input type="submit" value="{% trans "Submit" %}" class="submit" />
</form>
</div>
<div id="transfer-ownership" class="setting-item hide">
<h3>{% trans "Transfer Ownership" %}</h3>
<form id="repo-owner-form" action="" method="post" class="form">{% csrf_token %}
<p>{% trans "Transfer this library to another user:" %}</p>
<input type="text" name="repo_owner" value="" placeholder="{% trans "Email" %}" class="input" /><br />
<p class="error hide"></p>
<input type="submit" value="{% trans "Submit" %}" class="submit" />
</form>
</div>
{% if repo.encrypted and repo.enc_version == 2 %}
<div id="change-password" class="setting-item hide">
<h3>{% trans "Change Password" %}</h3>
<form id="repo-change-passwd-form" action="" method="post" class="form">{% csrf_token %}
<p>{% trans "Change the password of this library:" %}</p>
<label>{% trans "Old Password" %}</label><br />
<input type="password" name="old_passwd" class="input" /><br />
<label>{% blocktrans %}New Password(at least {{repo_password_min_length}} characters){% endblocktrans %}</label><br />
<input type="password" name="new_passwd" class="input" /><br />
<label>{% trans "New Password Again" %}</label><br />
<input type="password" name="new_passwd_again" class="input" /><br />
<p class="error hide"></p>
<input type="submit" value="{% trans "Submit" %}" class="submit" />
</form>
</div>
{% endif %}
{% if not repo.encrypted %}
<div id="shared-links" class="setting-item hide">
<h3>{% trans "Shared Links" %}</h3>
<p>{% trans "View and manage all the shared links in this library." %}</p>
<div id="tabs" class="tab-tabs">
<ul class="tab-tabs-nav hd ovhd">
<li class="tab"><a href="#upload-links" class="a">{% trans "Upload Links" %}</a></li>
<li class="tab"><a href="#download-links" class="a">{% trans "Download Links" %}</a></li>
</ul>
<div id="upload-links">
<table>
<tr>
<th width="5%"><!--icon--></th>
<th width="40%">{% trans "Name"%}</th>
<th width="15%">{% trans "Created By"%}</th>
<th width="15%">{% trans "Size"%}</th>
<th width="12%">{% trans "Visits"%}</th>
<th width="13%">{% trans "Operations"%}</th>
</tr>
{% if uploadlinks %}
{% for link in uploadlinks %}
<tr>
<td class="alc"><img src="{{ MEDIA_URL }}img/folder-icon-24.png" alt="{% trans "Directory icon"%}" /></td>
<td><a href="{% url 'repo' repo.id %}?p={{ link.path|urlencode }}">{{ link.dir_name }}</a></td>
<td><a href="{% url 'user_profile' link.username %}">{{ link.username|email2nickname }}</a></td>
<td>--</td>
<td>{{ link.view_cnt }}</td>
<td>
<span class="icon-trash op-icon vh rm-link" data-token={{ link.token }} data-type="upload" title="{% trans "Remove"%}"></span>
</td>
</tr>
{% endfor %}
{% endif %}
</table>
</div>
<div id="download-links" class="hide">
<table>
<tr>
<th width="5%"><!--icon--></th>
<th width="40%">{% trans "Name"%}</th>
<th width="15%">{% trans "Created By"%}</th>
<th width="15%">{% trans "Size"%}</th>
<th width="12%">{% trans "Visits"%}</th>
<th width="13%">{% trans "Operations"%}</th>
</tr>
{% if fileshares %}
{% for link in fileshares %}
<tr>
{% if link.s_type == 'd'%}
<td class="alc"><img src="{{ MEDIA_URL }}img/folder-icon-24.png" alt="{% trans "Directory icon"%}" /></td>
<td><a href="{% url 'repo' repo.id %}?p={{ link.path|urlencode }}">{{ link.filename }}</a></td>
<td><a href="{% url 'user_profile' link.username %}">{{ link.username|email2nickname }}</a></td>
{% else %}
<td class="alc"><img src="{{ MEDIA_URL }}img/file/{{ link.filename|file_icon_filter }}" alt="{% trans "File"%}" /></td>
<td><a href="{% url 'repo_view_file' repo.id %}?p={{ link.path|urlencode }}">{{ link.filename }}</a></td>
<td><a href="{% url 'user_profile' link.username %}">{{ link.username|email2nickname }}</a></td>
{% endif %}
<td>{{ link.filesize|filesizeformat}}</td>
<td>{{ link.view_cnt }}</td>
<td>
<span class="icon-trash op-icon vh rm-link" data-token={{ link.token }} data-type="download" title="{% trans "Remove"%}"></span>
</td>
</tr>
{% endfor %}
{% endif %}
</table>
</div>
</div>
</div>
{% endif %}
</div>
{% endblock %}
{% block extra_script %}
<script type="text/javascript">
$('#repo-basic-info-form input[name="history"]').change(function() {
var value = $(this).attr('value'),
days_input = $('#repo-basic-info-form input[name="days"]');
if (value == 'full_history' || value == 'no_history') {
days_input.attr('disabled', true).addClass('input-disabled');
} else {
days_input.attr('disabled', false).removeClass('input-disabled');
}
});
$('#repo-basic-info-form').submit(function() {
var form = $(this),
form_id = form.attr('id');
var repo_name = $('[name="repo_name"]', form).val(),
repo_desc = $('[name="repo_desc"]', form).val();
if (!$.trim(repo_name)) {
apply_form_error(form_id, "{% trans "Name is required." %}");
return false;
}
if (!$.trim(repo_desc)) {
apply_form_error(form_id, "{% trans "Description is required." %}");
return false;
}
var days;
var value = $(this).find('input[name="history"]:checked').val();
if (value == 'partial_history') {
days = $(this).find('input[name="days"]').val();
} else if (value == 'full_history') {
days = -1;
} else {
days = 0;
}
var submit_btn = $(this).children('input[type="submit"]');
disable(submit_btn);
$.ajax({
url: '{% url 'repo_change_basic_info' repo.id %}',
type: 'POST',
dataType: 'json',
beforeSend: prepareCSRFToken,
data: {
'repo_name': repo_name,
'repo_desc': repo_desc,
'days': days
},
success: function(data) {
if (data['success']) {
location.reload(true);
}
},
error: function(jqXHR, textStatus, errorThrown) {
if (jqXHR.responseText) {
apply_form_error(form_id, $.parseJSON(jqXHR.responseText).error);
} else {
apply_form_error(form_id, "{% trans "Failed. Please check the network." %}");
}
enable(submit_btn);
}
});
return false;
});
$('#repo-owner-form').submit(function() {
var form = $(this),
form_id = form.attr('id'),
new_owner = $('[name="repo_owner"]', form).val(),
submit_btn = $('input[type="submit"]', form);
if (!$.trim(new_owner)) {
return false;
}
disable(submit_btn);
$.ajax({
url: '{% url 'repo_transfer_owner' repo.id %}',
type: 'POST',
dataType: 'json',
beforeSend: prepareCSRFToken,
data: {
'repo_owner': new_owner
},
success: function(data) {
if (data['success']) {
location.href = '{% url 'myhome' %}';
}
},
error: function(jqXHR, textStatus, errorThrown) {
if (jqXHR.responseText) {
apply_form_error(form_id, $.parseJSON(jqXHR.responseText).error);
} else {
apply_form_error(form_id, "{% trans "Failed. Please check the network." %}");
}
enable(submit_btn);
}
});
return false;
});
{% if repo.encrypted and repo.enc_version == 2 %}
$('#repo-change-passwd-form').submit(function() {
var form = $(this),
form_id = form.attr('id'),
old_passwd, new_passwd, new_passwd_again;
old_passwd = $('input[name="old_passwd"]', form).val();
new_passwd = $('input[name="new_passwd"]', form).val();
new_passwd_again = $('input[name="new_passwd_again"]', form).val();
if (!$.trim(old_passwd)) {
apply_form_error(form_id, "{% trans "Please enter the old password" %}");
return false;
}
if (!$.trim(new_passwd)) {
apply_form_error(form_id, "{% trans "Please enter the new password" %}");
return false;
}
if ($.trim(new_passwd).length < {{repo_password_min_length}}) {
apply_form_error(form_id, "{% trans "New password is too short" %}");
return false;
}
if (!$.trim(new_passwd_again)) {
apply_form_error(form_id, "{% trans "Please enter the new password again" %}");
return false;
}
if ($.trim(new_passwd) != $.trim(new_passwd_again)) {
apply_form_error(form_id, "{% trans "New passwords don't match" %}");
return false;
}
var submit_btn = $(this).children('input[type="submit"]');
disable(submit_btn);
$.ajax({
url: '{% url 'repo_change_passwd' repo.id %}',
type: 'POST',
dataType: 'json',
beforeSend: prepareCSRFToken,
data: {
'old_passwd': old_passwd,
'new_passwd': new_passwd,
'new_passwd_again': new_passwd_again
},
success: function(data) {
if (data['success']) {
location.reload(true);
}
},
error: function(jqXHR, textStatus, errorThrown) {
if (jqXHR.responseText) {
apply_form_error(form_id, $.parseJSON(jqXHR.responseText).error);
} else {
apply_form_error(form_id, "{% trans "Failed. Please check the network." %}");
}
enable(submit_btn);
}
});
return false;
});
{% endif %}
$('.side-textnav-tabs .tab').click(function() {
var cur_tab = $(this),
cur_tab_con = $($('a', cur_tab).attr('href'));
$('.side-textnav-tabs .tab').removeClass('tab-cur');
$('.lib-setting .setting-item').addClass('hide');
cur_tab.addClass('tab-cur');
cur_tab_con.removeClass('hide')
return false;
});
{% if not repo.encrypted %}
$('#shared-links .rm-link').click(function() {
var op = $(this),
link_token = op.data('token'),
link_type = op.data('type'),
ajax_url;
if (link_type == 'upload') {
ajax_url = '{% url 'ajax_remove_shared_upload_link' %}';
} else {
ajax_url = '{% url 'ajax_remove_shared_link' %}';
}
$.ajax({
url: ajax_url + '?t=' + e(link_token),
dataType: 'json',
success: function(data) {
op.parents('tr').remove();
feedback("{% trans "Removed successfully." %}", 'success');
},
error: ajaxErrorHandler
});
return false;
});
{% endif %}
</script>
{% endblock %}

View File

@ -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 %}
<style type="text/css">
#left-panel { position: relative; }
.go-back { top:0; }
</style>
{% endblock %}
{% block left_panel %}
<a class="go-back" title="{% trans "Back to Library" %}" href="{% url 'repo' repo.id %}"><span class="icon-chevron-left"></span></a>
<div class="side-textnav">
<ul class="side-textnav-tabs">
<li class="tab"><a href="{% url 'repo_basic_info' repo.id %}">{% trans "Basic Info" %}</a></li>
<li class="tab"><a href="{% url 'repo_transfer_owner' repo.id %}">{% trans "Transfer Ownership" %}</a></li>
{% if repo.encrypted and repo.enc_version == 2 %}
<li class="tab"><a href="{% url 'repo_change_password' repo.id %}">{% trans "Change Password" %}</a></li>
{% endif %}
{% if not repo.encrypted %}
<li class="tab"><a href="{% url 'repo_shared_link' repo.id %}">{% trans "Shared Links" %}</a></li>
{% endif %}
<li class="tab tab-cur"><a href="{% url 'repo_share_manage' repo.id %}">{% trans "Sharing Management" %}</a></li>
<li class="tab"><a href="{% url 'repo_folder_perm' repo.id %}">{% trans "SubFolder Permission" %}</a></li>
</ul>
</div>
{% endblock %}
{% block right_panel %}
<div class="lib-setting">
<h2>{% trans "Library Settings" %}</h2>
<h3>{% trans "Sharing Management" %}</h3>
<p>{% trans "View and manage all the share of this library." %}</p>
<div id="tabs" class="tab-tabs">
<div class="hd ovhd">
<ul class="tab-tabs-nav fleft">
<li class="tab"><a href="#user-tab" class="a" id="user-tab">{% trans "User" %}</a></li>
<li class="tab"><a href="#group-tab" class="a" id="group-tab">{% trans "Group" %}</a></li>
</ul>
<div class="fright">
<button class="repo-share-btn"><img src="{{ MEDIA_URL }}img/add.png" alt="" class="add vam" /><span class="vam">{% trans "Share Library" %}</span></button>
</div>
</div>
<div id="user-tab">
<table>
<tr>
<th width="40%">{% trans "Share To"%}</th>
<th width="40%">{% trans "Permission"%}</th>
<th width="20%">{% trans "Operations"%}</th>
</tr>
{% if repo_share_user %}
{% for share in repo_share_user %}
<tr class="perm-item" data-to_user="{{ share.user }}">
<td><a href="{% url 'user_profile' share.user %}">{{ share.user }}</a></td>
<td>
<div class="perm-change">
{% if share.permission == 'rw' %}
<span class="share-perm-cur-value">{% trans "Read-Write" %}</span>
{% else %}
<span class="share-perm-cur-value">{% trans "Read-Only" %}</span>
{% endif %}
<img src="{{MEDIA_URL}}img/edit_12.png" alt="{% trans "Edit"%}" title="{% trans "Edit"%}" class="perm-edit-icon cspt vh" />
</div>
<select class="perm-toggle-select hide">
<option value="rw" {%if share.permission == 'rw' %}selected="selected"{% endif %}>{% trans "Read-Write" %}</option>
<option value="r" {%if not share.permission == 'rw' %}selected="selected"{% endif %}>{% trans "Read-Only"%}</option>
</select>
</td>
<td>
<a href="{% url 'repo_remove_share' %}?repo_id={{ share.repo_id }}&from={{ request.user.username|urlencode }}&to={{ share.user|urlencode }}" class="cancel-share op-icon vh" title="{% trans "Unshare"%}"><img src="{{MEDIA_URL}}img/rm.png" alt="" /></a>
</td>
</tr>
{% endfor %}
{% endif %}
</table>
</div>
<div id="group-tab" class="hide">
<table>
<tr>
<th width="40%">{% trans "Share To"%}</th>
<th width="40%">{% trans "Permission"%}</th>
<th width="20%">{% trans "Operations"%}</th>
</tr>
{% if repo_share_group %}
{% for share in repo_share_group %}
<tr class="perm-item" data-group_id="{{ share.group_id }}">
<td><a href="{% url 'group_info' share.group_id%}">{{ share.group_name }}</a></td>
<td>
<div class="perm-change">
{% if share.permission == 'rw' %}
<span class="perm-cur-value">{% trans "Read-Write" %}</span>
{% else %}
<span class="perm-cur-value">{% trans "Read-Only" %}</span>
{% endif %}
<img src="{{MEDIA_URL}}img/edit_12.png" alt="{% trans "Edit"%}" title="{% trans "Edit"%}" class="perm-edit-icon cspt vh" />
</div>
<select class="perm-toggle-select hide">
<option value="rw" {%if share.permission == 'rw' %}selected="selected"{% endif %}>{% trans "Read-Write" %}</option>
<option value="r" {%if not share.permission == 'rw' %}selected="selected"{% endif %}>{% trans "Read-Only"%}</option>
</select>
</td>
<td>
<a href="{% url 'repo_remove_share' %}?repo_id={{ share.repo_id }}&from={{ request.user.username|urlencode }}&gid={{ share.group_id }}" class="cancel-share op-icon vh" title="{% trans "Unshare"%}"><img src="{{MEDIA_URL}}img/rm.png" alt="" /></a>
</td>
</tr>
{% endfor %}
{% endif %}
</table>
</div>
</div>
</div>
{% url 'share_repo' as repo_share_url %}
{% with post_url=repo_share_url %}
{% include "snippets/repo_share_form.html" %}
{% endwith %}
{% endblock %}
{% block extra_script %}
<script type="text/javascript">
$(function () {
$.ajax({
url:'{% url 'get_contacts' %}',
cache: false,
dataType: 'json',
success: function(data) {
var share_list = [];
var contacts = data['contacts'], contact_email, group_name, group_name_py;
for (var i = 0, len = contacts.length; i < len; i++) {
contact_email = contacts[i].email;
share_list.push({value:contact_email, label:contact_email});
}
{% for group in request.user.joined_groups %}
group_name = '{{ group.group_name }}';
group_name_py = '{{ group.group_name|char2pinyin }}'
share_list.push({value:group_name + group_name_py, label:group_name});
{% endfor %}
$(".repo-share-btn").click(function() {
var form = $("#repo-share-form"),
hd = $('.hd', form),
btn_ct = $(this).parents('td'),
repo_name = btn_ct.attr('data-name');
var grp_options_ct = $('#share-grp-options');
if (!$.trim(grp_options_ct.html())) {
var grp_options = '<ul class="option-list">';
{% for group in request.user.joined_groups %}
grp_options += '<li> <label class="checkbox-label"> <span class="checkbox"><input type="checkbox" name="grp" value="{{ group.group_name }}" class="checkbox-orig"/></span> {% grp_avatar group.id 20 %} <span class="checkbox-option">{{ group.group_name }}</span> </label> </li>';
{% endfor %}
grp_options += '</ul>';
grp_options_ct.html(grp_options);
}
var contact_options_ct = $('#share-contact-options');
if (!$.trim(contact_options_ct.html())) {
var contact_options = '<ul class="option-list">';
for (var i = 0, len = contacts.length; i < len; i++) {
contact_email = contacts[i].email;
contact_options += ' <li> <label class="checkbox-label"> <span class="checkbox"><input type="checkbox" name="contact" value="' + contact_email + '" class="checkbox-orig" /></span>' + contacts[i].avatar + ' <span class="checkbox-option">' + contact_email + '</span> </label> </li>';
}
contact_options += '</ul>';
contact_options_ct.html(contact_options);
}
$('.checkbox-orig', form).unbind().click(function() {
$(this).parent().toggleClass('checkbox-checked');
});
$(".checkbox-label", form).unbind().hover(
function() {
$(this).addClass('hl');
},
function() {
$(this).removeClass('hl');
}
);
form.modal({appendTo: "#main", focus:false, containerCss:{"padding": 0}});
$('[name="repo_id"]', form).val('{{repo.id}}');
hd.html(hd.html().replace('%(lib_name)s', '<span class="op-target">' + repo_name + '</span>'));
$('#repo-share-tabs').tabs();
$('#simplemodal-container').css('height', 'auto');
addAutocomplete('#email_or_group', '#repo-share-form', share_list);
});
}
});
});
//check before post
$('#share-submit-btn').click(function() {
var form = $("#repo-share-form"),
cur_tab_id = $('.ui-tabs-selected a', form).attr('href'),
post_data = '',
input = $('[name="email_or_group"]', form);
switch(cur_tab_id) {
case '#share-enter':
post_data = input.val();
break;
case '#share-grp-options':
case '#share-contact-options':
$(cur_tab_id + ' .checkbox-checked .checkbox-orig').each(function() {
post_data += $(this).val() + ',';
});
input.val(post_data);
}
if (!post_data) {
apply_form_error(form.attr('id'), "{% trans "Please enter emails or groups, or select some." %}");
return false;
}
form.submit();
disable($(this));
});
{% include "repo_setting_extra_js.html" %}
$('.perm-toggle-select').on('change', function() {
var select = $(this),
perm_item = select.parents('.perm-item'),
perm = select.val();
if (is_user_tab == true) {
var to_user = perm_item.attr('data-to_user'),
data = { repo_id: '{{repo.id}}', email_or_group: to_user, permission: perm },
url = '{% url 'share_permission_admin' %}?share_type=' + 'personal';
} else {
var group_id = perm_item.attr('data-group_id'),
data = { repo_id: '{{repo.id}}', email_or_group: group_id, permission: perm },
url = '{% url 'share_permission_admin' %}?share_type=' + 'group';
}
perm_toggle(select, data, url)
});
</script>
{% endblock %}

View File

@ -0,0 +1,130 @@
{% extends "myhome_base.html" %}
{% load i18n avatar_tags seahub_tags %}
{% block sub_title %}{{repo.name}} - {% endblock %}
{% block extra_style %}
<style type="text/css">
#left-panel { position: relative; }
.go-back { top:0; }
</style>
{% endblock %}
{% block left_panel %}
<a class="go-back" title="{% trans "Back to Library" %}" href="{% url 'repo' repo.id %}"><span class="icon-chevron-left"></span></a>
<div class="side-textnav">
<ul class="side-textnav-tabs">
<li class="tab"><a href="{% url 'repo_basic_info' repo.id %}">{% trans "Basic Info" %}</a></li>
<li class="tab"><a href="{% url 'repo_transfer_owner' repo.id %}">{% trans "Transfer Ownership" %}</a></li>
{% if repo.encrypted and repo.enc_version == 2 %}
<li class="tab"><a href="{% url 'repo_change_password' repo.id %}">{% trans "Change Password" %}</a></li>
{% endif %}
{% if not repo.encrypted %}
<li class="tab tab-cur"><a href="{% url 'repo_shared_link' repo.id %}">{% trans "Shared Links" %}</a></li>
{% endif %}
<li class="tab"><a href="{% url 'repo_share_manage' repo.id %}">{% trans "Sharing Management" %}</a></li>
<li class="tab"><a href="{% url 'repo_folder_perm' repo.id %}">{% trans "SubFolder Permission" %}</a></li>
</ul>
</div>
{% endblock %}
{% block right_panel %}
<div class="lib-setting">
<h2>{% trans "Library Settings" %}</h2>
<div id="shared-links" class="setting-item">
<h3>{% trans "Shared Links" %}</h3>
<p>{% trans "View and manage all the shared links in this library." %}</p>
<div id="tabs" class="tab-tabs">
<ul class="tab-tabs-nav hd ovhd">
<li class="tab"><a href="#upload-links" class="a">{% trans "Upload Links" %}</a></li>
<li class="tab"><a href="#download-links" class="a">{% trans "Download Links" %}</a></li>
</ul>
<div id="upload-links">
<table>
<tr>
<th width="5%"><!--icon--></th>
<th width="40%">{% trans "Name"%}</th>
<th width="15%">{% trans "Created By"%}</th>
<th width="15%">{% trans "Size"%}</th>
<th width="12%">{% trans "Visits"%}</th>
<th width="13%">{% trans "Operations"%}</th>
</tr>
{% if uploadlinks %}
{% for link in uploadlinks %}
<tr>
<td class="alc"><img src="{{ MEDIA_URL }}img/folder-icon-24.png" alt="{% trans "Directory icon"%}" /></td>
<td><a href="{% url 'repo' repo.id %}?p={{ link.path|urlencode }}">{{ link.dir_name }}</a></td>
<td><a href="{% url 'user_profile' link.username %}">{{ link.username|email2nickname }}</a></td>
<td>--</td>
<td>{{ link.view_cnt }}</td>
<td>
<span class="icon-trash op-icon vh rm-link" data-token={{ link.token }} data-type="upload" title="{% trans "Remove"%}"></span>
</td>
</tr>
{% endfor %}
{% endif %}
</table>
</div>
<div id="download-links" class="hide">
<table>
<tr>
<th width="5%"><!--icon--></th>
<th width="40%">{% trans "Name"%}</th>
<th width="15%">{% trans "Created By"%}</th>
<th width="15%">{% trans "Size"%}</th>
<th width="12%">{% trans "Visits"%}</th>
<th width="13%">{% trans "Operations"%}</th>
</tr>
{% if fileshares %}
{% for link in fileshares %}
<tr>
{% if link.s_type == 'd'%}
<td class="alc"><img src="{{ MEDIA_URL }}img/folder-icon-24.png" alt="{% trans "Directory icon"%}" /></td>
<td><a href="{% url 'repo' repo.id %}?p={{ link.path|urlencode }}">{{ link.filename }}</a></td>
<td><a href="{% url 'user_profile' link.username %}">{{ link.username|email2nickname }}</a></td>
{% else %}
<td class="alc"><img src="{{ MEDIA_URL }}img/file/{{ link.filename|file_icon_filter }}" alt="{% trans "File"%}" /></td>
<td><a href="{% url 'repo_view_file' repo.id %}?p={{ link.path|urlencode }}">{{ link.filename }}</a></td>
<td><a href="{% url 'user_profile' link.username %}">{{ link.username|email2nickname }}</a></td>
{% endif %}
<td>{{ link.filesize|filesizeformat}}</td>
<td>{{ link.view_cnt }}</td>
<td>
<span class="icon-trash op-icon vh rm-link" data-token={{ link.token }} data-type="download" title="{% trans "Remove"%}"></span>
</td>
</tr>
{% endfor %}
{% endif %}
</table>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_script %}
<script type="text/javascript">
$('#shared-links .rm-link').click(function() {
var op = $(this),
link_token = op.data('token'),
link_type = op.data('type'),
ajax_url;
if (link_type == 'upload') {
ajax_url = '{% url 'ajax_remove_shared_upload_link' %}';
} else {
ajax_url = '{% url 'ajax_remove_shared_link' %}';
}
$.ajax({
url: ajax_url + '?t=' + e(link_token),
dataType: 'json',
success: function(data) {
op.parents('tr').remove();
feedback("{% trans "Removed successfully." %}", 'success');
},
error: ajaxErrorHandler
});
return false;
});
</script>
{% endblock %}

View File

@ -0,0 +1,85 @@
{% extends "myhome_base.html" %}
{% load i18n avatar_tags seahub_tags %}
{% block sub_title %}{{repo.name}} - {% endblock %}
{% block extra_style %}
<style type="text/css">
#left-panel { position: relative; }
.go-back { top:0; }
</style>
{% endblock %}
{% block left_panel %}
<a class="go-back" title="{% trans "Back to Library" %}" href="{% url 'repo' repo.id %}"><span class="icon-chevron-left"></span></a>
<div class="side-textnav">
<ul class="side-textnav-tabs">
<li class="tab"><a href="{% url 'repo_basic_info' repo.id %}">{% trans "Basic Info" %}</a></li>
<li class="tab tab-cur"><a href="{% url 'repo_transfer_owner' repo.id %}">{% trans "Transfer Ownership" %}</a></li>
{% if repo.encrypted and repo.enc_version == 2 %}
<li class="tab"><a href="{% url 'repo_change_password' repo.id %}">{% trans "Change Password" %}</a></li>
{% endif %}
{% if not repo.encrypted %}
<li class="tab"><a href="{% url 'repo_shared_link' repo.id %}">{% trans "Shared Links" %}</a></li>
{% endif %}
<li class="tab"><a href="{% url 'repo_share_manage' repo.id %}">{% trans "Sharing Management" %}</a></li>
<li class="tab"><a href="{% url 'repo_folder_perm' repo.id %}">{% trans "SubFolder Permission" %}</a></li>
</ul>
</div>
{% endblock %}
{% block right_panel %}
<div class="lib-setting">
<h2>{% trans "Library Settings" %}</h2>
<div id="transfer-ownership" class="setting-item">
<h3>{% trans "Transfer Ownership" %}</h3>
<form id="repo-owner-form" action="" method="post" class="form">{% csrf_token %}
<p>{% trans "Transfer this library to another user:" %}</p>
<input type="text" name="repo_owner" value="" placeholder="{% trans "Email" %}" class="input" /><br />
<p class="error hide"></p>
<input type="submit" value="{% trans "Submit" %}" class="submit" />
</form>
</div>
</div>
{% endblock %}
{% block extra_script %}
<script type="text/javascript">
$('#repo-owner-form').submit(function() {
var form = $(this),
form_id = form.attr('id'),
new_owner = $('[name="repo_owner"]', form).val(),
submit_btn = $('input[type="submit"]', form);
if (!$.trim(new_owner)) {
return false;
}
disable(submit_btn);
$.ajax({
url: '{% url 'ajax_repo_transfer_owner' repo.id %}',
type: 'POST',
dataType: 'json',
beforeSend: prepareCSRFToken,
data: {
'repo_owner': new_owner
},
success: function(data) {
if (data['success']) {
location.href = '{% url 'myhome' %}';
}
},
error: function(jqXHR, textStatus, errorThrown) {
if (jqXHR.responseText) {
apply_form_error(form_id, $.parseJSON(jqXHR.responseText).error);
} else {
apply_form_error(form_id, "{% trans "Failed. Please check the network." %}");
}
enable(submit_btn);
}
});
return false;
});
</script>
{% endblock %}

View File

@ -83,10 +83,12 @@ urlpatterns = patterns('',
url(r'^repo/(?P<repo_id>[-0-9a-f]{36})/privshare/$', gen_private_file_share, name='gen_private_file_share'),
url(r'^repo/(?P<repo_id>[-0-9a-f]{36})/(?P<obj_id>[0-9a-f]{40})/$', repo_access_file, name='repo_access_file'),
url(r'^repo/(?P<repo_id>[-0-9a-f]{36})/(?P<obj_id>[0-9a-f]{40})/download/$', download_file, name='download_file'),
url(r'^repo/(?P<repo_id>[-0-9a-f]{36})/settings/$', repo_settings, name='repo_settings'),
url(r'^repo/(?P<repo_id>[-0-9a-f]{36})/basic_info/$', repo_change_basic_info, name='repo_change_basic_info'),
url(r'^repo/(?P<repo_id>[-0-9a-f]{36})/owner/$', repo_transfer_owner, name='repo_transfer_owner'),
url(r'^repo/(?P<repo_id>[-0-9a-f]{36})/passwd/$', repo_change_passwd, name='repo_change_passwd'),
url(r'^repo/(?P<repo_id>[-0-9a-f]{36})/setting/basic-info/$', repo_basic_info, name='repo_basic_info'),
url(r'^repo/(?P<repo_id>[-0-9a-f]{36})/setting/transfer-owner/$', repo_transfer_owner, name='repo_transfer_owner'),
url(r'^repo/(?P<repo_id>[-0-9a-f]{36})/setting/change-password/$', repo_change_password, name='repo_change_password'),
url(r'^repo/(?P<repo_id>[-0-9a-f]{36})/setting/shared-link/$', repo_shared_link, name='repo_shared_link'),
url(r'^repo/(?P<repo_id>[-0-9a-f]{36})/setting/share-manage/$', repo_share_manage, name='repo_share_manage'),
url(r'^repo/(?P<repo_id>[-0-9a-f]{36})/setting/folder-perm/$', repo_folder_perm, name='repo_folder_perm'),
### share file/dir, upload link ###
url(r'^s/f/(?P<token>[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<repo_id>[-0-9a-f]{36})/setting/change-basic-info/$', ajax_repo_change_basic_info, name='ajax_repo_change_basic_info'),
url(r'^ajax/repo/(?P<repo_id>[-0-9a-f]{36})/setting/transfer-owner/$', ajax_repo_transfer_owner, name='ajax_repo_transfer_owner'),
url(r'^ajax/repo/(?P<repo_id>[-0-9a-f]{36})/setting/change-passwd/$', ajax_repo_change_passwd, name='ajax_repo_change_passwd'),
url(r'^ajax/repo/(?P<repo_id>[-0-9a-f]{36})/setting/user-folder-permission/add/$', add_user_folder_permission, name='add_user_folder_permission'),
url(r'^ajax/repo/(?P<repo_id>[-0-9a-f]{36})/setting/user-folder-permission/remove/$', remove_user_folder_permission, name='remove_user_folder_permission'),
url(r'^ajax/repo/(?P<repo_id>[-0-9a-f]{36})/setting/user-folder-permission/toggle/$', toggle_user_folder_permission, name='toggle_user_folder_permission'),
url(r'^ajax/repo/(?P<repo_id>[-0-9a-f]{36})/setting/group-folder-permission/add/$', add_group_folder_permission, name='add_group_folder_permission'),
url(r'^ajax/repo/(?P<repo_id>[-0-9a-f]{36})/setting/group-folder-permission/remove/$', remove_group_folder_permission, name='remove_group_folder_permission'),
url(r'^ajax/repo/(?P<repo_id>[-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'),

View File

@ -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}

View File

@ -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)

View File

@ -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)

View File

@ -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