Beispiel #1
0
def get_course_tab_list(request, course):
    """
    Retrieves the course tab list from xmodule.tabs and manipulates the set as necessary
    """
    user = request.user
    xmodule_tab_list = CourseTabList.iterate_displayable(course, user=user)

    # Now that we've loaded the tabs for this course, perform the Entrance Exam work.
    # If the user has to take an entrance exam, we'll need to hide away all but the
    # "Courseware" tab. The tab is then renamed as "Entrance Exam".
    course_tab_list = []
    must_complete_ee = user_must_complete_entrance_exam(request, user, course)
    for tab in xmodule_tab_list:
        if must_complete_ee:
            # Hide all of the tabs except for 'Courseware'
            # Rename 'Courseware' tab to 'Entrance Exam'
            if tab.type != 'courseware':
                continue
            tab.name = _("Entrance Exam")
        if tab.type == 'static_tab' and tab.course_staff_only and \
                not bool(user and has_access(user, 'staff', course, course.id)):
            continue
        course_tab_list.append(tab)

    # Add in any dynamic tabs, i.e. those that are not persisted
    course_tab_list += _get_dynamic_tabs(course, user)
    return course_tab_list
def get_course_tab_list(request, course):
    """
    Retrieves the course tab list from xmodule.tabs and manipulates the set as necessary
    """
    user = request.user
    xmodule_tab_list = CourseTabList.iterate_displayable(course, user=user)

    # Now that we've loaded the tabs for this course, perform the Entrance Exam work.
    # If the user has to take an entrance exam, we'll need to hide away all but the
    # "Courseware" tab. The tab is then renamed as "Entrance Exam".
    course_tab_list = []
    must_complete_ee = user_must_complete_entrance_exam(request, user, course)
    for tab in xmodule_tab_list:
        # Rename 'Home' tab to 'Information'
        if tab.type is 'course_info':
            tab.name = _("Information")
        if must_complete_ee:
            # Hide all of the tabs except for 'Courseware'
            # Rename 'Courseware' tab to 'Entrance Exam'
            if tab.type is not 'courseware':
                continue
            tab.name = _("Entrance Exam")
        course_tab_list.append(tab)

    # Add in any dynamic tabs, i.e. those that are not persisted
    course_tab_list += _get_dynamic_tabs(course, user)

    # Add course welcome tab if feature is enabled
    if settings.FEATURES.get('TMA_ENABLE_COURSE_WELCOME_PAGE'
                             ) and CourseWelcomeTab.is_enabled(course, user):
        course_tab_list.insert(0, CourseWelcomeTab({}))

    return course_tab_list
Beispiel #3
0
def get_course_tab_list(request, course):
    """
    Retrieves the course tab list from xmodule.tabs and manipulates the set as necessary
    """
    user = request.user
    is_user_enrolled = user.is_authenticated() and CourseEnrollment.is_enrolled(user, course.id)
    xmodule_tab_list = CourseTabList.iterate_displayable(
        course,
        user=user,
        settings=settings,
        is_user_authenticated=user.is_authenticated(),
        is_user_staff=has_access(user, 'staff', course, course.id),
        is_user_enrolled=is_user_enrolled,
        is_user_sneakpeek=not UserProfile.has_registered(user),
    )

    # Now that we've loaded the tabs for this course, perform the Entrance Exam work.
    # If the user has to take an entrance exam, we'll need to hide away all but the
    # "Courseware" tab. The tab is then renamed as "Entrance Exam".
    course_tab_list = []
    must_complete_ee = user_must_complete_entrance_exam(request, user, course)
    for tab in xmodule_tab_list:
        if must_complete_ee:
            # Hide all of the tabs except for 'Courseware'
            # Rename 'Courseware' tab to 'Entrance Exam'
            if tab.type is not 'courseware':
                continue
            tab.name = _("Entrance Exam")
        course_tab_list.append(tab)

    # Add in any dynamic tabs, i.e. those that are not persisted
    course_tab_list += _get_dynamic_tabs(course, user)
    return course_tab_list
