Commits

Luke Plant committed ea66212

Fixed bug with redirect loop from pages using @camp_admin_required decorator

Comments (0)

Files changed (2)

cciw/officers/tests/references.py

     def test_page_officers_denied(self):
         self._twill_login(OFFICER)
         tc.go(make_django_url("cciw.officers.views.manage_references", year=2000, number=1))
-        # Currently we get redirected to /officers/ page if insufficient
-        # privileges.
-        self.assertEqual(tc.get_browser().get_url().split('?')[0], make_django_url("cciw.officers.views.index"))
+        tc.code(403)
         tc.notfind('For camp 2000-1')
 
 

cciw/officers/views.py

 import datetime
 import operator
 import urlparse
+from functools import wraps
 
 from django import forms
 from django.conf import settings
 from django.contrib.admin.views.decorators import staff_member_required
 from django.contrib.auth import REDIRECT_FIELD_NAME
-from django.contrib.auth.decorators import user_passes_test
 from django.contrib.auth.models import User
 from django.contrib import messages
 from django.core.exceptions import PermissionDenied, ObjectDoesNotExist
 from django.core.urlresolvers import reverse
 from django.core.validators import email_re
-from django.http import Http404, HttpResponseRedirect, HttpResponse
+from django.http import Http404, HttpResponseRedirect, HttpResponse, HttpResponseForbidden
 from django.shortcuts import render, get_object_or_404
 from django.template import RequestContext
 from django.template.loader import render_to_string
             user.groups.filter(name=SECRETARY_GROUP_NAME)).exists() \
         or user.camps_as_admin.exists() > 0
 
-camp_admin_required = user_passes_test(_is_camp_admin)
+
+def user_passes_test_improved(test_func):
+    """
+    Like user_passes_test, but doesn't redirect user to login screen if they are
+    already logged in.
+    """
+    def decorator(view_func):
+        @wraps(view_func)
+        def _wrapped_view(request, *args, **kwargs):
+            if test_func(request.user):
+                return view_func(request, *args, **kwargs)
+            if request.user.is_authenticated():
+                return HttpResponseForbidden("<h1>Access denied</h1>")
+
+            path = request.build_absolute_uri()
+            # If the login url is the same scheme and net location then just
+            # use the path as the "next" url.
+            login_scheme, login_netloc = urlparse.urlparse(login_url or
+                                                           settings.LOGIN_URL)[:2]
+            current_scheme, current_netloc = urlparse.urlparse(path)[:2]
+            if ((not login_scheme or login_scheme == current_scheme) and
+                (not login_netloc or login_netloc == current_netloc)):
+                path = request.get_full_path()
+            from django.contrib.auth.views import redirect_to_login
+            return redirect_to_login(path, login_url, redirect_field_name)
+        return _wrapped_view
+    return decorator
+
+
+camp_admin_required = user_passes_test_improved(_is_camp_admin)
 
 
 def _is_cciw_secretary(user):