Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #4376 -- login_required now works with bound methods. Thanks, S…

…teven Bethard.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@6658 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 8eeb9feab071caf5ad568ce292d32a2ebf540f62 1 parent 8216abe
Luke Plant authored November 07, 2007
46  django/contrib/auth/decorators.py
@@ -8,19 +8,9 @@ def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIE
8 8
     redirecting to the log-in page if necessary. The test should be a callable
9 9
     that takes the user object and returns True if the user passes.
10 10
     """
11  
-    if not login_url:
12  
-        from django.conf import settings
13  
-        login_url = settings.LOGIN_URL
14  
-    def _dec(view_func):
15  
-        def _checklogin(request, *args, **kwargs):
16  
-            if test_func(request.user):
17  
-                return view_func(request, *args, **kwargs)
18  
-            return HttpResponseRedirect('%s?%s=%s' % (login_url, redirect_field_name, urlquote(request.get_full_path())))
19  
-        _checklogin.__doc__ = view_func.__doc__
20  
-        _checklogin.__dict__ = view_func.__dict__
21  
-
22  
-        return _checklogin
23  
-    return _dec
  11
+    def decorate(view_func):
  12
+        return _CheckLogin(view_func, test_func, login_url, redirect_field_name)
  13
+    return decorate
24 14
 
25 15
 def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME):
26 16
     """
@@ -42,3 +32,33 @@ def permission_required(perm, login_url=None):
42 32
     """
43 33
     return user_passes_test(lambda u: u.has_perm(perm), login_url=login_url)
44 34
 
  35
+class _CheckLogin(object):
  36
+    """
  37
+    Class that checks that the user passes the given test, redirecting to
  38
+    the log-in page if necessary. If the test is passed, the view function
  39
+    is invoked. The test should be a callable that takes the user object
  40
+    and returns True if the user passes.
  41
+
  42
+    We use a class here so that we can define __get__. This way, when a
  43
+    _CheckLogin object is used as a method decorator, the view function
  44
+    is properly bound to its instance.
  45
+    """
  46
+    def __init__(self, view_func, test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
  47
+        if not login_url:
  48
+            from django.conf import settings
  49
+            login_url = settings.LOGIN_URL
  50
+        self.view_func = view_func
  51
+        self.test_func = test_func
  52
+        self.login_url = login_url
  53
+        self.redirect_field_name = redirect_field_name
  54
+        
  55
+    def __get__(self, obj, cls=None):
  56
+        view_func = self.view_func.__get__(obj, cls)
  57
+        return _CheckLogin(view_func, self.test_func, self.login_url, self.redirect_field_name)
  58
+    
  59
+    def __call__(self, request, *args, **kwargs):
  60
+        if self.test_func(request.user):
  61
+            return self.view_func(request, *args, **kwargs)
  62
+        path = urlquote(request.get_full_path())
  63
+        tup = self.login_url, self.redirect_field_name, path
  64
+        return HttpResponseRedirect('%s?%s=%s' % tup)
50  tests/modeltests/test_client/models.py
@@ -250,6 +250,22 @@ def test_view_with_login(self):
250 250
         self.assertEqual(response.status_code, 200)
251 251
         self.assertEqual(response.context['user'].username, 'testclient')
252 252
 
  253
+    def test_view_with_method_login(self):
  254
+        "Request a page that is protected with a @login_required method"
  255
+        
  256
+        # Get the page without logging in. Should result in 302.
  257
+        response = self.client.get('/test_client/login_protected_method_view/')
  258
+        self.assertRedirects(response, 'http://testserver/accounts/login/?next=/test_client/login_protected_method_view/')
  259
+        
  260
+        # Log in
  261
+        login = self.client.login(username='testclient', password='password')
  262
+        self.failUnless(login, 'Could not log in')
  263
+
  264
+        # Request a page that requires a login
  265
+        response = self.client.get('/test_client/login_protected_method_view/')
  266
+        self.assertEqual(response.status_code, 200)
  267
+        self.assertEqual(response.context['user'].username, 'testclient')
  268
+
253 269
     def test_view_with_login_and_custom_redirect(self):
254 270
         "Request a page that is protected with @login_required(redirect_field_name='redirect_to')"
255 271
         
@@ -295,6 +311,40 @@ def test_logout(self):
295 311
         response = self.client.get('/test_client/login_protected_view/')
296 312
         self.assertRedirects(response, 'http://testserver/accounts/login/?next=/test_client/login_protected_view/')
297 313
 
  314
+    def test_view_with_permissions(self):
  315
+        "Request a page that is protected with @permission_required"
  316
+        
  317
+        # Get the page without logging in. Should result in 302.
  318
+        response = self.client.get('/test_client/permission_protected_view/')
  319
+        self.assertRedirects(response, 'http://testserver/accounts/login/?next=/test_client/permission_protected_view/')
  320
+        
  321
+        # Log in
  322
+        login = self.client.login(username='testclient', password='password')
  323
+        self.failUnless(login, 'Could not log in')
  324
+
  325
+        # Log in with wrong permissions. Should result in 302.
  326
+        response = self.client.get('/test_client/permission_protected_view/')
  327
+        self.assertRedirects(response, 'http://testserver/accounts/login/?next=/test_client/permission_protected_view/')
  328
+
  329
+        # TODO: Log in with right permissions and request the page again
  330
+
  331
+    def test_view_with_method_permissions(self):
  332
+        "Request a page that is protected with a @permission_required method"
  333
+        
  334
+        # Get the page without logging in. Should result in 302.
  335
+        response = self.client.get('/test_client/permission_protected_method_view/')
  336
+        self.assertRedirects(response, 'http://testserver/accounts/login/?next=/test_client/permission_protected_method_view/')
  337
+        
  338
+        # Log in
  339
+        login = self.client.login(username='testclient', password='password')
  340
+        self.failUnless(login, 'Could not log in')
  341
+
  342
+        # Log in with wrong permissions. Should result in 302.
  343
+        response = self.client.get('/test_client/permission_protected_method_view/')
  344
+        self.assertRedirects(response, 'http://testserver/accounts/login/?next=/test_client/permission_protected_method_view/')
  345
+
  346
+        # TODO: Log in with right permissions and request the page again
  347
+
298 348
     def test_session_modifying_view(self):
299 349
         "Request a page that modifies the session"
300 350
         # Session value isn't set initially
3  tests/modeltests/test_client/urls.py
@@ -13,7 +13,10 @@
13 13
     (r'^form_view/$', views.form_view),
14 14
     (r'^form_view_with_template/$', views.form_view_with_template),
15 15
     (r'^login_protected_view/$', views.login_protected_view),
  16
+    (r'^login_protected_method_view/$', views.login_protected_method_view),
16 17
     (r'^login_protected_view_custom_redirect/$', views.login_protected_view_changed_redirect),
  18
+    (r'^permission_protected_view/$', views.permission_protected_view),
  19
+    (r'^permission_protected_method_view/$', views.permission_protected_method_view),
17 20
     (r'^session_view/$', views.session_view),
18 21
     (r'^broken_view/$', views.broken_view),
19 22
     (r'^mail_sending_view/$', views.mail_sending_view),
34  tests/modeltests/test_client/views.py
@@ -3,7 +3,7 @@
3 3
 from django.core.mail import EmailMessage, SMTPConnection
4 4
 from django.template import Context, Template
5 5
 from django.http import HttpResponse, HttpResponseRedirect, HttpResponseNotFound
6  
-from django.contrib.auth.decorators import login_required
  6
+from django.contrib.auth.decorators import login_required, permission_required
7 7
 from django.newforms.forms import Form
8 8
 from django.newforms import fields
9 9
 from django.shortcuts import render_to_response
@@ -130,6 +130,38 @@ def login_protected_view_changed_redirect(request):
130 130
     return HttpResponse(t.render(c))
131 131
 login_protected_view_changed_redirect = login_required(redirect_field_name="redirect_to")(login_protected_view_changed_redirect)
132 132
 
  133
+def permission_protected_view(request):
  134
+    "A simple view that is permission protected."
  135
+    t = Template('This is a permission protected test. '
  136
+                 'Username is {{ user.username }}. '
  137
+                 'Permissions are {{ user.get_all_permissions }}.' ,
  138
+                 name='Permissions Template')
  139
+    c = Context({'user': request.user})
  140
+    return HttpResponse(t.render(c))
  141
+permission_protected_view = permission_required('modeltests.test_perm')(permission_protected_view)
  142
+
  143
+class _ViewManager(object):
  144
+    def login_protected_view(self, request):
  145
+        t = Template('This is a login protected test using a method. '
  146
+                     'Username is {{ user.username }}.',
  147
+                     name='Login Method Template')
  148
+        c = Context({'user': request.user})
  149
+        return HttpResponse(t.render(c))
  150
+    login_protected_view = login_required(login_protected_view)
  151
+
  152
+    def permission_protected_view(self, request):
  153
+        t = Template('This is a permission protected test using a method. '
  154
+                     'Username is {{ user.username }}. '
  155
+                     'Permissions are {{ user.get_all_permissions }}.' ,
  156
+                     name='Permissions Template')
  157
+        c = Context({'user': request.user})
  158
+        return HttpResponse(t.render(c))
  159
+    permission_protected_view = permission_required('modeltests.test_perm')(permission_protected_view)
  160
+
  161
+_view_manager = _ViewManager()
  162
+login_protected_method_view = _view_manager.login_protected_view
  163
+permission_protected_method_view = _view_manager.permission_protected_view
  164
+
133 165
 def session_view(request):
134 166
     "A view that modifies the session"
135 167
     request.session['tobacconist'] = 'hovercraft'

0 notes on commit 8eeb9fe

Please sign in to comment.
Something went wrong with that request. Please try again.