api.py 3.26 KB
Newer Older
1 2 3 4 5 6 7 8
"""
API for the gating djangoapp
"""
import logging
import json

from collections import defaultdict
from django.contrib.auth.models import User
9
from xmodule.modulestore.django import modulestore
10
from openedx.core.lib.gating import api as gating_api
11
from lms.djangoapps.grades.module_grades import get_module_score
12
from util import milestones_helpers
13 14 15 16

log = logging.getLogger(__name__)


17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
def _get_xblock_parent(xblock, category=None):
    """
    Returns the parent of the given XBlock. If an optional category is supplied,
    traverses the ancestors of the XBlock and returns the first with the
    given category.

    Arguments:
        xblock (XBlock): Get the parent of this XBlock
        category (str): Find an ancestor with this category (e.g. sequential)
    """
    parent = xblock.get_parent()
    if parent and category:
        if parent.category == category:
            return parent
        else:
            return _get_xblock_parent(parent, category)
    return parent


36
@gating_api.gating_enabled(default=False)
37
def evaluate_prerequisite(course, prereq_content_key, user_id):
38 39 40 41 42 43 44
    """
    Finds the parent subsection of the content in the course and evaluates
    any milestone relationships attached to that subsection. If the calculated
    grade of the prerequisite subsection meets the minimum score required by
    dependent subsections, the related milestone will be fulfilled for the user.

    Arguments:
45
        user_id (int): ID of User for which evaluation should occur
46
        course (CourseModule): The course
47
        prereq_content_key (UsageKey): The prerequisite content usage key
48 49 50 51

    Returns:
        None
    """
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
    xblock = modulestore().get_item(prereq_content_key)
    sequential = _get_xblock_parent(xblock, 'sequential')
    if sequential:
        prereq_milestone = gating_api.get_gating_milestone(
            course.id,
            sequential.location.for_branch(None),
            'fulfills'
        )
        if prereq_milestone:
            gated_content_milestones = defaultdict(list)
            for milestone in gating_api.find_gating_milestones(course.id, None, 'requires'):
                gated_content_milestones[milestone['id']].append(milestone)

            gated_content = gated_content_milestones.get(prereq_milestone['id'])
            if gated_content:
                user = User.objects.get(id=user_id)
                score = get_module_score(user, course, sequential) * 100
                for milestone in gated_content:
                    # Default minimum score to 100
                    min_score = 100
                    requirements = milestone.get('requirements')
                    if requirements:
                        try:
                            min_score = int(requirements.get('min_score'))
                        except (ValueError, TypeError):
                            log.warning(
                                'Failed to find minimum score for gating milestone %s, defaulting to 100',
                                json.dumps(milestone)
                            )

                    if score >= min_score:
                        milestones_helpers.add_user_milestone({'id': user_id}, prereq_milestone)
                    else:
                        milestones_helpers.remove_user_milestone({'id': user_id}, prereq_milestone)