Commits

Maciej Wiśniowski committed 5875890 Merge

merge with trunk

  • Participants
  • Parent commits cc2a6ee, 0d13cc7

Comments (0)

Files changed (14)

 c3761c18d35922bfa6b311c53332125326801163 1.0b3
 84a2f4b8a52466f6190eeb26dcb9fabca79e2dcc 1.0b4
 27337d044a8d76deb753f40ea94631567fb807c2 1.0
+8e19e9ceac1981c5c1e8ce8535794afd22710a74 1.0.1
+4e38edea63b1b7be92c684ce8749ac03e6230acf 1.0.2
+4e38edea63b1b7be92c684ce8749ac03e6230acf 1.0.2
+0000000000000000000000000000000000000000 1.0.2
+0000000000000000000000000000000000000000 1.0.2
+150b7c0e5592bf79767b3376caab695f1f4def73 1.0.2
+7754113e63c5389239bbd0e478b453d78046aa64 1.0.3
+7754113e63c5389239bbd0e478b453d78046aa64 1.0.3
+0000000000000000000000000000000000000000 1.0.3
+0000000000000000000000000000000000000000 1.0.3
+43de2a0faa9b287977db5b07b76e9064e169ea63 1.0.3
+43de2a0faa9b287977db5b07b76e9064e169ea63 1.0.3
+0000000000000000000000000000000000000000 1.0.3
+0000000000000000000000000000000000000000 1.0.3
+2efbcb22ad8654dc26dc2deb58f374300b9d6ded 1.0.3
 What is it?
 ===========
 
-django-permissions provides per-object permissions for Django
-
-Documentation
-=============
-
-For more documentation please visit: http://packages.python.org/django-permissions/
+django-permissions provides per-object permissions for Django on roles: http://en.wikipedia.org/wiki/Role-based_access_control
 
 Code
 ====
 Changes
 =======
 
+1.0.3 (2011-04-30)
+------------------
+
+Bugfix release
+
+* Bugfix: Removed mutuable parameters; issue #11
+
+Changes
+=======
+
+1.0.2 (2011-04-09)
+------------------
+
+Bugfix release
+
+* Bugfix: prevent to add same Users several times to a Role; issue #6 of django-workflows
+* Updated Development Status to "5 - Production/Stable"
+
+1.0.1 (2011-04-08)
+------------------
+
+Bugfix release
+
+* Bugfix: DatabaseErrors with Postgres; issue #5.
+* Bugfix: changed order of passed parameters to has_permission; issue #6
+* Bugfix: removed not needed import of "sets"; issue #8
+
 1.0 (2010-08-24)
 ----------------
 

File docs/conf.py

 # documentation root, use os.path.abspath to make it absolute, like shown here.
 #sys.path.append(os.path.abspath('.'))
 
-sys.path.append(os.path.abspath("../../../lfc_project"))
-sys.path.append(os.path.abspath("../../../parts/lfc"))
-sys.path.append(os.path.abspath("../../../parts/django"))
-sys.path.append(os.path.abspath("../../../parts/tagging"))
-sys.path.append(os.path.abspath("../../../parts/portlets"))
+sys.path.append(os.path.abspath("../../../project"))
 sys.path.append(os.path.abspath("../../../parts/permissions"))
 
 # -- General configuration -----------------------------------------------------

File docs/index.rst

 django-permissions
 ==================
 
-Contents:
+django-permissions is a generic framework for per-object permissions for Django based on roles: http://en.wikipedia.org/wiki/Role-based_access_control
+
+Contents
+========
 
 .. toctree::
    :maxdepth: 1

File docs/overview.rst

 ========
 
 * django-permissions is a generic framework for per-object permissions for
-  Django.
+  Django based on roles: http://en.wikipedia.org/wiki/Role-based_access_control
 
 Permissions
 ===========
 Local Roles
 ===========
 
-* Local roles are roles which are assigned to users and groups for a specific 
+* Local roles are roles which are assigned to users and groups for specific 
   content objects.
 
 Users

File docs/usage/simple.rst

 Simple
 ======
 
-.. warning::
-
-    django-permissions is in alpha state. Please consider the API as supposed
-    to be changed until it reaches beta state.
-
 Create a new user
 -----------------
 
 .. code-block:: python
 
     >>> from permissions.utils import has_permission
-    >>> result = has_permission(content, user, "view")
+    >>> has_permission(content, user, "view")
     True
 
 This will check whether the current user has the permission "View" for the

File permissions/__init__.py

+# permissions imports
 import permissions.utils
