Fixed #18991 -- Allowed permission lookup by "if in"

When looking permissions from PermWrapper it is now possible to use
{% if "someapp.someperm" in perms %} instead of
{% if perms.someapp.someperm %}.
This commit is contained in:
Anssi Kääriäinen 2012-09-30 18:13:23 +03:00
parent c2532825db
commit d5a4f209c3
7 changed files with 75 additions and 7 deletions

View File

@ -32,6 +32,17 @@ class PermWrapper(object):
# I am large, I contain multitudes. # I am large, I contain multitudes.
raise TypeError("PermWrapper is not iterable.") raise TypeError("PermWrapper is not iterable.")
def __contains__(self, perm_name):
"""
Lookup by "someapp" or "someapp.someperm" in perms.
"""
if '.' not in perm_name:
# The name refers to module.
return bool(self[perm_name])
module_name, perm_name = perm_name.split('.', 1)
return self[module_name][perm_name]
def auth(request): def auth(request):
""" """
Returns context variables required by apps that use Django's authentication Returns context variables required by apps that use Django's authentication

View File

@ -3,6 +3,8 @@ import os
from django.conf import global_settings from django.conf import global_settings
from django.contrib.auth import authenticate from django.contrib.auth import authenticate
from django.contrib.auth.tests.utils import skipIfCustomUser from django.contrib.auth.tests.utils import skipIfCustomUser
from django.contrib.auth.models import User, Permission
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.context_processors import PermWrapper, PermLookupDict from django.contrib.auth.context_processors import PermWrapper, PermLookupDict
from django.db.models import Q from django.db.models import Q
from django.test import TestCase from django.test import TestCase
@ -10,13 +12,13 @@ from django.test.utils import override_settings
class MockUser(object): class MockUser(object):
def has_module_perm(self, perm): def has_module_perms(self, perm):
if perm == 'mockapp.someapp': if perm == 'mockapp':
return True return True
return False return False
def has_perm(self, perm): def has_perm(self, perm):
if perm == 'someperm': if perm == 'mockapp.someperm':
return True return True
return False return False
@ -40,13 +42,19 @@ class PermWrapperTests(TestCase):
def test_permwrapper_in(self): def test_permwrapper_in(self):
""" """
Test that 'something' in PermWrapper doesn't end up in endless loop. Test that 'something' in PermWrapper works as expected.
""" """
perms = PermWrapper(MockUser()) perms = PermWrapper(MockUser())
with self.assertRaises(TypeError): # Works for modules and full permissions.
self.EQLimiterObject() in perms self.assertTrue('mockapp' in perms)
self.assertFalse('nonexisting' in perms)
self.assertTrue('mockapp.someperm' in perms)
self.assertFalse('mockapp.nonexisting' in perms)
def test_permlookupdict_in(self): def test_permlookupdict_in(self):
"""
No endless loops if accessed with 'in' - refs #18979.
"""
pldict = PermLookupDict(MockUser(), 'mockapp') pldict = PermLookupDict(MockUser(), 'mockapp')
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
self.EQLimiterObject() in pldict self.EQLimiterObject() in pldict
@ -92,9 +100,28 @@ class AuthContextProcessorTests(TestCase):
self.assertContains(response, "Session accessed") self.assertContains(response, "Session accessed")
def test_perms_attrs(self): def test_perms_attrs(self):
self.client.login(username='super', password='secret') u = User.objects.create_user(username='normal', password='secret')
u.user_permissions.add(
Permission.objects.get(
content_type=ContentType.objects.get_for_model(Permission),
codename='add_permission'))
self.client.login(username='normal', password='secret')
response = self.client.get('/auth_processor_perms/') response = self.client.get('/auth_processor_perms/')
self.assertContains(response, "Has auth permissions") self.assertContains(response, "Has auth permissions")
self.assertContains(response, "Has auth.add_permission permissions")
self.assertNotContains(response, "nonexisting")
def test_perm_in_perms_attrs(self):
u = User.objects.create_user(username='normal', password='secret')
u.user_permissions.add(
Permission.objects.get(
content_type=ContentType.objects.get_for_model(Permission),
codename='add_permission'))
self.client.login(username='normal', password='secret')
response = self.client.get('/auth_processor_perm_in_perms/')
self.assertContains(response, "Has auth permissions")
self.assertContains(response, "Has auth.add_permission permissions")
self.assertNotContains(response, "nonexisting")
def test_message_attrs(self): def test_message_attrs(self):
self.client.login(username='super', password='secret') self.client.login(username='super', password='secret')

