mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) discount indirect changes for access control purposes
Summary: This diff discounts indirect changes for access control purposes. A UserAction that updates a cell A, which in turn causes changes in other dependent cells, will be considered a change to cell A for access control purposes. The `engine.apply_user_actions` method now returns a `direct` array, with a boolean for each `stored` action, set to `true` if the action is attributed to the user or `false` if it is attributed to the engine. `GranularAccess` ignores actions attributed to the engine when checking for edit rights. Subtleties: * Removal of references to a removed row are considered direct changes. * Doesn't play well with undos as yet. An action that indirectly modifies a cell the user doesn't have rights to may succeed, but it will not be reversible. Test Plan: added tests, updated tests Reviewers: dsagal Reviewed By: dsagal Differential Revision: https://phab.getgrist.com/D2806
This commit is contained in:
@@ -123,7 +123,7 @@ class EngineTestCase(unittest.TestCase):
|
||||
self.assertEqualDocData({table_name: observed}, {table_name: expected})
|
||||
|
||||
|
||||
action_group_action_fields = ("stored", "undo", "calc")
|
||||
action_group_action_fields = ("stored", "undo", "calc", "direct")
|
||||
|
||||
@classmethod
|
||||
def _formatActionGroup(cls, action_group, use_repr=False):
|
||||
@@ -149,13 +149,12 @@ class EngineTestCase(unittest.TestCase):
|
||||
# Do some clean up on the observed data.
|
||||
observed = testutil.replace_nans(observed)
|
||||
|
||||
# Convert expected actions into a comparable form.
|
||||
# Convert observed and expected actions into a comparable form.
|
||||
for k in self.action_group_action_fields:
|
||||
if k in observed:
|
||||
observed[k] = map(actions.get_action_repr, observed[k])
|
||||
observed[k] = map(get_comparable_repr, observed[k])
|
||||
if k in expected:
|
||||
expected[k] = [actions.get_action_repr(a) if not isinstance(a, list) else a
|
||||
for a in expected[k]]
|
||||
expected[k] = map(get_comparable_repr, expected[k])
|
||||
|
||||
if observed != expected:
|
||||
o_lines = self._formatActionGroup(observed)
|
||||
@@ -552,6 +551,11 @@ def create_test_case(name, body):
|
||||
self._run_test_body(name, body)
|
||||
setattr(TestEngine, name, run)
|
||||
|
||||
# Convert observed/expected action into a comparable form.
|
||||
def get_comparable_repr(a):
|
||||
if isinstance(a, (list, int)):
|
||||
return a
|
||||
return actions.get_action_repr(a)
|
||||
|
||||
# Parse and create test cases on module load. This way the python unittest feature to run only
|
||||
# particular test cases can apply to these cases too.
|
||||
|
||||
Reference in New Issue
Block a user