예제 #1
0
    def get_assignments_with_due_date(self, request, course_key):
        """
        Returns a list of assignment (graded) blocks with due dates, including
        due date and location.

        Args:
            request (HttpRequest)
            course_key (CourseKey)
        """
        course_usage_key = modulestore().make_course_usage_key(course_key)
        all_blocks = get_blocks(
            request,
            course_usage_key,
            user=request.user,
            nav_depth=3,
            requested_fields=['display_name', 'due', 'graded', 'format'],
            block_types_filter=['sequential'])
        assignment_blocks = []
        for (location, block) in all_blocks['blocks'].iteritems():
            if block.get('graded', False):
                assignment_blocks.append(block)
                block['due'] = block['due'].isoformat() if block.get(
                    'due') is not None else None
                block['location'] = unicode(location)

        return assignment_blocks
예제 #2
0
    def get_assignments_with_due_date(self, request, course_key):
        """
        Returns a list of assignment (graded) blocks with due dates, including
        due date and location.

        Args:
            request (HttpRequest)
            course_key (CourseKey)
        """
        course_usage_key = modulestore().make_course_usage_key(course_key)
        all_blocks = get_blocks(
            request,
            course_usage_key,
            user=request.user,
            nav_depth=3,
            requested_fields=['display_name', 'due', 'graded', 'format'],
            block_types_filter=['sequential']
        )
        assignment_blocks = []
        for (location, block) in all_blocks['blocks'].iteritems():
            if block.get('graded', False):
                assignment_blocks.append(block)
                block['due'] = block['due'].isoformat() if block.get('due') is not None else None
                block['location'] = unicode(location)

        return assignment_blocks
예제 #3
0
    def render_to_fragment(self, request, course_id=None, **kwargs):
        """
        Renders the course outline as a fragment.
        """
        course_key = CourseKey.from_string(course_id)
        course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True)
        course_usage_key = modulestore().make_course_usage_key(course_key)
        all_blocks = get_blocks(
            request,
            course_usage_key,
            user=request.user,
            nav_depth=3,
            requested_fields=['children', 'display_name', 'type'],
            block_types_filter=['course', 'chapter', 'sequential']
        )

        course_block_tree = all_blocks['blocks'][all_blocks['root']]  # Get the root of the block tree

        context = {
            'csrf': csrf(request)['csrf_token'],
            'course': course,
            # Recurse through the block tree, fleshing out each child object
            'blocks': self.populate_children(course_block_tree, all_blocks['blocks'])
        }
        html = render_to_string('course_experience/course-outline-fragment.html', context)
        return Fragment(html)
예제 #4
0
def _assert_block_is_gated(store,
                           block,
                           is_gated,
                           user,
                           course,
                           request_factory,
                           has_upgrade_link=True):
    """
    Asserts that a block in a specific course is gated for a specific user
    Arguments:
        block: some sort of xblock descriptor, must implement .scope_ids.usage_id
        is_gated (bool): if True, this user is expected to be gated from this block
        user (int): user
        course_id (CourseLocator): id of course
    """
    checkout_link = '#' if has_upgrade_link else None
    for content_getter in (_get_content_from_fragment,
                           _get_content_from_lms_index):
        with patch.object(ContentTypeGatingPartition,
                          '_get_checkout_link',
                          return_value=checkout_link):
            content = content_getter(store, block, user.id, course,
                                     request_factory)  # pylint: disable=no-value-for-parameter
        if is_gated:
            assert 'content-paywall' in content
            if has_upgrade_link:
                assert 'certA_1' in content
            else:
                assert 'certA_1' not in content
        else:
            assert 'content-paywall' not in content

    fake_request = request_factory.get('')
    requested_fields = [
        'block_id', 'contains_gated_content', 'display_name',
        'student_view_data', 'student_view_url'
    ]
    blocks = get_blocks(fake_request,
                        course.location,
                        user=user,
                        requested_fields=requested_fields,
                        student_view_data=['html'])
    course_api_block = blocks['blocks'][str(block.location)]

    assert course_api_block.get('contains_gated_content', False) == is_gated

    if is_gated:
        assert 'authorization_denial_reason' in course_api_block
        assert 'block_id' in course_api_block
        assert 'display_name' in course_api_block
        assert 'student_view_data' not in course_api_block
        assert 'student_view_url' in course_api_block
    else:
        assert 'authorization_denial_reason' not in course_api_block
        if block.category == 'html':
            assert 'student_view_data' in course_api_block
