Update permission app to the new class based permissions

This commit is contained in:
Roberto Rosario
2011-12-08 16:35:26 -04:00
parent 8c7d06aa10
commit 563a1d176f
7 changed files with 161 additions and 129 deletions

View File

@@ -7,14 +7,16 @@ from navigation.api import register_links, register_multi_item_links
from project_setup.api import register_setup
from permissions.conf.settings import DEFAULT_ROLES
from permissions.models import Role
from permissions.models import Role, Permission, PermissionNamespace
PERMISSION_ROLE_VIEW = {'namespace': 'permissions', 'name': 'role_view', 'label': _(u'View roles')}
PERMISSION_ROLE_EDIT = {'namespace': 'permissions', 'name': 'role_edit', 'label': _(u'Edit roles')}
PERMISSION_ROLE_CREATE = {'namespace': 'permissions', 'name': 'role_create', 'label': _(u'Create roles')}
PERMISSION_ROLE_DELETE = {'namespace': 'permissions', 'name': 'role_delete', 'label': _(u'Delete roles')}
PERMISSION_PERMISSION_GRANT = {'namespace': 'permissions', 'name': 'permission_grant', 'label': _(u'Grant permissions')}
PERMISSION_PERMISSION_REVOKE = {'namespace': 'permissions', 'name': 'permission_revoke', 'label': _(u'Revoke permissions')}
permissions_namespace = PermissionNamespace('permissions', _(u'Permissions'))
PERMISSION_ROLE_VIEW = Permission.objects.register(permissions_namespace, 'role_view', _(u'View roles'))
PERMISSION_ROLE_EDIT = Permission.objects.register(permissions_namespace, 'role_edit', _(u'Edit roles'))
PERMISSION_ROLE_CREATE = Permission.objects.register(permissions_namespace, 'role_create', _(u'Create roles'))
PERMISSION_ROLE_DELETE = Permission.objects.register(permissions_namespace, 'role_delete', _(u'Delete roles'))
PERMISSION_PERMISSION_GRANT = Permission.objects.register(permissions_namespace, 'permission_grant', _(u'Grant permissions'))
PERMISSION_PERMISSION_REVOKE = Permission.objects.register(permissions_namespace, 'permission_revoke', _(u'Revoke permissions'))
role_list = {'text': _(u'roles'), 'view': 'role_list', 'famfam': 'medal_gold_1', 'icon': 'medal_gold_1.png', 'permissions': [PERMISSION_ROLE_VIEW]}
role_create = {'text': _(u'create new role'), 'view': 'role_create', 'famfam': 'medal_gold_add', 'permissions': [PERMISSION_ROLE_CREATE]}

View File

@@ -1,6 +1,6 @@
from django.contrib import admin
from permissions.models import Permission, PermissionHolder, Role, RoleMember
from permissions.models import StoredPermission, PermissionHolder, Role, RoleMember
class PermissionHolderInline(admin.StackedInline):
@@ -27,5 +27,5 @@ class RoleAdmin(admin.ModelAdmin):
inlines = [RoleMemberInline]
admin.site.register(Permission, PermissionAdmin)
admin.site.register(StoredPermission, PermissionAdmin)
admin.site.register(Role, RoleAdmin)

View File

