Commit 61a38ec8 by Bill Filler

fix comments from review

parent 1cac8216
......@@ -292,7 +292,7 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule):
self._update_position(context, len(display_items))
prereq_met = True
if self._find_gating_milestone():
if self._is_prereq_required():
if self.runtime.user_is_staff:
banner_text = _('This subsection is unlocked for learners when they meet the prerequisite requirements.')
else:
......@@ -323,13 +323,16 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule):
return fragment
def _find_gating_milestone(self):
def _is_prereq_required(self):
"""
Checks whether a gating milestone exists for this Section
Checks whether a prerequiste is required for this Section
Returns:
milestone if a prereq is required, False otherwise
"""
gating_service = self.runtime.service(self, 'gating')
if gating_service:
milestone = gating_service.get_gating_milestone(
milestone = gating_service.is_prereq_required(
self.course_id, self.location, 'requires'
)
return milestone
......
......@@ -148,7 +148,7 @@ def get_prerequisites(course_key):
milestones_by_block_id = {}
block_ids = []
for milestone in course_content_milestones:
prereq_content_key = milestone['namespace'].replace(GATING_NAMESPACE_QUALIFIER, '')
prereq_content_key = _get_gating_block_id(milestone)
block_id = UsageKey.from_string(prereq_content_key).block_id
block_ids.append(block_id)
milestones_by_block_id[block_id] = milestone
......@@ -273,7 +273,7 @@ def get_required_content(course_key, gated_content_key):
milestone = get_gating_milestone(course_key, gated_content_key, 'requires')
if milestone:
return (
milestone.get('namespace', '').replace(GATING_NAMESPACE_QUALIFIER, ''),
_get_gating_block_id(milestone),
milestone.get('requirements', {}).get('min_score')
)
else:
......@@ -317,7 +317,7 @@ def is_prereq_met(content_id, user_id, recalc_on_unmet=False):
Returns:
tuple: True|False,
prereq_meta_info = { 'url': prereq_url, 'display_name': prereq_name}
prereq_meta_info = { 'url': prereq_url|None, 'display_name': prereq_name|None}
"""
course_id = content_id.course_key
......@@ -329,9 +329,10 @@ def is_prereq_met(content_id, user_id, recalc_on_unmet=False):
user_id
)
prereq_met = not unfulfilled_milestones
prereq_meta_info = {'url': None, 'display_name': None}
if prereq_met or not recalc_on_unmet:
return prereq_met, {}
return prereq_met, prereq_meta_info
milestone = unfulfilled_milestones[0]
student = User.objects.get(id=user_id)
......@@ -341,7 +342,7 @@ def is_prereq_met(content_id, user_id, recalc_on_unmet=False):
course_structure = get_course_blocks(student, store.make_course_usage_key(course_id))
course = store.get_course(course_id, depth=0)
subsection_grade_factory = SubsectionGradeFactory(student, course, course_structure)
subsection_usage_key = UsageKey.from_string(milestone['namespace'].replace(GATING_NAMESPACE_QUALIFIER, ''))
subsection_usage_key = UsageKey.from_string(_get_gating_block_id(milestone))
if subsection_usage_key in course_structure:
# this will force a recalcuation of the subsection grade
......@@ -376,6 +377,12 @@ def update_milestone(milestone, subsection_grade, prereq_milestone, user_id):
milestones_helpers.remove_user_milestone({'id': user_id}, prereq_milestone)
return False
def _get_gating_block_id(milestone):
"""
Return the block id of the gating milestone
"""
return milestone.get('namespace', '').replace(GATING_NAMESPACE_QUALIFIER, '')
def _get_minimum_required_percentage(milestone):
"""
Returns the minimum percentage requirement for the given milestone.
......
"""
A wrapper class around requested methods exposed in api.py
A wrapper class to communicate with Gating api
"""
import types
from . import api as gating_api
class GatingService(object): # pylint: disable=too-few-public-methods
class GatingService(object):
"""
An xBlock service for xBlocks to talk to the Gating api.
NOTE: This is a Singleton class. We should only have one instance of it!
An XBlock service to talk to the Gating api.
"""
_instance = None
def is_prereq_met(self, content_id, user_id, recalc_on_unmet=False):
"""
Returns true if the prequiste has been met for a given milestone
REQUESTED_FUNCTIONS = [
'get_gating_milestone_meta_info',
'get_gating_milestone',
'is_prereq_met'
]
Arguments:
content_id (BlockUsageLocator): BlockUsageLocator for the content
user_id: The id of the user
recalc_on_unmet: Recalculate the grade if prereq has not yet been met
def __new__(cls, *args, **kwargs):
"""
This is the class factory to make sure this is a Singleton
"""
if not cls._instance:
cls._instance = super(GatingService, cls).__new__(cls, *args, **kwargs)
return cls._instance
Returns:
tuple: True|False,
prereq_meta_info = { 'url': prereq_url|None, 'display_name': prereq_name|None}
"""
return gating_api.is_prereq_met(content_id, user_id, recalc_on_unmet)
def __init__(self):
"""
Class initializer, which just inspects the libraries and exposes the same functions
listed in REQUESTED_FUNCTIONS
def is_prereq_required(self, course_key, content_key, relationship):
"""
self._bind_to_requested_functions()
Returns the prerequiste if one is required
def _bind_to_requested_functions(self):
"""
bind module functions. Since we use underscores to mean private methods, let's exclude those.
Arguments:
course_key (str|CourseKey): The course key
content_key (str|UsageKey): The content usage key
relationship (str): The relationship type (e.g. 'requires')
Returns:
dict or None: The gating milestone dict or None
"""
for attr_name in self.REQUESTED_FUNCTIONS:
attr = getattr(gating_api, attr_name, None)
if isinstance(attr, types.FunctionType) and not attr_name.startswith('_'):
if not hasattr(self, attr_name):
setattr(self, attr_name, attr)
return gating_api.get_gating_milestone(course_key, content_key, relationship)
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