Beispiel #4
0
def get_course_tab_list(course, user):
    """
    Retrieves the course tab list from xmodule.tabs and manipulates the set as necessary
    """
    user_is_enrolled = user.is_authenticated(
    ) and CourseEnrollment.is_enrolled(user, course.id)
    xmodule_tab_list = CourseTabList.iterate_displayable(
        course, settings, user.is_authenticated(),
        has_access(user, 'staff', course, course.id), user_is_enrolled)

    # Now that we've loaded the tabs for this course, perform the Entrance Exam work
    # If the user has to take an entrance exam, we'll need to hide away all of the tabs
    # except for the Courseware and Instructor tabs (latter is only viewed if applicable)
    # 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
    course_tab_list = []
    for tab in xmodule_tab_list:
        if user_must_complete_entrance_exam(request, user, course):
            # Hide all of the tabs except for 'Courseware' and 'Instructor'
            # Rename 'Courseware' tab to 'Entrance Exam'
            if tab.type not in ['courseware', 'instructor']:
                continue
            if tab.type == 'courseware':
                tab.name = _("Entrance Exam")
        course_tab_list.append(tab)
    return course_tab_list
Beispiel #5
0
def get_course_tab_list(course, user):
    """
    Retrieves the course tab list from xmodule.tabs and manipulates the set as necessary
    """
    user_is_enrolled = user.is_authenticated() and CourseEnrollment.is_enrolled(user, course.id)
    xmodule_tab_list = CourseTabList.iterate_displayable(
        course,
        settings,
        user.is_authenticated(),
        has_access(user, 'staff', course, course.id),
        user_is_enrolled
    )

    # Now that we've loaded the tabs for this course, perform the Entrance Exam work
    # If the user has to take an entrance exam, we'll need to hide away all of the tabs
    # except for the Courseware and Instructor tabs (latter is only viewed if applicable)
    # 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
    course_tab_list = []
    for tab in xmodule_tab_list:
        if user_must_complete_entrance_exam(request, user, course):
            # Hide all of the tabs except for 'Courseware' and 'Instructor'
            # Rename 'Courseware' tab to 'Entrance Exam'
            if tab.type not in ['courseware', 'instructor']:
                continue
            if tab.type == 'courseware':
                tab.name = _("Entrance Exam")
        course_tab_list.append(tab)
    return course_tab_list
