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 project_setup.api import register_setup
from permissions.conf.settings import DEFAULT_ROLES 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')} permissions_namespace = PermissionNamespace('permissions', _(u'Permissions'))
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_VIEW = Permission.objects.register(permissions_namespace, 'role_view', _(u'View roles'))
PERMISSION_ROLE_DELETE = {'namespace': 'permissions', 'name': 'role_delete', 'label': _(u'Delete roles')} PERMISSION_ROLE_EDIT = Permission.objects.register(permissions_namespace, 'role_edit', _(u'Edit roles'))
PERMISSION_PERMISSION_GRANT = {'namespace': 'permissions', 'name': 'permission_grant', 'label': _(u'Grant permissions')} PERMISSION_ROLE_CREATE = Permission.objects.register(permissions_namespace, 'role_create', _(u'Create roles'))
PERMISSION_PERMISSION_REVOKE = {'namespace': 'permissions', 'name': 'permission_revoke', 'label': _(u'Revoke permissions')} 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_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]} 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 django.contrib import admin
from permissions.models import Permission, PermissionHolder, Role, RoleMember from permissions.models import StoredPermission, PermissionHolder, Role, RoleMember
class PermissionHolderInline(admin.StackedInline): class PermissionHolderInline(admin.StackedInline):
@@ -27,5 +27,5 @@ class RoleAdmin(admin.ModelAdmin):
inlines = [RoleMemberInline] inlines = [RoleMemberInline]
admin.site.register(Permission, PermissionAdmin) admin.site.register(StoredPermission, PermissionAdmin)
admin.site.register(Role, RoleAdmin) 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.db import models
from django.contrib.contenttypes.models import ContentType 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): 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)] 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): def get_for_holder(self, holder):
ct = ContentType.objects.get_for_model(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) return self.model.objects.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'')

View File

@@ -1,33 +1,140 @@
import logging
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic from django.contrib.contenttypes import generic
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.exceptions import PermissionDenied
from permissions.managers import RoleMemberManager, PermissionManager from permissions.managers import (RoleMemberManager, StoredPermissionManager)
from permissions.runtime import namespace_titles, permission_titles
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')) namespace = models.CharField(max_length=64, verbose_name=_(u'namespace'))
name = models.CharField(max_length=64, verbose_name=_(u'name')) name = models.CharField(max_length=64, verbose_name=_(u'name'))
label = models.CharField(max_length=96, verbose_name=_(u'label')) label = models.CharField(max_length=96, verbose_name=_(u'label'))
objects = PermissionManager() objects = StoredPermissionManager()
class Meta: class Meta:
ordering = ('namespace', 'label') ordering = ('namespace', 'label')
unique_together = ('namespace', 'name') unique_together = ('namespace', 'name')
verbose_name = _(u'permission') verbose_name = _(u'permission')
verbose_name_plural = _(u'permissions') verbose_name_plural = _(u'permissions')
def __unicode__(self): def __unicode__(self):
return u'%s: %s' % (self.get_namespace_label(), self.get_label()) return unicode(self.volatile_permission)
def get_holders(self): def get_holders(self):
return [holder.holder_object for holder in self.permissionholder_set.all()] 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 isinstance(requester, User):
if requester.is_superuser or requester.is_staff: if requester.is_superuser or requester.is_staff:
return True return True
@@ -60,16 +167,10 @@ class Permission(models.Model):
return True return True
except PermissionHolder.DoesNotExist: except PermissionHolder.DoesNotExist:
return False 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): 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, holder_type = models.ForeignKey(ContentType,
related_name='permission_holder', related_name='permission_holder',
limit_choices_to={'model__in': ('user', 'group', 'role')}) 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 import itertools
from django.utils.translation import ugettext_lazy as _ 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.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext from django.template import RequestContext
from django.contrib import messages 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, \ from permissions import PERMISSION_ROLE_VIEW, PERMISSION_ROLE_EDIT, \
PERMISSION_ROLE_CREATE, PERMISSION_ROLE_DELETE, PERMISSION_PERMISSION_GRANT, \ PERMISSION_ROLE_CREATE, PERMISSION_ROLE_DELETE, PERMISSION_PERMISSION_GRANT, \
PERMISSION_PERMISSION_REVOKE 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 from permissions.widgets import role_permission_link
def role_list(request): def role_list(request):
check_permissions(request.user, [PERMISSION_ROLE_VIEW]) Permission.objects.check_permissions(request.user, [PERMISSION_ROLE_VIEW])
return object_list( return object_list(
request, request,
@@ -41,7 +40,7 @@ def role_list(request):
def role_permissions(request, role_id): 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) role = get_object_or_404(Role, pk=role_id)
form = RoleForm_view(instance=role) form = RoleForm_view(instance=role)
@@ -52,13 +51,13 @@ def role_permissions(request, role_id):
'name': u'generic_list_subtemplate.html', 'name': u'generic_list_subtemplate.html',
'context': { 'context': {
'title': _(u'permissions'), 'title': _(u'permissions'),
'object_list': Permission.objects.active_only(), 'object_list': Permission.objects.all(),
'extra_columns': [ 'extra_columns': [
{'name': _(u'namespace'), 'attribute': encapsulate(lambda x: get_permission_namespace_label(x))}, {'name': _(u'namespace'), 'attribute': encapsulate(lambda x: x.namespace)},
{'name': _(u'name'), 'attribute': encapsulate(lambda x: get_permission_label(x))}, {'name': _(u'name'), 'attribute': encapsulate(lambda x: x.label)},
{ {
'name':_(u'has permission'), '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, 'hide_link': True,
@@ -83,7 +82,7 @@ def role_permissions(request, role_id):
def role_edit(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', return update_object(request, template_name='generic_form.html',
form_class=RoleForm, object_id=role_id, extra_context={ form_class=RoleForm, object_id=role_id, extra_context={
@@ -91,7 +90,7 @@ def role_edit(request, role_id):
def role_create(request): 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, return create_object(request, model=Role,
template_name='generic_form.html', template_name='generic_form.html',
@@ -99,7 +98,7 @@ def role_create(request):
def role_delete(request, role_id): 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', '/'))) 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', '/'))) 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): 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', [])) items_property_list = loads(request.GET.get('items_property_list', []))
post_action_redirect = None post_action_redirect = None
@@ -126,7 +125,12 @@ def permission_grant(request):
items = [] items = []
for item_properties in items_property_list: 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']) ct = get_object_or_404(ContentType, app_label=item_properties['requester_app_label'], model=item_properties['requester_model'])
requester_model = ct.model_class() requester_model = ct.model_class()
requester = get_object_or_404(requester_model, pk=item_properties['requester_id']) requester = get_object_or_404(requester_model, pk=item_properties['requester_id'])
@@ -176,7 +180,7 @@ def permission_grant(request):
def permission_revoke(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', [])) items_property_list = loads(request.GET.get('items_property_list', []))
post_action_redirect = None post_action_redirect = None
@@ -185,7 +189,12 @@ def permission_revoke(request):
items = [] items = []
for item_properties in items_property_list: 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']) ct = get_object_or_404(ContentType, app_label=item_properties['requester_app_label'], model=item_properties['requester_model'])
requester_model = ct.model_class() requester_model = ct.model_class()
requester = get_object_or_404(requester_model, pk=item_properties['requester_id']) 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): 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) role = get_object_or_404(Role, pk=role_id)
return assign_remove( return assign_remove(