예제 #5
0
    def get(self, request, username, course_key, subsection_id):
        """
        Returns completion for a (user, subsection, course).
        """

        def get_completion(course_completions, all_blocks, block_id):
            """
            Recursively get the aggregate completion for a subsection,
            given the subsection block and a list of all blocks.

            Parameters:
                course_completions: a dictionary of completion values by block IDs
                all_blocks: a dictionary of the block structure for a subsection
                block_id: an ID of a block for which to get completion
            """
            block = all_blocks.get(block_id)
            child_ids = block.get('children', [])
            if not child_ids:
                return course_completions.get(block.serializer.instance, 0)

            completion = 0
            total_children = 0
            for child_id in child_ids:
                completion += get_completion(course_completions, all_blocks, child_id)
                total_children += 1

            return int(completion == total_children)

        user_id = User.objects.get(username=username).id
        block_types_filter = [
            'course',
            'chapter',
            'sequential',
            'vertical',
            'html',
            'problem',
            'video',
            'discussion',
            'drag-and-drop-v2'
        ]

        blocks = get_blocks(
            request,
            UsageKey.from_string(subsection_id),
            nav_depth=2,
            requested_fields=[
                'children'
            ],
            block_types_filter=block_types_filter
        )

        course_key = LearningContextKey.from_string(course_key)
        context_completions = BlockCompletion.get_learning_context_completions(user_id, course_key)
        aggregated_completion = get_completion(context_completions, blocks['blocks'], blocks['root'])

        return Response({"completion": aggregated_completion}, status=status.HTTP_200_OK)