def prepare_sections_with_grade(request, course):
    '''
    Create sections with grade details.

    Return format:
    {
        'sections': [
            {
                'display_name': name,
                # in case of cohorts or any other accessibility settings
                'hidden': hidden,
                'url_name': url_name,
                'units': UNITS,
                'rank': rank,
                'badge': bagde status,
                'points': grade points,
                'podium': podium status,
                'week': section_index + 1,
            },
        ],
    }

    where UNITS is a list
    [
        {
            'display_name': name,
            'position': unit position in section,
            'css_class': css class,
        }
        , ...
    ]

    sections with name 'hidden' are skipped.

    NOTE: assumes that if we got this far, user has access to course.  Returns
    [] if this is not the case.
    '''
    # Set the student to request user
    student = request.user

    # Get the field data cache
    field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
        course.id, student, course, depth=2,
    )
    
    # Get the course module
    with modulestore().bulk_operations(course.id):
        course_module = get_module_for_descriptor(
            student, request, course, field_data_cache, course.id, course=course
        )
        if course_module is None:
            return []

    # Get the field data cache
    staff_user = User.objects.filter(is_staff=1)[0]
    staff_field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
        course.id, staff_user, course, depth=2,
    )

    # Get the course module
    with modulestore().bulk_operations(course.id):
        staff_course_module = get_module_for_descriptor(
            staff_user, request, course, staff_field_data_cache, course.id, course=course
        )

    # staff accessible chapters
    staff_chapters = staff_course_module.get_display_items()

    # find the passing grade for the course
    nonzero_cutoffs = [cutoff for cutoff in course.grade_cutoffs.values() if cutoff > 0]
    success_cutoff = min(nonzero_cutoffs) if nonzero_cutoffs else 0

    # find the course progress
    progress = get_course_progress(student, course.id)

    # prepare a list of discussions participated by user
    discussions_participated = get_discussions_participated(
        request,
        course.id.to_deprecated_string(),
        student.id
    )

    # get courseware summary
    with outer_atomic():
        field_data_cache = grades.field_data_cache_for_grading(course, student)
        scores_client = ScoresClient.from_field_data_cache(field_data_cache)

    courseware_summary = grades.progress_summary(
        student, request, course, field_data_cache=field_data_cache, scores_client=scores_client
    )

    section_grades = {}
    for section in courseware_summary:
        earned = 0
        total = 0
        for sub_section in section['sections']:
            earned += sub_section['section_total'].earned
            total += sub_section['section_total'].possible

        section_score = earned / total if earned > 0 and total > 0 else 0
        section_grades[section['url_name']] = {
            'earned': earned,
            'total': total,
            'css_class': ('text-red', 'text-green')[int(section_score >= 0.6)] if total > 0 else ''
        }

    # Check for content which needs to be completed
    # before the rest of the content is made available
    required_content = milestones_helpers.get_required_content(course, student)

    # Check for gated content
    gated_content = gating_api.get_gated_content(course, student)

    # The user may not actually have to complete the entrance exam, if one is required
    if not user_must_complete_entrance_exam(request, student, course):
        required_content = [content for content in required_content if not content == course.entrance_exam_id]

    # define inner function
    def create_module(descriptor):
        '''creates an XModule instance given a descriptor'''
        return get_module_for_descriptor(
            student, request, descriptor, field_data_cache, course.id, course=course
        )

    with outer_atomic():
        submissions_scores = sub_api.get_scores(
            course.id.to_deprecated_string(),
            anonymous_id_for_user(student, course.id)
        )
        max_scores_cache = grades.MaxScoresCache.create_for_course(course)
        max_scores_cache.fetch_from_remote(field_data_cache.scorable_locations)


    sections = list()
    student_chapters = course_module.get_display_items()
    urlname_chapters = {}
    for student_chap in student_chapters:
        urlname_chapters.update({student_chap.url_name:student_chap})
    final_chapters = OrderedDict()
    for chapter_index, chapter in enumerate(staff_chapters):
        fin_chap = urlname_chapters.get(chapter.url_name)
        if fin_chap:
            final_chapters.update({str(chapter_index+1):{'hidden': False, 'chapter':fin_chap}})
        else:
            final_chapters.update({str(chapter_index+1):{'hidden':True}})

    for section_index, chapter_info in final_chapters.items():
        # Mark as hidden and Skip the current chapter if a hide flag is tripped
        if chapter_info['hidden']:
            sections.append({
                'hidden': True,
                'week': "WEEK {week}: ".format(week=section_index),
                'points': {
                    'total': 0,
                    'earned': 0,
                    'css_class': 'text-disabled'
                },
            })
            continue

        chapter = chapter_info['chapter']
        # get the points
        section_points = section_grades.get(chapter.url_name, {})

        units = list()
        for sequential in chapter.get_display_items():
            # Set hidden status of the sequential if it is gated/hidden from the user
            hidden = (
                gated_content and unicode(sequential.location) in gated_content or
                sequential.hide_from_toc
            )

            if hidden:
                continue

            for index, unit in enumerate(sequential.get_display_items()):
                css_class = 'dark-gray'
                if unit.graded:
                    total_excercises = 0
                    attempted_excercises = 0
                    unit_max_score = 0
                    unit_score = 0
                    for component in unit.get_display_items():
                        if component.category == 'problem':
                            if component.graded:
                                total_excercises += 1
                                attempted_excercises += is_attempted_internal(
                                    str(component.location), progress
                                )
                                (correct, total) = grades.get_score(
                                    student,
                                    component,
                                    create_module,
                                    scores_client,
                                    submissions_scores,
                                    max_scores_cache,
                                )
                                unit_max_score += total
                                unit_score += correct

                    if total_excercises:
                        css_class = 'blue'
                        if attempted_excercises == total_excercises:
                            css_class = 'green'
                            if unit_max_score and unit_score / unit_max_score < success_cutoff:
                                css_class = 'red'

                position = index + 1  # For jumping to the unit directly
                unit_context = {
                    'display_name': unit.display_name_with_default_escaped,
                    'position': position,
                    'css_class': css_class,
                    'courseware_url': reverse(
                        'courseware_position',
                        args=[
                            course.id,
                            chapter.url_name,
                            sequential.url_name,
                            position
                        ]
                    )
                }
                units.append(unit_context)

        competency = None
        if int(section_points.get('total')):
            competency = int(section_points.get('earned')) == int(section_points.get('total'))
        section_context = {
            'display_name': chapter.display_name_with_default_escaped,
            'url_name': chapter.url_name,
            'hidden': False,
            'rank': 1,
            'competency': competency,
            'points': {
                'total': int(section_points.get('total')),
                'earned': int(section_points.get('earned')),
                'css_class': section_points.get('css_class')
            },
            'participation': discussions_participated.get(chapter.url_name),
            'units': units,
            'week': "WEEK {week}: ".format(week=section_index),
        }
        sections.append(section_context)

    return sections