@@ -1,69 +1 @@
try:
from psycopg2 import OperationalError
except ImportError:
class OperationalError(Exception):
pass
from django.core.exceptions import ImproperlyConfigured
from django.db import transaction
from django.db.utils import DatabaseError
from django.shortcuts import get_object_or_404
from django.utils.translation import ugettext
from django.core.exceptions import PermissionDenied
from django.utils.translation import ugettext_lazy as _
from permissions import PERMISSION_ROLE_VIEW, PERMISSION_ROLE_EDIT, \
PERMISSION_ROLE_CREATE, PERMISSION_ROLE_DELETE, \
PERMISSION_PERMISSION_GRANT, PERMISSION_PERMISSION_REVOKE
from permissions.models import Permission
from permissions.runtime import namespace_titles, permission_titles
def set_namespace_title(namespace, title):
namespace_titles.setdefault(namespace, title)
@transaction.commit_manually
def register_permission(permission):
try:
permission_obj, created = Permission.objects.get_or_create(
namespace=permission['namespace'], name=permission['name'])
permission_obj.label = unicode(permission['label'])
permission_obj.save()
permission_titles['%s.%s' % (permission['namespace'], permission['name'])] = permission['label']
except DatabaseError:
transaction.rollback()
# Special case for ./manage.py syncdb
except (OperationalError, ImproperlyConfigured):
transaction.rollback()
# Special for DjangoZoom, which executes collectstatic media
# doing syncdb and creating the database tables
else:
transaction.commit()
def check_permissions(requester, permission_list):
for permission_item in permission_list:
permission = get_object_or_404(Permission,
namespace=permission_item['namespace'], name=permission_item['name'])
if permission.has_permission(requester):
return True
raise PermissionDenied(ugettext(u'Insufficient permissions.'))
def get_permission_label(permission):
return unicode(permission_titles.get('%s.%s' % (permission.namespace, permission.name), permission.label))
def get_permission_namespace_label(permission):
return namespace_titles[permission.namespace] if permission.namespace in namespace_titles else permission.namespace
register_permission(PERMISSION_ROLE_VIEW)
register_permission(PERMISSION_ROLE_EDIT)
register_permission(PERMISSION_ROLE_CREATE)
register_permission(PERMISSION_ROLE_DELETE)
register_permission(PERMISSION_PERMISSION_GRANT)
register_permission(PERMISSION_PERMISSION_REVOKE)

View File

@@ -1,7 +1,14 @@
import logging
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.db import transaction
from django.core.exceptions import PermissionDenied
from django.shortcuts import get_object_or_404
from django.db.utils import IntegrityError
from django.core.exceptions import ImproperlyConfigured
from permissions.runtime import permission_titles
logger = logging.getLogger(__name__)
class RoleMemberManager(models.Manager):
@@ -10,19 +17,7 @@ class RoleMemberManager(models.Manager):
return [role_member.role for role_member in self.model.objects.filter(member_type=member_type, member_id=member_obj.pk)]
class PermissionManager(models.Manager):
class StoredPermissionManager(models.Manager):
def get_for_holder(self, holder):
ct = ContentType.objects.get_for_model(holder)
return self.model.objects.active_only().filter(permissionholder__holder_type=ct).filter(permissionholder__holder_id=holder.pk)
def active_only(self):
namespaces = []
names = []
for key in permission_titles:
namespace, name = key.split(u'.')
if namespace:
namespaces.append(namespace)
if name:
names.append(name)
return super(PermissionManager, self).get_query_set().filter(namespace__in=namespaces).filter(name__in=names).exclude(label=u'')
return self.model.objects.filter(permissionholder__holder_type=ct).filter(permissionholder__holder_id=holder.pk)

View File

