Merge "DataTable column level policy"
This commit is contained in:
commit
0744e8e594
@ -236,6 +236,22 @@ class Column(html.HTMLElement):
|
||||
``link_attrs={"target": "_blank", "class": "link-foo link-bar"}``.
|
||||
Defaults to ``None``.
|
||||
|
||||
.. attribute:: policy_rules
|
||||
|
||||
List of scope and rule tuples to do policy checks on, the
|
||||
composition of which is (scope, rule)
|
||||
|
||||
scope: service type managing the policy for action
|
||||
rule: string representing the action to be checked
|
||||
|
||||
for a policy that requires a single rule check:
|
||||
policy_rules should look like
|
||||
"(("compute", "compute:create_instance"),)"
|
||||
for a policy that requires multiple rule checks:
|
||||
rules should look like
|
||||
"(("identity", "identity:list_users"),
|
||||
("identity", "identity:list_roles"))"
|
||||
|
||||
.. attribute:: help_text
|
||||
|
||||
A string of simple help text displayed in a tooltip when you hover
|
||||
@ -275,7 +291,7 @@ class Column(html.HTMLElement):
|
||||
empty_value=None, filters=None, classes=None, summation=None,
|
||||
auto=None, truncate=None, link_classes=None, wrap_list=False,
|
||||
form_field=None, form_field_attributes=None,
|
||||
update_action=None, link_attrs=None,
|
||||
update_action=None, link_attrs=None, policy_rules=None,
|
||||
cell_attributes_getter=None, help_text=None):
|
||||
|
||||
allowed_data_types = allowed_data_types or []
|
||||
@ -313,6 +329,7 @@ class Column(html.HTMLElement):
|
||||
self.form_field_attributes = form_field_attributes or {}
|
||||
self.update_action = update_action
|
||||
self.link_attrs = link_attrs or {}
|
||||
self.policy_rules = policy_rules or []
|
||||
self.help_text = help_text
|
||||
if link_classes:
|
||||
self.link_attrs['class'] = ' '.join(link_classes)
|
||||
@ -345,6 +362,19 @@ class Column(html.HTMLElement):
|
||||
def __repr__(self):
|
||||
return '<%s: %s>' % (self.__class__.__name__, self.name)
|
||||
|
||||
def allowed(self, request):
|
||||
"""Determine whether processing/displaying the column is allowed
|
||||
for the current request.
|
||||
"""
|
||||
if not self.policy_rules:
|
||||
return True
|
||||
|
||||
policy_check = getattr(settings, "POLICY_CHECK_FUNCTION", None)
|
||||
|
||||
if policy_check:
|
||||
return policy_check(self.policy_rules, request)
|
||||
return True
|
||||
|
||||
def get_raw_data(self, datum):
|
||||
"""Returns the raw data for this column, before any filters or
|
||||
formatting are applied to it. This is useful when doing calculations
|
||||
@ -1220,9 +1250,10 @@ class DataTable(object):
|
||||
# Create a new set
|
||||
columns = []
|
||||
for key, _column in self._columns.items():
|
||||
column = copy.copy(_column)
|
||||
column.table = self
|
||||
columns.append((key, column))
|
||||
if _column.allowed(request):
|
||||
column = copy.copy(_column)
|
||||
column.table = self
|
||||
columns.append((key, column))
|
||||
self.columns = collections.OrderedDict(columns)
|
||||
self._populate_data_cache()
|
||||
|
||||
|
@ -20,6 +20,7 @@ from django import forms
|
||||
from django import http
|
||||
from django import shortcuts
|
||||
from django.template import defaultfilters
|
||||
from django.test.utils import override_settings
|
||||
from django.utils.translation import ungettext_lazy
|
||||
|
||||
from mox3.mox import IsA # noqa
|
||||
@ -306,6 +307,12 @@ class MyTable(tables.DataTable):
|
||||
MyBatchActionWithHelpText)
|
||||
|
||||
|
||||
class TableWithColumnsPolicy(tables.DataTable):
|
||||
name = tables.Column('name')
|
||||
restricted = tables.Column('restricted',
|
||||
policy_rules=[('compute', 'role:admin')])
|
||||
|
||||
|
||||
class MyServerFilterTable(MyTable):
|
||||
class Meta(object):
|
||||
name = "my_table"
|
||||
@ -435,6 +442,22 @@ class DataTableTests(test.TestCase):
|
||||
self.assertEqual(forms.CharField, name_column.form_field.__class__)
|
||||
self.assertEqual({'class': 'test'}, name_column.form_field_attributes)
|
||||
|
||||
@override_settings(POLICY_CHECK_FUNCTION=lambda *args: False)
|
||||
def test_table_column_policy_not_allowed(self):
|
||||
self.table = TableWithColumnsPolicy(self.request, TEST_DATA)
|
||||
self.assertEqual(TEST_DATA, self.table.data)
|
||||
# The column "restricted" is not rendered because of policy
|
||||
expected_columns = ['<Column: name>']
|
||||
self.assertQuerysetEqual(self.table.columns.values(), expected_columns)
|
||||
|
||||
@override_settings(POLICY_CHECK_FUNCTION=lambda *args: True)
|
||||
def test_table_column_policy_allowed(self):
|
||||
self.table = TableWithColumnsPolicy(self.request, TEST_DATA)
|
||||
self.assertEqual(TEST_DATA, self.table.data)
|
||||
# Policy check returns True so the column "restricted" is rendered
|
||||
expected_columns = ['<Column: name>', '<Column: restricted>']
|
||||
self.assertQuerysetEqual(self.table.columns.values(), expected_columns)
|
||||
|
||||
def test_table_force_no_multiselect(self):
|
||||
class TempTable(MyTable):
|
||||
class Meta(object):
|
||||
|
Loading…
Reference in New Issue
Block a user