Code

Ticket #4376: django.contrib.auth.decorators.4.diff

File django.contrib.auth.decorators.4.diff, 9.6 KB (added by steven.bethard@…, 7 years ago)

Patch against revision 6364. This should now apply cleanly.

Line 
1Index: django/contrib/auth/decorators.py
2===================================================================
3--- django/contrib/auth/decorators.py   (revision 6363)
4+++ django/contrib/auth/decorators.py   (working copy)
5@@ -8,20 +8,10 @@
6     redirecting to the log-in page if necessary. The test should be a callable
7     that takes the user object and returns True if the user passes.
8     """
9-    if not login_url:
10-        from django.conf import settings
11-        login_url = settings.LOGIN_URL
12-    def _dec(view_func):
13-        def _checklogin(request, *args, **kwargs):
14-            if test_func(request.user):
15-                return view_func(request, *args, **kwargs)
16-            return HttpResponseRedirect('%s?%s=%s' % (login_url, redirect_field_name, urlquote(request.get_full_path())))
17-        _checklogin.__doc__ = view_func.__doc__
18-        _checklogin.__dict__ = view_func.__dict__
19+    def decorate(view_func):
20+        return _CheckLogin(view_func, test_func, login_url, redirect_field_name)
21+    return decorate
22 
23-        return _checklogin
24-    return _dec
25-
26 def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME):
27     """
28     Decorator for views that checks that the user is logged in, redirecting
29@@ -42,3 +32,33 @@
30     """
31     return user_passes_test(lambda u: u.has_perm(perm), login_url=login_url)
32 
33+class _CheckLogin(object):
34+    """
35+    Class that checks that the user passes the given test, redirecting to
36+    the log-in page if necessary. If the test is passed, the view function
37+    is invoked. The test should be a callable that takes the user object
38+    and returns True if the user passes.
39+
40+    We use a class here so that we can define __get__. This way, when a
41+    _CheckLogin object is used as a method decorator, the view function
42+    is properly bound to its instance.
43+    """
44+    def __init__(self, view_func, test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
45+        if not login_url:
46+            from django.conf import settings
47+            login_url = settings.LOGIN_URL
48+        self.view_func = view_func
49+        self.test_func = test_func
50+        self.login_url = login_url
51+        self.redirect_field_name = redirect_field_name
52+       
53+    def __get__(self, obj, cls=None):
54+        view_func = self.view_func.__get__(obj, cls)
55+        return _CheckLogin(view_func, self.test_func, self.login_url, self.redirect_field_name)
56+   
57+    def __call__(self, request, *args, **kwargs):
58+        if self.test_func(request.user):
59+            return self.view_func(request, *args, **kwargs)
60+        path = urlquote(request.get_full_path())
61+        tup = self.login_url, self.redirect_field_name, path
62+        return HttpResponseRedirect('%s?%s=%s' % tup)
63\ No newline at end of file
64Index: tests/modeltests/test_client/models.py
65===================================================================
66--- tests/modeltests/test_client/models.py      (revision 6363)
67+++ tests/modeltests/test_client/models.py      (working copy)
68@@ -250,6 +250,22 @@
69         self.assertEqual(response.status_code, 200)
70         self.assertEqual(response.context['user'].username, 'testclient')
71 
72+    def test_view_with_method_login(self):
73+        "Request a page that is protected with a @login_required method"
74+       
75+        # Get the page without logging in. Should result in 302.
76+        response = self.client.get('/test_client/login_protected_method_view/')
77+        self.assertRedirects(response, 'http://testserver/accounts/login/?next=/test_client/login_protected_method_view/')
78+       
79+        # Log in
80+        login = self.client.login(username='testclient', password='password')
81+        self.failUnless(login, 'Could not log in')
82+
83+        # Request a page that requires a login
84+        response = self.client.get('/test_client/login_protected_method_view/')
85+        self.assertEqual(response.status_code, 200)
86+        self.assertEqual(response.context['user'].username, 'testclient')
87+
88     def test_view_with_login_and_custom_redirect(self):
89         "Request a page that is protected with @login_required(redirect_field_name='redirect_to')"
90         
91@@ -295,6 +311,40 @@
92         response = self.client.get('/test_client/login_protected_view/')
93         self.assertRedirects(response, 'http://testserver/accounts/login/?next=/test_client/login_protected_view/')
94 
95+    def test_view_with_permissions(self):
96+        "Request a page that is protected with @permission_required"
97+       
98+        # Get the page without logging in. Should result in 302.
99+        response = self.client.get('/test_client/permission_protected_view/')
100+        self.assertRedirects(response, 'http://testserver/accounts/login/?next=/test_client/permission_protected_view/')
101+       
102+        # Log in
103+        login = self.client.login(username='testclient', password='password')
104+        self.failUnless(login, 'Could not log in')
105+
106+        # Log in with wrong permissions. Should result in 302.
107+        response = self.client.get('/test_client/permission_protected_view/')
108+        self.assertRedirects(response, 'http://testserver/accounts/login/?next=/test_client/permission_protected_view/')
109+
110+        # TODO: Log in with right permissions and request the page again
111+
112+    def test_view_with_method_permissions(self):
113+        "Request a page that is protected with a @permission_required method"
114+       
115+        # Get the page without logging in. Should result in 302.
116+        response = self.client.get('/test_client/permission_protected_method_view/')
117+        self.assertRedirects(response, 'http://testserver/accounts/login/?next=/test_client/permission_protected_method_view/')
118+       
119+        # Log in
120+        login = self.client.login(username='testclient', password='password')
121+        self.failUnless(login, 'Could not log in')
122+
123+        # Log in with wrong permissions. Should result in 302.
124+        response = self.client.get('/test_client/permission_protected_method_view/')
125+        self.assertRedirects(response, 'http://testserver/accounts/login/?next=/test_client/permission_protected_method_view/')
126+
127+        # TODO: Log in with right permissions and request the page again
128+
129     def test_session_modifying_view(self):
130         "Request a page that modifies the session"
131         # Session value isn't set initially
132Index: tests/modeltests/test_client/urls.py
133===================================================================
134--- tests/modeltests/test_client/urls.py        (revision 6363)
135+++ tests/modeltests/test_client/urls.py        (working copy)
136@@ -13,7 +13,10 @@
137     (r'^form_view/$', views.form_view),
138     (r'^form_view_with_template/$', views.form_view_with_template),
139     (r'^login_protected_view/$', views.login_protected_view),
140+    (r'^login_protected_method_view/$', views.login_protected_method_view),
141     (r'^login_protected_view_custom_redirect/$', views.login_protected_view_changed_redirect),
142+    (r'^permission_protected_view/$', views.permission_protected_view),
143+    (r'^permission_protected_method_view/$', views.permission_protected_method_view),
144     (r'^session_view/$', views.session_view),
145     (r'^broken_view/$', views.broken_view),
146     (r'^mail_sending_view/$', views.mail_sending_view),
147Index: tests/modeltests/test_client/views.py
148===================================================================
149--- tests/modeltests/test_client/views.py       (revision 6363)
150+++ tests/modeltests/test_client/views.py       (working copy)
151@@ -3,7 +3,7 @@
152 from django.core.mail import EmailMessage, SMTPConnection
153 from django.template import Context, Template
154 from django.http import HttpResponse, HttpResponseRedirect, HttpResponseNotFound
155-from django.contrib.auth.decorators import login_required
156+from django.contrib.auth.decorators import login_required, permission_required
157 from django.newforms.forms import Form
158 from django.newforms import fields
159 from django.shortcuts import render_to_response
160@@ -130,6 +130,38 @@
161     return HttpResponse(t.render(c))
162 login_protected_view_changed_redirect = login_required(redirect_field_name="redirect_to")(login_protected_view_changed_redirect)
163 
164+def permission_protected_view(request):
165+    "A simple view that is permission protected."
166+    t = Template('This is a permission protected test. '
167+                 'Username is {{ user.username }}. '
168+                 'Permissions are {{ user.get_all_permissions }}.' ,
169+                 name='Permissions Template')
170+    c = Context({'user': request.user})
171+    return HttpResponse(t.render(c))
172+permission_protected_view = permission_required('modeltests.test_perm')(permission_protected_view)
173+
174+class _ViewManager(object):
175+    def login_protected_view(self, request):
176+        t = Template('This is a login protected test using a method. '
177+                     'Username is {{ user.username }}.',
178+                     name='Login Method Template')
179+        c = Context({'user': request.user})
180+        return HttpResponse(t.render(c))
181+    login_protected_view = login_required(login_protected_view)
182+
183+    def permission_protected_view(self, request):
184+        t = Template('This is a permission protected test using a method. '
185+                     'Username is {{ user.username }}. '
186+                     'Permissions are {{ user.get_all_permissions }}.' ,
187+                     name='Permissions Template')
188+        c = Context({'user': request.user})
189+        return HttpResponse(t.render(c))
190+    permission_protected_view = permission_required('modeltests.test_perm')(permission_protected_view)
191+
192+_view_manager = _ViewManager()
193+login_protected_method_view = _view_manager.login_protected_view
194+permission_protected_method_view = _view_manager.permission_protected_view
195+
196 def session_view(request):
197     "A view that modifies the session"
198     request.session['tobacconist'] = 'hovercraft'