68 lines
2.7 KiB
Python
68 lines
2.7 KiB
Python
"""
|
|
This file contains celery tasks related to course content gating.
|
|
"""
|
|
|
|
|
|
import logging
|
|
|
|
from celery import shared_task
|
|
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
|
|
from edx_django_utils.monitoring import set_code_owner_attribute
|
|
from opaque_keys.edx.keys import CourseKey, UsageKey
|
|
|
|
from lms.djangoapps.course_blocks.api import get_course_blocks
|
|
from lms.djangoapps.gating import api as gating_api
|
|
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
@shared_task
|
|
@set_code_owner_attribute
|
|
def task_evaluate_subsection_completion_milestones(course_id, block_id, user_id):
|
|
"""
|
|
Updates users' milestones related to completion of a subsection.
|
|
Args:
|
|
course_id(str): Course id which triggered a completion event
|
|
block_id(str): Id of the completed block
|
|
user_id(int): Id of the user who completed a block
|
|
"""
|
|
store = modulestore()
|
|
course_key = CourseKey.from_string(course_id)
|
|
with store.bulk_operations(course_key):
|
|
course = store.get_course(course_key)
|
|
if not course or not course.enable_subsection_gating:
|
|
log.debug(
|
|
"Gating: ignoring evaluation of completion milestone because it disabled for course [%s]", course_id
|
|
)
|
|
else:
|
|
try:
|
|
user = User.objects.get(id=user_id)
|
|
course_structure = get_course_blocks(user, store.make_course_usage_key(course_key))
|
|
completed_block_usage_key = UsageKey.from_string(block_id).map_into_course(course.id)
|
|
subsection_block = _get_subsection_of_block(completed_block_usage_key, course_structure)
|
|
subsection = course_structure[subsection_block]
|
|
log.debug(
|
|
"Gating: Evaluating completion milestone for subsection [%s] and user [%s]",
|
|
str(subsection.location), user.id
|
|
)
|
|
gating_api.evaluate_prerequisite(course, subsection, user)
|
|
except KeyError:
|
|
log.error("Gating: Given prerequisite subsection [%s] not found in course structure", block_id)
|
|
|
|
|
|
def _get_subsection_of_block(usage_key, block_structure):
|
|
"""
|
|
Finds subsection of a block by recursively iterating over its parents
|
|
:param usage_key: key of the block
|
|
:param block_structure: block structure
|
|
:return: sequential block
|
|
"""
|
|
parents = block_structure.get_parents(usage_key)
|
|
if parents:
|
|
for parent_block in parents:
|
|
if parent_block.block_type == 'sequential':
|
|
return parent_block
|
|
else:
|
|
return _get_subsection_of_block(parent_block, block_structure)
|