@@ -1,33 +1,140 @@
import logging
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.contrib.auth.models import User
from django.core.exceptions import PermissionDenied
from permissions.managers import RoleMemberManager, PermissionManager
from permissions.runtime import namespace_titles, permission_titles
from permissions.managers import (RoleMemberManager, StoredPermissionManager)
logger = logging.getLogger(__name__)
class Permission(models.Model):
class PermissionNamespace(object):
def __init__(self, name, label):
self.name = name
self.label = label
def __unicode__(self):
return unicode(self.label)
#class LazyQuerySet(list):
# def __init__(self, model, items):
# self.model = model
# self.items = items
#
# def get(self, *args, **kwargs):
# print args
# print kwargs
class PermissionDoesNotExists(Exception):
pass
class PermissionManager(object):
_permissions = {}
DoesNotExist = PermissionDoesNotExists()
@classmethod
def register(cls, namespace, name, label):
permission = Permission(namespace, name, label)
cls._permissions[permission.uuid] = permission
return permission
@classmethod
def check_permissions(cls, requester, permission_list):
for permission in permission_list:
if permission.requester_has_this(requester):
return True
raise PermissionDenied(ugettext(u'Insufficient permissions.'))
@classmethod
def get_for_holder(cls, holder):
return StoredPermission.objects.get_for_holder(holder)
@classmethod
def all(cls):
return cls._permissions.values()
#return LazyQuerySet(cls, cls._permissions)
@classmethod
def get(cls, get_dict):
if 'pk' in get_dict:
try:
return cls._permissions[get_dict['pk']].get_stored_permission()
except KeyError:
raise Permission.DoesNotExist
def __init__(self, model):
self.model = model
class Permission(object):
DoesNotExist = PermissionDoesNotExists
def __init__(self, namespace, name, label):
self.namespace = namespace
self.name = name
self.label = label
self.pk = self.uuid
def __unicode__(self):
return unicode(self.label)
@property
def uuid(self):
return u'%s.%s' % (self.namespace.name, self.name)
def get_stored_permission(self):
stored_permission, created = StoredPermission.objects.get_or_create(
namespace=self.namespace.name,
name=self.name,
defaults={
'label': self.label
}
)
stored_permission.label = self.label
stored_permission.save()
stored_permission.volatile_permission = self
return stored_permission
def requester_has_this(self, requester):
stored_permission = self.get_stored_permission(
)
return stored_permission.requester_has_this(requester)
def save(self, *args, **kwargs):
return self.get_stored_permission(
)
Permission.objects = PermissionManager(Permission)
Permission._default_manager = Permission.objects
class StoredPermission(models.Model):
namespace = models.CharField(max_length=64, verbose_name=_(u'namespace'))
name = models.CharField(max_length=64, verbose_name=_(u'name'))
label = models.CharField(max_length=96, verbose_name=_(u'label'))
objects = PermissionManager()
objects = StoredPermissionManager()
class Meta:
ordering = ('namespace', 'label')
unique_together = ('namespace', 'name')
verbose_name = _(u'permission')
verbose_name_plural = _(u'permissions')
def __unicode__(self):
return u'%s: %s' % (self.get_namespace_label(), self.get_label())
return unicode(self.volatile_permission)
def get_holders(self):
return [holder.holder_object for holder in self.permissionholder_set.all()]
def has_permission(self, requester):
def requester_has_this(self, requester):
if isinstance(requester, User):
if requester.is_superuser or requester.is_staff:
return True
@@ -60,16 +167,10 @@ class Permission(models.Model):
return True
except PermissionHolder.DoesNotExist:
return False
def get_label(self):
return unicode(permission_titles.get('%s.%s' % (self.namespace, self.name), self.label))
def get_namespace_label(self):
return unicode(namespace_titles[self.namespace]) if self.namespace in namespace_titles else self.namespace
class PermissionHolder(models.Model):
permission = models.ForeignKey(Permission, verbose_name=_(u'permission'))
permission = models.ForeignKey(StoredPermission, verbose_name=_(u'permission'))
holder_type = models.ForeignKey(ContentType,
related_name='permission_holder',
limit_choices_to={'model__in': ('user', 'group', 'role')})

View File

@@ -1,8 +1 @@
from django.utils.translation import ugettext_lazy as _
namespace_titles = {
'permissions': _(u'Permissions')
}
permission_titles = {}

View File