예제 #6
0
def get_course_outline_block_tree(request, course_id):
    """
    Returns the root block of the course outline, with children as blocks.
    """

    def populate_children(block, all_blocks):
        """
        Replace each child id with the full block for the child.

        Given a block, replaces each id in its children array with the full
        representation of that child, which will be looked up by id in the
        passed all_blocks dict. Recursively do the same replacement for children
        of those children.
        """
        children = block.get('children', [])

        for i in range(len(children)):
            child_id = block['children'][i]
            child_detail = populate_children(all_blocks[child_id], all_blocks)
            block['children'][i] = child_detail

        return block

    def set_last_accessed_default(block):
        """
        Set default of False for resume_block on all blocks.
        """
        block['resume_block'] = False
        block['complete'] = False
        for child in block.get('children', []):
            set_last_accessed_default(child)

    def mark_blocks_completed(block, user, course_key):
        """
        Walk course tree, marking block completion.
        Mark 'most recent completed block as 'resume_block'

        """

        last_completed_child_position = BlockCompletion.get_latest_block_completed(user, course_key)

        if last_completed_child_position:
            # Mutex w/ NOT 'course_block_completions'
            recurse_mark_complete(
                course_block_completions=BlockCompletion.get_course_completions(user, course_key),
                latest_completion=last_completed_child_position,
                block=block
            )

    def recurse_mark_complete(course_block_completions, latest_completion, block):
        """
        Helper function to walk course tree dict,
        marking blocks as 'complete' and 'last_complete'

        If all blocks are complete, mark parent block complete
        mark parent blocks of 'last_complete' as 'last_complete'

        :param course_block_completions: dict[course_completion_object] =  completion_value
        :param latest_completion: course_completion_object
        :param block: course_outline_root_block block object or child block

        :return:
            block: course_outline_root_block block object or child block
        """
        locatable_block_string = BlockUsageLocator.from_string(block['id'])

        if course_block_completions.get(locatable_block_string):
            block['complete'] = True
            if locatable_block_string == latest_completion.block_key:
                block['resume_block'] = True

        if block.get('children'):
            for idx in range(len(block['children'])):
                recurse_mark_complete(
                    course_block_completions,
                    latest_completion,
                    block=block['children'][idx]
                )
                if block['children'][idx]['resume_block'] is True:
                    block['resume_block'] = True

            if len([child['complete'] for child in block['children'] if child['complete']]) == len(block['children']):
                block['complete'] = True

    def mark_last_accessed(user, course_key, block):
        """
        Recursively marks the branch to the last accessed block.
        """
        block_key = block.serializer.instance
        student_module_dict = get_student_module_as_dict(user, course_key, block_key)

        last_accessed_child_position = student_module_dict.get('position')
        if last_accessed_child_position and block.get('children'):
            block['resume_block'] = True
            if last_accessed_child_position <= len(block['children']):
                last_accessed_child_block = block['children'][last_accessed_child_position - 1]
                last_accessed_child_block['resume_block'] = True
                mark_last_accessed(user, course_key, last_accessed_child_block)
            else:
                # We should be using an id in place of position for last accessed.
                # However, while using position, if the child block is no longer accessible
                # we'll use the last child.
                block['children'][-1]['resume_block'] = True

    course_key = CourseKey.from_string(course_id)
    course_usage_key = modulestore().make_course_usage_key(course_key)

    all_blocks = get_blocks(
        request,
        course_usage_key,
        user=request.user,
        nav_depth=3,
        requested_fields=[
            'children',
            'display_name',
            'type',
            'due',
            'graded',
            'special_exam_info',
            'show_gated_sections',
            'format'
        ],
        block_types_filter=[
            'course',
            'chapter',
            'sequential',
            'vertical',
            'html',
            'problem',
            'video',
            'discussion'
        ]
    )

    course_outline_root_block = all_blocks['blocks'].get(all_blocks['root'], None)
    if course_outline_root_block:
        populate_children(course_outline_root_block, all_blocks['blocks'])
        set_last_accessed_default(course_outline_root_block)

        if visual_progress_enabled(course_key=course_key):
            mark_blocks_completed(
                block=course_outline_root_block,
                user=request.user,
                course_key=course_key
            )
        else:
            mark_last_accessed(request.user, course_key, course_outline_root_block)
    return course_outline_root_block
