Author: lukeplant
Date: 2007-11-07 16:45:07 -0600 (Wed, 07 Nov 2007)
New Revision: 6658

Modified:
   django/trunk/django/contrib/auth/decorators.py
   django/trunk/tests/modeltests/test_client/models.py
   django/trunk/tests/modeltests/test_client/urls.py
   django/trunk/tests/modeltests/test_client/views.py
Log:
Fixed #4376 -- login_required now works with bound methods.  Thanks, Steven 
Bethard.



Modified: django/trunk/django/contrib/auth/decorators.py
===================================================================
--- django/trunk/django/contrib/auth/decorators.py      2007-11-07 06:36:24 UTC 
(rev 6657)
+++ django/trunk/django/contrib/auth/decorators.py      2007-11-07 22:45:07 UTC 
(rev 6658)
@@ -8,20 +8,10 @@
     redirecting to the log-in page if necessary. The test should be a callable
     that takes the user object and returns True if the user passes.
     """
-    if not login_url:
-        from django.conf import settings
-        login_url = settings.LOGIN_URL
-    def _dec(view_func):
-        def _checklogin(request, *args, **kwargs):
-            if test_func(request.user):
-                return view_func(request, *args, **kwargs)
-            return HttpResponseRedirect('%s?%s=%s' % (login_url, 
redirect_field_name, urlquote(request.get_full_path())))
-        _checklogin.__doc__ = view_func.__doc__
-        _checklogin.__dict__ = view_func.__dict__
+    def decorate(view_func):
+        return _CheckLogin(view_func, test_func, login_url, 
redirect_field_name)
+    return decorate
 
-        return _checklogin
-    return _dec
-
 def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME):
     """
     Decorator for views that checks that the user is logged in, redirecting