+from permissions.exceptions import Unauthorized
 
 class PermissionBase(object):
     """Mix-in class for permissions.
         """
         return permissions.utils.remove_permission(self, role, permission)
 
-    def has_permission(self, user, permission, roles=[]):
+    def has_permission(self, user, permission, roles=None):
         """Returns True if the passed user has passed permission for this
         instance. Otherwise False.
 
             If passed, these roles will be assigned to the user temporarily
             before the permissions are checked.
         """
+        if roles is None:
+            roles = []
         return permissions.utils.has_permission(self, user, permission, roles)
 
-    def check_permission(self, user, permission, roles=[]):
+    def check_permission(self, user, permission, roles=None):
         """Raise Unauthorized if the the passed user hasn't passed permission 
         for this instance.
 
             If passed, these roles will be assigned to the user temporarily
             before the permissions are checked.
         """
+        if roles is None:
+            roles = []
+
         if not self.has_permission(user, permission, roles):
-            raise Unauthorized("User %s doesn't have permission %s for object %s" % (user, permission, obj.slug))
+            raise Unauthorized("User %s doesn't have permission %s for object %s" % (user, permission, self.slug))
 
     def add_inheritance_block(self, permission):
         """Adds an inheritance block for the passed permission.
         return permissions.utils.add_local_role(self, principal, role)
 
     def get_roles(self, principal):
-        """Returns local roles for passed principal (user or group).
+        """Returns *direct* local roles for passed principal (user or group).
         """
         return permissions.utils.get_local_roles(self, principal)
 
     def remove_role(self, principal, role):
-        """Adds a local role for the principal to the object.
+        """Removes a local role for the principal to the object.
 
         **Parameters:**
 

File permissions/backend.py

-# permissions import
+# permissions imports
 import permissions.utils
 
 class ObjectPermissionsBackend(object):
     """Django backend for object permissions. Needs Django 1.2.
 
-
     Use it together with the default ModelBackend like so::
 
         AUTHENTICATION_BACKENDS = (
             'django.contrib.auth.backends.ModelBackend',
             'permissions.backend.ObjectPermissionsBackend',
         )
+
+    Then you can use it like:
+
+        user.has_perm("view", your_object)
+
     """
     supports_object_permissions = True
     supports_anonymous_user = True
     def authenticate(self, username, password):
         return None
 
-    def has_permission(self, permission_codename, user, obj=None):
+    def has_permission(self, user_obj, perm, obj=None):
+        import warnings
+        warnings.warn(
+            "The use of has_permission is deprecated, please use the has_perm instead.",
+            PendingDeprecationWarning
+        )
+        return self.has_perm(user_obj, perm, obj)
+
+    def has_perm(self, user_obj, perm, obj=None):
         """Checks whether the passed user has passed permission for passed
         object (obj).
 
         Parameters
         ==========
 
-        permission
+        perm
             The permission's codename which should be checked.
 
-        user
+        user_obj
             The user for which the permission should be checked.
 
         obj
             The object for which the permission should be checked.
         """
-        return permissions.utils.has_permission(obj, user, permission_codename)
+        return permissions.utils.has_permission(obj, user_obj, perm)

File permissions/exceptions.py

 class Unauthorized(Exception):
-    pass
+    def __init__(self, str):
+        super(Unauthorized, self).__init__(str)

File permissions/models.py

-# python imports
-import sets
-
 # django imports
 from django.db import models
 from django.db.models import Q
 from django.contrib.contenttypes.models import ContentType
 from django.utils.translation import ugettext_lazy as _
 
+# permissions imports
+import permissions.utils
+
 class Permission(models.Model):
     """A permission which can be granted to users/groups and objects.
 
         return "%s (%s)" % (self.name, self.codename)
 
 class ObjectPermission(models.Model):
-    """Grants permission for specific user/group and object.
+    """Grants permission for a role and an content object (optional).
 
     **Attributes:**
 
     content = generic.GenericForeignKey(ct_field="content_type", fk_field="content_id")
 
     def __unicode__(self):
-        if self.role:
-            principal = self.role
-        else:
-            principal = self.user
-
-        return "%s / %s / %s - %s" % (self.permission.name, principal, self.content_type, self.content_id)
-
-    def get_principal(self):
-        """Returns the principal.
-        """
-        return self.user or self.group
-
-    def set_principal(self, principal):
-        """Sets the principal.
-        """
-        if isinstance(principal, User):
-            self.user = principal
-        else:
-            self.group = principal
-
-    principal = property(get_principal, set_principal)
+        return "%s / %s / %s - %s" % (self.permission.name, self.role, self.content_type, self.content_id)
 
 class ObjectPermissionInheritanceBlock(models.Model):
     """Blocks the inheritance for specific permission and object.
     def add_principal(self, principal, content=None):
         """Addes the given principal (user or group) ot the Role.
         """
-        if isinstance(principal, User):
-            PrincipalRoleRelation.objects.create(user=principal, role=self)
-        else:
-            PrincipalRoleRelation.objects.create(group=principal, role=self)
+        return permissions.utils.add_role(principal, self)
 
     def get_groups(self, content=None):
         """Returns all groups which has this role assigned. If content is given
     content_type = models.ForeignKey(ContentType, verbose_name=_(u"Content type"), blank=True, null=True)
     content_id = models.PositiveIntegerField(verbose_name=_(u"Content id"), blank=True, null=True)
     content = generic.GenericForeignKey(ct_field="content_type", fk_field="content_id")
-
+    
+    def __unicode__(self):
+        if self.user:
+            principal = self.user.username
+        else:
+            principal = self.group
+        
+        return "%s - %s" % (principal, self.role)
+        
     def get_principal(self):
         """Returns the principal.
         """

File permissions/templatetags/permissions_tags.py

 # django imports
 from django import template
-from django.core.exceptions import ImproperlyConfigured
-from django.contrib.auth.models import User, AnonymousUser
 
 import permissions.utils
 register = template.Library()
 
         return cls(bits[1], bits[2], nodelist_true, nodelist_false)
 
-    def __init__(self, obj, permission, nodelist_true, nodelist_false):
+    def __init__(self, obj, codename, nodelist_true, nodelist_false):
         self.obj = template.Variable(obj)
-        self.permission = permission
+        self.codename = codename
         self.nodelist_true = nodelist_true
         self.nodelist_false = nodelist_false
 
     def render(self, context):
         request = context.get("request")
         obj = self.obj.resolve(context)
-        if permissions.utils.has_permission(obj, request.user, self.permission):
+        if permissions.utils.has_permission(obj, request.user, self.codename):
             return self.nodelist_true.render(context)
         else:
             return self.nodelist_false

File permissions/tests.py

 from django.contrib.flatpages.models import FlatPage
 from django.contrib.auth.models import Group
 from django.contrib.auth.models import User
+from django.conf import settings
 from django.core.urlresolvers import reverse
 from django.test import TestCase
 from django.test.client import Client
 
 import permissions.utils
 
+class BackendTestCase(TestCase):
+    """
+    """
+    def setUp(self):
+        """
+        """
+        settings.AUTHENTICATION_BACKENDS = (
+            'django.contrib.auth.backends.ModelBackend',
+            'permissions.backend.ObjectPermissionsBackend',
+        )
+        
+        self.role_1 = permissions.utils.register_role("Role 1")        
+        self.user = User.objects.create(username="john")
+        self.page_1 = FlatPage.objects.create(url="/page-1/", title="Page 1")
+        self.view = permissions.utils.register_permission("View", "view")
+        
+        # Add user to role
+        self.role_1.add_principal(self.user)
+
+    def test_has_perm(self):
+        """Tests has perm of the backend.
+        """
+        result = self.user.has_perm(self.view, self.page_1)
+        self.assertEqual(result, False)
+        
+        # assign view permission to role 1
+        permissions.utils.grant_permission(self.page_1, self.role_1, self.view)
+
+        result = self.user.has_perm("view", self.page_1)
+        self.assertEqual(result, True)
+    
 class RoleTestCase(TestCase):
     """
-    """
+    """    
     def setUp(self):
         """
         """
 
         self.page_1 = FlatPage.objects.create(url="/page-1/", title="Page 1")
         self.page_2 = FlatPage.objects.create(url="/page-1/", title="Page 2")
-
+        
     def test_getter(self):
         """
         """
+        # Group
         result = permissions.utils.get_group(self.group.id)
         self.assertEqual(result, self.group)
 
         result = permissions.utils.get_group(42)
         self.assertEqual(result, None)
 
+        result = permissions.utils.get_group(self.group.name)
+        self.assertEqual(result, self.group)
+
+        result = permissions.utils.get_group("Not Existing")
+        self.assertEqual(result, None)
+
+        # Role
         result = permissions.utils.get_role(self.role_1.id)
         self.assertEqual(result, self.role_1)
 
         result = permissions.utils.get_role(42)
         self.assertEqual(result, None)
 