예제 #7
0
def get_course_outline_block_tree(request, course_id, user=None):
    """
    Returns the root block of the course outline, with children as blocks.
    """

    assert user is None or user.is_authenticated

    def populate_children(block, all_blocks):
        """
        Replace each child id with the full block for the child.

        Given a block, replaces each id in its children array with the full
        representation of that child, which will be looked up by id in the
        passed all_blocks dict. Recursively do the same replacement for children
        of those children.
        """
        children = block.get('children', [])

        for i in range(len(children)):
            child_id = block['children'][i]
            child_detail = populate_children(all_blocks[child_id], all_blocks)
            block['children'][i] = child_detail

        return block

    def set_last_accessed_default(block):
        """
        Set default of False for resume_block on all blocks.
        """
        block['resume_block'] = False
        block['complete'] = False
        for child in block.get('children', []):
            set_last_accessed_default(child)

    def mark_blocks_completed(block, user, course_key):
        """
        Walk course tree, marking block completion.
        Mark 'most recent completed block as 'resume_block'

        """
        last_completed_child_position = BlockCompletion.get_latest_block_completed(
            user, course_key)

        if last_completed_child_position:
            # Mutex w/ NOT 'course_block_completions'
            recurse_mark_complete(
                course_block_completions=BlockCompletion.
                get_course_completions(user, course_key),
                latest_completion=last_completed_child_position,
                block=block)

    def recurse_mark_complete(course_block_completions, latest_completion,
                              block):
        """
        Helper function to walk course tree dict,
        marking blocks as 'complete' and 'last_complete'

        If all blocks are complete, mark parent block complete
        mark parent blocks of 'last_complete' as 'last_complete'

        :param course_block_completions: dict[course_completion_object] =  completion_value
        :param latest_completion: course_completion_object
        :param block: course_outline_root_block block object or child block

        :return:
            block: course_outline_root_block block object or child block
        """
        block_key = block.serializer.instance

        if course_block_completions.get(block_key):
            block['complete'] = True
            if block_key == latest_completion.full_block_key:
                block['resume_block'] = True

        if block.get('children'):
            for idx in range(len(block['children'])):
                recurse_mark_complete(course_block_completions,
                                      latest_completion,
                                      block=block['children'][idx])
                if block['children'][idx].get('resume_block') is True:
                    block['resume_block'] = True

            completable_blocks = [
                child for child in block['children']
                if child.get('type') != 'discussion'
            ]
            if all(child.get('complete') for child in completable_blocks):
                block['complete'] = True

    def mark_last_accessed(user, course_key, block):
        """
        Recursively marks the branch to the last accessed block.
        """
        block_key = block.serializer.instance
        student_module_dict = get_student_module_as_dict(
            user, course_key, block_key)

        last_accessed_child_position = student_module_dict.get('position')
        if last_accessed_child_position and block.get('children'):
            block['resume_block'] = True
            if last_accessed_child_position <= len(block['children']):
                last_accessed_child_block = block['children'][
                    last_accessed_child_position - 1]
                last_accessed_child_block['resume_block'] = True
                mark_last_accessed(user, course_key, last_accessed_child_block)
            else:
                # We should be using an id in place of position for last accessed.
                # However, while using position, if the child block is no longer accessible
                # we'll use the last child.
                block['children'][-1]['resume_block'] = True

    def recurse_mark_scored(block):
        """
        Mark this block as 'scored' if any of its descendents are 'scored' (that is, 'has_score' and 'weight' > 0).
        """
        is_scored = block.get('has_score',
                              False) and block.get('weight', 1) > 0
        # Use a list comprehension to force the recursion over all children, rather than just stopping
        # at the first child that is scored.
        children_scored = any([
            recurse_mark_scored(child) for child in block.get('children', [])
        ])
        if is_scored or children_scored:
            block['scored'] = True
            return True
        else:
            block['scored'] = False
            return False

    def recurse_mark_auth_denial(block):
        """
        Mark this block as 'scored' if any of its descendents are 'scored' (that is, 'has_score' and 'weight' > 0).
        """
        own_denial_reason = {
            block['authorization_denial_reason']
        } if 'authorization_denial_reason' in block else set()
        # Use a list comprehension to force the recursion over all children, rather than just stopping
        # at the first child that is scored.
        child_denial_reasons = own_denial_reason.union(
            *(recurse_mark_auth_denial(child)
              for child in block.get('children', [])))
        if child_denial_reasons:
            block['all_denial_reasons'] = child_denial_reasons
        return child_denial_reasons

    course_key = CourseKey.from_string(course_id)
    course_usage_key = modulestore().make_course_usage_key(course_key)

    # Deeper query for course tree traversing/marking complete
    # and last completed block
    block_types_filter = [
        'course', 'chapter', 'sequential', 'vertical', 'html', 'problem',
        'video', 'discussion', 'drag-and-drop-v2', 'poll', 'word_cloud'
    ]
    all_blocks = get_blocks(request,
                            course_usage_key,
                            user=request.user,
                            nav_depth=3,
                            requested_fields=[
                                'children', 'display_name', 'type', 'due',
                                'graded', 'has_score', 'weight',
                                'special_exam_info', 'show_gated_sections',
                                'format'
                            ],
                            block_types_filter=block_types_filter)

    course_outline_root_block = all_blocks['blocks'].get(
        all_blocks['root'], None)
    if course_outline_root_block:
        populate_children(course_outline_root_block, all_blocks['blocks'])
        recurse_mark_scored(course_outline_root_block)
        recurse_mark_auth_denial(course_outline_root_block)
        if user:
            set_last_accessed_default(course_outline_root_block)
            mark_blocks_completed(block=course_outline_root_block,
                                  user=request.user,
                                  course_key=course_key)
    return course_outline_root_block
