From cbb0d34ca13e8ff52059b785a0742bf7620313e2 Mon Sep 17 00:00:00 2001 From: lian Date: Mon, 2 Mar 2015 14:10:44 +0800 Subject: [PATCH 01/11] [web-api] Use p and size as args --- seahub/api2/urls.py | 2 +- seahub/api2/views.py | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/seahub/api2/urls.py b/seahub/api2/urls.py index 877656cffe..904f7191b2 100644 --- a/seahub/api2/urls.py +++ b/seahub/api2/urls.py @@ -36,7 +36,7 @@ urlpatterns = patterns('', url(r'^repos/(?P[-0-9-a-f]{36})/dir/sub_repo/$', DirSubRepoView.as_view()), url(r'^repos/(?P[-0-9-a-f]{36})/dir/share/$', DirShareView.as_view()), url(r'^repos/(?P[-0-9-a-f]{36})/dir/download/$', DirDownloadView.as_view()), - url(r'^repos/(?P[-0-9-a-f]{36})/thumbnail/(?P.+)$', ThumbnailView.as_view(), name='api2-thumbnail'), + url(r'^repos/(?P[-0-9-a-f]{36})/thumbnail/$', ThumbnailView.as_view(), name='api2-thumbnail'), url(r'^starredfiles/', StarredFileView.as_view(), name='starredfiles'), url(r'^shared-repos/$', SharedRepos.as_view(), name='sharedrepos'), url(r'^shared-repos/(?P[-0-9-a-f]{36})/$', SharedRepo.as_view(), name='sharedrepo'), diff --git a/seahub/api2/views.py b/seahub/api2/views.py index f10d3a12ff..82b673b87c 100644 --- a/seahub/api2/views.py +++ b/seahub/api2/views.py @@ -3474,7 +3474,7 @@ class ThumbnailView(APIView): permission_classes = (IsAuthenticated,) throttle_classes = (UserRateThrottle, ) - def get(self, request, repo_id, path): + def get(self, request, repo_id): repo = get_repo(repo_id) if not repo: @@ -3489,10 +3489,14 @@ class ThumbnailView(APIView): return api_error(status.HTTP_403_FORBIDDEN, 'Thumbnail function is not enabled.') - size = request.GET.get('s', None) + size = request.GET.get('size', None) + path = request.GET.get('p', None) if size is None: return api_error(status.HTTP_400_BAD_REQUEST, 'Size is missing.') + if path is None: + return api_error(status.HTTP_400_BAD_REQUEST, 'Path is missing.') + obj_id = get_file_id_by_path(repo_id, path) if obj_id is None: From 52d23ed46e5a70a041f848f95c98c8fc9e1ff10c Mon Sep 17 00:00:00 2001 From: lian Date: Mon, 2 Mar 2015 15:12:10 +0800 Subject: [PATCH 02/11] [image-preivew] abort ajax request if mouse leave preview wrap --- seahub/templates/repo.html | 75 +++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/seahub/templates/repo.html b/seahub/templates/repo.html index 4c98d5447f..a325c49076 100644 --- a/seahub/templates/repo.html +++ b/seahub/templates/repo.html @@ -2370,7 +2370,7 @@ function updateCmt() { {% endif %} {% if not repo.encrypted and ENABLE_THUMBNAIL %} -var timer, +var timer, ajaxRequest = $.ajax(), default_size = {{PREVIEW_DEFAULT_SIZE}}, preview_wrap = $('
') .appendTo("body") @@ -2385,50 +2385,59 @@ $("#repo-file-list").on({ file_item = thumbnail.closest('.file-item'); timer = setTimeout(function () { - $.ajax({ - url: '{% url 'thumbnail_create' repo.id %}?path=' + e(cur_path+file_item.attr('data-name')) + '&size=' + default_size, - cache: false, - dataType: 'json', - success: function(data) { - image_preview.attr("src", data.thumbnail_src); + ajaxRequest = $.ajax({ + url: '{% url 'thumbnail_create' repo.id %}?path=' + e(cur_path+file_item.attr('data-name')) + '&size=' + default_size, + cache: false, + dataType: 'json', + success: function(data) { + image_preview.attr("src", data.thumbnail_src); - var file_item_offset = file_item.offset(), - thumbnail_offset = thumbnail.offset(), + var file_item_offset = file_item.offset(), + thumbnail_offset = thumbnail.offset(), - wrap_width = preview_wrap.outerWidth(), - wrap_padding = parseInt(preview_wrap.css('padding-top')), + wrap_width = preview_wrap.outerWidth(), + wrap_padding = parseInt(preview_wrap.css('padding-top')), - caret_width = parseInt(caret.css('border-top-width')), - caret_pos_x = (default_size)/2 + wrap_padding - caret_width, - caret_pos_y = default_size + 2 * wrap_padding, + caret_width = parseInt(caret.css('border-top-width')), + caret_pos_x = (default_size)/2 + wrap_padding - caret_width, + caret_pos_y = default_size + 2 * wrap_padding, - wrap_left = file_item_offset.left - wrap_width - caret_width; + wrap_left = file_item_offset.left - wrap_width - caret_width; - if (wrap_left >= 0) { - caret.removeClass('bottom-outer-caret') - .addClass('right-outer-caret') - .css({'top':caret_pos_x + 'px', 'left':caret_pos_y + 'px'}); + if (wrap_left >= 0) { + caret.removeClass('bottom-outer-caret') + .addClass('right-outer-caret') + .css({'top':caret_pos_x + 'px', 'left':caret_pos_y + 'px'}); - preview_wrap.css({ - 'top' : (thumbnail_offset.top + (thumbnail.height() - wrap_width)/2) + 'px', - 'left' : wrap_left + 'px' - }).fadeIn(); - } else { - caret.removeClass("right-outer-caret") - .addClass("bottom-outer-caret") - .css({'top':caret_pos_y + 'px', 'left':caret_pos_x + 'px'}); + preview_wrap.css({ + 'top' : (thumbnail_offset.top + (thumbnail.height() - wrap_width)/2) + 'px', + 'left' : wrap_left + 'px' + }).fadeIn(); + } else { + caret.removeClass("right-outer-caret") + .addClass("bottom-outer-caret") + .css({'top':caret_pos_y + 'px', 'left':caret_pos_x + 'px'}); - preview_wrap.css({ - 'top' : (file_item_offset.top - wrap_width) - caret_width + 'px', - 'left' : (thumbnail_offset.left + (thumbnail.width() - wrap_width)/2) + 'px' - }).fadeIn(); + preview_wrap.css({ + 'top' : (file_item_offset.top - wrap_width) - caret_width + 'px', + 'left' : (thumbnail_offset.left + (thumbnail.width() - wrap_width)/2) + 'px' + }).fadeIn(); + } + }, + error: function(xhr, textStatus, errorThrown) { + if (textStatus != "abort") { + if (xhr.responseText) { + feedback($.parseJSON(xhr.responseText).error, 'error'); + } else { + feedback("{% trans "Failed. Please check the network." %}", 'error'); + }; + }; } - }, - error: ajaxErrorHandler }); }, 200); }, mouseleave: function() { + ajaxRequest.abort(); clearTimeout(timer); preview_wrap.hide(); image_preview.attr('src', ''); // for ff. In ff, when hover, the last preview image would be shown first, then the right one. From 317362468ae257d68a29c9a004e9f0139d0da723 Mon Sep 17 00:00:00 2001 From: llj Date: Mon, 2 Mar 2015 16:46:44 +0800 Subject: [PATCH 03/11] bugfix for fileupload --- seahub/templates/repo.html | 9 ++++++--- seahub/templates/view_shared_upload_link.html | 7 +++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/seahub/templates/repo.html b/seahub/templates/repo.html index 4c98d5447f..4b34e074af 100644 --- a/seahub/templates/repo.html +++ b/seahub/templates/repo.html @@ -325,6 +325,7 @@ $(function() { var file = data.files[0]; if (file.name == '.') { data.files.shift(); + return; } if (file.webkitRelativePath) { // for 'upload folder' file.relative_path = file.webkitRelativePath; @@ -338,7 +339,9 @@ $(function() { fu_status.html(fu_status_.uploading); }) .bind('fileuploadsubmit', function(e, data) { - var _this = $(this); + if (data.files.length == 0) { + return false; + } var file = data.files[0]; // get url(token) for every file if (!file.error) { @@ -359,7 +362,7 @@ $(function() { {% endif %} data.url = ret['url']; - data.jqXHR = _this.fileupload('send', data); + data.jqXHR = popup.fileupload('send', data); }, error: function() { file.error = "{% trans "Failed to get upload url" %}"; @@ -2071,7 +2074,7 @@ $('#add-new-file-form, #add-new-dir-form, #rename-form, #mv-form').submit(functi paddingTop: 50 }, focus:false}); var det_text = op == 'mv' ? "{% trans "Moving %(name)s" %}": "{% trans "Copying %(name)s" %}"; - details.html(det_text.replace('%(name)s', trimFilename(obj_name, 20))); + details.html(det_text.replace('%(name)s', trimFilename(obj_name, 20))).removeClass('vh'); $('#mv-progress').progressbar(); req_progress(); }, 100); diff --git a/seahub/templates/view_shared_upload_link.html b/seahub/templates/view_shared_upload_link.html index 14e8dde4e3..93b076eba4 100644 --- a/seahub/templates/view_shared_upload_link.html +++ b/seahub/templates/view_shared_upload_link.html @@ -117,6 +117,7 @@ form.fileupload({ var file = data.files[0]; if (file.name == '.') { data.files.shift(); + return; } if (file.webkitRelativePath) { // for 'upload folder' file.relative_path = file.webkitRelativePath; @@ -127,7 +128,9 @@ form.fileupload({ {% endif %} }) .bind('fileuploadsubmit', function(e, data) { - var _this = $(this); + if (data.files.length == 0) { + return false; + } var file = data.files[0]; // get url(token) for every file if (!file.error) { @@ -148,7 +151,7 @@ form.fileupload({ {% endif %} data.url = ret['url']; - data.jqXHR = _this.fileupload('send', data); + data.jqXHR = form.fileupload('send', data); }, error: function() { file.error = "{% trans "Failed to get upload url" %}"; From a9a2f8a6aaefcf80bd1715e63d63e2308a2ce881 Mon Sep 17 00:00:00 2001 From: Shuai Lin Date: Tue, 3 Mar 2015 20:56:17 +0800 Subject: [PATCH 04/11] improve client last access time in devices page Take repos' last sync time into consideration. --- seahub/utils/devices.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/seahub/utils/devices.py b/seahub/utils/devices.py index c6357738fd..3f4ceb424f 100644 --- a/seahub/utils/devices.py +++ b/seahub/utils/devices.py @@ -1,4 +1,5 @@ import logging +import datetime from seaserv import seafile_api from seahub.api2.models import TokenV2, DESKTOP_PLATFORMS @@ -10,6 +11,10 @@ __all__ = [ 'do_unlink_device', ] +def _last_sync_time(repos): + latest_sync_time = max([r['sync_time'] for r in repos]) + return datetime.datetime.fromtimestamp(latest_sync_time) + def get_user_devices(username): devices = TokenV2.objects.get_user_devices(username) @@ -18,7 +23,11 @@ def get_user_devices(username): for device in devices: if device['platform'] in DESKTOP_PLATFORMS: peer_id = device['device_id'] - device['synced_repos'] = peer_repos_map.get(peer_id, []) + repos = peer_repos_map.get(peer_id, []) + device['synced_repos'] = repos + if repos: + device['last_accessed'] = max(device['last_accessed'], + _last_sync_time(repos)) return devices @@ -61,7 +70,7 @@ def get_user_synced_repo_infos(username): def do_unlink_device(username, platform, device_id): if platform in DESKTOP_PLATFORMS: # For desktop client, we also remove the sync tokens - msg = 'failed to delete_repo_tokens_by_peer_id' + msg = 'failed to delete_repo_tokens_by_peer_id' try: if seafile_api.delete_repo_tokens_by_peer_id(username, device_id) < 0: logger.warning(msg) From f63d6aab6eed0c400c3ef1477d3d414d71effd0e Mon Sep 17 00:00:00 2001 From: lian Date: Thu, 5 Mar 2015 15:24:47 +0800 Subject: [PATCH 05/11] [web-api] Check if dir existes before copy file --- seahub/api2/views.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/seahub/api2/views.py b/seahub/api2/views.py index 82b673b87c..ca62482cbd 100644 --- a/seahub/api2/views.py +++ b/seahub/api2/views.py @@ -1140,6 +1140,10 @@ class OpCopyView(APIView): return api_error(status.HTTP_400_BAD_REQUEST, 'Missing argument.') + if seafile_api.get_dir_id_by_path(repo_id, parent_dir) is None or \ + seafile_api.get_dir_id_by_path(repo_id, dst_dir) is None: + return api_error(status.HTTP_400_BAD_REQUEST, 'Path does not exist.') + parent_dir_utf8 = parent_dir.encode('utf-8') for file_name in file_names.split(':'): file_name = unquote(file_name.encode('utf-8')) From 146926920e739f74bb01d32bb6801cc30e58c793 Mon Sep 17 00:00:00 2001 From: zhengxie Date: Thu, 5 Mar 2015 14:48:07 +0800 Subject: [PATCH 06/11] Add shibboleth login option --- seahub/auth/views.py | 17 ++++++++++------- seahub/templates/registration/login.html | 10 ++++++++++ seahub/urls.py | 5 +++++ seahub/views/__init__.py | 3 +++ 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/seahub/auth/views.py b/seahub/auth/views.py index 2c0a12a3ce..32c7f2ed89 100644 --- a/seahub/auth/views.py +++ b/seahub/auth/views.py @@ -191,14 +191,17 @@ def login(request, template_name='registration/login.html', else: signup_url = '' + enable_shib_login = getattr(settings, 'ENABLE_SHIB_LOGIN', False) + return render_to_response(template_name, { - 'form': form, - redirect_field_name: redirect_to, - 'site': current_site, - 'site_name': current_site.name, - 'remember_days': settings.LOGIN_REMEMBER_DAYS, - 'signup_url': signup_url, - }, context_instance=RequestContext(request)) + 'form': form, + redirect_field_name: redirect_to, + 'site': current_site, + 'site_name': current_site.name, + 'remember_days': settings.LOGIN_REMEMBER_DAYS, + 'signup_url': signup_url, + 'enable_shib_login': enable_shib_login, + }, context_instance=RequestContext(request)) def login_simple_check(request): """A simple check for login called by thirdpart systems(OA, etc). diff --git a/seahub/templates/registration/login.html b/seahub/templates/registration/login.html index 96a153cfe5..dcbbe964f6 100644 --- a/seahub/templates/registration/login.html +++ b/seahub/templates/registration/login.html @@ -61,6 +61,10 @@ {% if enable_signup %} {% trans "Signup" %} {% endif %} + + {% if enable_shib_login %} + + {% endif %} {% endblock %} @@ -126,5 +130,11 @@ $(function() { }); })(); +$(function() { + $('#shib-login').click(function() { + window.location = "{% url 'shib_login' %}"; + return false; + }); +}); {% endblock %} diff --git a/seahub/urls.py b/seahub/urls.py index 43c4ff405a..9d78aab29a 100644 --- a/seahub/urls.py +++ b/seahub/urls.py @@ -253,6 +253,11 @@ if getattr(settings, 'MULTI_TENANCY', False): (r'^org/', include('seahub_extra.organizations.urls')), ) +if getattr(settings, 'ENABLE_SHIB_LOGIN', False): + urlpatterns += patterns('', + url(r'^shib-login/', shib_login, name="shib_login"), + ) + # serve office converter static files from seahub.utils import HAS_OFFICE_CONVERTER, CLUSTER_MODE, OFFICE_CONVERTOR_NODE if HAS_OFFICE_CONVERTER: diff --git a/seahub/views/__init__.py b/seahub/views/__init__.py index 665186b7f2..54264af5c6 100644 --- a/seahub/views/__init__.py +++ b/seahub/views/__init__.py @@ -1953,3 +1953,6 @@ def image_view(request, filename): if content_encoding: response['Content-Encoding'] = content_encoding return response + +def shib_login(request): + return HttpResponseRedirect(reverse('myhome')) From 75cf92aca694a4dd8a7282150d8f28dce4c9ea62 Mon Sep 17 00:00:00 2001 From: David Kreitschmann Date: Thu, 5 Mar 2015 00:09:06 +0100 Subject: [PATCH 07/11] Environment variable for shibboleth user name can be changed. The default is REMOTE_USER which is provided by e.g. apache modules. --- thirdpart/shibboleth/app_settings.py | 2 ++ thirdpart/shibboleth/middleware.py | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/thirdpart/shibboleth/app_settings.py b/thirdpart/shibboleth/app_settings.py index e64b19fc1a..57bed1f8ca 100755 --- a/thirdpart/shibboleth/app_settings.py +++ b/thirdpart/shibboleth/app_settings.py @@ -11,6 +11,8 @@ SHIB_ATTRIBUTE_MAP = getattr(settings, 'SHIBBOLETH_ATTRIBUTE_MAP', default_shib_ #Set to true if you are testing and want to insert sample headers. SHIB_MOCK_HEADERS = getattr(settings, 'SHIBBOLETH_MOCK_HEADERS', False) +SHIB_USER_HEADER = getattr(settings, 'SHIBBOLETH_USER_HEADER', "REMOTE_USER") + LOGIN_URL = getattr(settings, 'LOGIN_URL', None) if not LOGIN_URL: diff --git a/thirdpart/shibboleth/middleware.py b/thirdpart/shibboleth/middleware.py index 58c9e22694..f91e90dd05 100755 --- a/thirdpart/shibboleth/middleware.py +++ b/thirdpart/shibboleth/middleware.py @@ -1,7 +1,7 @@ from django.contrib.auth.middleware import RemoteUserMiddleware from django.core.exceptions import ImproperlyConfigured -from shibboleth.app_settings import SHIB_ATTRIBUTE_MAP, LOGOUT_SESSION_KEY +from shibboleth.app_settings import SHIB_ATTRIBUTE_MAP, LOGOUT_SESSION_KEY, SHIB_USER_HEADER from seahub import auth from seahub.api2.models import Token @@ -35,7 +35,7 @@ class ShibbolethRemoteUserMiddleware(RemoteUserMiddleware): #Locate the remote user header. try: - username = request.META[self.header] + username = request.META[SHIB_USER_HEADER] except KeyError: # If specified header doesn't exist then return (leaving # request.user set to AnonymousUser by the From 4b094b698b2beeb2b8c514fcf8ea31adf0501c34 Mon Sep 17 00:00:00 2001 From: lian Date: Thu, 5 Mar 2015 15:49:49 +0800 Subject: [PATCH 08/11] [web-api] check if dst-repo/dst-dir existes before copy file --- seahub/api2/views.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/seahub/api2/views.py b/seahub/api2/views.py index ca62482cbd..e28f7880b2 100644 --- a/seahub/api2/views.py +++ b/seahub/api2/views.py @@ -1140,8 +1140,11 @@ class OpCopyView(APIView): return api_error(status.HTTP_400_BAD_REQUEST, 'Missing argument.') + if not get_repo(dst_repo): + return api_error(status.HTTP_404_NOT_FOUND, 'Repo not found.') + if seafile_api.get_dir_id_by_path(repo_id, parent_dir) is None or \ - seafile_api.get_dir_id_by_path(repo_id, dst_dir) is None: + seafile_api.get_dir_id_by_path(dst_repo, dst_dir) is None: return api_error(status.HTTP_400_BAD_REQUEST, 'Path does not exist.') parent_dir_utf8 = parent_dir.encode('utf-8') From d20b0ed44ecce9cb6eb77da34a7f5863154dd3f2 Mon Sep 17 00:00:00 2001 From: lian Date: Thu, 5 Mar 2015 16:06:51 +0800 Subject: [PATCH 09/11] [web-api] update copy file api set parent-dir default '/' if no parameter 'p' --- seahub/api2/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seahub/api2/views.py b/seahub/api2/views.py index e28f7880b2..12df5ef06a 100644 --- a/seahub/api2/views.py +++ b/seahub/api2/views.py @@ -1131,7 +1131,7 @@ class OpCopyView(APIView): if resp: return resp - parent_dir = request.GET.get('p', None) + parent_dir = request.POST.get('p', '/') dst_repo = request.POST.get('dst_repo', None) dst_dir = request.POST.get('dst_dir', None) file_names = request.POST.get("file_names", None) From 6757126da95cb2bf26a6a8e6cbfcab3caaf06e06 Mon Sep 17 00:00:00 2001 From: zhengxie Date: Thu, 5 Mar 2015 16:37:10 +0800 Subject: [PATCH 10/11] [shib] Fix bug when authenticate shib user, issure #394 --- thirdpart/shibboleth/backends.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/thirdpart/shibboleth/backends.py b/thirdpart/shibboleth/backends.py index bfd51ffbe3..edbbc26d28 100644 --- a/thirdpart/shibboleth/backends.py +++ b/thirdpart/shibboleth/backends.py @@ -41,11 +41,12 @@ class ShibbolethRemoteUserBackend(RemoteUserBackend): # Note that this could be accomplished in one try-except clause, but # instead we use get_or_create when creating unknown users since it has # built-in safeguards for multiple threads. - if self.create_unknown_user: - user = User.objects.create_user(email=username, is_active=True) - else: - try: - user = User.objects.get(email=username) - except User.DoesNotExist: + try: + user = User.objects.get(email=username) + except User.DoesNotExist: + if self.create_unknown_user: + user = User.objects.create_user(email=username, is_active=True) + else: pass + return user From 7bd7986384a9a7268b5a0282779f14fb31224d27 Mon Sep 17 00:00:00 2001 From: zhengxie Date: Thu, 5 Mar 2015 17:15:10 +0800 Subject: [PATCH 11/11] Fix bug in shib login --- seahub/templates/registration/login.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/seahub/templates/registration/login.html b/seahub/templates/registration/login.html index dcbbe964f6..55ee0d9aed 100644 --- a/seahub/templates/registration/login.html +++ b/seahub/templates/registration/login.html @@ -130,11 +130,13 @@ $(function() { }); })(); +{% if enable_shib_login %} $(function() { $('#shib-login').click(function() { window.location = "{% url 'shib_login' %}"; return false; }); }); +{% endif %} {% endblock %}