+        result = permissions.utils.get_role(self.role_1.name)
+        self.assertEqual(result, self.role_1)
+
+        result = permissions.utils.get_role("Not Existing")
+        self.assertEqual(result, None)
+
         result = permissions.utils.get_user(self.user.id)
         self.assertEqual(result, self.user)
 
         result = permissions.utils.get_user(42)
         self.assertEqual(result, None)
 
+        result = permissions.utils.get_user(self.user.username)
+        self.assertEqual(result, self.user)
+
+        result = permissions.utils.get_user("Not Existing")
+        self.assertEqual(result, None)
+
     def test_global_roles_user(self):
         """
         """
         self.assertEqual(result, False)
 
         result = permissions.utils.get_roles(self.user)
-        self.assertEqual(result, [self.role_1])
+        self.assertEqual(list(result), [self.role_1])
 
         # Add role 2
         result = permissions.utils.add_role(self.user, self.role_2)
         self.assertEqual(result, True)
 
         result = permissions.utils.get_roles(self.user)
-        self.assertEqual(result, [self.role_1, self.role_2])
+        self.assertEqual(list(result), [self.role_1, self.role_2])
 
         # Remove role 1
         result = permissions.utils.remove_role(self.user, self.role_1)
         self.assertEqual(result, False)
 
         result = permissions.utils.get_roles(self.user)
-        self.assertEqual(result, [self.role_2])
+        self.assertEqual(list(result), [self.role_2])
 
         # Remove role 2
         result = permissions.utils.remove_role(self.user, self.role_2)
         self.assertEqual(result, True)
 
         result = permissions.utils.get_roles(self.user)
-        self.assertEqual(result, [])
+        self.assertEqual(list(result), [])
 
     def test_global_roles_group(self):
         """
         result = permissions.utils.add_role(self.group, self.role_1)
         self.assertEqual(result, False)
 
-        result = permissions.utils.get_roles(self.group)
+        result = permissions.utils.get_global_roles(self.group)
         self.assertEqual(result, [self.role_1])
 
         # Add role 2
         result = permissions.utils.add_role(self.group, self.role_2)
         self.assertEqual(result, True)
 
-        result = permissions.utils.get_roles(self.group)
+        result = permissions.utils.get_global_roles(self.group)
         self.assertEqual(result, [self.role_1, self.role_2])
 
         # Remove role 1
         result = permissions.utils.remove_role(self.group, self.role_1)
         self.assertEqual(result, False)
 
-        result = permissions.utils.get_roles(self.group)
+        result = permissions.utils.get_global_roles(self.group)
         self.assertEqual(result, [self.role_2])
 
         # Remove role 2
         result = permissions.utils.remove_role(self.group, self.role_2)
         self.assertEqual(result, True)
 
-        result = permissions.utils.get_roles(self.group)
+        result = permissions.utils.get_global_roles(self.group)
         self.assertEqual(result, [])
 
     def test_remove_roles_user(self):
         self.assertEqual(result, True)
 
         result = permissions.utils.get_roles(self.user)
-        self.assertEqual(result, [self.role_1, self.role_2])
+        self.assertEqual(list(result), [self.role_1, self.role_2])
 
         # Remove roles
         result = permissions.utils.remove_roles(self.user)
         self.assertEqual(result, True)
 
         result = permissions.utils.get_roles(self.user)
-        self.assertEqual(result, [])
+        self.assertEqual(list(result), [])
 
         # Remove roles
         result = permissions.utils.remove_roles(self.user)
         result = permissions.utils.add_role(self.group, self.role_2)
         self.assertEqual(result, True)
 
-        result = permissions.utils.get_roles(self.group)
+        result = permissions.utils.get_global_roles(self.group)
         self.assertEqual(result, [self.role_1, self.role_2])
 
         # Remove roles
         result = permissions.utils.remove_roles(self.group)
         self.assertEqual(result, True)
 
-        result = permissions.utils.get_roles(self.group)
+        result = permissions.utils.get_global_roles(self.group)
         self.assertEqual(result, [])
 
         # Remove roles
         self.assertEqual(result[0].username, "john")
         self.assertEqual(result[1].username, "jane")
         self.assertEqual(len(result), 2)
+        
+    def test_get_users_3(self):
+        """
+        """
+        self.role_1.add_principal(self.user)
+        result = self.role_1.get_users()
+        self.assertEqual(result, [self.user])
+        
+        # Add same user again
+        self.role_1.add_principal(self.user)
+        result = self.role_1.get_users()
+        self.assertEqual(result, [self.user])
 
 class PermissionTestCase(TestCase):
     """
         """
         """
         # Permission
