diff --git a/media/css/seahub.css b/media/css/seahub.css
index 308221bf7f..b2024fe410 100644
--- a/media/css/seahub.css
+++ b/media/css/seahub.css
@@ -1848,6 +1848,7 @@ textarea:-moz-placeholder {/* for FF */
.displayed-op .op:hover {
text-decoration:none;
}
+.audit-item .audit-select-hidden,
.repo-file-list .hidden-op {
position:absolute;
background:#fff;
@@ -1856,6 +1857,7 @@ textarea:-moz-placeholder {/* for FF */
border-radius:5px;
z-index:10;
}
+.audit-select-hidden li a,
.hidden-op li a {
display:block;
padding:0 12px;
@@ -1864,6 +1866,13 @@ textarea:-moz-placeholder {/* for FF */
width:500px;
padding:10px 20px;
}
+.perm-dir-tree-cont {
+ padding:5px;
+ height:100px;
+ overflow:auto;
+ border:1px solid #eee;
+ margin:5px 0 10px;
+}
.file-tree-cont, .dir-tree-cont {
padding:5px;
height:280px;
@@ -3347,6 +3356,11 @@ textarea:-moz-placeholder {/* for FF */
}
/* repo setting */
+.user-perm-add-tr input,
+.group-perm-add-tr input {
+ padding:2px 5px;
+}
+
.user-perm-add-perm,
.group-perm-add-perm,
.perm-toggle-select,
@@ -3368,3 +3382,25 @@ textarea:-moz-placeholder {/* for FF */
#perm-add-jstree-wrap {
background:#fcfcfc;
}
+
+/* file audit*/
+.audit-show-select {
+ font-weight: normal;
+ font-size: 13px;
+ padding-right: 2px;
+}
+#audit-unselect-op div {
+ display: inline-block;
+ height: 20px;
+ border: 1px solid #ccc;
+ background: #f2f2f2;
+ cursor: pointer;
+}
+#audit-unselect-op span {
+ margin-right: 5px;
+}
+#audit-unselect-op a {
+ margin: 0 8px;
+ text-decoration: none;
+ font-size: 14px;
+}
diff --git a/seahub/api2/views.py b/seahub/api2/views.py
index 7c17879ac8..57be64c459 100644
--- a/seahub/api2/views.py
+++ b/seahub/api2/views.py
@@ -26,7 +26,6 @@ from django.http import HttpResponse, Http404
from django.template import RequestContext
from django.template.loader import render_to_string
from django.shortcuts import render_to_response
-from django.utils import timezone
from .throttling import ScopedRateThrottle
from .authentication import TokenAuthentication
@@ -63,6 +62,7 @@ from seahub.utils import gen_file_get_url, gen_token, gen_file_upload_url, \
get_org_user_events
from seahub.utils.star import star_file, unstar_file
from seahub.utils.file_types import IMAGE, DOCUMENT
+from seahub.utils.timeutils import utc_to_local
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, check_folder_permission
@@ -2549,12 +2549,6 @@ class EventsView(APIView):
else:
d['author'] = e.repo_owner
- def utc_to_local(dt):
- tz = timezone.get_default_timezone()
- utc = dt.replace(tzinfo=timezone.utc)
- local = timezone.make_naive(utc, tz)
- return local
-
epoch = datetime.datetime(1970, 1, 1)
local = utc_to_local(e.timestamp)
time_diff = local - epoch
diff --git a/seahub/group/templates/group/group_info.html b/seahub/group/templates/group/group_info.html
index 1ee53abf79..ab975492c7 100644
--- a/seahub/group/templates/group/group_info.html
+++ b/seahub/group/templates/group/group_info.html
@@ -49,7 +49,7 @@
{% endif %}
{{ repo.owner|email2nickname }} |
-
+ |
{% if is_staff or repo.share_from_me %}
{% endif %}
@@ -141,8 +141,9 @@ $('.cancel-share').click(function() {
var btn_ct = $(this).parent(),
repo_id = btn_ct.data('id'),
repo_owner = btn_ct.attr('data-owner'),
+ repo_perm = btn_ct.attr('data-perm'),
repo_name = btn_ct.attr('data-name');
- $(this).data('url', '{% url 'repo_remove_share' %}?repo_id=' + e(repo_id) + '&from=' + e(repo_owner) + '&gid={{ group.id }}').attr('data-target', repo_name);
+ $(this).data('url', '{% url 'repo_remove_share' %}?repo_id=' + e(repo_id) + '&from=' + e(repo_owner) + '&gid={{ group.id }}' + '&permission=' + e(repo_perm)).attr('data-target', repo_name);
});
addConfirmTo($('.cancel-share'), {
'title': "{% trans "Unshare Library" %}",
diff --git a/seahub/settings.py b/seahub/settings.py
index 999906ffaa..c29548364d 100644
--- a/seahub/settings.py
+++ b/seahub/settings.py
@@ -427,6 +427,11 @@ PREVIEW_DEFAULT_SIZE = '100'
# for origin image file: size(MB)
THUMBNAIL_IMAGE_SIZE_LIMIT = 30
+#####################
+# Folder Permission #
+#####################
+ENABLE_FOLDER_PERM = False
+
#################
# Email sending #
#################
diff --git a/seahub/share/templates/share/list_priv_shared_folders.html b/seahub/share/templates/share/list_priv_shared_folders.html
index b158d1e205..789b10dd68 100644
--- a/seahub/share/templates/share/list_priv_shared_folders.html
+++ b/seahub/share/templates/share/list_priv_shared_folders.html
@@ -40,14 +40,14 @@
| {{ repo.props.repo_desc }} |
{% if repo.props.share_type == 'group' %}
-
+
{% endif %}
{% if repo.props.share_type == 'personal' %}
-
+
{% endif %}
{% if repo.props.share_type == 'public' %}
{% if not org %}
-
+
{% else %}
{% endif %}
@@ -92,10 +92,8 @@ $('.share-permission-select').change(function() {
success: function(data) {
if (data['success']) {
feedback("{% trans "Edit succeeded" %}", 'success');
- select.prev().children('.share-permission-cur-value').html(select.children('option[value="' +select.val() + '"]').text());
+ location.reload(true);
}
- select.addClass('hide');
- select.prev().removeClass('hide');
},
error: function() {
feedback("{% trans "Edit failed." %}", 'error');
diff --git a/seahub/share/templates/share/repos.html b/seahub/share/templates/share/repos.html
index e88f619ae7..0e4374511b 100644
--- a/seahub/share/templates/share/repos.html
+++ b/seahub/share/templates/share/repos.html
@@ -44,13 +44,13 @@
| {{ repo.props.repo_desc }} |
{% if repo.props.share_type == 'group' %}
-
+
{% endif %}
{% if repo.props.share_type == 'personal' %}
-
+
{% endif %}
{% if repo.props.share_type == 'public' %}
-
+
{% endif %}
|
diff --git a/seahub/share/templates/share/user_share_list.html b/seahub/share/templates/share/user_share_list.html
index 95de698b34..b8284ba986 100644
--- a/seahub/share/templates/share/user_share_list.html
+++ b/seahub/share/templates/share/user_share_list.html
@@ -56,9 +56,9 @@
{% endif %}
{% if repo.share_in %}
-
+
{% else %}
-
+
{% endif %}
diff --git a/seahub/share/views.py b/seahub/share/views.py
index de2b59464f..e5568cfa06 100644
--- a/seahub/share/views.py
+++ b/seahub/share/views.py
@@ -40,8 +40,8 @@ from seahub.views import is_registered_user, check_repo_access_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, \
- is_valid_username, send_html_email, is_org_context, \
- normalize_file_path, normalize_dir_path
+ is_valid_username, send_html_email, is_org_context, normalize_file_path, \
+ normalize_dir_path, send_perm_audit_msg, get_origin_repo_info
from seahub.settings import SITE_ROOT, REPLACE_FROM_EMAIL, ADD_REPLY_TO_HEADER
# Get an instance of a logger
@@ -253,8 +253,18 @@ def share_repo(request):
if is_valid_username(share_to):
share_to_users.append(share_to)
+ origin_repo_id, origin_path = get_origin_repo_info(repo.id)
+ if origin_repo_id is not None:
+ perm_repo_id = origin_repo_id
+ perm_path = origin_path
+ else:
+ perm_repo_id = repo.id
+ perm_path = '/'
+
if share_to_all:
share_to_public(request, repo, permission)
+ send_perm_audit_msg('add-repo-perm', username, 'all', \
+ perm_repo_id, perm_path, permission)
if not check_user_share_quota(username, repo, users=share_to_users,
groups=share_to_groups):
@@ -266,11 +276,15 @@ def share_repo(request):
for group in share_to_groups:
share_to_group(request, repo, group, permission)
+ send_perm_audit_msg('add-repo-perm', username, group.id, \
+ perm_repo_id, perm_path, permission)
for email in share_to_users:
# Add email to contacts.
mail_sended.send(sender=None, user=request.user.username, email=email)
share_to_user(request, repo, email, permission)
+ send_perm_audit_msg('add-repo-perm', username, email, \
+ perm_repo_id, perm_path, permission)
return HttpResponseRedirect(next)
@@ -285,10 +299,23 @@ def repo_remove_share(request):
repo_id = request.GET.get('repo_id', '')
group_id = request.GET.get('gid', '')
from_email = request.GET.get('from', '')
- if not is_valid_username(from_email):
+ perm = request.GET.get('permission', None)
+ if not is_valid_username(from_email) or perm is None:
return render_error(request, _(u'Argument is not valid'))
username = request.user.username
+ repo = seafile_api.get_repo(repo_id)
+ if not repo:
+ return render_error(request, _(u'Library does not exist'))
+
+ origin_repo_id, origin_path = get_origin_repo_info(repo.id)
+ if origin_repo_id is not None:
+ perm_repo_id = origin_repo_id
+ perm_path = origin_path
+ else:
+ perm_repo_id = repo.id
+ perm_path = '/'
+
# if request params don't have 'gid', then remove repos that share to
# to other person; else, remove repos that share to groups
if not group_id:
@@ -304,6 +331,8 @@ def repo_remove_share(request):
org_remove_share(org_id, repo_id, from_email, to_email)
else:
seaserv.remove_share(repo_id, from_email, to_email)
+ send_perm_audit_msg('delete-repo-perm', from_email, to_email, \
+ perm_repo_id, perm_path, perm)
else:
try:
group_id = int(group_id)
@@ -323,6 +352,8 @@ def repo_remove_share(request):
del_org_group_repo(repo_id, org_id, group_id)
else:
seafile_api.unset_group_repo(repo_id, group_id, from_email)
+ send_perm_audit_msg('delete-repo-perm', from_email, group_id, \
+ perm_repo_id, perm_path, perm)
messages.success(request, _('Successfully removed share'))
@@ -566,6 +597,19 @@ def share_permission_admin(request):
permission = form.cleaned_data['permission']
from_email = request.user.username
+ repo = seafile_api.get_repo(repo_id)
+ if not repo:
+ return render_error(request, _(u'Library does not exist'))
+
+ origin_repo_id, origin_path = get_origin_repo_info(repo.id)
+ if origin_repo_id is not None:
+ perm_repo_id = origin_repo_id
+ perm_path = origin_path
+ else:
+ perm_repo_id = repo.id
+ perm_path = '/'
+
+
if share_type == 'personal':
if not is_valid_username(email_or_group):
return HttpResponse(json.dumps({'success': False}), status=400,
@@ -579,6 +623,9 @@ def share_permission_admin(request):
else:
seafile_api.set_share_permission(repo_id, from_email,
email_or_group, permission)
+ send_perm_audit_msg('modify-repo-perm', from_email, \
+ email_or_group, perm_repo_id, perm_path, permission)
+
except SearpcError:
return HttpResponse(json.dumps({'success': False}), status=500,
content_type=content_type)
@@ -592,8 +639,12 @@ def share_permission_admin(request):
seaserv.seafserv_threaded_rpc.set_org_group_repo_permission(
org_id, int(email_or_group), repo_id, permission)
else:
- seafile_api.set_group_repo_permission(int(email_or_group),
- repo_id, permission)
+ group_id = int(email_or_group)
+ seafile_api.set_group_repo_permission(group_id,
+ repo_id,
+ permission)
+ send_perm_audit_msg('modify-repo-perm', from_email, \
+ group_id, perm_repo_id, perm_path, permission)
except SearpcError:
return HttpResponse(json.dumps({'success': False}), status=500,
content_type=content_type)
@@ -608,6 +659,8 @@ def share_permission_admin(request):
org_id, repo_id, permission)
else:
seafile_api.add_inner_pub_repo(repo_id, permission)
+ send_perm_audit_msg('modify-repo-perm', from_email, 'all', \
+ perm_repo_id, perm_path, permission)
except SearpcError:
return HttpResponse(json.dumps({'success': False}), status=500,
content_type=content_type)
diff --git a/seahub/templates/pubrepo.html b/seahub/templates/pubrepo.html
index 55932167ff..18837a5e99 100644
--- a/seahub/templates/pubrepo.html
+++ b/seahub/templates/pubrepo.html
@@ -38,7 +38,7 @@
{{ repo.props.user|email2nickname }} |
{% if request.user.is_staff or repo.share_from_me %}
-
+
{% endif %}
|
diff --git a/seahub/templates/repo_basic_info.html b/seahub/templates/repo_basic_info.html
index 4d0f7691ac..b5d354615e 100644
--- a/seahub/templates/repo_basic_info.html
+++ b/seahub/templates/repo_basic_info.html
@@ -23,8 +23,10 @@
{% if not repo.encrypted %}
{% trans "Shared Links" %}
{% endif %}
- {% trans "Sharing Management" %}
- {% trans "SubFolder Permission" %}
+ {% trans "Sharing Permission" %}
+ {% if ENABLE_FOLDER_PERM %}
+ {% trans "Folder Permission" %}
+ {% endif %}
{% endblock %}
diff --git a/seahub/templates/repo_change_password.html b/seahub/templates/repo_change_password.html
index e281db9268..90ff64cfec 100644
--- a/seahub/templates/repo_change_password.html
+++ b/seahub/templates/repo_change_password.html
@@ -23,8 +23,10 @@
{% if not repo.encrypted %}
{% trans "Shared Links" %}
{% endif %}
- {% trans "Sharing Management" %}
- {% trans "SubFolder Permission" %}
+ {% trans "Sharing Permission" %}
+ {% if ENABLE_FOLDER_PERM %}
+ {% trans "Folder Permission" %}
+ {% endif %}
{% endblock %}
diff --git a/seahub/templates/repo_folder_perm.html b/seahub/templates/repo_folder_perm.html
index bc0dd47b7b..4f5a240ccd 100644
--- a/seahub/templates/repo_folder_perm.html
+++ b/seahub/templates/repo_folder_perm.html
@@ -23,8 +23,8 @@
{% if not repo.encrypted %}
{% trans "Shared Links" %}
{% endif %}
- {% trans "Sharing Management" %}
- {% trans "SubFolder Permission" %}
+ {% trans "Sharing Permission" %}
+ {% trans "Folder Permission" %}
{% endblock %}
@@ -33,7 +33,7 @@
{% trans "Library Settings" %}
{% trans "Folder Permission" %}
-
{% trans "View and manage all the folder permissions in this library." %}
+
{% trans "View and manage all folder permissions in this library." %}
@@ -54,9 +54,9 @@
|
- |
+ |
-
+
|
@@ -71,7 +71,7 @@
|
{% if user_folder_perms %}
{% for perm in user_folder_perms %}
-
+
{{ perm.user }} |
{{ perm.folder_name }} |
@@ -107,11 +107,11 @@
|
-
+
|
-
+
|
@@ -126,7 +126,7 @@
|
{% if group_folder_perms %}
{% for perm in group_folder_perms %}
-
+
{{ perm.group_name }} |
{{ perm.folder_name }}
@@ -157,7 +157,7 @@
{% trans "Please selecte a directory" %}

-
+
@@ -197,7 +197,7 @@ group_list.push({value:group_id, label:group_name});
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()});
+ widget.css({'max-width':user_input.width() + 2 * parseInt(widget.css('padding-top')), 'max-height':$(window).height() + $(window).scrollTop() - user_input.offset().top - user_input.outerHeight()});
})
.autocomplete({
source: user_list
@@ -205,7 +205,7 @@ user_input.bind('autocompleteopen', function(e, ui) {
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()});
+ widget.css({'max-width':group_input.width() + 2 * parseInt(widget.css('padding-top')), 'max-height':$(window).height() + $(window).scrollTop() - group_input.offset().top - group_input.outerHeight()});
})
.autocomplete({
source: group_list,
@@ -250,15 +250,16 @@ $('.perm-toggle-select').on('change', function() {
});
$('.perm-delete-btn').on('click', function() {
var perm_item = $(this).parents('.perm-item'),
+ perm = perm_item.attr('data-perm'),
path = perm_item.attr('data-path');
if (is_user_tab == true) {
var user = perm_item.attr('data-user'),
- data = { 'user': user, 'path': path },
+ data = { 'user': user, 'path': path, 'perm': perm },
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 },
+ data = { 'group_id': group_id, 'path': path, 'perm': perm},
url = '{% url 'remove_group_folder_permission' repo.id %}';
}
@@ -329,7 +330,7 @@ function selectClickHandler(event) {
}
if (path_array.length == 1) {
path = path_array.shift();
- folder_name.val('Root Directory');
+ folder_name.val('/');
} else {
var root = path_array.shift(),
path = root + path_array.join('/'),
diff --git a/seahub/templates/repo_share_manage.html b/seahub/templates/repo_share_manage.html
index 76ec1f0a21..6f186215f0 100644
--- a/seahub/templates/repo_share_manage.html
+++ b/seahub/templates/repo_share_manage.html
@@ -23,8 +23,10 @@
{% if not repo.encrypted %}
- {% trans "Shared Links" %}
{% endif %}
- - {% trans "Sharing Management" %}
- - {% trans "SubFolder Permission" %}
+ - {% trans "Sharing Permission" %}
+ {% if ENABLE_FOLDER_PERM %}
+ - {% trans "Folder Permission" %}
+ {% endif %}
{% endblock %}
@@ -33,7 +35,7 @@
{% trans "Library Settings" %}
{% trans "Sharing Management" %}
- {% trans "View and manage all the share of this library." %}
+ {% trans "View and manage sharing permissions of this library." %}
|
-
+
|
{% endfor %}
@@ -105,7 +107,7 @@
-
+
|
{% endfor %}
diff --git a/seahub/templates/repo_shared_link.html b/seahub/templates/repo_shared_link.html
index 959f908bce..1d544c10de 100644
--- a/seahub/templates/repo_shared_link.html
+++ b/seahub/templates/repo_shared_link.html
@@ -23,8 +23,10 @@
{% if not repo.encrypted %}
- {% trans "Shared Links" %}
{% endif %}
- - {% trans "Sharing Management" %}
- - {% trans "SubFolder Permission" %}
+ - {% trans "Sharing Permission" %}
+ {% if ENABLE_FOLDER_PERM %}
+ - {% trans "Folder Permission" %}
+ {% endif %}
{% endblock %}
diff --git a/seahub/templates/repo_transfer_owner.html b/seahub/templates/repo_transfer_owner.html
index dfad1c46f2..c903e248c6 100644
--- a/seahub/templates/repo_transfer_owner.html
+++ b/seahub/templates/repo_transfer_owner.html
@@ -23,8 +23,10 @@
{% if not repo.encrypted %}
{% trans "Shared Links" %}
{% endif %}
-
{% trans "Sharing Management" %}
-
{% trans "SubFolder Permission" %}
+
{% trans "Sharing Permission" %}
+ {% if ENABLE_FOLDER_PERM %}
+
{% trans "Folder Permission" %}
+ {% endif %}
{% endblock %}
diff --git a/seahub/templates/shared_file_view.html b/seahub/templates/shared_file_view.html
index d1623764a6..e62b20d456 100644
--- a/seahub/templates/shared_file_view.html
+++ b/seahub/templates/shared_file_view.html
@@ -33,7 +33,7 @@
{% endif %}
{% endif %}
{% if not traffic_over_limit %}
-
{% trans "Download" %} ({{file_size|filesizeformat}})
+
{% trans "Download" %} ({{file_size|filesizeformat}})
{% endif %}
{% include 'snippets/file_content_html.html' %}
diff --git a/seahub/templates/snippets/my_shared_repos.html b/seahub/templates/snippets/my_shared_repos.html
index 6b2cd4f05a..1fff609577 100644
--- a/seahub/templates/snippets/my_shared_repos.html
+++ b/seahub/templates/snippets/my_shared_repos.html
@@ -26,7 +26,7 @@
{% endif %}
{% if repo.share_type == 'personal' %}
-
+
{% endif %}
diff --git a/seahub/urls.py b/seahub/urls.py
index 3126d74618..7dd39f1344 100644
--- a/seahub/urls.py
+++ b/seahub/urls.py
@@ -254,9 +254,13 @@ if getattr(settings, 'ENABLE_PAYMENT', False):
if getattr(settings, 'ENABLE_SYSADMIN_EXTRA', False):
- from seahub_extra.sysadmin_extra.views import sys_login_admin
+ from seahub_extra.sysadmin_extra.views import sys_login_admin, \
+ sys_log_file_audit, sys_log_file_update, sys_log_perm_audit
urlpatterns += patterns('',
url(r'^sys/loginadmin/', sys_login_admin, name='sys_login_admin'),
+ url(r'^sys/log/fileaudit/', sys_log_file_audit, name='sys_log_file_audit'),
+ url(r'^sys/log/fileupdate/', sys_log_file_update, name='sys_log_file_update'),
+ url(r'^sys/log/permaudit/', sys_log_perm_audit, name='sys_log_perm_audit'),
)
if getattr(settings, 'MULTI_TENANCY', False):
diff --git a/seahub/utils/__init__.py b/seahub/utils/__init__.py
index 137578d0c8..56ab881453 100644
--- a/seahub/utils/__init__.py
+++ b/seahub/utils/__init__.py
@@ -10,6 +10,7 @@ import tempfile
import locale
import ConfigParser
import mimetypes
+import contextlib
from datetime import datetime
from urlparse import urlparse, urljoin
@@ -31,8 +32,8 @@ from django.views.static import serve as django_static_serve
from seahub.api2.models import Token, TokenV2
import seaserv
-from seaserv import seafile_api
-from seaserv import seafserv_rpc, seafserv_threaded_rpc, get_repo, get_commits,\
+from seaserv import seafile_api, send_message, seafserv_rpc, \
+ seafserv_threaded_rpc, get_repo, get_commits,\
CCNET_SERVER_ADDR, CCNET_SERVER_PORT, get_org_by_id, is_org_staff, \
get_org_id_by_group, get_personal_groups_by_user, \
list_personal_repos_by_owner, get_group_repos, \
@@ -526,6 +527,14 @@ if EVENTS_CONFIG_FILE:
EVENTS_ENABLED = True
SeafEventsSession = seafevents.init_db_session_class(EVENTS_CONFIG_FILE)
+ @contextlib.contextmanager
+ def _get_seafevents_session():
+ try:
+ session = SeafEventsSession()
+ yield session
+ finally:
+ session.close()
+
def _same_events(e1, e2):
"""Two events are equal should follow two rules:
1. event1.repo_id = event2.repo_id
@@ -634,6 +643,48 @@ if EVENTS_CONFIG_FILE:
def get_org_user_events(org_id, username, start, count):
return _get_events(username, start, count, org_id=org_id)
+ def get_file_audit_events(email, org_id, repo_id, start, limit):
+ """Return file audit events list. (If no file audit, return 'None')
+
+ For example:
+ ``get_file_audit_events(email, org_id, repo_id, 0, 10)`` returns the first 10
+ events.
+ ``get_file_audit_events(email, org_id, repo_id, 5, 10)`` returns the 6th through
+ 15th events.
+ """
+ with _get_seafevents_session() as session:
+ events = seafevents.get_file_audit_events(session, email, org_id, repo_id, start, limit)
+
+ return events if events else None
+
+ def get_file_update_events(email, org_id, repo_id, start, limit):
+ """Return file update events list. (If no file update, return 'None')
+
+ For example:
+ ``get_file_update_events(email, org_id, repo_id, 0, 10)`` returns the first 10
+ events.
+ ``get_file_update_events(email, org_id, repo_id, 5, 10)`` returns the 6th through
+ 15th events.
+ """
+ with _get_seafevents_session() as session:
+ events = seafevents.get_file_update_events(session, email, org_id, repo_id, start, limit)
+
+ return events if events else None
+
+ def get_perm_audit_events(email, org_id, repo_id, start, limit):
+ """Return repo perm events list. (If no repo perm, return 'None')
+
+ For example:
+ ``get_repo_perm_events(email, org_id, repo_id, 0, 10)`` returns the first 10
+ events.
+ ``get_repo_perm_events(email, org_id, repo_id, 5, 10)`` returns the 6th through
+ 15th events.
+ """
+ with _get_seafevents_session() as session:
+ events = seafevents.get_perm_audit_events(session, email, org_id, repo_id, start, limit)
+
+ return events if events else None
+
else:
EVENTS_ENABLED = False
def get_user_events():
@@ -1192,3 +1243,31 @@ def clear_token(username):
Token.objects.filter(user = username).delete()
TokenV2.objects.filter(user = username).delete()
seafile_api.delete_repo_tokens_by_email(username)
+
+def send_perm_audit_msg(etype, from_user, to, repo_id, path, perm):
+ """Send repo permission audit msg.
+
+ Arguments:
+ - `request`:
+ - `repo`:
+ - `obj_id`:
+ - `dl_type`: web or api
+ """
+ msg = 'perm-update\t%s\t%s\t%s\t%s\t%s\t%s' % \
+ (etype, from_user, to, repo_id, path, perm)
+ msg_utf8 = msg.encode('utf-8')
+
+ try:
+ send_message('seahub.stats', msg_utf8)
+ except Exception as e:
+ logger.error("Error when sending perm-audit-%s message: %s" %
+ (etype, str(e)))
+
+def get_origin_repo_info(repo_id):
+ repo = seafile_api.get_repo(repo_id)
+ if repo.origin_repo_id is not None:
+ origin_repo_id = repo.origin_repo_id
+ origin_path = repo.origin_path
+ return (origin_repo_id, origin_path)
+
+ return (None, None)
diff --git a/seahub/utils/repo.py b/seahub/utils/repo.py
index 6a4060c8fb..14a6ed5736 100644
--- a/seahub/utils/repo.py
+++ b/seahub/utils/repo.py
@@ -1,11 +1,15 @@
# -*- coding: utf-8 -*-
+import logging
from django.utils.translation import ugettext as _
import seaserv
from seaserv import seafile_api
-from seahub.utils import EMPTY_SHA1, is_valid_username
+from seahub.utils import EMPTY_SHA1
from seahub.views import check_repo_access_permission
+from seahub.base.accounts import User
+
+logger = logging.getLogger(__name__)
def list_dir_by_path(cmmt, path):
if cmmt.root_id == EMPTY_SHA1:
@@ -13,11 +17,11 @@ def list_dir_by_path(cmmt, path):
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):
+def check_user_folder_perm_args(from_user, repo_id, path, to_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':
+ if check_repo_access_permission(repo_id, from_user) != 'rw':
return {'error': _('Permission denied'), 'status': 403}
if perm is not None:
@@ -34,16 +38,21 @@ def check_user_folder_perm_args(request_user, repo_id, path, user, perm=None):
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}
+ try:
+ user = User.objects.get(email = to_user)
+ except User.DoesNotExist:
+ user = None
+
+ if user is None:
+ return {'error': _('Invalid username, should be a user already registered'), 'status': 400}
return {'success': True}
-def check_group_folder_perm_args(request_user, repo_id, path, group_id, perm = None):
+def check_group_folder_perm_args(from_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':
+ if check_repo_access_permission(repo_id, from_user) != 'rw':
return {'error': _('Permission denied'), 'status': 403}
if perm is not None:
@@ -60,7 +69,8 @@ def check_group_folder_perm_args(request_user, repo_id, path, group_id, perm = N
if path != '/' and path.endswith('/'):
return {'error': _('Path should NOT ends with "/"'), 'status': 400}
- if group_id and not seaserv.get_group(group_id):
+ if not seaserv.get_group(group_id):
return {'error': _('Invalid group'), 'status': 400}
return {'success': True}
+
diff --git a/seahub/utils/timeutils.py b/seahub/utils/timeutils.py
index 8ce0f950a3..daf988ce38 100644
--- a/seahub/utils/timeutils.py
+++ b/seahub/utils/timeutils.py
@@ -26,4 +26,10 @@ def value_to_db_datetime(value):
# MySQL doesn't support microseconds
return six.text_type(value.replace(microsecond=0))
-
+
+def utc_to_local(dt):
+ # change from UTC timezone to current seahub timezone
+ tz = timezone.get_default_timezone()
+ utc = dt.replace(tzinfo=timezone.utc)
+ local = timezone.make_naive(utc, tz)
+ return local
diff --git a/seahub/views/__init__.py b/seahub/views/__init__.py
index 30a3c6e5a9..8b56d696b9 100644
--- a/seahub/views/__init__.py
+++ b/seahub/views/__init__.py
@@ -53,9 +53,10 @@ from seahub.utils import render_permission_error, render_error, list_to_string,
gen_file_get_url, string2list, MAX_INT, IS_EMAIL_CONFIGURED, \
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
+ user_traffic_over_limit, send_perm_audit_msg, get_origin_repo_info
from seahub.utils.paginator import get_page_range
from seahub.utils.star import get_dir_starred_files
+from seahub.utils.timeutils import utc_to_local
from seahub.views.modules import MOD_PERSONAL_WIKI, enable_mod_for_user, \
disable_mod_for_user
from seahub.utils.devices import get_user_devices, do_unlink_device
@@ -63,7 +64,8 @@ import seahub.settings as settings
from seahub.settings import FILE_PREVIEW_MAX_SIZE, INIT_PASSWD, USE_PDFJS, \
FILE_ENCODING_LIST, FILE_ENCODING_TRY_LIST, AVATAR_FILE_STORAGE, \
SEND_EMAIL_ON_ADDING_SYSTEM_MEMBER, SEND_EMAIL_ON_RESETTING_USER_PASSWD, \
- ENABLE_SUB_LIBRARY, ENABLE_REPO_HISTORY_SETTING, REPO_PASSWORD_MIN_LENGTH
+ ENABLE_SUB_LIBRARY, ENABLE_REPO_HISTORY_SETTING, \
+ REPO_PASSWORD_MIN_LENGTH, ENABLE_FOLDER_PERM
# Get an instance of a logger
logger = logging.getLogger(__name__)
@@ -477,6 +479,7 @@ def repo_basic_info(request, repo_id):
'no_history_enabled': no_history_enabled,
'partial_history_enabled': partial_history_enabled,
'days_enabled': days_enabled,
+ 'ENABLE_FOLDER_PERM': ENABLE_FOLDER_PERM,
}, context_instance=RequestContext(request))
@login_required
@@ -491,6 +494,7 @@ def repo_transfer_owner(request, repo_id):
return render_to_response('repo_transfer_owner.html', {
'repo': repo,
+ 'ENABLE_FOLDER_PERM': ENABLE_FOLDER_PERM,
}, context_instance=RequestContext(request))
@login_required
@@ -506,6 +510,7 @@ def repo_change_password(request, repo_id):
return render_to_response('repo_change_password.html', {
'repo': repo,
'repo_password_min_length': REPO_PASSWORD_MIN_LENGTH,
+ 'ENABLE_FOLDER_PERM': ENABLE_FOLDER_PERM,
}, context_instance=RequestContext(request))
@login_required
@@ -565,6 +570,7 @@ def repo_shared_link(request, repo_id):
'repo': repo,
'fileshares': p_fileshares,
'uploadlinks': p_uploadlinks,
+ 'ENABLE_FOLDER_PERM': ENABLE_FOLDER_PERM,
}, context_instance=RequestContext(request))
@login_required
@@ -598,6 +604,7 @@ def repo_share_manage(request, repo_id):
'repo': repo,
'repo_share_user': repo_share_user,
'repo_share_group': repo_share_group,
+ 'ENABLE_FOLDER_PERM': ENABLE_FOLDER_PERM,
}, context_instance=RequestContext(request))
@login_required
@@ -607,11 +614,42 @@ def repo_folder_perm(request, repo_id):
username = request.user.username
can_access, repo = can_access_repo_setting(request, repo_id, username)
- if not can_access:
+ if not can_access or not ENABLE_FOLDER_PERM:
raise Http404
+ def not_need_delete(perm):
+ repo_id = perm.repo_id
+ path = perm.path
+ group_id = perm.group_id if hasattr(perm, 'group_id') else None
+ email = perm.user if hasattr(perm, 'user') else None
+
+ repo = get_repo(repo_id)
+ dir_id = seafile_api.get_dir_id_by_path(repo_id, path)
+
+ if group_id is not None:
+ # is a group folder perm
+ group = get_group(group_id)
+ if repo is None or dir_id is None or group is None:
+ seafile_api.rm_folder_group_perm(repo_id, path, group_id)
+ return False
+
+ if email is not None:
+ # is a user folder perm
+ try:
+ user = User.objects.get(email=email)
+ except User.DoesNotExist:
+ user = None
+
+ if repo is None or dir_id is None or user is None:
+ seafile_api.rm_folder_user_perm(repo_id, path, email)
+ return False
+
+ return True
+
# for user folder permission
user_folder_perms = seafile_api.list_folder_user_perm_by_repo(repo_id)
+ user_folder_perms = filter(lambda x: not_need_delete(x), user_folder_perms)
+
user_folder_perms.reverse()
for folder_perm in user_folder_perms:
@@ -624,6 +662,8 @@ def repo_folder_perm(request, repo_id):
# for group folder permission
group_folder_perms = seafile_api.list_folder_group_perm_by_repo(repo_id)
+ group_folder_perms = filter(lambda x: not_need_delete(x), group_folder_perms)
+
group_folder_perms.reverse()
for folder_perm in group_folder_perms:
@@ -633,15 +673,26 @@ def repo_folder_perm(request, repo_id):
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 that already registered
+ sys_contacts = []
contacts = Contact.objects.get_contacts_by_user(username)
+ for contact in contacts:
+ try:
+ user = User.objects.get(email = contact.contact_email)
+ except User.DoesNotExist:
+ user = None
+
+ if user is not None:
+ sys_contacts.append(contact.contact_email)
return render_to_response('repo_folder_perm.html', {
'repo': repo,
'user_folder_perms': user_folder_perms,
'group_folder_perms': group_folder_perms,
- 'contacts': contacts,
+ 'contacts': sys_contacts,
}, context_instance=RequestContext(request))
def upload_error_msg (code):
@@ -1098,6 +1149,9 @@ def unsetinnerpub(request, repo_id):
Only system admin, organization admin or repo owner can perform this op.
"""
repo = get_repo(repo_id)
+ perm = request.GET.get('permission', None)
+ if perm is None:
+ return render_error(request, _(u'Argument is not valid'))
if not repo:
messages.error(request, _('Failed to unshare the library, as it does not exist.'))
return HttpResponseRedirect(reverse('share_admin'))
@@ -1124,6 +1178,17 @@ def unsetinnerpub(request, repo_id):
else:
seaserv.unset_inner_pub_repo(repo.id)
+ origin_repo_id, origin_path = get_origin_repo_info(repo.id)
+ if origin_repo_id is not None:
+ perm_repo_id = origin_repo_id
+ perm_path = origin_path
+ else:
+ perm_repo_id = repo.id
+ perm_path = '/'
+
+ send_perm_audit_msg('delete-repo-perm', username, 'all', \
+ perm_repo_id, perm_path, perm)
+
messages.success(request, _('Unshare "%s" successfully.') % repo.name)
except SearpcError:
messages.error(request, _('Failed to unshare "%s".') % repo.name)
@@ -1793,14 +1858,6 @@ def group_events_data(events):
"""
Group events according to the date.
"""
- # e.timestamp is a datetime.datetime in UTC
- # change from UTC timezone to current seahub timezone
- def utc_to_local(dt):
- tz = timezone.get_default_timezone()
- utc = dt.replace(tzinfo=timezone.utc)
- local = timezone.make_naive(utc, tz)
- return local
-
event_groups = []
for e in events:
e.time = utc_to_local(e.timestamp)
diff --git a/seahub/views/ajax.py b/seahub/views/ajax.py
index 88136d28e4..b15dd3d430 100644
--- a/seahub/views/ajax.py
+++ b/seahub/views/ajax.py
@@ -45,7 +45,7 @@ from seahub.utils import check_filename_with_rename, EMPTY_SHA1, \
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, \
- is_valid_username
+ is_valid_username, send_perm_audit_msg
from seahub.utils.repo import check_group_folder_perm_args, \
check_user_folder_perm_args
from seahub.utils.star import star_file, unstar_file
@@ -1715,7 +1715,10 @@ def repo_history_changes(request, repo_id):
# perm check
if check_repo_access_permission(repo.id, request.user) is None:
- return HttpResponse(json.dumps(changes), content_type=content_type)
+ if request.user.is_staff is True:
+ pass # Allow system staff to check repo changes
+ else:
+ return HttpResponse(json.dumps(changes), content_type=content_type)
username = request.user.username
try:
@@ -2109,6 +2112,8 @@ def add_user_folder_permission(request, repo_id):
try:
seafile_api.add_folder_user_perm(repo_id, path, perm, user)
+ send_perm_audit_msg('add-repo-perm', request.user.username, user, \
+ repo_id, path, perm)
except SearpcError, e:
return HttpResponse(json.dumps({"error": e.msg}), status=500,
content_type=content_type)
@@ -2127,8 +2132,9 @@ def remove_user_folder_permission(request, repo_id):
user = request.GET.get('user', None)
path = request.GET.get('path', None)
+ perm = request.GET.get('perm', None)
- if not user or not path:
+ if not user or not path or not perm:
return HttpResponse(json.dumps({"error": _('Argument missing')}),
status=400,
content_type=content_type)
@@ -2140,6 +2146,8 @@ def remove_user_folder_permission(request, repo_id):
try:
seafile_api.rm_folder_user_perm(repo_id, path, user)
+ send_perm_audit_msg('delete-repo-perm', request.user.username, user, \
+ repo_id, path, perm)
return HttpResponse(json.dumps({'success': True}),
content_type=content_type)
except SearpcError, e:
@@ -2161,7 +2169,6 @@ def toggle_user_folder_permission(request, repo_id):
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,
@@ -2174,6 +2181,8 @@ def toggle_user_folder_permission(request, repo_id):
try:
seafile_api.set_folder_user_perm(repo_id, path, perm, user)
+ send_perm_audit_msg('modify-repo-perm', request.user.username, user, \
+ repo_id, path, perm)
return HttpResponse(json.dumps({'success': True}),
content_type=content_type)
except SearpcError, e:
@@ -2207,6 +2216,8 @@ def add_group_folder_permission(request, repo_id):
try:
seafile_api.add_folder_group_perm(repo_id, path, perm, group_id)
+ send_perm_audit_msg('add-repo-perm', request.user.username, \
+ group_id, repo_id, path, perm)
except SearpcError, e:
return HttpResponse(json.dumps({"error": e.msg}), status=500,
content_type=content_type)
@@ -2225,8 +2236,9 @@ def remove_group_folder_permission(request, repo_id):
group_id = int(request.GET.get('group_id', None))
path = request.GET.get('path', None)
+ perm = request.GET.get('perm', None)
- if not group_id or not path:
+ if not group_id or not path or not perm:
return HttpResponse(json.dumps({"error": _('Argument missing')}),
status=400,
content_type=content_type)
@@ -2238,6 +2250,8 @@ def remove_group_folder_permission(request, repo_id):
try:
seafile_api.rm_folder_group_perm(repo_id, path, group_id)
+ send_perm_audit_msg('delete-repo-perm', request.user.username, \
+ group_id, repo_id, path, perm)
return HttpResponse(json.dumps({'success': True}),
content_type=content_type)
except SearpcError, e:
@@ -2271,6 +2285,8 @@ def toggle_group_folder_permission(request, repo_id):
try:
seafile_api.set_folder_group_perm(repo_id, path, perm, group_id)
+ send_perm_audit_msg('modify-repo-perm', request.user.username, \
+ group_id, repo_id, path, perm)
return HttpResponse(json.dumps({'success': True}),
content_type=content_type)
except SearpcError, e:
diff --git a/seahub/views/file.py b/seahub/views/file.py
index e2ba3f5f75..5e8e76e513 100644
--- a/seahub/views/file.py
+++ b/seahub/views/file.py
@@ -1079,8 +1079,8 @@ def send_file_download_msg(request, repo, path, dl_type):
ip = get_remote_ip(request)
user_agent = request.META.get("HTTP_USER_AGENT")
- msg = 'file-download-%s\t%s\t%s\t%s\t%s\t%s\t%s' % \
- (dl_type, username, ip, user_agent, repo.id, repo.name, path)
+ msg = 'file-download-%s\t%s\t%s\t%s\t%s\t%s' % \
+ (dl_type, username, ip, user_agent, repo.id, path)
msg_utf8 = msg.encode('utf-8')
try:
@@ -1137,6 +1137,7 @@ def download_file(request, repo_id, obj_id):
# send stats message
if from_shared_link:
+ send_file_download_msg(request, repo, path, 'share-link')
try:
file_size = seafile_api.get_file_size(repo.store_id, repo.version,
obj_id)