@@ -42,3 +32,33 @@
     """
     return user_passes_test(lambda u: u.has_perm(perm), login_url=login_url)
 
+class _CheckLogin(object):
+    """
+    Class that checks that the user passes the given test, redirecting to
+    the log-in page if necessary. If the test is passed, the view function
+    is invoked. The test should be a callable that takes the user object
+    and returns True if the user passes.
+
+    We use a class here so that we can define __get__. This way, when a
+    _CheckLogin object is used as a method decorator, the view function
+    is properly bound to its instance.
+    """
+    def __init__(self, view_func, test_func, login_url=None, 
redirect_field_name=REDIRECT_FIELD_NAME):
+        if not login_url:
+            from django.conf import settings
+            login_url = settings.LOGIN_URL
+        self.view_func = view_func
+        self.test_func = test_func
+        self.login_url = login_url
+        self.redirect_field_name = redirect_field_name
+        
+    def __get__(self, obj, cls=None):
+        view_func = self.view_func.__get__(obj, cls)
+        return _CheckLogin(view_func, self.test_func, self.login_url, 
self.redirect_field_name)
+    
+    def __call__(self, request, *args, **kwargs):
+        if self.test_func(request.user):
+            return self.view_func(request, *args, **kwargs)
+        path = urlquote(request.get_full_path())
+        tup = self.login_url, self.redirect_field_name, path
+        return HttpResponseRedirect('%s?%s=%s' % tup)

Modified: django/trunk/tests/modeltests/test_client/models.py
===================================================================
--- django/trunk/tests/modeltests/test_client/models.py 2007-11-07 06:36:24 UTC 
(rev 6657)
+++ django/trunk/tests/modeltests/test_client/models.py 2007-11-07 22:45:07 UTC 
(rev 6658)
@@ -250,6 +250,22 @@
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.context['user'].username, 'testclient')
 
+    def test_view_with_method_login(self):
+        "Request a page that is protected with a @login_required method"
+        
+        # Get the page without logging in. Should result in 302.
+        response = self.client.get('/test_client/login_protected_method_view/')
+        self.assertRedirects(response, 
'http://testserver/accounts/login/?next=/test_client/login_protected_method_view/')
+        
+        # Log in
+        login = self.client.login(username='testclient', password='password')
+        self.failUnless(login, 'Could not log in')
+
+        # Request a page that requires a login
+        response = self.client.get('/test_client/login_protected_method_view/')
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(response.context['user'].username, 'testclient')
+
     def test_view_with_login_and_custom_redirect(self):
         "Request a page that is protected with 
@login_required(redirect_field_name='redirect_to')"
         
@@ -295,6 +311,40 @@
         response = self.client.get('/test_client/login_protected_view/')
         self.assertRedirects(response, 
'http://testserver/accounts/login/?next=/test_client/login_protected_view/')
 
+    def test_view_with_permissions(self):
+        "Request a page that is protected with @permission_required"
+        
+        # Get the page without logging in. Should result in 302.
+        response = self.client.get('/test_client/permission_protected_view/')
+        self.assertRedirects(response, 
'http://testserver/accounts/login/?next=/test_client/permission_protected_view/')
+        
+        # Log in
+        login = self.client.login(username='testclient', password='password')
+        self.failUnless(login, 'Could not log in')
+
+        # Log in with wrong permissions. Should result in 302.
+        response = self.client.get('/test_client/permission_protected_view/')
+        self.assertRedirects(response, 
'http://testserver/accounts/login/?next=/test_client/permission_protected_view/')
+
+        # TODO: Log in with right permissions and request the page again
+
+    def test_view_with_method_permissions(self):
+        "Request a page that is protected with a @permission_required method"
+        
+        # Get the page without logging in. Should result in 302.
+        response = 
self.client.get('/test_client/permission_protected_method_view/')
+        self.assertRedirects(response, 
'http://testserver/accounts/login/?next=/test_client/permission_protected_method_view/')
+        
+        # Log in
+        login = self.client.login(username='testclient', password='password')
+        self.failUnless(login, 'Could not log in')
+
+        # Log in with wrong permissions. Should result in 302.
+        response = 
self.client.get('/test_client/permission_protected_method_view/')
+        self.assertRedirects(response, 
'http://testserver/accounts/login/?next=/test_client/permission_protected_method_view/')
+
+        # TODO: Log in with right permissions and request the page again
+
     def test_session_modifying_view(self):
         "Request a page that modifies the session"
         # Session value isn't set initially

Modified: django/trunk/tests/modeltests/test_client/urls.py
===================================================================
--- django/trunk/tests/modeltests/test_client/urls.py   2007-11-07 06:36:24 UTC 
(rev 6657)
+++ django/trunk/tests/modeltests/test_client/urls.py   2007-11-07 22:45:07 UTC 
(rev 6658)
@@ -13,7 +13,10 @@
     (r'^form_view/$', views.form_view),
     (r'^form_view_with_template/$', views.form_view_with_template),
     (r'^login_protected_view/$', views.login_protected_view),
+    (r'^login_protected_method_view/$', views.login_protected_method_view),
     (r'^login_protected_view_custom_redirect/$', 
views.login_protected_view_changed_redirect),
+    (r'^permission_protected_view/$', views.permission_protected_view),
+    (r'^permission_protected_method_view/$', 
views.permission_protected_method_view),
     (r'^session_view/$', views.session_view),
     (r'^broken_view/$', views.broken_view),
     (r'^mail_sending_view/$', views.mail_sending_view),

Modified: django/trunk/tests/modeltests/test_client/views.py
===================================================================
--- django/trunk/tests/modeltests/test_client/views.py  2007-11-07 06:36:24 UTC 
(rev 6657)
+++ django/trunk/tests/modeltests/test_client/views.py  2007-11-07 22:45:07 UTC 
(rev 6658)
@@ -3,7 +3,7 @@
 from django.core.mail import EmailMessage, SMTPConnection
 from django.template import Context, Template
 from django.http import HttpResponse, HttpResponseRedirect, 
HttpResponseNotFound
-from django.contrib.auth.decorators import login_required
+from django.contrib.auth.decorators import login_required, permission_required
 from django.newforms.forms import Form
 from django.newforms import fields
 from django.shortcuts import render_to_response
@@ -130,6 +130,38 @@
     return HttpResponse(t.render(c))
 login_protected_view_changed_redirect = 
login_required(redirect_field_name="redirect_to")(login_protected_view_changed_redirect)
 
+def permission_protected_view(request):
+    "A simple view that is permission protected."
+    t = Template('This is a permission protected test. '
+                 'Username is {{ user.username }}. '
+                 'Permissions are {{ user.get_all_permissions }}.' ,
+                 name='Permissions Template')
+    c = Context({'user': request.user})
+    return HttpResponse(t.render(c))
+permission_protected_view = 
permission_required('modeltests.test_perm')(permission_protected_view)
+
+class _ViewManager(object):
+    def login_protected_view(self, request):
+        t = Template('This is a login protected test using a method. '
+                     'Username is {{ user.username }}.',
+                     name='Login Method Template')
+        c = Context({'user': request.user})
+        return HttpResponse(t.render(c))
+    login_protected_view = login_required(login_protected_view)
+
+    def permission_protected_view(self, request):
+        t = Template('This is a permission protected test using a method. '
+                     'Username is {{ user.username }}. '
+                     'Permissions are {{ user.get_all_permissions }}.' ,
+                     name='Permissions Template')
+        c = Context({'user': request.user})
+        return HttpResponse(t.render(c))
+    permission_protected_view = 
permission_required('modeltests.test_perm')(permission_protected_view)
+
+_view_manager = _ViewManager()
+login_protected_method_view = _view_manager.login_protected_view
+permission_protected_method_view = _view_manager.permission_protected_view
+
 def session_view(request):
     "A view that modifies the session"
     request.session['tobacconist'] = 'hovercraft'


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to