-        self.assertEqual(self.permission.__unicode__(), "View (view)")
+        self.assertEqual(self.permission.__unicode__(), u"View (view)")
 
         # ObjectPermission
         permissions.utils.grant_permission(self.page_1, self.role_1, self.permission)
         opr = ObjectPermission.objects.get(permission=self.permission, role=self.role_1)
-        self.assertEqual(opr.__unicode__(), "View / Role 1 / flat page - 1")
+        self.assertEqual(opr.__unicode__(), u"View / %s / flat page - %s" % (self.role_1, self.page_1.id))
 
         # ObjectPermissionInheritanceBlock
         permissions.utils.add_inheritance_block(self.page_1, self.permission)
         opb = ObjectPermissionInheritanceBlock.objects.get(permission=self.permission)
 
-        self.assertEqual(opb.__unicode__(), "View (view) / flat page - 1")
+        self.assertEqual(opb.__unicode__(), u"View (view) / flat page - %s" % (self.page_1.id))
 
     def test_reset(self):
         """

File permissions/utils.py

+# python imports
+import warnings
+
 # django imports
 from django.db import IntegrityError
+from django.db import connection
+from django.db.models import Q
 from django.contrib.auth.models import User
 from django.contrib.auth.models import Group
 from django.contrib.contenttypes.models import ContentType
 from django.core.exceptions import ObjectDoesNotExist
 
 # permissions imports
+from permissions.exceptions import Unauthorized
 from permissions.models import ObjectPermission
 from permissions.models import ObjectPermissionInheritanceBlock
 from permissions.models import Permission
     """
     if isinstance(principal, User):
         try:
-            ppr = PrincipalRoleRelation.objects.get(user=principal, role=role, content_id=None, content_type=None)
+            PrincipalRoleRelation.objects.get(user=principal, role=role, content_id=None, content_type=None)
         except PrincipalRoleRelation.DoesNotExist:
             PrincipalRoleRelation.objects.create(user=principal, role=role)
             return True
     else:
         try:
-            ppr = PrincipalRoleRelation.objects.get(group=principal, role=role, content_id=None, content_type=None)
+            PrincipalRoleRelation.objects.get(group=principal, role=role, content_id=None, content_type=None)
         except PrincipalRoleRelation.DoesNotExist:
             PrincipalRoleRelation.objects.create(group=principal, role=role)
             return True
     ctype = ContentType.objects.get_for_model(obj)
     if isinstance(principal, User):
         try:
-            ppr = PrincipalRoleRelation.objects.get(user=principal, role=role, content_id=obj.id, content_type=ctype)
+            PrincipalRoleRelation.objects.get(user=principal, role=role, content_id=obj.id, content_type=ctype)
         except PrincipalRoleRelation.DoesNotExist:
             PrincipalRoleRelation.objects.create(user=principal, role=role, content=obj)
             return True
     else:
         try:
-            ppr = PrincipalRoleRelation.objects.get(group=principal, role=role, content_id=obj.id, content_type=ctype)
+            PrincipalRoleRelation.objects.get(group=principal, role=role, content_id=obj.id, content_type=ctype)
         except PrincipalRoleRelation.DoesNotExist:
             PrincipalRoleRelation.objects.create(group=principal, role=role, content=obj)
             return True
     return True
 
 def remove_local_role(obj, principal, role):
-    """Removes role from obj and principle.
+    """Removes role from passed object and principle.
 
     **Parameters:**
 
     else:
         return False
 
-def get_roles(principal, obj=None):
-    """Returns all roles of passed user for passed content object. This takes
-    direct and roles via a group into account. If an object is passed local
-    roles will also added.
+def get_roles(user, obj=None):
+    """Returns *all* roles of the passed user.
+
+    This takes direct roles and roles via the user's groups into account.
+
+    If an object is passed local roles will also added. Then all local roles
+    from all ancestors and all user's groups are also taken into account.
+
+    This is the method to use if one want to know whether the passed user
+    has a role in general (for the passed object).
 
     **Parameters:**
 
+    user
+        The user for which the roles are returned.
+
     obj
-        The object from which the roles are removed.
+        The object for which local roles will returned.
 