@@ -2,7 +2,7 @@ import operator
import itertools
from django.utils.translation import ugettext_lazy as _
from django.http import HttpResponseRedirect
from django.http import HttpResponseRedirect, Http404
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
from django.contrib import messages
@@ -22,12 +22,11 @@ from permissions.forms import RoleForm, RoleForm_view
from permissions import PERMISSION_ROLE_VIEW, PERMISSION_ROLE_EDIT, \
PERMISSION_ROLE_CREATE, PERMISSION_ROLE_DELETE, PERMISSION_PERMISSION_GRANT, \
PERMISSION_PERMISSION_REVOKE
from permissions.api import check_permissions, namespace_titles, get_permission_label, get_permission_namespace_label
from permissions.widgets import role_permission_link
def role_list(request):
check_permissions(request.user, [PERMISSION_ROLE_VIEW])
Permission.objects.check_permissions(request.user, [PERMISSION_ROLE_VIEW])
return object_list(
request,
@@ -41,7 +40,7 @@ def role_list(request):
def role_permissions(request, role_id):
check_permissions(request.user, [PERMISSION_PERMISSION_GRANT, PERMISSION_PERMISSION_REVOKE])
Permission.objects.check_permissions(request.user, [PERMISSION_PERMISSION_GRANT, PERMISSION_PERMISSION_REVOKE])
role = get_object_or_404(Role, pk=role_id)
form = RoleForm_view(instance=role)
@@ -52,13 +51,13 @@ def role_permissions(request, role_id):
'name': u'generic_list_subtemplate.html',
'context': {
'title': _(u'permissions'),
'object_list': Permission.objects.active_only(),
'object_list': Permission.objects.all(),
'extra_columns': [
{'name': _(u'namespace'), 'attribute': encapsulate(lambda x: get_permission_namespace_label(x))},
{'name': _(u'name'), 'attribute': encapsulate(lambda x: get_permission_label(x))},
{'name': _(u'namespace'), 'attribute': encapsulate(lambda x: x.namespace)},
{'name': _(u'name'), 'attribute': encapsulate(lambda x: x.label)},
{
'name':_(u'has permission'),
'attribute': encapsulate(lambda x: two_state_template(x.has_permission(role))),
'attribute': encapsulate(lambda x: two_state_template(x.requester_has_this(role))),
},
],
'hide_link': True,
@@ -83,7 +82,7 @@ def role_permissions(request, role_id):
def role_edit(request, role_id):
check_permissions(request.user, [PERMISSION_ROLE_EDIT])
Permission.objects.check_permissions(request.user, [PERMISSION_ROLE_EDIT])
return update_object(request, template_name='generic_form.html',
form_class=RoleForm, object_id=role_id, extra_context={
@@ -91,7 +90,7 @@ def role_edit(request, role_id):
def role_create(request):
check_permissions(request.user, [PERMISSION_ROLE_CREATE])
Permission.objects.check_permissions(request.user, [PERMISSION_ROLE_CREATE])
return create_object(request, model=Role,
template_name='generic_form.html',
@@ -99,7 +98,7 @@ def role_create(request):
def role_delete(request, role_id):
check_permissions(request.user, [PERMISSION_ROLE_DELETE])
Permission.objects.check_permissions(request.user, [PERMISSION_ROLE_DELETE])
next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', '/')))
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/')))
@@ -117,7 +116,7 @@ def role_delete(request, role_id):
def permission_grant(request):
check_permissions(request.user, [PERMISSION_PERMISSION_GRANT])
Permission.objects.check_permissions(request.user, [PERMISSION_PERMISSION_GRANT])
items_property_list = loads(request.GET.get('items_property_list', []))
post_action_redirect = None
@@ -126,7 +125,12 @@ def permission_grant(request):
items = []
for item_properties in items_property_list:
permission = get_object_or_404(Permission, pk=item_properties['permission_id'])
#permission = get_object_or_404(Permission, pk=item_properties['permission_id'])
try:
permission = Permission.objects.get({'pk': item_properties['permission_id']})
except Permission.DoesNotExist:
raise Http404
ct = get_object_or_404(ContentType, app_label=item_properties['requester_app_label'], model=item_properties['requester_model'])
requester_model = ct.model_class()
requester = get_object_or_404(requester_model, pk=item_properties['requester_id'])
@@ -176,7 +180,7 @@ def permission_grant(request):
def permission_revoke(request):
check_permissions(request.user, [PERMISSION_PERMISSION_REVOKE])
Permission.objects.check_permissions(request.user, [PERMISSION_PERMISSION_REVOKE])
items_property_list = loads(request.GET.get('items_property_list', []))
post_action_redirect = None
@@ -185,7 +189,12 @@ def permission_revoke(request):
items = []
for item_properties in items_property_list:
permission = get_object_or_404(Permission, pk=item_properties['permission_id'])
#permission = get_object_or_404(Permission, pk=item_properties['permission_id'])
try:
permission = Permission.objects.get({'pk': item_properties['permission_id']})
except Permission.DoesNotExist:
raise Http404
ct = get_object_or_404(ContentType, app_label=item_properties['requester_app_label'], model=item_properties['requester_model'])
requester_model = ct.model_class()
requester = get_object_or_404(requester_model, pk=item_properties['requester_id'])
@@ -265,7 +274,7 @@ def remove_role_member(role, selection):
def role_members(request, role_id):
check_permissions(request.user, [PERMISSION_ROLE_EDIT])
Permission.objects.check_permissions(request.user, [PERMISSION_ROLE_EDIT])
role = get_object_or_404(Role, pk=role_id)
return assign_remove(