Skip to content
Snippets Groups Projects
Commit f2d4e0cc authored by Michael Terry's avatar Michael Terry
Browse files

AA-408: Treat group_access as inheritable in gating transformer

ContentTypeGateTransformer was not considering parent values of
'group_access' when providing its own default value for it.

Also fix a few minor bugs around the place.
parent 857f1d0d
Branches
Tags
No related merge requests found
......@@ -58,7 +58,7 @@ def update_masters_access_course(sender, instance, **kwargs): # pylint: disable
masters_id = getattr(settings, 'COURSE_ENROLLMENT_MODES', {}).get('masters', {}).get('id', None)
verified_id = getattr(settings, 'COURSE_ENROLLMENT_MODES', {}).get('verified', {}).get('id', None)
if not (masters_id and verified_id):
log.error("Missing settings.COURSE_ENROLLMENT_MODES -> verified:%s masters:%s", verified, masters)
log.error("Missing settings.COURSE_ENROLLMENT_MODES -> verified:%s masters:%s", verified_id, masters_id)
return
course_id = instance.course_id
......
......@@ -31,6 +31,7 @@ class StackedConfigModelAdmin(ConfigurationModelAdmin):
form = StackedConfigModelAdminForm
raw_id_fields = ('course',)
search_fields = ('site__domain', 'org', 'org_course', 'course__id')
def get_fieldsets(self, request, obj=None):
return (
......@@ -65,13 +66,12 @@ class StackedConfigModelAdmin(ConfigurationModelAdmin):
def stackable_fields(self):
return list(self.model.STACKABLE_FIELDS)
@property
def config_fields(self):
fields = super(StackedConfigModelAdmin, self).get_fields(request, obj)
def get_config_fields(self, request, obj=None):
fields = super().get_fields(request, obj)
return [field for field in fields if field not in self.key_fields]
def get_fields(self, request, obj=None):
return self.key_fields + self.config_fields
return self.key_fields + self.get_config_fields(request, obj)
def get_displayable_field_names(self):
"""
......
......@@ -6,6 +6,7 @@ Limits access for certain users to certain types of content.
from django.conf import settings
from lms.djangoapps.course_blocks.transformers.user_partitions import UserPartitionTransformer
from openedx.core.djangoapps.content.block_structure.transformer import BlockStructureTransformer
from openedx.features.content_type_gating.helpers import CONTENT_GATING_PARTITION_ID
from openedx.features.content_type_gating.models import ContentTypeGatingConfig
......@@ -15,6 +16,8 @@ class ContentTypeGateTransformer(BlockStructureTransformer):
"""
A transformer that adds a partition condition for all graded content
so that the content is only visible to verified users.
This transformer requires that the UserPartitionTransformer also be included in your transformer list.
"""
WRITE_VERSION = 1
READ_VERSION = 1
......@@ -48,6 +51,24 @@ class ContentTypeGateTransformer(BlockStructureTransformer):
for parent_block_key in block_structure.get_parents(block_key):
self._set_contains_gated_content_on_parents(block_structure, parent_block_key)
@staticmethod
def _get_block_group_access(block_structure, block_key):
"""
Gets the current group_access value for a block, supporting inheritance when possible.
In order to support inheritance, UserPartitionTransformer must also be used.
"""
# See user_partitions.py for the code that sets this field.
merged_access = block_structure.get_transformer_block_field(
block_key, UserPartitionTransformer, 'merged_group_access', None
)
if merged_access:
current_access = merged_access.get_allowed_groups()
else:
# This fallback code has a bug if UserPartitionTranformer is not being used -- it does not consider
# inheritance from parent blocks. This is why our class docstring recommends UserPartitionTranformer.
current_access = block_structure.get_xblock_field(block_key, 'group_access')
return current_access or {}
def transform(self, usage_info, block_structure):
if not ContentTypeGatingConfig.enabled_for_enrollment(
user=usage_info.user,
......@@ -61,9 +82,7 @@ class ContentTypeGateTransformer(BlockStructureTransformer):
weight_not_zero = block_structure.get_xblock_field(block_key, 'weight') != 0
problem_eligible_for_content_gating = graded and has_score and weight_not_zero
if problem_eligible_for_content_gating:
current_access = block_structure.get_xblock_field(block_key, 'group_access')
if current_access is None:
current_access = {}
current_access = self._get_block_group_access(block_structure, block_key)
current_access.setdefault(
CONTENT_GATING_PARTITION_ID,
[settings.CONTENT_TYPE_GATE_GROUP_IDS['full_access']]
......
......@@ -56,7 +56,7 @@ class ContentTypeGatingFieldOverride(FieldOverrideProvider):
if parent is not None:
merged_group_access = parent.merged_group_access
if merged_group_access and CONTENT_GATING_PARTITION_ID in merged_group_access:
return original_group_access
return default
original_group_access.setdefault(
CONTENT_GATING_PARTITION_ID,
......@@ -67,5 +67,5 @@ class ContentTypeGatingFieldOverride(FieldOverrideProvider):
@classmethod
def enabled_for(cls, course):
"""This simple override provider is always enabled"""
"""Check our stackable config for this specific course"""
return ContentTypeGatingConfig.enabled_for_course(course_key=course.scope_ids.usage_id.course_key)
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