Files
edx-platform/lms/djangoapps/course_blocks/transformers/start_date.py
usamasadiq 3d1f3cea64 Ran pyupgrade on lms/djangoapps/course_blocks
Ran pyupgrade on lms/djangoapps/course_goals
Ran pyugprade on lms/djangoapps/course_home_api
2021-02-19 16:29:52 +05:00

111 lines
3.9 KiB
Python

"""
Start Date Transformer implementation.
"""
from datetime import datetime
from pytz import UTC
from lms.djangoapps.courseware.access_utils import check_start_date
from openedx.core.djangoapps.content.block_structure.transformer import (
BlockStructureTransformer,
FilteringTransformerMixin
)
from xmodule.course_metadata_utils import DEFAULT_START_DATE
from .utils import collect_merged_date_field
class StartDateTransformer(FilteringTransformerMixin, BlockStructureTransformer):
"""
A transformer that enforces the 'start' and 'days_early_for_beta'
fields on blocks by removing blocks from the block structure for
which the user does not have access. The 'start' field on a
block is percolated down to its descendants, so that all blocks
enforce the 'start' field from their ancestors. The assumed
'start' value for a block is then the maximum of its parent and its
own.
For a block with multiple parents, the assumed parent start date
value is a computed minimum of the start dates of all its parents.
So as long as one parent chain allows access, the block has access.
Staff users are exempted from visibility rules.
"""
WRITE_VERSION = 1
READ_VERSION = 1
MERGED_START_DATE = 'merged_start_date'
@classmethod
def name(cls):
"""
Unique identifier for the transformer's class;
same identifier used in setup.py.
"""
return "start_date"
@classmethod
def _check_has_scheduled_content(cls, block_structure, scheduled_content_condition):
'''
Returns a block structure where the root course block has been
updated to include a has_scheduled_content field (True if the course
has any blocks with release dates in the future, False otherwise).
'''
has_scheduled_content = False
for block_key in block_structure.topological_traversal():
if scheduled_content_condition(block_key):
has_scheduled_content = True
break
block_structure.override_xblock_field(
block_structure.root_block_usage_key, 'has_scheduled_content', has_scheduled_content
)
@classmethod
def _get_merged_start_date(cls, block_structure, block_key):
"""
Returns the merged value for the start date for the block with
the given block_key in the given block_structure.
"""
return block_structure.get_transformer_block_field(
block_key, cls, cls.MERGED_START_DATE, False
)
@classmethod
def collect(cls, block_structure):
"""
Collects any information that's necessary to execute this
transformer's transform method.
"""
block_structure.request_xblock_fields('days_early_for_beta')
collect_merged_date_field(
block_structure,
transformer=cls,
xblock_field_name='start',
merged_field_name=cls.MERGED_START_DATE,
default_date=DEFAULT_START_DATE,
func_merge_parents=min,
func_merge_ancestors=max,
)
def transform_block_filters(self, usage_info, block_structure):
# Users with staff access bypass the Start Date check.
if usage_info.has_staff_access or usage_info.allow_start_dates_in_future:
return [block_structure.create_universal_filter()]
now = datetime.now(UTC)
removal_condition = lambda block_key: not check_start_date(
usage_info.user,
block_structure.get_xblock_field(block_key, 'days_early_for_beta'),
self._get_merged_start_date(block_structure, block_key),
usage_info.course_key,
now=now,
)
if usage_info.include_has_scheduled_content:
self._check_has_scheduled_content(block_structure, removal_condition)
return [block_structure.create_removal_filter(removal_condition)]