-    principal
-        The principal (user or group) from which the roles are removed.
     """
-    roles = get_global_roles(principal)
+    role_ids = []
+    groups = user.groups.all()
+    groups_ids_str = ", ".join([str(g.id) for g in groups])
 
-    if obj is not None:
-        roles.extend(get_local_roles(obj, principal))
+    # Gobal roles for user and the user's groups
+    cursor = connection.cursor()
 
-    if isinstance(principal, User):
-        for group in principal.groups.all():
-            if obj is not None:
-                roles.extend(get_local_roles(obj, group))
-            roles.extend(get_roles(group))
+    if groups_ids_str:
+        cursor.execute("""SELECT role_id
+                          FROM permissions_principalrolerelation
+                          WHERE (user_id=%s OR group_id IN (%s))
+                          AND content_id is Null""" % (user.id, groups_ids_str))
+    else:
+        cursor.execute("""SELECT role_id
+                          FROM permissions_principalrolerelation
+                          WHERE user_id=%s
+                          AND content_id is Null""" % user.id)
 
-    return roles
+    for row in cursor.fetchall():
+        role_ids.append(row[0])
+
+    # Local roles for user and the user's groups and all ancestors of the
+    # passed object.
+    while obj:
+        ctype = ContentType.objects.get_for_model(obj)
+
+        if groups_ids_str:
+            cursor.execute("""SELECT role_id
+                              FROM permissions_principalrolerelation
+                              WHERE (user_id='%s' OR group_id IN (%s))
+                              AND content_id='%s'
+                              AND content_type_id='%s'""" % (user.id, groups_ids_str, obj.id, ctype.id))
+        else:
+            cursor.execute("""SELECT role_id
+                              FROM permissions_principalrolerelation
+                              WHERE user_id='%s'
+                              AND content_id='%s'
+                              AND content_type_id='%s'""" % (user.id, obj.id, ctype.id))
+
+        for row in cursor.fetchall():
+            role_ids.append(row[0])
+
+        try:
+            obj = obj.get_parent_for_permissions()
+        except AttributeError:
+            obj = None
+    
+    return Role.objects.filter(pk__in=role_ids)
 
 def get_global_roles(principal):
-    """Returns global roles of passed principal (user or group).
+    """Returns *direct* global roles of passed principal (user or group).
     """
     if isinstance(principal, User):
         return [prr.role for prr in PrincipalRoleRelation.objects.filter(
             user=principal, content_id=None, content_type=None)]
     else:
+        if isinstance(principal, Group):
+            principal = (principal,)
         return [prr.role for prr in PrincipalRoleRelation.objects.filter(
-            group=principal, content_id=None, content_type=None)]
+            group__in=principal, content_id=None, content_type=None)]
 
 def get_local_roles(obj, principal):
-    """Returns local for passed user and content object.
+    """Returns *direct* local roles for passed principal and content object.
     """
     ctype = ContentType.objects.get_for_model(obj)
 
         return [prr.role for prr in PrincipalRoleRelation.objects.filter(
             group=principal, content_id=obj.id, content_type=ctype)]
 
-def has_role(principal, role, obj=None):
-    """Returns True if the passed principal has passed role. If an object is
-    passed local roles will also taking into account.
-
-    **Parameters:**
-
-    principal
-        The principal (user or group) for which the roles are checked.
-
-    role
-        The role which is checked. Either the role name or the Role instance.
-
-    obj
-        The object for which the role is checked
-    """
-    if isinstance(role, str):
-        role = Role.objects.get(name=role)
-
-    roles = get_roles(principal, obj)
-    return role in roles
-
-def has_local_role(principal, role, obj):
-    """Returns True if the passed principal has the passed role for passed
-    object.
-
-    **Parameters:**
-
-    principal
-        The principal (user or group) for which the roles are checked.
-
-    role
-        The role which is checked. Either the role name or the Role instance.
-
-    obj
-        The object for which the role is checked
-    """
-    if isinstance(role, str):
-        role = Role.objects.get(name=role)
-
-    roles = get_local_roles(obj, principal)
-    return role in roles
-
-def has_global_role(principal, role):
-    """Returns True if the passed principal has the global role for passed
-    object.
-    
-    **Parameters:**
-
-    principal
-        The principal (user or group) for which the roles are checked.
-
-    role
-        The role which is checked. Either the role name or the Role instance.
-
-    obj
-        The object for which the role is checked
-    """
-    if isinstance(role, str):
-        role = Role.objects.get(name=role)
-
-    roles = get_roles(principal)
-    return role in roles
-
 # Permissions ################################################################
 
-def check_permission(obj, user, permission, roles=None):
+def check_permission(obj, user, codename, roles=None):
     """Checks whether passed user has passed permission for passed obj.
 
     **Parameters:**
         If given these roles will be assigned to the user temporarily before
         the permissions are checked.
     """
-    if not has_permission(obj, user, permission):
+    if not has_permission(obj, user, codename):
         raise Unauthorized("User '%s' doesn't have permission '%s' for object '%s' (%s)"
             % (user, codename, obj.slug, obj.__class__.__name__))
 
     codename
         The permission's codename which should be checked.
 
-    user
-        The user for which the permission should be checked.
+    request
+        The current request.
 
     roles
         If given these roles will be assigned to the user temporarily before
         the permissions are checked.
     """
