def test_entrance_exam_milestone_removal(self):
     """
     Unit Test: test removal of entrance exam milestone content
     """
     parent_locator = unicode(self.course.location)
     created_block = create_xblock(
         parent_locator=parent_locator,
         user=self.user,
         category='chapter',
         display_name=('Entrance Exam'),
         is_entrance_exam=True
     )
     add_entrance_exam_milestone(self.course.id, created_block)
     content_milestones = milestones_helpers.get_course_content_milestones(
         unicode(self.course.id),
         unicode(created_block.location),
         self.milestone_relationship_types['FULFILLS']
     )
     self.assertEqual(len(content_milestones), 1)
     user = UserFactory()
     request = RequestFactory().request()
     request.user = user
     remove_entrance_exam_milestone_reference(request, self.course.id)
     content_milestones = milestones_helpers.get_course_content_milestones(
         unicode(self.course.id),
         unicode(created_block.location),
         self.milestone_relationship_types['FULFILLS']
     )
     self.assertEqual(len(content_milestones), 0)
Пример #2
0
 def test_entrance_exam_milestone_removal(self):
     """
     Unit Test: test removal of entrance exam milestone content
     """
     parent_locator = six.text_type(self.course.location)
     created_block = create_xblock(parent_locator=parent_locator,
                                   user=self.user,
                                   category='chapter',
                                   display_name=('Entrance Exam'),
                                   is_entrance_exam=True)
     add_entrance_exam_milestone(self.course.id, created_block)
     content_milestones = milestones_helpers.get_course_content_milestones(
         six.text_type(self.course.id),
         six.text_type(created_block.location),
         self.milestone_relationship_types['FULFILLS'])
     self.assertEqual(len(content_milestones), 1)
     user = UserFactory()
     request = RequestFactory().request()
     request.user = user
     remove_entrance_exam_milestone_reference(request, self.course.id)
     content_milestones = milestones_helpers.get_course_content_milestones(
         six.text_type(self.course.id),
         six.text_type(created_block.location),
         self.milestone_relationship_types['FULFILLS'])
     self.assertEqual(len(content_milestones), 0)
Пример #3
0
    def get_content_milestones(self, request, course_key):
        """
        Returns dict of subsections with prerequisites and whether the prerequisite has been completed or not
        """
        def _get_key_of_prerequisite(namespace):
            return re.sub('.gating', '', namespace)

        all_course_milestones = get_course_content_milestones(course_key)

        uncompleted_prereqs = {
            milestone['content_id']
            for milestone in get_course_content_milestones(
                course_key, user_id=request.user.id)
        }

        gated_content = {
            milestone['content_id']: {
                'completed_prereqs': milestone['content_id']
                not in uncompleted_prereqs,
                'prerequisite':
                _get_key_of_prerequisite(milestone['namespace'])
            }
            for milestone in all_course_milestones
        }

        return gated_content
Пример #4
0
def evaluate_entrance_exam(course, block, user_id):
    """
    Update milestone fulfillments for the specified content module
    """
    # Fulfillment Use Case: Entrance Exam
    # If this module is part of an entrance exam, we'll need to see if the student
    # has reached the point at which they can collect the associated milestone
    if milestones_helpers.is_entrance_exams_enabled():
        entrance_exam_enabled = getattr(course, 'entrance_exam_enabled', False)
        in_entrance_exam = getattr(block, 'in_entrance_exam', False)
        if entrance_exam_enabled and in_entrance_exam:
            # We don't have access to the true request object in this context, but we can use a mock
            request = RequestFactory().request()
            request.user = User.objects.get(id=user_id)
            exam_pct = get_entrance_exam_score(request, course)
            if exam_pct >= course.entrance_exam_minimum_score_pct:
                exam_key = UsageKey.from_string(course.entrance_exam_id)
                relationship_types = milestones_helpers.get_milestone_relationship_types(
                )
                content_milestones = milestones_helpers.get_course_content_milestones(
                    course.id,
                    exam_key,
                    relationship=relationship_types['FULFILLS'])
                # Add each milestone to the user's set...
                user = {'id': request.user.id}
                for milestone in content_milestones:
                    milestones_helpers.add_user_milestone(user, milestone)
