mirror of
https://github.com/jazzband/django-admin2.git
synced 2026-03-17 06:30:25 +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:
|
||||
return ''
|
||||
new_permissions = self.clone()
|
||||
new_permissions._view = None
|
||||
new_permissions._model_admin = admin
|
||||
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):
|
||||
'''
|
||||
Return a clone of the permission wrapper with a new object bind
|
||||
|
|
@ -248,30 +272,17 @@ class TemplatePermissionChecker(object):
|
|||
new_permissions._obj = obj
|
||||
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
|
||||
|
||||
def __getitem__(self, key):
|
||||
match = self._has_named_permission_regex.match(key)
|
||||
if match:
|
||||
# the key was a has_*_permission, so get the *has permission
|
||||
# wrapper*
|
||||
# the key was a has_*_permission, so bind the correspodning view
|
||||
view_name = match.groupdict()['name']
|
||||
if view_name not in self.view_name_mapping:
|
||||
raise KeyError
|
||||
view = self.get_view_by_name(view_name)
|
||||
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
|
||||
return self.bind_view(view_name)
|
||||
# the name might be a named object admin. So get that one and bind it
|
||||
# to the permission checking
|
||||
try:
|
||||
admin_site = self._model_admin.admin
|
||||
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()]
|
||||
|
||||
|
||||
@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
|
||||
def for_admin(permissions, admin):
|
||||
"""
|
||||
|
|
@ -69,3 +56,30 @@ def for_admin(permissions, admin):
|
|||
if permissions == '':
|
||||
return permissions
|
||||
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):
|
||||
do_not_call_in_templates = True
|
||||
permission_classes = (permissions.IsStaffPermission,)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
|
|
|||
|
|
@ -154,6 +154,86 @@ class TemplatePermissionTest(TestCase):
|
|||
context)
|
||||
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):
|
||||
model_admin = ModelAdmin2(Post, djadmin2.default)
|
||||
request = self.factory.get(reverse('admin2:blog_post_index'))
|
||||
|
|
|
|||
Loading…
Reference in a new issue