Beispiel #7
0
def toc_for_course(request, course, active_chapter, active_section, field_data_cache):
    '''
    Create a table of contents from the module store

    Return format:
    [ {'display_name': name, 'url_name': url_name,
       'sections': SECTIONS, 'active': bool}, ... ]

    where SECTIONS is a list
    [ {'display_name': name, 'url_name': url_name,
       'format': format, 'due': due, 'active' : bool, 'graded': bool}, ...]

    active is set for the section and chapter corresponding to the passed
    parameters, which are expected to be url_names of the chapter+section.
    Everything else comes from the xml, or defaults to "".

    chapters with name 'hidden' are skipped.

    NOTE: assumes that if we got this far, user has access to course.  Returns
    None if this is not the case.

    field_data_cache must include data from the course module and 2 levels of its descendents
    '''

    with modulestore().bulk_operations(course.id):
        course_module = get_module_for_descriptor(request.user, request, course, field_data_cache, course.id)
        if course_module is None:
            return None

        toc_chapters = list()
        chapters = course_module.get_display_items()

        # See if the course is gated by one or more content milestones
        required_content = milestones_helpers.get_required_content(course, request.user)

        # The user may not actually have to complete the entrance exam, if one is required
        if not user_must_complete_entrance_exam(request, request.user, course):
            required_content = [content for content in required_content if not content == course.entrance_exam_id]

        for chapter in chapters:
            # Only show required content, if there is required content
            # chapter.hide_from_toc is read-only (boo)
            local_hide_from_toc = False
            if required_content:
                if unicode(chapter.location) not in required_content:
                    local_hide_from_toc = True

            # Skip the current chapter if a hide flag is tripped
            if chapter.hide_from_toc or local_hide_from_toc:
                continue

            sections = list()
            for section in chapter.get_display_items():

                active = (chapter.url_name == active_chapter and
                          section.url_name == active_section)

                if not section.hide_from_toc:
                    sections.append({'display_name': section.display_name_with_default,
                                     'url_name': section.url_name,
                                     'format': section.format if section.format is not None else '',
                                     'due': get_extended_due_date(section),
                                     'active': active,
                                     'graded': section.graded,
                                     })
            toc_chapters.append({
                'display_name': chapter.display_name_with_default,
                'url_name': chapter.url_name,
                'sections': sections,
                'active': chapter.url_name == active_chapter
            })
        return toc_chapters