Пример #5
0
 def _fulfill_content_milestones(user, course_key, content_key):
     """
     Internal helper to handle milestone fulfillments for the specified content module
     """
     # Fulfillment Use Case: Entrance Exam
     # If this module is part of an entrance exam, we'll need to see if the student
     # has reached the point at which they can collect the associated milestone
     if settings.FEATURES.get('ENTRANCE_EXAMS', False):
         course = modulestore().get_course(course_key)
         content = modulestore().get_item(content_key)
         entrance_exam_enabled = getattr(course, 'entrance_exam_enabled', False)
         in_entrance_exam = getattr(content, 'in_entrance_exam', False)
         if entrance_exam_enabled and in_entrance_exam:
             # We don't have access to the true request object in this context, but we can use a mock
             request = RequestFactory().request()
             request.user = user
             exam_pct = get_entrance_exam_score(request, course)
             if exam_pct >= course.entrance_exam_minimum_score_pct:
                 exam_key = UsageKey.from_string(course.entrance_exam_id)
                 relationship_types = milestones_helpers.get_milestone_relationship_types()
                 content_milestones = milestones_helpers.get_course_content_milestones(
                     course_key,
                     exam_key,
                     relationship=relationship_types['FULFILLS']
                 )
                 # Add each milestone to the user's set...
                 user = {'id': request.user.id}
                 for milestone in content_milestones:
                     milestones_helpers.add_user_milestone(user, milestone)
Пример #6
0
def evaluate_entrance_exam(course_grade, user):
    """
    Evaluates any entrance exam milestone relationships attached
    to the given course. If the course_grade meets the
    minimum score required, the dependent milestones will be marked
    fulfilled for the user.
    """
    course = course_grade.course_data.course
    if ENTRANCE_EXAMS.is_enabled() and getattr(course, 'entrance_exam_enabled',
                                               False):
        if get_entrance_exam_content(user, course):
            exam_chapter_key = get_entrance_exam_usage_key(course)
            exam_score_ratio = get_entrance_exam_score_ratio(
                course_grade, exam_chapter_key)
            if exam_score_ratio >= course.entrance_exam_minimum_score_pct:
                relationship_types = milestones_helpers.get_milestone_relationship_types(
                )
                content_milestones = milestones_helpers.get_course_content_milestones(
                    course.id,
                    exam_chapter_key,
                    relationship=relationship_types['FULFILLS'])
                # Mark each entrance exam dependent milestone as fulfilled by the user.
                for milestone in content_milestones:
                    milestones_helpers.add_user_milestone({'id': user.id},
                                                          milestone)
Пример #7
0
def evaluate_entrance_exam(course, block, user_id):
    """
    Update milestone fulfillments for the specified content module
    """
    # Fulfillment Use Case: Entrance Exam
    # If this module is part of an entrance exam, we'll need to see if the student
    # has reached the point at which they can collect the associated milestone
    if milestones_helpers.is_entrance_exams_enabled():
        entrance_exam_enabled = getattr(course, 'entrance_exam_enabled', False)
        in_entrance_exam = getattr(block, 'in_entrance_exam', False)
        if entrance_exam_enabled and in_entrance_exam:
            # We don't have access to the true request object in this context, but we can use a mock
            request = RequestFactory().request()
            request.user = User.objects.get(id=user_id)
            exam_pct = get_entrance_exam_score(request, course)
            if exam_pct >= course.entrance_exam_minimum_score_pct:
                exam_key = UsageKey.from_string(course.entrance_exam_id)
                relationship_types = milestones_helpers.get_milestone_relationship_types()
                content_milestones = milestones_helpers.get_course_content_milestones(
                    course.id,
                    exam_key,
                    relationship=relationship_types['FULFILLS']
                )
                # Add each milestone to the user's set...
                user = {'id': request.user.id}
                for milestone in content_milestones:
                    milestones_helpers.add_user_milestone(user, milestone)
    def test_import_delete_pre_exiting_entrance_exam(self):
        """
        Check that pre existed entrance exam content should be overwrite with the imported course.
        """
        exam_url = '/course/{}/entrance_exam/'.format(unicode(self.course.id))
        resp = self.client.post(exam_url, {'entrance_exam_minimum_score_pct': 0.5}, http_accept='application/json')
        self.assertEqual(resp.status_code, 201)

        # Reload the test course now that the exam module has been added
        self.course = modulestore().get_course(self.course.id)
        metadata = CourseMetadata.fetch_all(self.course)
        self.assertTrue(metadata['entrance_exam_enabled'])
        self.assertIsNotNone(metadata['entrance_exam_minimum_score_pct'])
        self.assertEqual(metadata['entrance_exam_minimum_score_pct']['value'], 0.5)
        self.assertTrue(len(milestones_helpers.get_course_milestones(unicode(self.course.id))))
        content_milestones = milestones_helpers.get_course_content_milestones(
            unicode(self.course.id),
            metadata['entrance_exam_id']['value'],
            milestones_helpers.get_milestone_relationship_types()['FULFILLS']
        )
        self.assertTrue(len(content_milestones))

        # Now import entrance exam course
        with open(self.entrance_exam_tar) as gtar:
            args = {"name": self.entrance_exam_tar, "course-data": [gtar]}
            resp = self.client.post(self.url, args)
        self.assertEquals(resp.status_code, 200)
        course = self.store.get_course(self.course.id)
        self.assertIsNotNone(course)
        self.assertEquals(course.entrance_exam_enabled, True)
        self.assertEquals(course.entrance_exam_minimum_score_pct, 0.7)
 def test_get_course_content_milestones_returns_none_when_app_disabled(self):
     response = milestones_helpers.get_course_content_milestones(
         unicode(self.course.id),
         'i4x://doesnt/matter/for/this/test',
         'requires'
     )
     self.assertEqual(len(response), 0)
