Refactored permission class registration.

This commit is contained in:
Jannis Leidel 2009-07-10 01:07:20 +02:00
parent 4b6fae8a27
commit 13cc721580
8 changed files with 15 additions and 108 deletions

View file

@ -1,7 +1,7 @@
from django.contrib.flatpages.models import FlatPage
from django.utils.translation import ugettext_lazy as _
from authority import permissions
from authority import permissions, site
class FlatPagePermission(permissions.BasePermission):
"""
@ -39,7 +39,6 @@ class FlatPagePermission(permissions.BasePermission):
{% endifhasperm %}
"""
model = FlatPage
label = 'flatpage_permission'
checks = ('review', 'top_secret')
@ -48,3 +47,5 @@ class FlatPagePermission(permissions.BasePermission):
return self.browse_flatpage(obj=flatpage)
return False
top_secret.short_description=_('Is allowed to see top secret flatpages')
site.register(FlatPage, FlatPagePermission)

View file

@ -1,4 +1,6 @@
import sys
from authority.sites import site, get_check, get_choices_for
LOADING = False
def autodiscover():

View file

@ -5,7 +5,6 @@ from django.utils.translation import ugettext_lazy as _
from django.utils.text import capfirst, truncate_words
from authority.models import Permission
from authority import permissions
from authority.widgets import GenericForeignKeyRawIdWidget
class PermissionInline(generic.GenericTabularInline):
@ -15,7 +14,7 @@ class PermissionInline(generic.GenericTabularInline):
def formfield_for_dbfield(self, db_field, **kwargs):
if db_field.name == 'codename':
perm_choices = permissions.registry.get_choices_for(self.parent_model)
perm_choices = permissions.get_choices_for(self.parent_model)
kwargs['label'] = _('permission')
kwargs['widget'] = forms.Select(choices=perm_choices)
return db_field.formfield(**kwargs)

View file

@ -9,7 +9,7 @@ from django.conf import settings
from django.contrib.auth.decorators import user_passes_test
from django.contrib.auth import REDIRECT_FIELD_NAME
from authority import permissions
from authority import permissions, get_check
from authority.views import permission_denied
def permission_required(perm, *model_lookups, **kwargs):
@ -42,7 +42,7 @@ def permission_required(perm, *model_lookups, **kwargs):
raise ValueError(
'The argument %s needs to be a model.' % model)
objs.append(get_object_or_404(model_class, **{lookup: value}))
check = permissions.registry.get_check(request.user, perm)
check = get_check(request.user, perm)
granted = False
if check is not None:
granted = check(*objs)

View file

@ -3,8 +3,8 @@ from django.utils.translation import ugettext_lazy as _
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import User, Group
from authority import permissions, get_choices_for
from authority.models import Permission
from authority import permissions
class BasePermissionForm(forms.ModelForm):
codename = forms.CharField(label=_('Permission'))
@ -18,7 +18,7 @@ class BasePermissionForm(forms.ModelForm):
if obj and perm:
self.base_fields['codename'].widget = forms.HiddenInput()
elif obj and not perm:
perm_choices = permissions.registry.get_choices_for(self.obj)
perm_choices = get_choices_for(self.obj)
self.base_fields['codename'].widget = forms.Select(choices=perm_choices)
super(BasePermissionForm, self).__init__(*args, **kwargs)

View file

@ -3,6 +3,7 @@ from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.contrib.auth.models import User, Group
from django.utils.translation import ugettext_lazy as _
from authority.managers import PermissionManager
class Permission(models.Model):

View file

