예제 #1
0
    def render_to_fragment(self,
                           request,
                           course_id,
                           user_is_enrolled=True,
                           **kwargs):  # pylint: disable=arguments-differ
        """
        Renders the course outline as a fragment.
        """
        course_key = CourseKey.from_string(course_id)
        course_overview = get_course_overview_with_access(
            request.user,
            'load',
            course_key,
            check_if_enrolled=user_is_enrolled)
        course = modulestore().get_course(course_key)

        course_block_tree = get_course_outline_block_tree(
            request, course_id, request.user if user_is_enrolled else None)
        if not course_block_tree:
            return None

        context = {
            'csrf':
            csrf(request)['csrf_token'],
            'course':
            course_overview,
            'due_date_display_format':
            course.due_date_display_format,
            'blocks':
            course_block_tree,
            'enable_links':
            user_is_enrolled
            or course.course_visibility == COURSE_VISIBILITY_PUBLIC,
        }

        resume_block = get_resume_block(
            course_block_tree) if user_is_enrolled else None

        if not resume_block:
            self.mark_first_unit_to_resume(course_block_tree)

        xblock_display_names = self.create_xblock_id_and_name_dict(
            course_block_tree)
        gated_content = self.get_content_milestones(request, course_key)

        context['gated_content'] = gated_content
        context['xblock_display_names'] = xblock_display_names

        page_context = kwargs.get('page_context', None)
        if page_context:
            context['self_paced'] = page_context.get(
                'pacing_type', 'instructor_paced') == 'self_paced'

        # We're using this flag to prevent old self-paced dates from leaking out on courses not
        # managed by edx-when.
        context['in_edx_when'] = edx_when_api.is_enabled_for_course(course_key)

        html = render_to_string(
            'course_experience/course-outline-fragment.html', context)
        return Fragment(html)
    def render_to_fragment(self, request, course_id, user_is_enrolled=True, **kwargs):  # pylint: disable=arguments-differ
        """
        Renders the course outline as a fragment.
        """
        from lms.urls import RESET_COURSE_DEADLINES_NAME

        course_key = CourseKey.from_string(course_id)
        course_overview = get_course_overview_with_access(
            request.user, 'load', course_key, check_if_enrolled=user_is_enrolled
        )
        course = modulestore().get_course(course_key)

        course_block_tree = get_course_outline_block_tree(
            request, course_id, request.user if user_is_enrolled else None
        )
        if not course_block_tree:
            return None

        resume_block = get_resume_block(course_block_tree) if user_is_enrolled else None

        if not resume_block:
            self.mark_first_unit_to_resume(course_block_tree)

        xblock_display_names = self.create_xblock_id_and_name_dict(course_block_tree)
        gated_content = self.get_content_milestones(request, course_key)

        missed_deadlines, missed_gated_content = dates_banner_should_display(course_key, request.user)

        reset_deadlines_url = reverse(RESET_COURSE_DEADLINES_NAME)

        context = {
            'csrf': csrf(request)['csrf_token'],
            'course': course_overview,
            'due_date_display_format': course.due_date_display_format,
            'blocks': course_block_tree,
            'enable_links': user_is_enrolled or course.course_visibility == COURSE_VISIBILITY_PUBLIC,
            'course_key': course_key,
            'gated_content': gated_content,
            'xblock_display_names': xblock_display_names,
            'self_paced': course.self_paced,

            # We're using this flag to prevent old self-paced dates from leaking out on courses not
            # managed by edx-when.
            'in_edx_when': edx_when_api.is_enabled_for_course(course_key),
            'reset_deadlines_url': reset_deadlines_url,
            'verified_upgrade_link': verified_upgrade_deadline_link(request.user, course=course),
            'on_course_outline_page': True,
            'missed_deadlines': missed_deadlines,
            'missed_gated_content': missed_gated_content,
            'has_ended': course.has_ended(),
        }

        html = render_to_string('course_experience/course-outline-fragment.html', context)
        return Fragment(html)
예제 #3
0
def instructor_dashboard_2(request, course_id):
    """ Display the instructor dashboard for a course. """
    try:
        course_key = CourseKey.from_string(course_id)
    except InvalidKeyError:
        log.error(u"Unable to find course with course key %s while loading the Instructor Dashboard.", course_id)
        return HttpResponseServerError()

    course = get_course_by_id(course_key, depth=0)

    access = {
        'admin': request.user.is_staff,
        'instructor': bool(has_access(request.user, 'instructor', course)),
        'finance_admin': CourseFinanceAdminRole(course_key).has_user(request.user),
        'sales_admin': CourseSalesAdminRole(course_key).has_user(request.user),
        'staff': bool(has_access(request.user, 'staff', course)),
        'forum_admin': has_forum_access(request.user, course_key, FORUM_ROLE_ADMINISTRATOR),
        'data_researcher': request.user.has_perm(permissions.CAN_RESEARCH, course_key),
    }

    if not request.user.has_perm(permissions.VIEW_DASHBOARD, course_key):
        raise Http404()

    is_white_label = CourseMode.is_white_label(course_key)

    reports_enabled = configuration_helpers.get_value('SHOW_ECOMMERCE_REPORTS', False)

    sections = []
    if access['staff']:
        sections.extend([
            _section_course_info(course, access),
            _section_membership(course, access),
            _section_cohort_management(course, access),
            _section_discussions_management(course, access),
            _section_student_admin(course, access),
        ])
    if access['data_researcher']:
        sections.append(_section_data_download(course, access))

    analytics_dashboard_message = None
    if show_analytics_dashboard_message(course_key) and (access['staff'] or access['instructor']):
        # Construct a URL to the external analytics dashboard
        analytics_dashboard_url = '{0}/courses/{1}'.format(settings.ANALYTICS_DASHBOARD_URL, six.text_type(course_key))
        link_start = HTML(u"<a href=\"{}\" rel=\"noopener\" target=\"_blank\">").format(analytics_dashboard_url)
        analytics_dashboard_message = _(
            u"To gain insights into student enrollment and participation {link_start}"
            u"visit {analytics_dashboard_name}, our new course analytics product{link_end}."
        )
        analytics_dashboard_message = Text(analytics_dashboard_message).format(
            link_start=link_start, link_end=HTML("</a>"), analytics_dashboard_name=settings.ANALYTICS_DASHBOARD_NAME)

        # Temporarily show the "Analytics" section until we have a better way of linking to Insights
        sections.append(_section_analytics(course, access))

    # Check if there is corresponding entry in the CourseMode Table related to the Instructor Dashboard course
    course_mode_has_price = False
    paid_modes = CourseMode.paid_modes_for_course(course_key)
    if len(paid_modes) == 1:
        course_mode_has_price = True
    elif len(paid_modes) > 1:
        log.error(
            u"Course %s has %s course modes with payment options. Course must only have "
            u"one paid course mode to enable eCommerce options.",
            six.text_type(course_key), len(paid_modes)
        )

    if access['instructor'] and is_enabled_for_course(course_key):
        sections.insert(3, _section_extensions(course))

    # Gate access to course email by feature flag & by course-specific authorization
    if is_bulk_email_feature_enabled(course_key) and (access['staff'] or access['instructor']):
        sections.append(_section_send_email(course, access))

    # Gate access to Special Exam tab depending if either timed exams or proctored exams
    # are enabled in the course

    user_has_access = any([
        request.user.is_staff,
        CourseStaffRole(course_key).has_user(request.user),
        CourseInstructorRole(course_key).has_user(request.user)
    ])
    course_has_special_exams = course.enable_proctored_exams or course.enable_timed_exams
    can_see_special_exams = course_has_special_exams and user_has_access and settings.FEATURES.get(
        'ENABLE_SPECIAL_EXAMS', False)

    if can_see_special_exams:
        sections.append(_section_special_exams(course, access))
    # Certificates panel
    # This is used to generate example certificates
    # and enable self-generated certificates for a course.
    # Note: This is hidden for all CCXs
    certs_enabled = CertificateGenerationConfiguration.current().enabled and not hasattr(course_key, 'ccx')
    if certs_enabled and access['admin']:
        sections.append(_section_certificates(course))

    openassessment_blocks = modulestore().get_items(
        course_key, qualifiers={'category': 'openassessment'}
    )
    # filter out orphaned openassessment blocks
    openassessment_blocks = [
        block for block in openassessment_blocks if block.parent is not None
    ]
    if len(openassessment_blocks) > 0 and access['staff']:
        sections.append(_section_open_response_assessment(request, course, openassessment_blocks, access))

    disable_buttons = not CourseEnrollment.objects.is_small_course(course_key)

    certificate_white_list = CertificateWhitelist.get_certificate_white_list(course_key)
    generate_certificate_exceptions_url = reverse(
        'generate_certificate_exceptions',
        kwargs={'course_id': six.text_type(course_key), 'generate_for': ''}
    )
    generate_bulk_certificate_exceptions_url = reverse(
        'generate_bulk_certificate_exceptions',
        kwargs={'course_id': six.text_type(course_key)}
    )
    certificate_exception_view_url = reverse(
        'certificate_exception_view',
        kwargs={'course_id': six.text_type(course_key)}
    )

    certificate_invalidation_view_url = reverse(
        'certificate_invalidation_view',
        kwargs={'course_id': six.text_type(course_key)}
    )

    certificate_invalidations = CertificateInvalidation.get_certificate_invalidations(course_key)

    context = {
        'course': course,
        'studio_url': get_studio_url(course, 'course'),
        'sections': sections,
        'disable_buttons': disable_buttons,
        'analytics_dashboard_message': analytics_dashboard_message,
        'certificate_white_list': certificate_white_list,
        'certificate_invalidations': certificate_invalidations,
        'generate_certificate_exceptions_url': generate_certificate_exceptions_url,
        'generate_bulk_certificate_exceptions_url': generate_bulk_certificate_exceptions_url,
        'certificate_exception_view_url': certificate_exception_view_url,
        'certificate_invalidation_view_url': certificate_invalidation_view_url,
        'xqa_server': settings.FEATURES.get('XQA_SERVER', "http://your_xqa_server.com"),
    }

    return render_to_response('instructor/instructor_dashboard_2/instructor_dashboard_2.html', context)
def instructor_dashboard_2(request, course_id):
    """ Display the instructor dashboard for a course. """
    try:
        course_key = CourseKey.from_string(course_id)
    except InvalidKeyError:
        log.error(u"Unable to find course with course key %s while loading the Instructor Dashboard.", course_id)
        return HttpResponseServerError()

    course = get_course_by_id(course_key, depth=0)

    access = {
        'admin': request.user.is_staff,
        'instructor': bool(has_access(request.user, 'instructor', course)),
        'finance_admin': CourseFinanceAdminRole(course_key).has_user(request.user),
        'sales_admin': CourseSalesAdminRole(course_key).has_user(request.user),
        'staff': bool(has_access(request.user, 'staff', course)),
        'forum_admin': has_forum_access(request.user, course_key, FORUM_ROLE_ADMINISTRATOR),
    }

    if not access['staff']:
        raise Http404()

    is_white_label = CourseMode.is_white_label(course_key)

    reports_enabled = configuration_helpers.get_value('SHOW_ECOMMERCE_REPORTS', False)

    sections = [
        _section_course_info(course, access),
        _section_membership(course, access),
        _section_cohort_management(course, access),
        _section_discussions_management(course, access),
        _section_student_admin(course, access),
        _section_data_download(course, access),
    ]

    analytics_dashboard_message = None
    if show_analytics_dashboard_message(course_key):
        # Construct a URL to the external analytics dashboard
        analytics_dashboard_url = '{0}/courses/{1}'.format(settings.ANALYTICS_DASHBOARD_URL, unicode(course_key))
        link_start = HTML(u"<a href=\"{}\" target=\"_blank\">").format(analytics_dashboard_url)
        analytics_dashboard_message = _(
            u"To gain insights into student enrollment and participation {link_start}"
            u"visit {analytics_dashboard_name}, our new course analytics product{link_end}."
        )
        analytics_dashboard_message = Text(analytics_dashboard_message).format(
            link_start=link_start, link_end=HTML("</a>"), analytics_dashboard_name=settings.ANALYTICS_DASHBOARD_NAME)

        # Temporarily show the "Analytics" section until we have a better way of linking to Insights
        sections.append(_section_analytics(course, access))

    # Check if there is corresponding entry in the CourseMode Table related to the Instructor Dashboard course
    course_mode_has_price = False
    paid_modes = CourseMode.paid_modes_for_course(course_key)
    if len(paid_modes) == 1:
        course_mode_has_price = True
    elif len(paid_modes) > 1:
        log.error(
            u"Course %s has %s course modes with payment options. Course must only have "
            u"one paid course mode to enable eCommerce options.",
            unicode(course_key), len(paid_modes)
        )

    if access['instructor'] and is_enabled_for_course(course_key, request=request):
        sections.insert(3, _section_extensions(course))

    # Gate access to course email by feature flag & by course-specific authorization
    if BulkEmailFlag.feature_enabled(course_key):
        sections.append(_section_send_email(course, access))

    # Gate access to Metrics tab by featue flag and staff authorization
    if settings.FEATURES['CLASS_DASHBOARD'] and access['staff']:
        sections.append(_section_metrics(course, access))

    # Gate access to Ecommerce tab
    if course_mode_has_price and (access['finance_admin'] or access['sales_admin']):
        sections.append(_section_e_commerce(course, access, paid_modes[0], is_white_label, reports_enabled))

    # Gate access to Special Exam tab depending if either timed exams or proctored exams
    # are enabled in the course

    user_has_access = any([
        request.user.is_staff,
        CourseStaffRole(course_key).has_user(request.user),
        CourseInstructorRole(course_key).has_user(request.user)
    ])
    course_has_special_exams = course.enable_proctored_exams or course.enable_timed_exams
    can_see_special_exams = course_has_special_exams and user_has_access and settings.FEATURES.get(
        'ENABLE_SPECIAL_EXAMS', False)

    if can_see_special_exams:
        sections.append(_section_special_exams(course, access))

    # Certificates panel
    # This is used to generate example certificates
    # and enable self-generated certificates for a course.
    # Note: This is hidden for all CCXs
    certs_enabled = CertificateGenerationConfiguration.current().enabled and not hasattr(course_key, 'ccx')
    if certs_enabled and access['admin']:
        sections.append(_section_certificates(course))

    openassessment_blocks = modulestore().get_items(
        course_key, qualifiers={'category': 'openassessment'}
    )
    # filter out orphaned openassessment blocks
    openassessment_blocks = [
        block for block in openassessment_blocks if block.parent is not None
    ]
    if len(openassessment_blocks) > 0:
        sections.append(_section_open_response_assessment(request, course, openassessment_blocks, access))

    disable_buttons = not _is_small_course(course_key)

    certificate_white_list = CertificateWhitelist.get_certificate_white_list(course_key)
    generate_certificate_exceptions_url = reverse(
        'generate_certificate_exceptions',
        kwargs={'course_id': unicode(course_key), 'generate_for': ''}
    )
    generate_bulk_certificate_exceptions_url = reverse(
        'generate_bulk_certificate_exceptions',
        kwargs={'course_id': unicode(course_key)}
    )
    certificate_exception_view_url = reverse(
        'certificate_exception_view',
        kwargs={'course_id': unicode(course_key)}
    )

    certificate_invalidation_view_url = reverse(
        'certificate_invalidation_view',
        kwargs={'course_id': unicode(course_key)}
    )

    certificate_invalidations = CertificateInvalidation.get_certificate_invalidations(course_key)

    context = {
        'course': course,
        'studio_url': get_studio_url(course, 'course'),
        'sections': sections,
        'disable_buttons': disable_buttons,
        'analytics_dashboard_message': analytics_dashboard_message,
        'certificate_white_list': certificate_white_list,
        'certificate_invalidations': certificate_invalidations,
        'generate_certificate_exceptions_url': generate_certificate_exceptions_url,
        'generate_bulk_certificate_exceptions_url': generate_bulk_certificate_exceptions_url,
        'certificate_exception_view_url': certificate_exception_view_url,
        'certificate_invalidation_view_url': certificate_invalidation_view_url,
    }

    return render_to_response('instructor/instructor_dashboard_2/instructor_dashboard_2.html', context)
    def render_to_fragment(self,
                           request,
                           course_id,
                           user_is_enrolled=True,
                           **kwargs):  # pylint: disable=arguments-differ
        """
        Renders the course outline as a fragment.
        """
        from lms.urls import RESET_COURSE_DEADLINES_NAME
        from openedx.features.course_experience.urls import COURSE_HOME_VIEW_NAME

        course_key = CourseKey.from_string(course_id)
        course_overview = get_course_overview_with_access(
            request.user,
            'load',
            course_key,
            check_if_enrolled=user_is_enrolled)
        course = modulestore().get_course(course_key)

        course_block_tree = get_course_outline_block_tree(
            request, course_id, request.user if user_is_enrolled else None)
        if not course_block_tree:
            return None

        context = {
            'csrf': csrf(request)['csrf_token'],
            'course': course_overview,
            'due_date_display_format': course.due_date_display_format,
            'blocks': course_block_tree,
            'enable_links': user_is_enrolled
            or course.course_visibility == COURSE_VISIBILITY_PUBLIC,
            'course_key': course_key,
        }

        resume_block = get_resume_block(
            course_block_tree) if user_is_enrolled else None

        if not resume_block:
            self.mark_first_unit_to_resume(course_block_tree)

        xblock_display_names = self.create_xblock_id_and_name_dict(
            course_block_tree)
        gated_content = self.get_content_milestones(request, course_key)

        context['gated_content'] = gated_content
        context['xblock_display_names'] = xblock_display_names

        page_context = kwargs.get('page_context', None)
        if page_context:
            context['self_paced'] = page_context.get(
                'pacing_type', 'instructor_paced') == 'self_paced'

        # We're using this flag to prevent old self-paced dates from leaking out on courses not
        # managed by edx-when.
        context['in_edx_when'] = edx_when_api.is_enabled_for_course(course_key)

        reset_deadlines_url = reverse(RESET_COURSE_DEADLINES_NAME)
        reset_deadlines_redirect_url_base = COURSE_HOME_VIEW_NAME

        course_enrollment = None
        if not request.user.is_anonymous:
            course_enrollment = CourseEnrollment.objects.filter(
                course=course_overview, user=request.user).filter(
                    Q(mode=CourseMode.AUDIT)
                    | Q(mode=CourseMode.VERIFIED)).first()

        context['reset_deadlines_url'] = reset_deadlines_url
        context[
            'reset_deadlines_redirect_url_base'] = reset_deadlines_redirect_url_base
        context['reset_deadlines_redirect_url_id_dict'] = {
            'course_id': str(course.id)
        }
        context['enrollment_mode'] = getattr(course_enrollment, 'mode', None)
        context['verified_upgrade_link'] = verified_upgrade_deadline_link(
            request.user, course=course),
        context['on_course_outline_page'] = True,

        html = render_to_string(
            'course_experience/course-outline-fragment.html', context)
        return Fragment(html)
예제 #6
0
 def test_is_enabled(self):
     items = make_items()
     course_id = items[0][0].course_key
     assert not api.is_enabled_for_course(course_id)
     api.set_dates_for_course(course_id, items)
     assert api.is_enabled_for_course(course_id)