Пример #10
0
 def test_get_course_content_milestones_returns_none_when_app_disabled(self):
     response = milestones_helpers.get_course_content_milestones(
         unicode(self.course.id),
         'i4x://doesnt/matter/for/this/test',
         'requires'
     )
     self.assertEqual(len(response), 0)
Пример #11
0
    def test_import_delete_pre_exiting_entrance_exam(self):
        """
        Check that pre existed entrance exam content should be overwrite with the imported course.
        """
        exam_url = '/course/{}/entrance_exam/'.format(unicode(self.course.id))
        resp = self.client.post(exam_url,
                                {'entrance_exam_minimum_score_pct': 0.5},
                                http_accept='application/json')
        self.assertEqual(resp.status_code, 201)

        # Reload the test course now that the exam module has been added
        self.course = modulestore().get_course(self.course.id)
        metadata = CourseMetadata.fetch_all(self.course)
        self.assertTrue(metadata['entrance_exam_enabled'])
        self.assertIsNotNone(metadata['entrance_exam_minimum_score_pct'])
        self.assertEqual(metadata['entrance_exam_minimum_score_pct']['value'],
                         0.5)
        self.assertTrue(
            len(
                milestones_helpers.get_course_milestones(
                    unicode(self.course.id))))
        content_milestones = milestones_helpers.get_course_content_milestones(
            unicode(self.course.id), metadata['entrance_exam_id']['value'],
            milestones_helpers.get_milestone_relationship_types()['FULFILLS'])
        self.assertTrue(len(content_milestones))

        # Now import entrance exam course
        with open(self.entrance_exam_tar) as gtar:
            args = {"name": self.entrance_exam_tar, "course-data": [gtar]}
            resp = self.client.post(self.url, args)
        self.assertEquals(resp.status_code, 200)
        course = self.store.get_course(self.course.id)
        self.assertIsNotNone(course)
        self.assertEquals(course.entrance_exam_enabled, True)
        self.assertEquals(course.entrance_exam_minimum_score_pct, 0.7)
Пример #12
0
    def test_contentstore_views_entrance_exam_post(self):
        """
        Unit Test: test_contentstore_views_entrance_exam_post
        """
        resp = self.client.post(self.exam_url, {},
                                http_accept='application/json')
        self.assertEqual(resp.status_code, 201)
        resp = self.client.get(self.exam_url)
        self.assertEqual(resp.status_code, 200)

        # Reload the test course now that the exam module has been added
        self.course = modulestore().get_course(self.course.id)
        metadata = CourseMetadata.fetch_all(self.course)
        self.assertTrue(metadata['entrance_exam_enabled'])
        self.assertIsNotNone(metadata['entrance_exam_minimum_score_pct'])
        self.assertIsNotNone(metadata['entrance_exam_id']['value'])
        self.assertTrue(
            len(
                milestones_helpers.get_course_milestones(
                    six.text_type(self.course.id))))
        content_milestones = milestones_helpers.get_course_content_milestones(
            six.text_type(self.course.id),
            metadata['entrance_exam_id']['value'],
            self.milestone_relationship_types['FULFILLS'])
        self.assertTrue(len(content_milestones))
