Commit 3f6baa99 by Nimisha Asthagiri

Transformer: VisibilityTransformer

parent a40d2b65
"""
Tests for VisibilityTransformer.
"""
import ddt
from ..visibility import VisibilityTransformer
from .test_helpers import BlockParentsMapTestCase, update_block
@ddt.ddt
class VisibilityTransformerTestCase(BlockParentsMapTestCase):
"""
VisibilityTransformer Test
"""
# Following test cases are based on BlockParentsMapTestCase.parents_map
@ddt.data(
({}, {0, 1, 2, 3, 4, 5, 6}, {}),
({0}, {}, {1, 2, 3, 4, 5, 6}),
({1}, {0, 2, 5, 6}, {3, 4}),
({2}, {0, 1, 3, 4, 6}, {5}),
({3}, {0, 1, 2, 4, 5, 6}, {}),
({4}, {0, 1, 2, 3, 5, 6}, {}),
({5}, {0, 1, 2, 3, 4, 6}, {}),
({6}, {0, 1, 2, 3, 4, 5}, {}),
({1, 2}, {0}, {3, 4, 5, 6}),
({2, 4}, {0, 1, 3}, {5, 6}),
({1, 2, 3, 4, 5, 6}, {0}, {}),
)
@ddt.unpack
def test_block_visibility(
self, staff_only_blocks, expected_visible_blocks, blocks_with_differing_access
):
for idx, _ in enumerate(self.parents_map):
block = self.get_block(idx)
block.visible_to_staff_only = (idx in staff_only_blocks)
update_block(block)
self.assert_transform_results(
self.student,
expected_visible_blocks,
blocks_with_differing_access,
[VisibilityTransformer()],
)
"""
Visibility Transformer implementation.
"""
from openedx.core.lib.block_cache.transformer import BlockStructureTransformer
class VisibilityTransformer(BlockStructureTransformer):
"""
A transformer that enforces the visible_to_staff_only field on
blocks by removing blocks from the block structure for which the
user does not have access. The visible_to_staff_only field on a
block is percolated down to its descendants, so that all blocks
enforce the visibility settings from their ancestors.
For a block with multiple parents, access is denied only if
visibility is denied for all its parents.
Staff users are exempted from visibility rules.
"""
VERSION = 1
MERGED_VISIBLE_TO_STAFF_ONLY = 'merged_visible_to_staff_only'
@classmethod
def name(cls):
"""
Unique identifier for the transformer's class;
same identifier used in setup.py.
"""
return "visibility"
@classmethod
def get_visible_to_staff_only(cls, block_structure, block_key):
"""
Returns whether the block with the given block_key in the
given block_structure should be visible to staff only per
computed value from ancestry chain.
"""
return block_structure.get_transformer_block_field(
block_key, cls, cls.MERGED_VISIBLE_TO_STAFF_ONLY, False
)
@classmethod
def collect(cls, block_structure):
"""
Collects any information that's necessary to execute this
transformer's transform method.
"""
for block_key in block_structure.topological_traversal():
# compute merged value of visible_to_staff_only from all parents
parents = block_structure.get_parents(block_key)
all_parents_visible_to_staff_only = all( # pylint: disable=invalid-name
cls.get_visible_to_staff_only(block_structure, parent_key)
for parent_key in parents
) if parents else False
# set the merged value for this block
block_structure.set_transformer_block_field(
block_key,
cls,
cls.MERGED_VISIBLE_TO_STAFF_ONLY,
# merge visible_to_staff_only from all parents and this block
(
all_parents_visible_to_staff_only or
block_structure.get_xblock(block_key).visible_to_staff_only
)
)
def transform(self, usage_info, block_structure):
"""
Mutates block_structure based on the given usage_info.
"""
# Users with staff access bypass the Visibility check.
if usage_info.has_staff_access:
return
block_structure.remove_block_if(
lambda block_key: self.get_visible_to_staff_only(block_structure, block_key)
)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment