diff --git a/media/css/seahub.css b/media/css/seahub.css index e1ccae600a..8e90f13ecf 100644 --- a/media/css/seahub.css +++ b/media/css/seahub.css @@ -188,6 +188,7 @@ .sf2-icon-lock:before { content: "\e02c"; } .sf2-icon-unlock:before { content: "\e02d"; } .sf2-icon-admin-log:before { content: "\e02e"; } +.sf2-icon-info:before { content: "\e02f"; } /******* tags **********/ body, @@ -1068,6 +1069,31 @@ textarea:-moz-placeholder {/* for FF */ bottom:0; width:100%; } + +/**** details-side-panel ****/ +.details-panel { + width:320px; +} +.details-panel-img-container { + text-align:center; + height:160px; + padding:6px 0; +} +.details-panel-img-container .thumbnail { + max-width:calc(100% - 4px); /* `-4px` for full width thumbnail */ + max-height:100%; +} +.details-panel-text-info-container { + padding:10px 20px; +} +.details-panel-text-info-container table { + margin:0; +} +.details-panel-text-info-container th, +.details-panel-text-info-container td { + border:none; +} + /**** messages ****/ .messages { position:fixed; diff --git a/media/css/sf_font2/seafile-font2.eot b/media/css/sf_font2/seafile-font2.eot index 711268160e..081d65245c 100644 Binary files a/media/css/sf_font2/seafile-font2.eot and b/media/css/sf_font2/seafile-font2.eot differ diff --git a/media/css/sf_font2/seafile-font2.svg b/media/css/sf_font2/seafile-font2.svg index 7f4bcea577..d405f2936a 100644 --- a/media/css/sf_font2/seafile-font2.svg +++ b/media/css/sf_font2/seafile-font2.svg @@ -54,4 +54,5 @@ + diff --git a/media/css/sf_font2/seafile-font2.ttf b/media/css/sf_font2/seafile-font2.ttf index 29be07f75b..d7286e852c 100644 Binary files a/media/css/sf_font2/seafile-font2.ttf and b/media/css/sf_font2/seafile-font2.ttf differ diff --git a/media/css/sf_font2/seafile-font2.woff b/media/css/sf_font2/seafile-font2.woff index b1f1ac9bc9..6741f5ebbd 100644 Binary files a/media/css/sf_font2/seafile-font2.woff and b/media/css/sf_font2/seafile-font2.woff differ diff --git a/seahub/api2/endpoints/admin/upload_links.py b/seahub/api2/endpoints/admin/upload_links.py index be75a90fbf..33f34b562d 100644 --- a/seahub/api2/endpoints/admin/upload_links.py +++ b/seahub/api2/endpoints/admin/upload_links.py @@ -126,7 +126,7 @@ class AdminUploadLinkUpload(APIView): return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) result = {} - result['upload_link'] = gen_file_upload_url(token, 'upload-api') + result['upload_link'] = gen_file_upload_url(upload_token, 'upload-api') return Response(result) diff --git a/seahub/api2/endpoints/repo_trash.py b/seahub/api2/endpoints/repo_trash.py index 3ef29bc548..6097f8f44a 100644 --- a/seahub/api2/endpoints/repo_trash.py +++ b/seahub/api2/endpoints/repo_trash.py @@ -104,7 +104,13 @@ class RepoTrash(APIView): items = [] if len(deleted_entries) > 1: - for item in deleted_entries[0:-1]: + entries_without_scan_stat = deleted_entries[0:-1] + + # sort entry by delete time + entries_without_scan_stat.sort(lambda x, y : cmp(y.delete_time, + x.delete_time)) + + for item in entries_without_scan_stat: item_info = self.get_item_info(item) items.append(item_info) diff --git a/seahub/api2/endpoints/repos.py b/seahub/api2/endpoints/repos.py new file mode 100644 index 0000000000..75ea8bef70 --- /dev/null +++ b/seahub/api2/endpoints/repos.py @@ -0,0 +1,67 @@ +# Copyright (c) 2012-2016 Seafile Ltd. +import logging + +from rest_framework.authentication import SessionAuthentication +from rest_framework.permissions import IsAuthenticated +from rest_framework.response import Response +from rest_framework.views import APIView +from rest_framework import status + +from seahub.api2.throttling import UserRateThrottle +from seahub.api2.authentication import TokenAuthentication +from seahub.api2.utils import api_error + +from seahub.base.templatetags.seahub_tags import email2nickname, \ + email2contact_email +from seahub.utils import is_org_context +from seahub.views import check_folder_permission + +from seaserv import seafile_api + +logger = logging.getLogger(__name__) + +class RepoView(APIView): + + authentication_classes = (TokenAuthentication, SessionAuthentication) + permission_classes = (IsAuthenticated, ) + throttle_classes = (UserRateThrottle, ) + + def get(self, request, repo_id): + """ Return repo info + + Permission checking: + 1. all authenticated user can perform this action. + """ + + # resource check + repo = seafile_api.get_repo(repo_id) + if not repo: + error_msg = 'Library %s not found.' % repo_id + return api_error(status.HTTP_404_NOT_FOUND, error_msg) + + # permission check + permission = check_folder_permission(request, repo_id, '/') + if permission is None: + error_msg = 'Permission denied.' + return api_error(status.HTTP_403_FORBIDDEN, error_msg) + + 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) + + result = { + "repo_id": repo.id, + "repo_name": repo.name, + + "owner_email": repo_owner, + "owner_name": email2nickname(repo_owner), + "owner_contact_email": email2contact_email(repo_owner), + + "size": repo.size, + "encrypted": repo.encrypted, + "file_count": repo.file_count, + "permission": permission, + } + + return Response(result) diff --git a/seahub/api2/views.py b/seahub/api2/views.py index 8ac293a1f4..73e846b9fb 100644 --- a/seahub/api2/views.py +++ b/seahub/api2/views.py @@ -851,7 +851,6 @@ class Repo(APIView): "id":repo.id, "owner":owner, "name":repo.name, - "desc":repo.desc, "mtime":repo.latest_modify, "size":repo.size, "encrypted":repo.encrypted, @@ -860,6 +859,7 @@ class Repo(APIView): "modifier_email": repo.last_modifier, "modifier_contact_email": email2contact_email(repo.last_modifier), "modifier_name": email2nickname(repo.last_modifier), + "file_count": repo.file_count, } if repo.encrypted: repo_json["enc_version"] = repo.enc_version diff --git a/seahub/templates/js/sysadmin-templates.html b/seahub/templates/js/sysadmin-templates.html index 7a648b21fe..9893d19064 100644 --- a/seahub/templates/js/sysadmin-templates.html +++ b/seahub/templates/js/sysadmin-templates.html @@ -5,7 +5,7 @@