Пример #13
0
 def has_pending_milestones_for_user(block_key, usage_info):
     """
     Test whether the current user has any unfulfilled milestones preventing
     them from accessing this block.
     """
     return bool(
         milestones_helpers.get_course_content_milestones(
             unicode(block_key.course_key), unicode(block_key), 'requires',
             usage_info.user.id))
Пример #14
0
    def get_content_milestones_old(self, request, course_key):
        """
        Returns dict of subsections with prerequisites and whether the prerequisite has been completed or not
        """

        all_course_prereqs = get_course_content_milestones(course_key)

        content_ids_of_unfulfilled_prereqs = {
            milestone['content_id']
            for milestone in get_course_content_milestones(course_key, user_id=request.user.id)
        }

        course_content_milestones = {
            milestone['content_id']: {
                'completed_prereqs': milestone['content_id'] not in content_ids_of_unfulfilled_prereqs
            }
            for milestone in all_course_prereqs
        }

        return course_content_milestones
Пример #15
0
 def has_pending_milestones_for_user(block_key, usage_info):
     """
     Test whether the current user has any unfulfilled milestones preventing
     them from accessing this block.
     """
     return bool(milestones_helpers.get_course_content_milestones(
         unicode(block_key.course_key),
         unicode(block_key),
         'requires',
         usage_info.user.id
     ))
Пример #16
0
def compute_is_prereq_met(content_id, user_id, recalc_on_unmet=False):
    """
    Returns true if the prequiste has been met for a given milestone.
    Will recalculate the subsection grade if specified and prereq unmet

    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

    Returns:
        tuple: True|False,
        prereq_meta_info = { 'url': prereq_url|None, 'display_name': prereq_name|None}
    """
    course_key = content_id.course_key

    # if unfullfilled milestones exist it means prereq has not been met
    unfulfilled_milestones = milestones_helpers.get_course_content_milestones(
        course_key,
        content_id,
        'requires',
        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, prereq_meta_info

    milestone = unfulfilled_milestones[0]
    student = User.objects.get(id=user_id)
    store = modulestore()

    with store.bulk_operations(course_key):
        subsection_usage_key = UsageKey.from_string(_get_gating_block_id(milestone))
        subsection = store.get_item(subsection_usage_key)
        prereq_meta_info = {
            'url': reverse('jump_to', kwargs={'course_id': course_key, 'location': subsection_usage_key}),
            'display_name': subsection.display_name
        }

        try:
            subsection_structure = get_course_blocks(student, subsection_usage_key)
            if any(subsection_structure):
                subsection_grade_factory = SubsectionGradeFactory(student, course_structure=subsection_structure)
                if subsection_usage_key in subsection_structure:
                    # this will force a recalcuation of the subsection grade
                    subsection_grade = subsection_grade_factory.update(subsection_structure[subsection_usage_key], persist_grade=False)
                    prereq_met = update_milestone(milestone, subsection_grade, milestone, user_id)
        except ItemNotFoundError as err:
            log.warning("Could not find course_block for subsection=%s error=%s", subsection_usage_key, err)

    return prereq_met, prereq_meta_info
Пример #17
0
    def get_content_milestones_old(self, request, course_key):
        """
        Returns dict of subsections with prerequisites and whether the prerequisite has been completed or not
        """

        all_course_prereqs = get_course_content_milestones(course_key)

        content_ids_of_unfulfilled_prereqs = {
            milestone['content_id']
            for milestone in get_course_content_milestones(course_key, user_id=request.user.id)
        }

        course_content_milestones = {
            milestone['content_id']: {
                'completed_prereqs': milestone['content_id'] not in content_ids_of_unfulfilled_prereqs
            }
            for milestone in all_course_prereqs
        }

        return course_content_milestones
Пример #18
0
    def get_content_milestones(self, request, course_key):
        """
        Returns dict of subsections with prerequisites and whether the prerequisite has been completed or not
        """
        def _get_key_of_prerequisite(namespace):
            return re.sub('.gating', '', namespace)

        all_course_milestones = get_course_content_milestones(course_key)

        uncompleted_prereqs = {
            milestone['content_id']
            for milestone in get_course_content_milestones(course_key, user_id=request.user.id)
        }

        gated_content = {
            milestone['content_id']: {
                'completed_prereqs': milestone['content_id'] not in uncompleted_prereqs,
                'prerequisite': _get_key_of_prerequisite(milestone['namespace'])
            }
            for milestone in all_course_milestones
        }

        return gated_content
Пример #19
0
Файл: api.py Проект: saadow123/1
def compute_is_prereq_met(content_id, user_id, recalc_on_unmet=False):
    """
    Returns true if the prequiste has been met for a given milestone.
    Will recalculate the subsection grade if specified and prereq unmet

    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

    Returns:
        tuple: True|False,
        prereq_meta_info = { 'url': prereq_url|None, 'display_name': prereq_name|None}
    """
    course_key = content_id.course_key

    # if unfullfilled milestones exist it means prereq has not been met
    unfulfilled_milestones = milestones_helpers.get_course_content_milestones(
        course_key, content_id, 'requires', 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, prereq_meta_info

    milestone = unfulfilled_milestones[0]
    student = User.objects.get(id=user_id)
    store = modulestore()

    with store.bulk_operations(course_key):
        subsection_usage_key = UsageKey.from_string(
            _get_gating_block_id(milestone))
        subsection = store.get_item(subsection_usage_key)
        prereq_meta_info = {
            'url':
            reverse('jump_to',
                    kwargs={
                        'course_id': course_key,
                        'location': subsection_usage_key
                    }),
            'display_name':
            subsection.display_name,
            'id':
            str(subsection_usage_key)
        }
        prereq_met = update_milestone(milestone, subsection_usage_key,
                                      milestone, student)

    return prereq_met, prereq_meta_info
Пример #20
0
def _can_access_descriptor_with_milestones(user, descriptor, course_key):
    """
    Returns if the object is blocked by an unfulfilled milestone.

    Args:
        user: the user trying to access this content
        descriptor: the object being accessed
        course_key: key for the course for this descriptor
    """
    if milestones_helpers.get_course_content_milestones(course_key, unicode(descriptor.location), 'requires', user.id):
        debug("Deny: user has not completed all milestones for content")
        return ACCESS_DENIED
    else:
        return ACCESS_GRANTED
Пример #21
0
 def test_entrance_exam_milestone_addition(self):
     """
     Unit Test: test addition of entrance exam milestone content
     """
     parent_locator = unicode(self.course.location)
     created_block = create_xblock(parent_locator=parent_locator,
                                   user=self.user,
                                   category='chapter',
                                   display_name=('Entrance Exam'),
                                   is_entrance_exam=True)
     add_entrance_exam_milestone(self.course.id, created_block)
     content_milestones = milestones_helpers.get_course_content_milestones(
         unicode(self.course.id), unicode(created_block.location),
         self.milestone_relationship_types['FULFILLS'])
     self.assertTrue(len(content_milestones))
     self.assertEqual(
         len(milestones_helpers.get_course_milestones(self.course.id)), 1)
Пример #22
0
def compute_is_prereq_met(content_id, user_id, recalc_on_unmet=False):
    """
    Returns true if the prequiste has been met for a given milestone.
    Will recalculate the subsection grade if specified and prereq unmet

    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

    Returns:
        tuple: True|False,
        prereq_meta_info = { 'url': prereq_url|None, 'display_name': prereq_name|None}
    """
    course_key = content_id.course_key

    # if unfullfilled milestones exist it means prereq has not been met
    unfulfilled_milestones = milestones_helpers.get_course_content_milestones(
        course_key,
        content_id,
        'requires',
        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, prereq_meta_info

    milestone = unfulfilled_milestones[0]
    student = User.objects.get(id=user_id)
    store = modulestore()

    with store.bulk_operations(course_key):
        subsection_usage_key = UsageKey.from_string(_get_gating_block_id(milestone))
        subsection = store.get_item(subsection_usage_key)
        prereq_meta_info = {
            'url': reverse('jump_to', kwargs={'course_id': course_key, 'location': subsection_usage_key}),
            'display_name': subsection.display_name
        }
        prereq_met = update_milestone(milestone, subsection_usage_key, milestone, student)

    return prereq_met, prereq_meta_info
Пример #23
0
 def test_entrance_exam_milestone_addition(self):
     """
     Unit Test: test addition of entrance exam milestone content
     """
     parent_locator = unicode(self.course.location)
     created_block = create_xblock(
         parent_locator=parent_locator,
         user=self.user,
         category='chapter',
         display_name=('Entrance Exam'),
         is_entrance_exam=True
     )
     add_entrance_exam_milestone(self.course.id, created_block)
     content_milestones = milestones_helpers.get_course_content_milestones(
         unicode(self.course.id),
         unicode(created_block.location),
         self.milestone_relationship_types['FULFILLS']
     )
     self.assertTrue(len(content_milestones))
     self.assertEqual(len(milestones_helpers.get_course_milestones(self.course.id)), 1)
Пример #24
0
def evaluate_entrance_exam(course_grade, user):
    """
    Evaluates any entrance exam milestone relationships attached
    to the given course. If the course_grade meets the
    minimum score required, the dependent milestones will be marked
    fulfilled for the user.
    """
    course = course_grade.course_data.course
    if milestones_helpers.is_entrance_exams_enabled() and getattr(course, 'entrance_exam_enabled', False):
        if get_entrance_exam_content(user, course):
            exam_chapter_key = get_entrance_exam_usage_key(course)
            exam_score_ratio = get_entrance_exam_score_ratio(course_grade, exam_chapter_key)
            if exam_score_ratio >= course.entrance_exam_minimum_score_pct:
                relationship_types = milestones_helpers.get_milestone_relationship_types()
                content_milestones = milestones_helpers.get_course_content_milestones(
                    course.id,
                    exam_chapter_key,
                    relationship=relationship_types['FULFILLS']
                )
                # Mark each entrance exam dependent milestone as fulfilled by the user.
                for milestone in content_milestones:
                    milestones_helpers.add_user_milestone({'id': user.id}, milestone)
Пример #25
0
    def test_contentstore_views_entrance_exam_post(self):
        """
        Unit Test: test_contentstore_views_entrance_exam_post
        """
        resp = self.client.post(self.exam_url, {}, http_accept='application/json')
        self.assertEqual(resp.status_code, 201)
        resp = self.client.get(self.exam_url)
        self.assertEqual(resp.status_code, 200)

        # Reload the test course now that the exam module has been added
        self.course = modulestore().get_course(self.course.id)
        metadata = CourseMetadata.fetch_all(self.course)
        self.assertTrue(metadata['entrance_exam_enabled'])
        self.assertIsNotNone(metadata['entrance_exam_minimum_score_pct'])
        self.assertIsNotNone(metadata['entrance_exam_id']['value'])
        self.assertTrue(len(milestones_helpers.get_course_milestones(unicode(self.course.id))))
        content_milestones = milestones_helpers.get_course_content_milestones(
            unicode(self.course.id),
            metadata['entrance_exam_id']['value'],
            self.milestone_relationship_types['FULFILLS']
        )
        self.assertTrue(len(content_milestones))
def compute_is_prereq_met(content_id, user_id, recalc_on_unmet=False):
    """
    Returns true if the prequiste has been met for a given milestone.
    Will recalculate the subsection grade if specified and prereq unmet

    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

    Returns:
        tuple: True|False,
        prereq_meta_info = { 'url': prereq_url|None, 'display_name': prereq_name|None}
    """
    course_key = content_id.course_key

    # if unfullfilled milestones exist it means prereq has not been met
    unfulfilled_milestones = milestones_helpers.get_course_content_milestones(
        course_key, content_id, 'requires', 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, prereq_meta_info

    milestone = unfulfilled_milestones[0]
    student = User.objects.get(id=user_id)
    store = modulestore()

    with store.bulk_operations(course_key):
        subsection_usage_key = UsageKey.from_string(
            _get_gating_block_id(milestone))
        subsection = store.get_item(subsection_usage_key)
        prereq_meta_info = {
            'url':
            reverse('jump_to',
                    kwargs={
                        'course_id': course_key,
                        'location': subsection_usage_key
                    }),
            'display_name':
            subsection.display_name
        }

        try:
            subsection_structure = get_course_blocks(student,
                                                     subsection_usage_key)
            if any(subsection_structure):
                subsection_grade_factory = SubsectionGradeFactory(
                    student, course_structure=subsection_structure)
                if subsection_usage_key in subsection_structure:
                    # this will force a recalcuation of the subsection grade
                    subsection_grade = subsection_grade_factory.update(
                        subsection_structure[subsection_usage_key],
                        persist_grade=False)
                    prereq_met = update_milestone(milestone, subsection_grade,
                                                  milestone, user_id)
        except ItemNotFoundError as err:
            log.warning(
                "Could not find course_block for subsection=%s error=%s",
                subsection_usage_key, err)

    return prereq_met, prereq_meta_info
Пример #27
0
 def has_pending_milestones(self, usage_key):
     return bool(
         milestones_helpers.get_course_content_milestones(
             str(self.course_key), str(usage_key), 'requires',
             self.user.id))