View File

@ -0,0 +1,4 @@
{% if 'auth' in perms %}Has auth permissions{% endif %}
{% if 'auth.add_permission' in perms %}Has auth.add_permission permissions{% endif %}
{% if 'nonexisting' in perms %}nonexisting perm found{% endif %}
{% if 'auth.nonexisting' in perms %}auth.nonexisting perm found{% endif %}

View File

@ -1 +1,4 @@
{% if perms.auth %}Has auth permissions{% endif %} {% if perms.auth %}Has auth permissions{% endif %}
{% if perms.auth.add_permission %}Has auth.add_permission permissions{% endif %}
{% if perms.nonexisting %}nonexisting perm found{% endif %}
{% if perms.auth.nonexisting in perms %}auth.nonexisting perm found{% endif %}

View File

@ -37,6 +37,10 @@ def auth_processor_perms(request):
return render_to_response('context_processors/auth_attrs_perms.html', return render_to_response('context_processors/auth_attrs_perms.html',
RequestContext(request, {}, processors=[context_processors.auth])) RequestContext(request, {}, processors=[context_processors.auth]))
def auth_processor_perm_in_perms(request):
return render_to_response('context_processors/auth_attrs_perm_in_perms.html',
RequestContext(request, {}, processors=[context_processors.auth]))
def auth_processor_messages(request): def auth_processor_messages(request):
info(request, "Message 1") info(request, "Message 1")
return render_to_response('context_processors/auth_attrs_messages.html', return render_to_response('context_processors/auth_attrs_messages.html',
@ -58,6 +62,7 @@ urlpatterns = urlpatterns + patterns('',
(r'^auth_processor_attr_access/$', auth_processor_attr_access), (r'^auth_processor_attr_access/$', auth_processor_attr_access),
(r'^auth_processor_user/$', auth_processor_user), (r'^auth_processor_user/$', auth_processor_user),
(r'^auth_processor_perms/$', auth_processor_perms), (r'^auth_processor_perms/$', auth_processor_perms),
(r'^auth_processor_perm_in_perms/$', auth_processor_perm_in_perms),
(r'^auth_processor_messages/$', auth_processor_messages), (r'^auth_processor_messages/$', auth_processor_messages),
url(r'^userpage/(.+)/$', userpage, name="userpage"), url(r'^userpage/(.+)/$', userpage, name="userpage"),
) )

View File

@ -180,6 +180,10 @@ Django 1.5 also includes several smaller improvements worth noting:
and inversion, expanding the types of expressions that can be passed to the and inversion, expanding the types of expressions that can be passed to the
database. database.
* When using :class:`~django.template.RequestContext`, it is now possible to
look up permissions by using ``{% if 'someapp.someperm' in perms %}``
in templates.
Backwards incompatible changes in 1.5 Backwards incompatible changes in 1.5
===================================== =====================================

View File

@ -1710,6 +1710,20 @@ Thus, you can check permissions in template ``{% if %}`` statements:
<p>You don't have permission to do anything in the foo app.</p> <p>You don't have permission to do anything in the foo app.</p>
{% endif %} {% endif %}
.. versionadded:: 1.5
Permission lookup by "if in".
It is possible to also look permissions up by ``{% if in %}`` statements.
For example:
.. code-block:: html+django
{% if 'foo' in perms %}
{% if 'foo.can_vote' in perms %}
<p>In lookup works, too.</p>
{% endif %}
{% endif %}
Groups Groups
====== ======