@ -1,61 +1,11 @@
from inspect import getmembers, ismethod
from django.db.models import Q
from django.db.models.base import ModelBase
from django.db.models.fields import BLANK_CHOICE_DASH
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ImproperlyConfigured
from django.template.defaultfilters import slugify
from django.utils.translation import ugettext_lazy as _
from authority.models import Permission
class AlreadyRegistered(Exception):
pass
class NotRegistered(Exception):
pass
class PermissionRegistry(dict):
"""
A dictionary that contains permission instances and their labels.
"""
_choices = {}
def get_permission_by_label(self, label):
for perm_cls, perm_label in self.items():
if perm_label == label:
return perm_cls
return None
def get_check(self, user, label):
perm_label, check_name = label.split('.')
perm_cls = self.get_permission_by_label(perm_label)
if perm_cls is None:
return None
perm_instance = perm_cls(user)
return getattr(perm_instance, check_name, None)
def get_permissions_by_model(self, model):
return [perm for perm in self if perm.model == model]
def get_choices_for(self, obj, default=BLANK_CHOICE_DASH):
model_cls = obj
if not isinstance(obj, ModelBase):
model_cls = obj.__class__
if model_cls in self._choices:
choices = self._choices[model_cls]
else:
choices = [] + default
for perm in self.get_permissions_by_model(model_cls):
for name, check in getmembers(perm, ismethod):
if name in perm.checks:
signature = '%s.%s' % (perm.label, name)
label = getattr(check, 'short_description', signature)
choices.append((signature, label))
self._choices[model_cls] = choices
return choices
registry = PermissionRegistry()
class PermissionMetaclass(type):
"""
Used to generate the default set of permission checks "add", "change" and
@ -64,61 +14,15 @@ class PermissionMetaclass(type):
def __new__(cls, name, bases, attrs):
new_class = super(
PermissionMetaclass, cls).__new__(cls, name, bases, attrs)
if new_class.__name__ == "BasePermission":
return new_class
if not new_class.model:
raise ImproperlyConfigured(
"Permission %s requires a model attribute." % new_class)
if not new_class.label:
new_class.label = "%s_permission" % new_class.__name__.lower()
new_class.label = slugify(new_class.label)
if new_class in registry:
raise AlreadyRegistered(
"The permission %s is already registered" % new_class)
if new_class.label in registry.values():
raise ImproperlyConfigured(
"The name of %s conflicts with %s" % \
(new_class, registry[new_class.label]))
registry[new_class] = new_class.label
if new_class.checks is None:
new_class.checks = []
# force check names to be lower case
new_class.checks = [check.lower() for check in new_class.checks]
generic_checks = ['add', 'browse', 'change', 'delete']
for check_name in new_class.checks:
check_func = getattr(new_class, check_name, None)
if check_func is not None:
func = new_class.create_check(check_name, check_func)
func.__name__ = check_name
func.short_description = getattr(check_func, 'short_description',
_("%(object_name)s permission '%(check)s'") % {
'object_name': new_class.model._meta.object_name,
'check': check_name})
setattr(new_class, check_name, func)
else:
generic_checks.append(check_name)
for check_name in generic_checks:
func = new_class.create_check(check_name, generic=True)
object_name = new_class.model._meta.object_name
func_name = "%s_%s" % (check_name, object_name.lower())
func.short_description = _("Can %(check)s this %(object_name)s") % {
'object_name': new_class.model._meta.object_name.lower(),
'check': check_name}
func.check_name = check_name
if func_name not in new_class.checks:
new_class.checks.append(func_name)
setattr(new_class, func_name, func)
return new_class
def _create_check(cls, check_name, check_func=None, generic=False):
def check(self, *args, **kwargs):
granted = self.can(check_name, generic, *args, **kwargs)
if check_func and not granted:
return check_func(self, *args, **kwargs)
return granted
return check
create_check = classmethod(_create_check)
class BasePermission(object):
"""
Base Permission class to be used to define app permissions.
@ -127,7 +31,7 @@ class BasePermission(object):
checks = ()
label = None
model = None
generic_checks = ['add', 'browse', 'change', 'delete']
def __init__(self, user=None, group=None, *args, **kwargs):
self.user = user

View file

@ -3,7 +3,7 @@ from django.core.urlresolvers import reverse
from django.core.exceptions import ImproperlyConfigured
from django.contrib.auth.models import User, AnonymousUser
from authority import permissions
from authority import permissions, get_check
from authority.models import Permission
from authority.views import add_url_for_obj
from authority.forms import UserPermissionForm
@ -51,7 +51,7 @@ class ComparisonNode(ResolverNode):
objs.append(self.resolve(obj, context))
else:
objs = None
check = permissions.registry.get_check(user, perm)
check = get_check(user, perm)
if check is not None:
if check(*objs):
# return True if check was successful
@ -206,7 +206,7 @@ class PermissionForObjectNode(ResolverNode):
user = self.resolve(self.user, context)
granted = False
if not isinstance(user, AnonymousUser):
check = permissions.registry.get_check(user, perm)
check = get_check(user, perm)
if check is not None:
granted = check(*objs)
context[var_name] = granted