+    ctype = ContentType.objects.get_for_model(obj)
+    cache_key = "%s-%s-%s" % (ctype.id, obj.id, codename)
+    result = None # _get_cached_permission(user, cache_key)
+    if result is not None:
+        return result
+
     if roles is None:
         roles = []
 
     if user.is_superuser:
         return True
 
-    if user.is_anonymous():
-        user = None
-    else:
+    if not user.is_anonymous():
         roles.extend(get_roles(user, obj))
 
     ct = ContentType.objects.get_for_model(obj)
 
+    result = False
     while obj is not None:
         p = ObjectPermission.objects.filter(
-            content_type=ct, content_id=obj.id, role__in=roles, permission__codename = codename)
+            content_type=ct, content_id=obj.id, role__in=roles, permission__codename = codename).values("id")
 
-        if p.count() > 0:
-            return True
+        if len(p) > 0:
+            result = True
+            break
 
         if is_inherited(obj, codename) == False:
-            return False
+            result = False
+            break
 
         try:
             obj = obj.get_parent_for_permissions()
             ct = ContentType.objects.get_for_model(obj)
         except AttributeError:
-            return False
+            result = False
+            break
 
-    return False
+    _cache_permission(user, cache_key, result)
+    return result
 
 # Inheritance ################################################################
 
         ObjectPermissionInheritanceBlock.objects.get(content_type = ct, content_id=obj.id, permission=permission)
     except ObjectPermissionInheritanceBlock.DoesNotExist:
         try:
-            result = ObjectPermissionInheritanceBlock.objects.create(content=obj, permission=permission)
+            ObjectPermissionInheritanceBlock.objects.create(content=obj, permission=permission)
         except IntegrityError:
             return False
     return True
 
     **Parameters:**
 
-        obj
-            The content object for which an inheritance block should be added.
+    obj
+        The content object for which an inheritance block should be added.
 
-        permission
-            The permission for which an inheritance block should be removed.
-            Either a permission object or the codename of a permission.
+    permission
+        The permission for which an inheritance block should be removed.
+        Either a permission object or the codename of a permission.
     """
     if not isinstance(permission, Permission):
         try:
 
     **Parameters:**
 
-        obj
-            The content object for which the permission should be checked.
+    obj
+        The content object for which the permission should be checked.
 
-        codename
-            The permission which should be checked. Must be the codename of
-            the permission.
+    codename
+        The permission which should be checked. Must be the codename of the 
+        permission.
     """
     ct = ContentType.objects.get_for_model(obj)
     try:
     else:
         return False
 
-def get_group(id):
+def get_group(name):
     """Returns the group with passed id or None.
     """
-    try:
-        return Group.objects.get(pk=id)
-    except Group.DoesNotExist:
-        return None
+    if isinstance(name, (int, long)):
+        warnings.warn(
+            "The use of get_group with an id is deprecated, please use the group name instead.",
+            PendingDeprecationWarning
+        )
+        try:
+            return Group.objects.get(pk=name)
+        except Group.DoesNotExist:
+            return None
+    else:
+        try:
+            return Group.objects.get(name=name)
+        except Group.DoesNotExist:
+            return None
 
-def get_role(id):
-    """Returns the role with passed id or None.
+def get_role(name):
+    """Returns the role with passed name or None.
     """
-    try:
-        return Role.objects.get(pk=id)
-    except Role.DoesNotExist:
-        return None
+    if isinstance(name, (int, long)):
+        warnings.warn(
+            "The use of get_role with an id is deprecated, please use the group name instead.",
+            PendingDeprecationWarning
+        )
+        try:
+            return Role.objects.get(pk=name)
+        except Role.DoesNotExist:
+            return None
+    else:
+        try:
+            return Role.objects.get(name=name)
+        except Role.DoesNotExist:
+            return None
 
-def get_user(id):
+def get_user(username):
     """Returns the user with passed id or None.
     """
-    try:
-        return User.objects.get(pk=id)
-    except User.DoesNotExist:
-        return None
+    if isinstance(username, (int, long)):
+        warnings.warn(
+            "The use of get_user with an id is deprecated, please use the username instead.",
+            PendingDeprecationWarning
+        )
+        try:
+            return User.objects.get(pk=username)
+        except User.DoesNotExist:
+            return None
+    else:
+        try:
+            return User.objects.get(username=username)
+        except User.DoesNotExist:
+            return None
+
+def has_group(user, group):
+    """Returns True if passed user has passed group.
+    """
+    if isinstance(group, str):
+        group = Group.objects.get(name=group)
+
+    return group in user.groups.all()
 
 def reset(obj):
     """Resets all permissions and inheritance blocks of passed object.
 
 # Registering ################################################################
 