예제 #8
0
def get_course_outline_block_tree(request, course_id, user=None):
    """
    Returns the root block of the course outline, with children as blocks.
    """

    assert user is None or user.is_authenticated

    def populate_children(block, all_blocks):
        """
        Replace each child id with the full block for the child.

        Given a block, replaces each id in its children array with the full
        representation of that child, which will be looked up by id in the
        passed all_blocks dict. Recursively do the same replacement for children
        of those children.
        """
        children = block.get('children', [])

        for i in range(len(children)):
            child_id = block['children'][i]
            child_detail = populate_children(all_blocks[child_id], all_blocks)
            block['children'][i] = child_detail

        return block

    def set_last_accessed_default(block):
        """
        Set default of False for resume_block on all blocks.
        """
        block['resume_block'] = False
        block['complete'] = False
        for child in block.get('children', []):
            set_last_accessed_default(child)

    def mark_blocks_completed(block, user, course_key):
        """
        Walk course tree, marking block completion.
        Mark 'most recent completed block as 'resume_block'

        """
        last_completed_child_position = BlockCompletion.get_latest_block_completed(user, course_key)

        if last_completed_child_position:
            # Mutex w/ NOT 'course_block_completions'
            recurse_mark_complete(
                course_block_completions=BlockCompletion.get_course_completions(user, course_key),
                latest_completion=last_completed_child_position,
                block=block
            )

    def recurse_mark_complete(course_block_completions, latest_completion, block):
        """
        Helper function to walk course tree dict,
        marking blocks as 'complete' and 'last_complete'

        If all blocks are complete, mark parent block complete
        mark parent blocks of 'last_complete' as 'last_complete'

        :param course_block_completions: dict[course_completion_object] =  completion_value
        :param latest_completion: course_completion_object
        :param block: course_outline_root_block block object or child block

        :return:
            block: course_outline_root_block block object or child block
        """
        block_key = block.serializer.instance

        if course_block_completions.get(block_key):
            block['complete'] = True
            if block_key == latest_completion.full_block_key:
                block['resume_block'] = True

        if block.get('children'):
            for idx in range(len(block['children'])):
                recurse_mark_complete(
                    course_block_completions,
                    latest_completion,
                    block=block['children'][idx]
                )
                if block['children'][idx].get('resume_block') is True:
                    block['resume_block'] = True

            completable_blocks = [child for child in block['children']
                                  if child.get('type') != 'discussion']
            if all(child.get('complete') for child in completable_blocks):
                block['complete'] = True

    def mark_last_accessed(user, course_key, block):
        """
        Recursively marks the branch to the last accessed block.
        """
        block_key = block.serializer.instance
        student_module_dict = get_student_module_as_dict(user, course_key, block_key)

        last_accessed_child_position = student_module_dict.get('position')
        if last_accessed_child_position and block.get('children'):
            block['resume_block'] = True
            if last_accessed_child_position <= len(block['children']):
                last_accessed_child_block = block['children'][last_accessed_child_position - 1]
                last_accessed_child_block['resume_block'] = True
                mark_last_accessed(user, course_key, last_accessed_child_block)
            else:
                # We should be using an id in place of position for last accessed.
                # However, while using position, if the child block is no longer accessible
                # we'll use the last child.
                block['children'][-1]['resume_block'] = True

    course_key = CourseKey.from_string(course_id)
    course_usage_key = modulestore().make_course_usage_key(course_key)

    # Deeper query for course tree traversing/marking complete
    # and last completed block
    block_types_filter = [
        'course',
        'chapter',
        'sequential',
        'vertical',
        'html',
        'problem',
        'video',
        'discussion',
        'drag-and-drop-v2',
        'poll',
        'word_cloud'
    ]
    all_blocks = get_blocks(
        request,
        course_usage_key,
        user=request.user,
        nav_depth=3,
        requested_fields=[
            'children',
            'display_name',
            'type',
            'due',
            'graded',
            'special_exam_info',
            'show_gated_sections',
            'format'
        ],
        block_types_filter=block_types_filter
    )

    course_outline_root_block = all_blocks['blocks'].get(all_blocks['root'], None)
    if course_outline_root_block:
        populate_children(course_outline_root_block, all_blocks['blocks'])
        if user:
            set_last_accessed_default(course_outline_root_block)
            mark_blocks_completed(
                block=course_outline_root_block,
                user=request.user,
                course_key=course_key
            )
    return course_outline_root_block