{% trans "System Admin" %}

@@ -105,6 +106,7 @@ <% if (app.pageOptions.folder_perm_enabled) { %>
  • {% trans "Folder Permission" %}
  • <% } %> +
  • {% trans "Details" %}
  • @@ -115,6 +117,44 @@ <% } %> + + + {% endblock %} diff --git a/seahub/urls.py b/seahub/urls.py index ed39134483..da5ac9fa5b 100644 --- a/seahub/urls.py +++ b/seahub/urls.py @@ -26,6 +26,7 @@ from seahub.api2.endpoints.shared_folders import SharedFolders from seahub.api2.endpoints.shared_repos import SharedRepos, SharedRepo from seahub.api2.endpoints.upload_links import UploadLinks, UploadLink from seahub.api2.endpoints.repos_batch import ReposBatchView +from seahub.api2.endpoints.repos import RepoView from seahub.api2.endpoints.file import FileView from seahub.api2.endpoints.dir import DirView from seahub.api2.endpoints.repo_trash import RepoTrash @@ -207,6 +208,7 @@ urlpatterns = patterns( ## user::repos url(r'^api/v2.1/repos/batch/$', ReposBatchView.as_view(), name='api-v2.1-repos-batch'), + url(r'^api/v2.1/repos/(?P[-0-9a-f]{36})/$', RepoView.as_view(), name='api-v2.1-repo-view'), url(r'^api/v2.1/repos/(?P[-0-9a-f]{36})/file/$', FileView.as_view(), name='api-v2.1-file-view'), url(r'^api/v2.1/repos/(?P[-0-9a-f]{36})/dir/$', DirView.as_view(), name='api-v2.1-dir-view'), url(r'^api/v2.1/repos/(?P[-0-9a-f]{36})/trash/$', RepoTrash.as_view(), name='api-v2.1-repo-trash'), @@ -348,6 +350,7 @@ urlpatterns = patterns( url(r'^sys/uploadlink/remove/$', sys_upload_link_remove, name='sys_upload_link_remove'), url(r'^sys/notificationadmin/', notification_list, name='notification_list'), url(r'^sys/invitationadmin/$', sys_invitation_admin, name='sys_invitation_admin'), + url(r'^sys/invitationadmin/remove/$', sys_invitation_remove, name='sys_invitation_remove'), url(r'^sys/sudo/', sys_sudo_mode, name='sys_sudo_mode'), url(r'^sys/check-license/', sys_check_license, name='sys_check_license'), url(r'^useradmin/add/$', user_add, name="user_add"), diff --git a/seahub/utils/__init__.py b/seahub/utils/__init__.py index c2ee586cc1..79feffcd18 100644 --- a/seahub/utils/__init__.py +++ b/seahub/utils/__init__.py @@ -215,15 +215,27 @@ def calculate_repos_last_modify(repo_list): def normalize_dir_path(path): """Add '/' at the end of directory path if necessary. + + And make sure path starts with '/' """ - if path[-1] != '/': - path = path + '/' - return path + + path = path.strip('/') + if path == '': + return '/' + else: + return '/' + path + '/' def normalize_file_path(path): """Remove '/' at the end of file path if necessary. + + And make sure path starts with '/' """ - return path.rstrip('/') + + path = path.strip('/') + if path == '': + return '' + else: + return '/' + path # modified from django1.5:/core/validators, and remove the support for single # quote in email address diff --git a/seahub/views/sysadmin.py b/seahub/views/sysadmin.py index 82574ab7b3..3677e43bcd 100644 --- a/seahub/views/sysadmin.py +++ b/seahub/views/sysadmin.py @@ -16,7 +16,7 @@ from django.conf import settings as dj_settings from django.core.urlresolvers import reverse from django.contrib import messages from django.http import HttpResponse, Http404, HttpResponseRedirect, HttpResponseNotAllowed -from django.shortcuts import render_to_response +from django.shortcuts import render_to_response, get_object_or_404 from django.template import RequestContext from django.utils import timezone from django.utils.translation import ugettext as _ @@ -2316,6 +2316,27 @@ def sys_invitation_admin(request): }, context_instance=RequestContext(request)) +@login_required +@sys_staff_required +def sys_invitation_remove(request): + """Delete an invitation. + """ + ct = 'application/json; charset=utf-8' + result = {} + + if not ENABLE_GUEST_INVITATION: + return HttpResponse(json.dumps({}), status=400, content_type=ct) + + inv_id = request.POST.get('inv_id', '') + if not inv_id: + result = {'error': "Argument missing"} + return HttpResponse(json.dumps(result), status=400, content_type=ct) + + inv = get_object_or_404(Invitation, pk=inv_id) + inv.delete() + + return HttpResponse(json.dumps({'success': True}), content_type=ct) + @login_required @sys_staff_required def sys_terms_admin(request): diff --git a/static/scripts/app/views/myhome-repos.js b/static/scripts/app/views/myhome-repos.js index b0d90091d1..e92ad0c803 100644 --- a/static/scripts/app/views/myhome-repos.js +++ b/static/scripts/app/views/myhome-repos.js @@ -6,7 +6,9 @@ define([ 'app/collections/repos', 'app/views/repo', 'app/views/add-repo', -], function($, _, Backbone, Common, RepoCollection, RepoView, AddRepoView) { + 'app/views/repo-details' +], function($, _, Backbone, Common, RepoCollection, RepoView, AddRepoView, + RepoDetailsView) { 'use strict'; var ReposView = Backbone.View.extend({ @@ -27,11 +29,13 @@ define([ this.listenTo(this.repos, 'add', this.addOne); this.listenTo(this.repos, 'reset', this.reset); + this.repoDetailsView = new RepoDetailsView(); + this.render(); }, addOne: function(repo, collection, options) { - var view = new RepoView({model: repo}); + var view = new RepoView({model: repo, myReposView: this}); if (options.prepend) { this.$tableBody.prepend(view.render().el); } else { @@ -115,6 +119,8 @@ define([ hide: function() { this.$el.detach(); + + this.repoDetailsView.hide(); }, createRepo: function() { diff --git a/static/scripts/app/views/repo-details.js b/static/scripts/app/views/repo-details.js new file mode 100644 index 0000000000..f62a93a911 --- /dev/null +++ b/static/scripts/app/views/repo-details.js @@ -0,0 +1,73 @@ +define([ + 'jquery', + 'underscore', + 'backbone', + 'common' +], function($, _, Backbone, Common) { + 'use strict'; + + var View = Backbone.View.extend({ + id: 'repo-details', + className: 'details-panel right-side-panel', + + template: _.template($('#repo-details-tmpl').html()), + + initialize: function() { + $("#main").append(this.$el); + + var _this = this; + $(document).keydown(function(e) { + // ESCAPE key pressed + if (e.which == 27) { + _this.hide(); + } + }); + + $(window).resize(function() { + _this.setConMaxHeight(); + }); + }, + + events: { + 'click .js-close': 'close' + }, + + render: function() { + this.$el.html(this.template(this.data)); + }, + + update: function(part_data) { + if (part_data.error) { + this.$('#file-count').html('' + gettext("Error") + ''); + } else { + this.$('#file-count').html(part_data.file_count); + } + }, + + setConMaxHeight: function() { + this.$('.right-side-panel-con').css({ + 'height': $(window).height() - // this.$el `position:fixed; top:0;` + this.$('.right-side-panel-hd').outerHeight(true) + }); + }, + + hide: function() { + this.$el.css({'right': '-320px'}); + }, + + close: function() { + this.hide(); + return false; + }, + + show: function(options) { + this.data = options; + this.render(); + this.$el.css({'right': '0px'}); + this.setConMaxHeight(); + } + + }); + + return View; +}); diff --git a/static/scripts/app/views/repo.js b/static/scripts/app/views/repo.js index a0448cb60e..22e79b5ad3 100644 --- a/static/scripts/app/views/repo.js +++ b/static/scripts/app/views/repo.js @@ -24,6 +24,7 @@ define([ transferTemplate: _.template($('#repo-transfer-form-tmpl').html()), events: { + 'click': 'clickItem', 'click td:lt(2)': 'visitRepo', 'click .repo-delete-btn': 'del', 'click .repo-share-btn': 'share', @@ -32,12 +33,15 @@ define([ 'click .js-repo-change-password': 'changePassword', 'click .js-popup-history-setting': 'popupHistorySetting', 'click .js-popup-share-link-admin': 'popupShareLinkAdmin', - 'click .js-popup-folder-perm-admin': 'popupFolderPermAdmin' + 'click .js-popup-folder-perm-admin': 'popupFolderPermAdmin', + 'click .js-repo-details': 'viewDetails' }, - initialize: function() { + initialize: function(options) { HLItemView.prototype.initialize.call(this); + this.myReposView = options.myReposView; + this.listenTo(this.model, "change", this.render); }, @@ -65,6 +69,14 @@ define([ return this; }, + clickItem: function(e) { + var target = e.target || event.srcElement; + if (this.$('td').is(target) && + $('#repo-details').css('right') == '0px') { // after `#repo-details` is shown + this.viewDetails(); + } + }, + visitRepo: function() { if ($(window).width() < 768) { location.href = this.$('.repo-name-span a').attr('href'); @@ -312,6 +324,38 @@ define([ this.togglePopup(); // close the popup new RepoChangePasswordDialog(options); return false; + }, + + viewDetails: function() { + var obj = this.model.toJSON(); + var icon_size = Common.isHiDPI() ? 96 : 24; + var data = $.extend({}, obj, { + icon_url: this.model.getIconUrl(icon_size), + big_icon_url: this.model.getIconUrl(96) + }); + var detailsView = this.myReposView.repoDetailsView; + detailsView.show(data); + + // fetch other data + $.ajax({ + url: Common.getUrl({ + 'name': 'repo_v2.1', + 'repo_id': this.model.get('id') + }), + cache: false, + dataType: 'json', + success: function(data) { + detailsView.update({ + 'file_count': data.file_count + }); + }, + error: function() { + detailsView.update({'error': true}); + } + }); + + this.togglePopup(); // close the popup + return false; } }); diff --git a/static/scripts/common.js b/static/scripts/common.js index 7d02e20bfb..1eb274640c 100644 --- a/static/scripts/common.js +++ b/static/scripts/common.js @@ -106,6 +106,7 @@ define([ case 'dir_shared_items': return siteRoot + 'api2/repos/' + options.repo_id + '/dir/shared_items/'; case 'shared_repos': return siteRoot + 'api2/shared-repos/' + options.repo_id + '/'; case 'repo': return siteRoot + 'api2/repos/' + options.repo_id + '/'; + case 'repo_v2.1': return siteRoot + 'api/v2.1/repos/' + options.repo_id + '/'; case 'repo_owner': return siteRoot + 'api2/repos/' + options.repo_id + '/owner/'; case 'repo_history_limit': return siteRoot + 'api2/repos/' + options.repo_id + '/history-limit/'; case 'repo_shared_download_links': return siteRoot + 'api2/repos/' + options.repo_id + '/download-shared-links/'; diff --git a/tests/api/endpoints/test_repos.py b/tests/api/endpoints/test_repos.py new file mode 100644 index 0000000000..4fadb3382f --- /dev/null +++ b/tests/api/endpoints/test_repos.py @@ -0,0 +1,102 @@ +import json +from django.core.urlresolvers import reverse +from seaserv import seafile_api +from seahub.test_utils import BaseTestCase +from seahub.base.templatetags.seahub_tags import email2nickname, \ + email2contact_email + +class RepoViewTest(BaseTestCase): + + def setUp(self): + self.user_name = self.user.username + self.admin_name = self.admin.username + self.url = reverse('api-v2.1-repo-view', args=[self.repo.id]) + + def tearDown(self): + self.remove_repo() + + def test_can_get(self): + + self.login_as(self.user) + + resp = self.client.get(self.url) + self.assertEqual(200, resp.status_code) + json_resp = json.loads(resp.content) + + assert json_resp['repo_id'] == self.repo.id + assert json_resp['repo_name'] == self.repo.name + + assert json_resp['owner_email'] == self.user_name + assert json_resp['owner_name'] == email2nickname(self.user_name) + assert json_resp['owner_contact_email'] == email2contact_email(self.user_name) + + assert json_resp['permission'] == 'rw' + + self.assertFalse(json_resp['encrypted']) + self.assertIsNotNone(json_resp['file_count']) + self.assertIsNotNone(json_resp['size']) + + def test_can_get_be_shared_repo_info(self): + + # create admin repo + admin_repo_id = seafile_api.create_repo(name='test-repo', desc='', + username=self.admin_name, passwd=None) + admin_repo = seafile_api.get_repo(admin_repo_id) + + # share admin repo to current user + permission = 'r' + seafile_api.share_repo(admin_repo_id, self.admin_name, + self.user_name, permission) + + self.login_as(self.user) + + url = reverse('api-v2.1-repo-view', args=[admin_repo_id]) + resp = self.client.get(url) + self.assertEqual(200, resp.status_code) + json_resp = json.loads(resp.content) + + assert json_resp['repo_id'] == admin_repo.id + assert json_resp['repo_name'] == admin_repo.name + + assert json_resp['owner_email'] == self.admin_name + assert json_resp['owner_name'] == email2nickname(self.admin_name) + assert json_resp['owner_contact_email'] == email2contact_email(self.admin_name) + + assert json_resp['permission'] == permission + + self.assertFalse(json_resp['encrypted']) + self.assertIsNotNone(json_resp['file_count']) + self.assertIsNotNone(json_resp['size']) + + self.remove_repo(admin_repo_id) + + def test_get_with_invalid_authentication(self): + + self.login_as(self.admin) + + resp = self.client.get(self.url) + self.assertEqual(403, resp.status_code) + + def test_get_with_invalid_permission(self): + + admin_repo_id = seafile_api.create_repo(name='test-repo', desc='', + username=self.admin_name, passwd=None) + + self.login_as(self.user) + + url = reverse('api-v2.1-repo-view', args=[admin_repo_id]) + resp = self.client.get(url) + self.assertEqual(403, resp.status_code) + + self.remove_repo(admin_repo_id) + + def test_get_with_invalid_repo(self): + + self.login_as(self.user) + + repo_id = self.repo.id + invalid_repo_id = repo_id[0:-5] + '12345' + + url = reverse('api-v2.1-repo-view', args=[invalid_repo_id]) + resp = self.client.get(url) + self.assertEqual(404, resp.status_code) diff --git a/tests/api/test_repo.py b/tests/api/test_repo.py index 37f16d08f4..5af39d09aa 100644 --- a/tests/api/test_repo.py +++ b/tests/api/test_repo.py @@ -21,8 +21,8 @@ class RepoTest(BaseTestCase): self.assertIsNotNone(json_resp['size']) self.assertIsNotNone(json_resp['name']) self.assertIsNotNone(json_resp['root']) - self.assertIsNotNone(json_resp['desc']) self.assertIsNotNone(json_resp['type']) + self.assertIsNotNone(json_resp['file_count']) def test_can_delete(self): self.login_as(self.user) diff --git a/tests/api/test_repos.py b/tests/api/test_repos.py index b524082e1e..363b53bb24 100644 --- a/tests/api/test_repos.py +++ b/tests/api/test_repos.py @@ -59,7 +59,6 @@ class ReposApiTest(ApiTestBase): self.assertIsNotNone(rinfo['size']) self.assertIsNotNone(rinfo['name']) self.assertIsNotNone(rinfo['root']) - self.assertIsNotNone(rinfo['desc']) self.assertIsNotNone(rinfo['type']) assert len(rinfo['modifier_email']) > 0 assert len(rinfo['modifier_name']) > 0 @@ -84,7 +83,6 @@ class ReposApiTest(ApiTestBase): #self.assertIsNotNone(commit['parent_id']) #allow null self.assertIsNotNone(commit['new_merge']) self.assertIsNotNone(commit['repo_id']) - self.assertIsNotNone(commit['desc']) self.assertIsNotNone(commit['id']) self.assertIsNotNone(commit['conflict']) #self.assertIsNotNone(commit['second_parent_id']) #allow null diff --git a/tests/seahub/utils/__init__.py b/tests/seahub/utils/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/seahub/utils/test_normalize_dir_path.py b/tests/seahub/utils/test_normalize_dir_path.py new file mode 100644 index 0000000000..95430a78d6 --- /dev/null +++ b/tests/seahub/utils/test_normalize_dir_path.py @@ -0,0 +1,31 @@ +import posixpath +from random import randint + +from tests.common.utils import randstring +from seahub.test_utils import BaseTestCase +from seahub.utils import normalize_dir_path + +class NormalizeDirPathTest(BaseTestCase): + + def test_normalize_dir_path(self): + + slash = '/' + folder_1 = randstring(3) + folder_2 = randstring(3) + + random_slash = '' + for i in range(1, randint(1,10)): + random_slash += slash + + posix_path = posixpath.join(folder_1, folder_2) + correct_path = slash + posix_path + slash + + path_without_slash = posix_path + path_starts_with_random_slash = random_slash + posix_path + path_ends_with_random_slash = posix_path + random_slash + path_with_slash = random_slash + posix_path + random_slash + + assert normalize_dir_path(path_without_slash) == correct_path + assert normalize_dir_path(path_starts_with_random_slash) == correct_path + assert normalize_dir_path(path_ends_with_random_slash) == correct_path + assert normalize_dir_path(path_with_slash) == correct_path diff --git a/tests/seahub/utils/test_normalize_file_path.py b/tests/seahub/utils/test_normalize_file_path.py new file mode 100644 index 0000000000..9774c25dc9 --- /dev/null +++ b/tests/seahub/utils/test_normalize_file_path.py @@ -0,0 +1,31 @@ +import posixpath +from random import randint + +from tests.common.utils import randstring +from seahub.test_utils import BaseTestCase +from seahub.utils import normalize_file_path + +class NormalizeDirPathTest(BaseTestCase): + + def test_normalize_file_path(self): + + slash = '/' + folder_1 = randstring(3) + folder_2 = randstring(3) + + random_slash = '' + for i in range(1, randint(1,10)): + random_slash += slash + + posix_path = posixpath.join(folder_1, folder_2) + correct_path = slash + posix_path + + path_without_slash = posix_path + path_starts_with_random_slash = random_slash + posix_path + path_ends_with_random_slash = posix_path + random_slash + path_with_slash = random_slash + posix_path + random_slash + + assert normalize_file_path(path_without_slash) == correct_path + assert normalize_file_path(path_starts_with_random_slash) == correct_path + assert normalize_file_path(path_ends_with_random_slash) == correct_path + assert normalize_file_path(path_with_slash) == correct_path diff --git a/thirdpart/shibboleth/middleware.py b/thirdpart/shibboleth/middleware.py index b2ff68c48a..78deae205d 100755 --- a/thirdpart/shibboleth/middleware.py +++ b/thirdpart/shibboleth/middleware.py @@ -1,3 +1,5 @@ +import logging + from django.conf import settings from django.contrib.auth.middleware import RemoteUserMiddleware from django.core.exceptions import ImproperlyConfigured @@ -14,6 +16,9 @@ from seahub.profile.models import Profile from seahub.utils.file_size import get_quota_from_string from seahub.utils.user_permissions import get_user_role +# Get an instance of a logger +logger = logging.getLogger(__name__) + class ShibbolethRemoteUserMiddleware(RemoteUserMiddleware): """ @@ -35,7 +40,7 @@ class ShibbolethRemoteUserMiddleware(RemoteUserMiddleware): #To support logout. If this variable is True, do not #authenticate user and return now. - if request.session.get(LOGOUT_SESSION_KEY) == True: + if request.session.get(LOGOUT_SESSION_KEY) is True: return else: #Delete the shib reauth session key if present. @@ -84,7 +89,8 @@ class ShibbolethRemoteUserMiddleware(RemoteUserMiddleware): # call make profile. self.make_profile(user, shib_meta) user_role = self.update_user_role(user, shib_meta) - self.update_user_quota(user, user_role) + if user_role: + self.update_user_quota(user, user_role) #setup session. self.setup_session(request) request.shib_login = True @@ -169,6 +175,7 @@ class ShibbolethRemoteUserMiddleware(RemoteUserMiddleware): def update_user_quota(self, user, user_role): if user.permissions.role_quota(): quota = get_quota_from_string(user.permissions.role_quota()) + logger.info('Set quota[%d] for user: %s, role[%s]' % (quota, user.username, user_role)) seafile_api.set_role_quota(user_role, quota) else: return