[#3601] Version 0.6
authorEric Mc Sween <eric.mcsween@auf.org>
Wed, 16 Jan 2013 16:52:25 +0000 (11:52 -0500)
committerEric Mc Sween <eric.mcsween@auf.org>
Wed, 16 Jan 2013 16:52:25 +0000 (11:52 -0500)
* Bugfix dans qeval()
* Renvoyer un status code 403 pour les pages de déni de permission

CHANGES
auf/django/permissions/__init__.py
doc/conf.py
setup.py
tests/simpletests/__init__.py
tests/simpletests/models.py
tests/simpletests/tests.py

diff --git a/CHANGES b/CHANGES
index 046b180..e0c97e5 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,10 @@
+0.6 (2013-01-16)
+================
+
+* Bugfix dans qeval()
+
+* Retourner un code HTTP 403 pour les pages de déni de permission.
+
 0.5 (2012-07-26)
 ================
 
index fc331d1..0d3f02b 100644 (file)
@@ -8,7 +8,8 @@ from django.conf import settings
 from django.contrib.auth.views import redirect_to_login
 from django.core.exceptions import ImproperlyConfigured, PermissionDenied
 from django.db.models import Q
-from django.shortcuts import render
+from django.http import HttpResponseForbidden
+from django.template.loader import render_to_string
 from django.utils.importlib import import_module
 
 
@@ -129,77 +130,76 @@ def qeval(obj, q):
     """
     Evaluates a Q object on an instance of a model.
     """
-
     # Evaluate all children
     for child in q.children:
         if isinstance(child, Q):
-            result = qeval(child)
+            result = qeval(obj, child)
         else:
             filter, value = child
             bits = filter.split('__')
             path = bits[:-1]
             lookup = bits[-1]
+            obj_value = obj
             for attr in path:
-                obj = getattr(obj, attr)
-            if lookup == 'exact':
-                result = obj == value
+                if obj_value is None:
+                    break
+                obj_value = getattr(obj_value, attr)
+            if obj_value is None:
+                result = value is None or (lookup == 'isnull' and value)
+            elif lookup == 'exact':
+                result = obj_value == value
             elif lookup == 'iexact':
-                result = obj.lower() == value.lower()
+                result = obj_value.lower() == value.lower()
             elif lookup == 'contains':
-                result = value in obj
+                result = value in obj_value
             elif lookup == 'icontains':
-                result = value.lower() in obj.lower()
+                result = value.lower() in obj_value.lower()
             elif lookup == 'in':
-                result = obj in value
+                result = obj_value in value
             elif lookup == 'gt':
-                result = obj > value
+                result = obj_value > value
             elif lookup == 'gte':
-                result = obj >= value
+                result = obj_value >= value
             elif lookup == 'lt':
-                result = obj < value
+                result = obj_value < value
             elif lookup == 'lte':
-                result = obj <= value
+                result = obj_value <= value
             elif lookup == 'startswith':
-                result = obj.startswith(value)
+                result = obj_value.startswith(value)
             elif lookup == 'istartswith':
-                result = obj.lower().istartswith(value.lower())
+                result = obj_value.lower().istartswith(value.lower())
             elif lookup == 'endswith':
-                result = obj.lower().iendswith(value.lower())
+                result = obj_value.lower().iendswith(value.lower())
             elif lookup == 'range':
-                result = value[0] <= obj <= value[1]
+                result = value[0] <= obj_value <= value[1]
             elif lookup == 'year':
-                result = obj.year == value
+                result = obj_value.year == value
             elif lookup == 'month':
-                result = obj.month == value
+                result = obj_value.month == value
             elif lookup == 'day':
-                result = obj.day == value
+                result = obj_value.day == value
             elif lookup == 'week_day':
-                result = (obj.weekday() + 1) % 7 + 1 == value
+                result = (obj_value.weekday() + 1) % 7 + 1 == value
             elif lookup == 'isnull':
-                result = (obj is None) if value else (obj is not None)
+                # We took care of the case where obj_value is None earlier,
+                # so at this point, obj_value is not None
+                result = not value
             elif lookup == 'search':
                 raise NotImplementedError(
                     'qeval does not implement "__search"'
                 )
             elif lookup == 'regex':
-                result = bool(re.search(value, obj))
+                result = bool(re.search(value, obj_value))
             elif lookup == 'iregex':
-                result = bool(re.search(value, obj, re.I))
+                result = bool(re.search(value, obj_value, re.I))
             else:
-                obj = getattr(obj, lookup)
-                result = obj == value
+                obj_value = getattr(obj_value, lookup)
+                result = obj_value == value
 
         # See if we can shortcut
-        if result and q.connector == Q.OR:
-            return True
-        if not result and q.connector == Q.AND:
-            return False
-
-    # We could'nt shortcut
-    if q.connector == Q.OR:
-        result = False
-    if q.connector == Q.AND:
-        result = True
+        if (result and q.connector == Q.OR) \
+           or (not result and q.connector == Q.AND):
+            break
 
     # Negate if necessary
     if q.negated:
@@ -256,6 +256,6 @@ class PermissionDeniedMiddleware(object):
                     path = request.get_full_path()
                 return redirect_to_login(path, login_url, 'next')
             else:
-                return render(request, '403.html')
+                return HttpResponseForbidden(render_to_string('403.html'))
         else:
             return None
index 0370026..cb44dcc 100644 (file)
@@ -50,9 +50,9 @@ copyright = u'2012, Eric Mc Sween'
 # built documents.
 #
 # The short X.Y version.
-version = '0.5'
+version = '0.6'
 # The full version, including alpha/beta/rc tags.
-release = '0.5'
+release = '0.6'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
index 413404b..11b4e2f 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -3,7 +3,7 @@
 from setuptools import setup, find_packages
 
 name = 'auf.django.permissions'
-version = '0.5'
+version = '0.6'
 
 setup(name=name,
       version=version,
index 42aa460..b843d5b 100644 (file)
@@ -8,7 +8,7 @@ from tests.simpletests.models import Food
 
 def role_provider(user):
     if user.username == 'alice':
-        return [VegetarianRole()]
+        return [VegetarianRole(user)]
     elif user.username == 'bob':
         return [HippieRole()]
     else:
@@ -17,6 +17,9 @@ def role_provider(user):
 
 class VegetarianRole(Role):
 
+    def __init__(self, user):
+        self.user = user
+
     def get_filter_for_perm(self, perm, model):
         if model is Food:
             if perm == 'eat':
@@ -25,6 +28,10 @@ class VegetarianRole(Role):
                 return True
             elif perm == 'throw':
                 return False
+            elif perm == 'give':
+                return Q(is_meat=True) | Q(name__contains='canned')
+            elif perm == 'paint':
+                return Q(owner__username__startswith='a')
         return False
 
 
index 2cb4b80..b3f54b9 100644 (file)
@@ -1,8 +1,11 @@
+from django.contrib.auth.models import User
 from django.db import models
 
 
 class Food(models.Model):
+    owner = models.ForeignKey(User, null=True, blank=True)
+    name = models.CharField(max_length=255)
     is_meat = models.BooleanField()
 
     def __unicode__(self):
-        return u'Food #%d' % self.id
+        return self.name
index d8bf7f6..6c67080 100644 (file)
@@ -14,9 +14,12 @@ class HasPermTestCase(TransactionTestCase):
         self.superman = User.objects.create(
             username='superman', is_superuser=True
         )
-        self.carrot = Food.objects.create(is_meat=False)
-        self.celery = Food.objects.create(is_meat=False)
-        self.steak = Food.objects.create(is_meat=True)
+        self.carrot = Food.objects.create(
+            owner=self.alice, name=u'carrot', is_meat=False
+        )
+        self.celery = Food.objects.create(name=u'celery', is_meat=False)
+        self.steak = Food.objects.create(name=u'steak', is_meat=True)
+        self.soup = Food.objects.create(name=u'canned soup', is_meat=False)
 
     def test_global_permissions(self):
         self.assertTrue(self.bob.has_perm('eat'))
@@ -28,11 +31,14 @@ class HasPermTestCase(TransactionTestCase):
         self.assertFalse(self.alice.has_perm('throw', self.carrot))
         self.assertFalse(self.alice.has_perm('eat', self.steak))
         self.assertTrue(self.alice.has_perm('buy', self.steak))
+        self.assertFalse(self.alice.has_perm('give', self.carrot))
+        self.assertTrue(self.alice.has_perm('paint', self.carrot))
+        self.assertFalse(self.alice.has_perm('paint', self.steak))
 
     def test_queryset_filtering(self):
         self.assertEqual(
             set(Food.objects.with_perm(self.alice, 'eat')),
-            set([self.carrot, self.celery])
+            set([self.carrot, self.celery, self.soup])
         )
         self.assertEqual(
             set(Food.objects.with_perm(self.alice, 'throw')),