예제 #9
0
def get_course_outline_block_tree(request, course_id):
    """
    Returns the root block of the course outline, with children as blocks.
    """
    def populate_children(block, all_blocks):
        """
        Replace each child id with the full block for the child.

        Given a block, replaces each id in its children array with the full
        representation of that child, which will be looked up by id in the
        passed all_blocks dict. Recursively do the same replacement for children
        of those children.
        """
        children = block.get('children', [])

        for i in range(len(children)):
            child_id = block['children'][i]
            child_detail = populate_children(all_blocks[child_id], all_blocks)
            block['children'][i] = child_detail

        return block

    def set_last_accessed_default(block):
        """
        Set default of False for last_accessed on all blocks.
        """
        block['last_accessed'] = False
        for child in block.get('children', []):
            set_last_accessed_default(child)

    def mark_last_accessed(user, course_key, block):
        """
        Recursively marks the branch to the last accessed block.
        """
        block_key = block.serializer.instance
        student_module_dict = get_student_module_as_dict(
            user, course_key, block_key)
        last_accessed_child_position = student_module_dict.get('position')
        if last_accessed_child_position and block.get('children'):
            block['last_accessed'] = True
            if last_accessed_child_position <= len(block['children']):
                last_accessed_child_block = block['children'][
                    last_accessed_child_position - 1]
                last_accessed_child_block['last_accessed'] = True
                mark_last_accessed(user, course_key, last_accessed_child_block)
            else:
                # We should be using an id in place of position for last accessed. However, while using position, if
                # the child block is no longer accessible we'll use the last child.
                block['children'][-1]['last_accessed'] = True

    course_key = CourseKey.from_string(course_id)
    course_usage_key = modulestore().make_course_usage_key(course_key)

    all_blocks = get_blocks(
        request,
        course_usage_key,
        user=request.user,
        nav_depth=3,
        requested_fields=[
            'children', 'display_name', 'type', 'due', 'graded',
            'special_exam_info', 'format'
        ],
        block_types_filter=['course', 'chapter', 'sequential'])

    course_outline_root_block = all_blocks['blocks'][all_blocks['root']]
    populate_children(course_outline_root_block, all_blocks['blocks'])
    set_last_accessed_default(course_outline_root_block)
    mark_last_accessed(request.user, course_key, course_outline_root_block)

    return course_outline_root_block
예제 #10
0
def get_course_outline_block_tree(request,
                                  course_id,
                                  user=None,
                                  allow_start_dates_in_future=False):  # lint-amnesty, pylint: disable=too-many-statements
    """
    Returns the root block of the course outline, with children as blocks.

    allow_start_dates_in_future (bool): When True, will allow blocks to be
            returned that can bypass the StartDateTransformer's filter to show
            blocks with start dates in the future.
    """

    assert user is None or user.is_authenticated

    def populate_children(block, all_blocks):
        """
        Replace each child id with the full block for the child.

        Given a block, replaces each id in its children array with the full
        representation of that child, which will be looked up by id in the
        passed all_blocks dict. Recursively do the same replacement for children
        of those children.
        """
        children = block.get('children', [])

        for i in range(len(children)):
            child_id = block['children'][i]
            child_detail = populate_children(all_blocks[child_id], all_blocks)
            block['children'][i] = child_detail

        return block

    def recurse_mark_scored(block):
        """
        Mark this block as 'scored' if any of its descendents are 'scored' (that is, 'has_score' and 'weight' > 0).
        """
        is_scored = block.get('has_score',
                              False) and block.get('weight', 1) > 0
        # Use a list comprehension to force the recursion over all children, rather than just stopping
        # at the first child that is scored.
        children_scored = any(
            recurse_mark_scored(child) for child in block.get('children', []))
        if is_scored or children_scored:
            block['scored'] = True
            return True
        else:
            block['scored'] = False
            return False

    def recurse_num_graded_problems(block):
        """
        Marks each block with the number of graded and scored leaf blocks below it as 'num_graded_problems'
        """
        is_scored = block.get('has_score') and block.get('weight', 1) > 0
        is_graded = block.get('graded')
        is_countable = block.get('type') not in ('lti', 'lti_consumer')
        is_graded_problem = is_scored and is_graded and is_countable

        num_graded_problems = 1 if is_graded_problem else 0
        num_graded_problems += sum(
            recurse_num_graded_problems(child)
            for child in block.get('children', []))

        block['num_graded_problems'] = num_graded_problems
        return num_graded_problems

    def recurse_mark_auth_denial(block):
        """
        Mark this block as 'scored' if any of its descendents are 'scored' (that is, 'has_score' and 'weight' > 0).
        """
        own_denial_reason = {
            block['authorization_denial_reason']
        } if 'authorization_denial_reason' in block else set()
        # Use a list comprehension to force the recursion over all children, rather than just stopping
        # at the first child that is scored.
        child_denial_reasons = own_denial_reason.union(
            *(recurse_mark_auth_denial(child)
              for child in block.get('children', [])))
        if child_denial_reasons:
            block['all_denial_reasons'] = child_denial_reasons
        return child_denial_reasons

    course_key = CourseKey.from_string(course_id)
    course_usage_key = modulestore().make_course_usage_key(course_key)

    all_blocks = get_blocks(
        request,
        course_usage_key,
        user=user,
        nav_depth=3,
        requested_fields=[
            'children',
            'contains_gated_content',
            'display_name',
            'due',
            'effort_activities',
            'effort_time',
            'format',
            'graded',
            'has_scheduled_content',
            'has_score',
            'show_gated_sections',
            'special_exam_info',
            'start',
            'type',
            'weight',
            'completion',
            'complete',
            'resume_block',
        ],
        allow_start_dates_in_future=allow_start_dates_in_future,
    )

    course_outline_root_block = all_blocks['blocks'].get(
        all_blocks['root'], None)
    if course_outline_root_block:
        populate_children(course_outline_root_block, all_blocks['blocks'])
        recurse_mark_scored(course_outline_root_block)
        recurse_num_graded_problems(course_outline_root_block)
        recurse_mark_auth_denial(course_outline_root_block)
    return course_outline_root_block
예제 #11
0
def get_course_outline_block_tree(request, course_id):
    """
    Returns the root block of the course outline, with children as blocks.
    """

    def populate_children(block, all_blocks):
        """
        Replace each child id with the full block for the child.

        Given a block, replaces each id in its children array with the full
        representation of that child, which will be looked up by id in the
        passed all_blocks dict. Recursively do the same replacement for children
        of those children.
        """
        children = block.get('children', [])

        for i in range(len(children)):
            child_id = block['children'][i]
            child_detail = populate_children(all_blocks[child_id], all_blocks)
            block['children'][i] = child_detail

        return block

    def set_last_accessed_default(block):
        """
        Set default of False for last_accessed on all blocks.
        """
        block['last_accessed'] = False
        for child in block.get('children', []):
            set_last_accessed_default(child)

    def mark_last_accessed(user, course_key, block):
        """
        Recursively marks the branch to the last accessed block.
        """
        block_key = block.serializer.instance
        student_module_dict = get_student_module_as_dict(user, course_key, block_key)
        last_accessed_child_position = student_module_dict.get('position')
        if last_accessed_child_position and block.get('children'):
            block['last_accessed'] = True
            if last_accessed_child_position <= len(block['children']):
                last_accessed_child_block = block['children'][last_accessed_child_position - 1]
                last_accessed_child_block['last_accessed'] = True
                mark_last_accessed(user, course_key, last_accessed_child_block)
            else:
                # We should be using an id in place of position for last accessed. However, while using position, if
                # the child block is no longer accessible we'll use the last child.
                block['children'][-1]['last_accessed'] = True

    course_key = CourseKey.from_string(course_id)
    course_usage_key = modulestore().make_course_usage_key(course_key)

    all_blocks = get_blocks(
        request,
        course_usage_key,
        user=request.user,
        nav_depth=3,
        requested_fields=['children', 'display_name', 'type', 'due', 'graded', 'special_exam_info', 'format'],
        block_types_filter=['course', 'chapter', 'sequential']
    )

    course_outline_root_block = all_blocks['blocks'].get(all_blocks['root'], None)
    if course_outline_root_block:
        populate_children(course_outline_root_block, all_blocks['blocks'])
        set_last_accessed_default(course_outline_root_block)
        mark_last_accessed(request.user, course_key, course_outline_root_block)
    return course_outline_root_block
예제 #12
0
    def get(self, request, username, course_id):
        """
        Gets a progress information.

        Args:
            request (Request): Django request object.
            username (string): URI element specifying the user's username.
            course_id (string): URI element specifying the course location.

        Return:
            A JSON serialized representation of the certificate.
        """

        def aggregate_progress(course_completions, all_blocks, block_id):
            """
            Recursively get the progress for a units (vertical),
            given list of all blocks.
            Parameters:
                course_completions: a dictionary of completion values by block IDs
                all_blocks: a dictionary of the block structure for a subsection
                block_id: an ID of a block for which to get completion
            """
            block = all_blocks.get(block_id)
            child_ids = block.get('children', [])
            if block.get('type', None) == 'vertical':
                self.units_progress_list.append([block_id, 0, 0])

            if not child_ids and (block.get('type', None) in block_xblocks_types_filter):
                self.units_progress_list[-1][1] += 1
                self.units_progress_list[-1][2] += course_completions.get(block.serializer.instance, 0)

            for child_id in child_ids:
                aggregate_progress(course_completions, all_blocks, child_id)

        def calculate_progress():
            """
            Calculate course progress from units progress
            """
            number_of_units = len(self.units_progress_list)
            if number_of_units == 0:
                return float(0.0)
            else:
                cumulative_sum = 0
                for unit_progress in self.units_progress_list:
                    if unit_progress[1] == 0:
                        number_of_units -= 1
                    else:
                        cumulative_sum += unit_progress[2]/unit_progress[1]
                return round(cumulative_sum/number_of_units, 3)

        course_object_id = CourseKey.from_string(course_id)
        self.check_object_permissions(self.request, courses.get_course_by_id(course_object_id))
        course_usage_key = modulestore().make_course_usage_key(course_object_id)

        try:
            user_id = User.objects.get(username=username).id
        except User.DoesNotExist:
            return Response(
                status=404,
                data={'error_code': u'Not found.'}
            )

        block_navigation_types_filter = [
            'course',
            'chapter',
            'sequential',
            'vertical',
        ]

        block_xblocks_types_filter = [
            'html',
            'problem',
            'video',
            'drag-and-drop-v2',
            'poll',
            'videojs',
            'embedded_answers',
            'inline-dropdown',
            'openassessment',
            'audioplayer',
        ]

        block_types_filter = block_navigation_types_filter + block_xblocks_types_filter

        try:
            blocks = get_blocks(request, course_usage_key, nav_depth=3, requested_fields=[
                'children', 'type',
            ],
                block_types_filter=block_types_filter
            )
        except ItemNotFoundError:
            return Response(
                status=404,
                data={'error_code': u'Not found.'}
            )

        course_completions = BlockCompletion.get_course_completions(user_id, course_object_id)
        aggregate_progress(course_completions, blocks['blocks'], blocks['root'])
        calculated_progress = calculate_progress()
        response_dict = {"username": username,
                         "course_id": course_id,
                         "completion_value": calculated_progress}

        return Response(response_dict, status=status.HTTP_200_OK)