-def register_permission(name, codename, ctypes=[]):
+def register_permission(name, codename, ctypes=None):
     """Registers a permission to the framework. Returns the permission if the
     registration was successfully, otherwise False.
 
     **Parameters:**
 
-        name
-            The unique name of the permission. This is displayed to the
-            customer.
-        codename
-            The unique codename of the permission. This is used internally to
-            identify the permission.
-        content_types
-            The content type for which the permission is active. This can be
-            used to display only reasonable permissions for an object. This
-            must be a Django ContentType
+    name
+        The unique name of the permission. This is displayed to the customer.
+
+    codename
+        The unique codename of the permission. This is used internally to
+        identify the permission.
+
+    content_types
+        The content type for which the permission is active. This can be
+        used to display only reasonable permissions for an object. This
+        must be a Django ContentType
     """
-    try:
-        p = Permission.objects.create(name=name, codename=codename)
+    if ctypes is None:
+        ctypes = []
 
-        ctypes = [ContentType.objects.get_for_model(ctype) for ctype in ctypes]
-        if ctypes:
-            p.content_types = ctypes
-            p.save()
-    except IntegrityError:
+    # Permission with same codename and/or name must not exist.
+    if Permission.objects.filter(Q(name=name) | Q(codename=codename)):
         return False
+
+    p = Permission.objects.create(name=name, codename=codename)
+
+    ctypes = [ContentType.objects.get_for_model(ctype) for ctype in ctypes]
+    if ctypes:
+        p.content_types = ctypes
+        p.save()
+
     return p
 
 def unregister_permission(codename):
 
     **Parameters:**
 
-        codename
-            The unique codename of the permission.
+    codename
+        The unique codename of the permission.
     """
     try:
         permission = Permission.objects.get(codename=codename)
     name
         The unique role name.
     """
-    try:
-        role = Role.objects.create(name=name)
-    except IntegrityError:
+    role, created = Role.objects.get_or_create(name=name)
+    if created:
+        return role
+    else:
         return False
-    return role
 
 def unregister_role(name):
     """Unregisters the role with passed name.
     name
         The unique group name.
     """
-    try:
-        group = Group.objects.create(name=name)
-    except IntegrityError:
+    group, created = Group.objects.get_or_create(name=name)
+    if created:
+        return group
+    else:
         return False
-    return group
 
 def unregister_group(name):
     """Unregisters the group with passed name. Returns True if the
         return False
 
     group.delete()
-    return True
+    return True
+
+def _cache_permission(user, cache_key, data):
+    """Stores the passed data on the passed user object.
+
+    **Parameters:**
+
+    user
+        The user on which the data is stored.
+
+    cache_key
+        The key under which the data is stored.
+
+    data
+        The data which is stored.
+    """
+    if not getattr(user, "permissions", None):
+        user.permissions = {}
+    user.permissions[cache_key] = data
+
+def _get_cached_permission(user, cache_key):
+    """Returns the stored data from passed user object for passed cache_key.
+
+    **Parameters:**
+
+    user
+        The user from which the data is retrieved.
+
+    cache_key
+        The key under which the data is stored.
+
+    """
+    permissions = getattr(user, "permissions", None)
+    if permissions:
+        return user.permissions.get(cache_key, None)
 from setuptools import setup, find_packages
 import os
 
-version = '1.0'
+version = '1.0.3'
 
 here = os.path.abspath(os.path.dirname(__file__))
 README = open(os.path.join(here, 'README.txt')).read()
       description='Generic per-object permissions for Django',
       long_description=README,
       classifiers=[
-          'Development Status :: 4 - Beta',
+          'Development Status :: 5 - Production/Stable',
           'Environment :: Web Environment',
           'Framework :: Django',
           'License :: OSI Approved :: BSD License',