Beispiel #8
0
def toc_for_course(user, request, course, active_chapter, active_section, field_data_cache):
    '''
    Create a table of contents from the module store

    Return format:
    { 'chapters': [
            {'display_name': name, 'url_name': url_name, 'sections': SECTIONS, 'active': bool},
        ],
        'previous_of_active_section': {..},
        'next_of_active_section': {..}
    }

    where SECTIONS is a list
    [ {'display_name': name, 'url_name': url_name,
       'format': format, 'due': due, 'active' : bool, 'graded': bool}, ...]

    where previous_of_active_section and next_of_active_section have information on the
    next/previous sections of the active section.

    active is set for the section and chapter corresponding to the passed
    parameters, which are expected to be url_names of the chapter+section.
    Everything else comes from the xml, or defaults to "".

    chapters with name 'hidden' are skipped.

    NOTE: assumes that if we got this far, user has access to course.  Returns
    None if this is not the case.

    field_data_cache must include data from the course module and 2 levels of its descendants
    '''

    with modulestore().bulk_operations(course.id):
        course_module = get_module_for_descriptor(
            user, request, course, field_data_cache, course.id, course=course
        )
        if course_module is None:
            return None, None, None

        toc_chapters = list()
        chapters = course_module.get_display_items()

        # Check for content which needs to be completed
        # before the rest of the content is made available
        required_content = milestones_helpers.get_required_content(course, user)

        # Check for gated content
        gated_content = gating_api.get_gated_content(course, user)

        # The user may not actually have to complete the entrance exam, if one is required
        if not user_must_complete_entrance_exam(request, user, course):
            required_content = [content for content in required_content if not content == course.entrance_exam_id]

        previous_of_active_section, next_of_active_section = None, None
        last_processed_section, last_processed_chapter = None, None
        found_active_section = False
        for chapter in chapters:
            # Only show required content, if there is required content
            # chapter.hide_from_toc is read-only (bool)
            display_id = slugify(chapter.display_name_with_default_escaped)
            local_hide_from_toc = False
            if required_content:
                if unicode(chapter.location) not in required_content:
                    local_hide_from_toc = True

            # Skip the current chapter if a hide flag is tripped
            if chapter.hide_from_toc or local_hide_from_toc:
                continue

            sections = list()
            for section in chapter.get_display_items():
                # skip the section if it is gated/hidden from the user
                if gated_content and unicode(section.location) in gated_content:
                    continue
                if section.hide_from_toc:
                    continue

                is_section_active = (chapter.url_name == active_chapter and section.url_name == active_section)
                if is_section_active:
                    found_active_section = True

                section_context = {
                    'display_name': section.display_name_with_default_escaped,
                    'url_name': section.url_name,
                    'format': section.format if section.format is not None else '',
                    'due': section.due,
                    'active': is_section_active,
                    'graded': section.graded,
                }
                _add_timed_exam_info(user, course, section, section_context)

                # update next and previous of active section, if applicable
                if is_section_active:
                    if last_processed_section:
                        previous_of_active_section = last_processed_section.copy()
                        previous_of_active_section['chapter_url_name'] = last_processed_chapter.url_name
                elif found_active_section and not next_of_active_section:
                    next_of_active_section = section_context.copy()
                    next_of_active_section['chapter_url_name'] = chapter.url_name

                sections.append(section_context)
                last_processed_section = section_context
                last_processed_chapter = chapter

            toc_chapters.append({
                'display_name': chapter.display_name_with_default_escaped,
                'display_id': display_id,
                'url_name': chapter.url_name,
                'sections': sections,
                'active': chapter.url_name == active_chapter
            })
        return {
            'chapters': toc_chapters,
            'previous_of_active_section': previous_of_active_section,
            'next_of_active_section': next_of_active_section,
        }
Beispiel #9
0
def toc_for_course(user, request, course, active_chapter, active_section, field_data_cache):
    '''
    Create a table of contents from the module store

    Return format:
    [ {'display_name': name, 'url_name': url_name,
       'sections': SECTIONS, 'active': bool}, ... ]

    where SECTIONS is a list
    [ {'display_name': name, 'url_name': url_name,
       'format': format, 'due': due, 'active' : bool, 'graded': bool}, ...]

    active is set for the section and chapter corresponding to the passed
    parameters, which are expected to be url_names of the chapter+section.
    Everything else comes from the xml, or defaults to "".

    chapters with name 'hidden' are skipped.

    NOTE: assumes that if we got this far, user has access to course.  Returns
    None if this is not the case.

    field_data_cache must include data from the course module and 2 levels of its descendents
    '''

    with modulestore().bulk_operations(course.id):
        course_module = get_module_for_descriptor(
            user, request, course, field_data_cache, course.id, course=course
        )
        if course_module is None:
            return None

        toc_chapters = list()
        chapters = course_module.get_display_items()

        # See if the course is gated by one or more content milestones
        required_content = milestones_helpers.get_required_content(course, user)

        # The user may not actually have to complete the entrance exam, if one is required
        if not user_must_complete_entrance_exam(request, user, course):
            required_content = [content for content in required_content if not content == course.entrance_exam_id]

        for chapter in chapters:
            # Only show required content, if there is required content
            # chapter.hide_from_toc is read-only (boo)
            display_id = slugify(chapter.display_name_with_default)
            local_hide_from_toc = False
            if required_content:
                if unicode(chapter.location) not in required_content:
                    local_hide_from_toc = True

            # Skip the current chapter if a hide flag is tripped
            if chapter.hide_from_toc or local_hide_from_toc:
                continue

            sections = list()
            for section in chapter.get_display_items():

                active = (chapter.url_name == active_chapter and
                          section.url_name == active_section)

                if not section.hide_from_toc:
                    section_context = {
                        'display_name': section.display_name_with_default,
                        'url_name': section.url_name,
                        'format': section.format if section.format is not None else '',
                        'due': section.due,
                        'active': active,
                        'graded': section.graded,
                    }

                    #
                    # Add in rendering context if exam is a timed exam (which includes proctored)
                    #

                    section_is_time_limited = (
                        getattr(section, 'is_time_limited', False) and
                        settings.FEATURES.get('ENABLE_SPECIAL_EXAMS', False)
                    )
                    if section_is_time_limited:
                        # We need to import this here otherwise Lettuce test
                        # harness fails. When running in 'harvest' mode, the
                        # test service appears to get into trouble with
                        # circular references (not sure which as edx_proctoring.api
                        # doesn't import anything from edx-platform). Odd thing
                        # is that running: manage.py lms runserver --settings=acceptance
                        # works just fine, it's really a combination of Lettuce and the
                        # 'harvest' management command
                        #
                        # One idea is that there is some coupling between
                        # lettuce and the 'terrain' Djangoapps projects in /common
                        # This would need more investigation
                        from edx_proctoring.api import get_attempt_status_summary

                        #
                        # call into edx_proctoring subsystem
                        # to get relevant proctoring information regarding this
                        # level of the courseware
                        #
                        # This will return None, if (user, course_id, content_id)
                        # is not applicable
                        #
                        timed_exam_attempt_context = None
                        try:
                            timed_exam_attempt_context = get_attempt_status_summary(
                                user.id,
                                unicode(course.id),
                                unicode(section.location)
                            )
                        except Exception, ex:  # pylint: disable=broad-except
                            # safety net in case something blows up in edx_proctoring
                            # as this is just informational descriptions, it is better
                            # to log and continue (which is safe) than to have it be an
                            # unhandled exception
                            log.exception(ex)

                        if timed_exam_attempt_context:
                            # yes, user has proctoring context about
                            # this level of the courseware
                            # so add to the accordion data context
                            section_context.update({
                                'proctoring': timed_exam_attempt_context,
                            })

                    sections.append(section_context)
            toc_chapters.append({
                'display_name': chapter.display_name_with_default,
                'display_id': display_id,
                'url_name': chapter.url_name,
                'sections': sections,
                'active': chapter.url_name == active_chapter
            })
        return toc_chapters