mirror of
https://github.com/jazzband/django-admin2.git
synced 2026-05-26 15:44:07 +00:00
Adding |for_view filter to bind permissions for a view name.
This commit is contained in:
parent
9ce77ae572
commit
635bbca553
4 changed files with 136 additions and 30 deletions
|
|
@ -236,9 +236,33 @@ class TemplatePermissionChecker(object):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return ''
|
return ''
|
||||||
new_permissions = self.clone()
|
new_permissions = self.clone()
|
||||||
|
new_permissions._view = None
|
||||||
new_permissions._model_admin = admin
|
new_permissions._model_admin = admin
|
||||||
return new_permissions
|
return new_permissions
|
||||||
|
|
||||||
|
def bind_view(self, view):
|
||||||
|
'''
|
||||||
|
Return a clone of the permission wrapper with a new view bind to it.
|
||||||
|
'''
|
||||||
|
if isinstance(view, six.string_types):
|
||||||
|
if view not in self.view_name_mapping:
|
||||||
|
return ''
|
||||||
|
view_name = self.view_name_mapping[view]
|
||||||
|
view = getattr(self._model_admin, view_name)
|
||||||
|
# we don't support binding view classes yet, only the name of views
|
||||||
|
# are processed. We have the problem with view classes that we cannot
|
||||||
|
# tell which model admin it was attached to.
|
||||||
|
else:
|
||||||
|
return ''
|
||||||
|
# if view is a class and not instantiated yet, do it!
|
||||||
|
if isinstance(view, type):
|
||||||
|
view = view(
|
||||||
|
request=self._request,
|
||||||
|
**self._model_admin.get_default_view_kwargs())
|
||||||
|
new_permissions = self.clone()
|
||||||
|
new_permissions._view = view
|
||||||
|
return new_permissions
|
||||||
|
|
||||||
def bind_object(self, obj):
|
def bind_object(self, obj):
|
||||||
'''
|
'''
|
||||||
Return a clone of the permission wrapper with a new object bind
|
Return a clone of the permission wrapper with a new object bind
|
||||||
|
|
@ -248,30 +272,17 @@ class TemplatePermissionChecker(object):
|
||||||
new_permissions._obj = obj
|
new_permissions._obj = obj
|
||||||
return new_permissions
|
return new_permissions
|
||||||
|
|
||||||
def get_view_by_name(self, view_name):
|
|
||||||
view_name = self.view_name_mapping[view_name]
|
|
||||||
model_admin = self._model_admin
|
|
||||||
view_class = getattr(model_admin, view_name)
|
|
||||||
view = view_class(
|
|
||||||
request=self._request,
|
|
||||||
**model_admin.get_default_view_kwargs())
|
|
||||||
return view
|
|
||||||
|
|
||||||
#########################################
|
#########################################
|
||||||
# interface exposed to the template users
|
# interface exposed to the template users
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
match = self._has_named_permission_regex.match(key)
|
match = self._has_named_permission_regex.match(key)
|
||||||
if match:
|
if match:
|
||||||
# the key was a has_*_permission, so get the *has permission
|
# the key was a has_*_permission, so bind the correspodning view
|
||||||
# wrapper*
|
|
||||||
view_name = match.groupdict()['name']
|
view_name = match.groupdict()['name']
|
||||||
if view_name not in self.view_name_mapping:
|
return self.bind_view(view_name)
|
||||||
raise KeyError
|
# the name might be a named object admin. So get that one and bind it
|
||||||
view = self.get_view_by_name(view_name)
|
# to the permission checking
|
||||||
return self.bind_view(view)
|
|
||||||
# the name might be a named object admin. So get that one and try to
|
|
||||||
# check the permission there for further traversal
|
|
||||||
try:
|
try:
|
||||||
admin_site = self._model_admin.admin
|
admin_site = self._model_admin.admin
|
||||||
model_admin = admin_site.get_admin_by_name(key)
|
model_admin = admin_site.get_admin_by_name(key)
|
||||||
|
|
|
||||||
|
|
@ -45,19 +45,6 @@ def formset_visible_fieldlist(formset):
|
||||||
return [f.label for f in formset.forms[0].visible_fields()]
|
return [f.label for f in formset.forms[0].visible_fields()]
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
|
||||||
def for_object(permissions, obj):
|
|
||||||
"""
|
|
||||||
Only useful in the permission handling. This filter binds a new object to
|
|
||||||
the permission handler to check for object-level permissions.
|
|
||||||
"""
|
|
||||||
# some permission check has failed earlier, so we don't bother trying to
|
|
||||||
# bind a new object to it.
|
|
||||||
if permissions == '':
|
|
||||||
return permissions
|
|
||||||
return permissions.bind_object(obj)
|
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def for_admin(permissions, admin):
|
def for_admin(permissions, admin):
|
||||||
"""
|
"""
|
||||||
|
|
@ -69,3 +56,30 @@ def for_admin(permissions, admin):
|
||||||
if permissions == '':
|
if permissions == '':
|
||||||
return permissions
|
return permissions
|
||||||
return permissions.bind_admin(admin)
|
return permissions.bind_admin(admin)
|
||||||
|
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def for_view(permissions, view):
|
||||||
|
"""
|
||||||
|
Only useful in the permission handling. This filter binds a new view to
|
||||||
|
the permission handler to check for view names that are not known during
|
||||||
|
template compile time.
|
||||||
|
"""
|
||||||
|
# some permission check has failed earlier, so we don't bother trying to
|
||||||
|
# bind a new admin to it.
|
||||||
|
if permissions == '':
|
||||||
|
return permissions
|
||||||
|
return permissions.bind_view(view)
|
||||||
|
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def for_object(permissions, obj):
|
||||||
|
"""
|
||||||
|
Only useful in the permission handling. This filter binds a new object to
|
||||||
|
the permission handler to check for object-level permissions.
|
||||||
|
"""
|
||||||
|
# some permission check has failed earlier, so we don't bother trying to
|
||||||
|
# bind a new object to it.
|
||||||
|
if permissions == '':
|
||||||
|
return permissions
|
||||||
|
return permissions.bind_object(obj)
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ from .utils import admin2_urlname, model_options
|
||||||
|
|
||||||
|
|
||||||
class PermissionMixin(object):
|
class PermissionMixin(object):
|
||||||
|
do_not_call_in_templates = True
|
||||||
permission_classes = (permissions.IsStaffPermission,)
|
permission_classes = (permissions.IsStaffPermission,)
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,86 @@ class TemplatePermissionTest(TestCase):
|
||||||
context)
|
context)
|
||||||
self.assertEqual(result, '')
|
self.assertEqual(result, '')
|
||||||
|
|
||||||
|
def test_view_binding(self):
|
||||||
|
user_admin = djadmin2.default.get_admin_by_name('auth_user')
|
||||||
|
post_admin = djadmin2.default.get_admin_by_name('blog_post')
|
||||||
|
request = self.factory.get(reverse('admin2:auth_user_index'))
|
||||||
|
request.user = self.user
|
||||||
|
permissions = TemplatePermissionChecker(request, user_admin)
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'post_admin': post_admin,
|
||||||
|
'post_add_view': post_admin.create_view,
|
||||||
|
'permissions': permissions,
|
||||||
|
}
|
||||||
|
|
||||||
|
result = self.render(
|
||||||
|
'{% load admin2_tags %}'
|
||||||
|
'{{ permissions|for_view:"add" }}',
|
||||||
|
context)
|
||||||
|
self.assertEqual(result, 'False')
|
||||||
|
|
||||||
|
# view classes are not supported yet
|
||||||
|
result = self.render(
|
||||||
|
'{% load admin2_tags %}'
|
||||||
|
'{{ permissions|for_view:post_add_view }}',
|
||||||
|
context)
|
||||||
|
self.assertEqual(result, '')
|
||||||
|
|
||||||
|
result = self.render(
|
||||||
|
'{% load admin2_tags %}'
|
||||||
|
# user add permission
|
||||||
|
'{{ permissions.has_add_permission }}'
|
||||||
|
'{% with permissions|for_admin:"blog_post"|for_view:"add" as post_add_perm %}'
|
||||||
|
# post add permission
|
||||||
|
'{{ post_add_perm }}'
|
||||||
|
'{% endwith %}',
|
||||||
|
context)
|
||||||
|
self.assertEqual(result, 'FalseFalse')
|
||||||
|
|
||||||
|
post_add_permission = Permission.objects.get(
|
||||||
|
content_type__app_label='blog',
|
||||||
|
content_type__model='post',
|
||||||
|
codename='add_post')
|
||||||
|
self.user.user_permissions.add(post_add_permission)
|
||||||
|
user_change_permission = Permission.objects.get(
|
||||||
|
content_type__app_label='auth',
|
||||||
|
content_type__model='user',
|
||||||
|
codename='change_user')
|
||||||
|
self.user.user_permissions.add(user_change_permission)
|
||||||
|
|
||||||
|
# invalidate the users permission cache
|
||||||
|
if hasattr(self.user, '_perm_cache'):
|
||||||
|
del self.user._perm_cache
|
||||||
|
|
||||||
|
result = self.render(
|
||||||
|
'{% load admin2_tags %}'
|
||||||
|
# user add permission
|
||||||
|
'{{ permissions.has_add_permission }}'
|
||||||
|
'{% with permissions|for_admin:"blog_post"|for_view:"add" as post_add_perm %}'
|
||||||
|
# post add permission
|
||||||
|
'{{ post_add_perm }}'
|
||||||
|
'{% endwith %}'
|
||||||
|
# user change permission
|
||||||
|
'{{ permissions|for_view:"change" }}',
|
||||||
|
context)
|
||||||
|
self.assertEqual(result, 'FalseTrueTrue')
|
||||||
|
|
||||||
|
# giving a string (the name of the view) also works
|
||||||
|
result = self.render(
|
||||||
|
'{% load admin2_tags %}'
|
||||||
|
'{% with permissions|for_view:"change" as user_change_perm %}'
|
||||||
|
'1{{ user_change_perm }}'
|
||||||
|
'2{{ user_change_perm|for_view:"add" }}'
|
||||||
|
# this shouldn't return True or False but '' since the
|
||||||
|
# previously bound change view doesn't belong to the newly
|
||||||
|
# bound blog_post admin
|
||||||
|
'3{{ user_change_perm|for_admin:"blog_post" }}'
|
||||||
|
'4{{ user_change_perm|for_admin:"blog_post"|for_view:"add" }}'
|
||||||
|
'{% endwith %}',
|
||||||
|
context)
|
||||||
|
self.assertEqual(result, '1True2False34True')
|
||||||
|
|
||||||
def test_object_level_permission(self):
|
def test_object_level_permission(self):
|
||||||
model_admin = ModelAdmin2(Post, djadmin2.default)
|
model_admin = ModelAdmin2(Post, djadmin2.default)
|
||||||
request = self.factory.get(reverse('admin2:blog_post_index'))
|
request = self.factory.get(reverse('admin2:blog_post_index'))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue