Skip to content
Snippets Groups Projects
Unverified Commit b2ba363f authored by Michael Terry's avatar Michael Terry Committed by GitHub
Browse files

Merge pull request #25503 from edx/mikix/parent-access

AA-408: Treat group_access as inheritable in gating transformer
parents fe9395bd f2d4e0cc
No related branches found
No related tags found
No related merge requests found
...@@ -58,7 +58,7 @@ def update_masters_access_course(sender, instance, **kwargs): # pylint: disable ...@@ -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) masters_id = getattr(settings, 'COURSE_ENROLLMENT_MODES', {}).get('masters', {}).get('id', None)
verified_id = getattr(settings, 'COURSE_ENROLLMENT_MODES', {}).get('verified', {}).get('id', None) verified_id = getattr(settings, 'COURSE_ENROLLMENT_MODES', {}).get('verified', {}).get('id', None)
if not (masters_id and verified_id): 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 return
course_id = instance.course_id course_id = instance.course_id
......
...@@ -31,6 +31,7 @@ class StackedConfigModelAdmin(ConfigurationModelAdmin): ...@@ -31,6 +31,7 @@ class StackedConfigModelAdmin(ConfigurationModelAdmin):
form = StackedConfigModelAdminForm form = StackedConfigModelAdminForm
raw_id_fields = ('course',) raw_id_fields = ('course',)
search_fields = ('site__domain', 'org', 'org_course', 'course__id')
def get_fieldsets(self, request, obj=None): def get_fieldsets(self, request, obj=None):
return ( return (
...@@ -65,13 +66,12 @@ class StackedConfigModelAdmin(ConfigurationModelAdmin): ...@@ -65,13 +66,12 @@ class StackedConfigModelAdmin(ConfigurationModelAdmin):
def stackable_fields(self): def stackable_fields(self):
return list(self.model.STACKABLE_FIELDS) return list(self.model.STACKABLE_FIELDS)
@property def get_config_fields(self, request, obj=None):
def config_fields(self): fields = super().get_fields(request, obj)
fields = super(StackedConfigModelAdmin, self).get_fields(request, obj)
return [field for field in fields if field not in self.key_fields] return [field for field in fields if field not in self.key_fields]
def get_fields(self, request, obj=None): 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): def get_displayable_field_names(self):
""" """
......
...@@ -6,6 +6,7 @@ Limits access for certain users to certain types of content. ...@@ -6,6 +6,7 @@ Limits access for certain users to certain types of content.
from django.conf import settings 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.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.helpers import CONTENT_GATING_PARTITION_ID
from openedx.features.content_type_gating.models import ContentTypeGatingConfig from openedx.features.content_type_gating.models import ContentTypeGatingConfig
...@@ -15,6 +16,8 @@ class ContentTypeGateTransformer(BlockStructureTransformer): ...@@ -15,6 +16,8 @@ class ContentTypeGateTransformer(BlockStructureTransformer):
""" """
A transformer that adds a partition condition for all graded content A transformer that adds a partition condition for all graded content
so that the content is only visible to verified users. 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 WRITE_VERSION = 1
READ_VERSION = 1 READ_VERSION = 1
...@@ -48,6 +51,24 @@ class ContentTypeGateTransformer(BlockStructureTransformer): ...@@ -48,6 +51,24 @@ class ContentTypeGateTransformer(BlockStructureTransformer):
for parent_block_key in block_structure.get_parents(block_key): for parent_block_key in block_structure.get_parents(block_key):
self._set_contains_gated_content_on_parents(block_structure, parent_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): def transform(self, usage_info, block_structure):
if not ContentTypeGatingConfig.enabled_for_enrollment( if not ContentTypeGatingConfig.enabled_for_enrollment(
user=usage_info.user, user=usage_info.user,
...@@ -61,9 +82,7 @@ class ContentTypeGateTransformer(BlockStructureTransformer): ...@@ -61,9 +82,7 @@ class ContentTypeGateTransformer(BlockStructureTransformer):
weight_not_zero = block_structure.get_xblock_field(block_key, 'weight') != 0 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 problem_eligible_for_content_gating = graded and has_score and weight_not_zero
if problem_eligible_for_content_gating: if problem_eligible_for_content_gating:
current_access = block_structure.get_xblock_field(block_key, 'group_access') current_access = self._get_block_group_access(block_structure, block_key)
if current_access is None:
current_access = {}
current_access.setdefault( current_access.setdefault(
CONTENT_GATING_PARTITION_ID, CONTENT_GATING_PARTITION_ID,
[settings.CONTENT_TYPE_GATE_GROUP_IDS['full_access']] [settings.CONTENT_TYPE_GATE_GROUP_IDS['full_access']]
......
...@@ -56,7 +56,7 @@ class ContentTypeGatingFieldOverride(FieldOverrideProvider): ...@@ -56,7 +56,7 @@ class ContentTypeGatingFieldOverride(FieldOverrideProvider):
if parent is not None: if parent is not None:
merged_group_access = parent.merged_group_access merged_group_access = parent.merged_group_access
if merged_group_access and CONTENT_GATING_PARTITION_ID in 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( original_group_access.setdefault(
CONTENT_GATING_PARTITION_ID, CONTENT_GATING_PARTITION_ID,
...@@ -67,5 +67,5 @@ class ContentTypeGatingFieldOverride(FieldOverrideProvider): ...@@ -67,5 +67,5 @@ class ContentTypeGatingFieldOverride(FieldOverrideProvider):
@classmethod @classmethod
def enabled_for(cls, course): 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) return ContentTypeGatingConfig.enabled_for_course(course_key=course.scope_ids.usage_id.course_key)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment