def _section_membership(course, access):
    """ Provide data for the corresponding dashboard section """
    course_key = course.id
    section_data = {
        "section_key": "membership",
        "section_display_name": _("Membership"),
        "access": access,
        "enroll_button_url": reverse(
            "students_update_enrollment", kwargs={"course_id": course_key.to_deprecated_string()}
        ),
        "unenroll_button_url": reverse(
            "students_update_enrollment", kwargs={"course_id": course_key.to_deprecated_string()}
        ),
        "upload_student_csv_button_url": reverse(
            "register_and_enroll_students", kwargs={"course_id": course_key.to_deprecated_string()}
        ),
        "modify_beta_testers_button_url": reverse(
            "bulk_beta_modify_access", kwargs={"course_id": course_key.to_deprecated_string()}
        ),
        "list_course_role_members_url": reverse(
            "list_course_role_members", kwargs={"course_id": course_key.to_deprecated_string()}
        ),
        "modify_access_url": reverse("modify_access", kwargs={"course_id": course_key.to_deprecated_string()}),
        "list_forum_members_url": reverse(
            "list_forum_members", kwargs={"course_id": course_key.to_deprecated_string()}
        ),
        "update_forum_role_membership_url": reverse(
            "update_forum_role_membership", kwargs={"course_id": course_key.to_deprecated_string()}
        ),
        "cohorts_ajax_url": reverse("cohorts", kwargs={"course_key_string": course_key.to_deprecated_string()}),
        "advanced_settings_url": get_studio_url(course, "settings/advanced"),
    }
    return section_data
Esempio n. 2
0
def course_info(request, course_id):
    """
    Display the course's info.html, or 404 if there is no such course.

    Assumes the course_id is in a valid format.
    """
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    course = get_course_with_access(request.user, "load", course_key)
    staff_access = has_access(request.user, "staff", course)
    masq = setup_masquerade(request, staff_access)  # allow staff to toggle masquerade on info page
    reverifications = fetch_reverify_banner_info(request, course_key)
    studio_url = get_studio_url(course_key, "course_info")

    context = {
        "request": request,
        "course_id": course_key.to_deprecated_string(),
        "cache": None,
        "course": course,
        "staff_access": staff_access,
        "masquerade": masq,
        "studio_url": studio_url,
        "reverifications": reverifications,
    }

    return render_to_response("courseware/info.html", context)
Esempio n. 3
0
def course_info(request, course_id):
    """
    Display the course's info.html, or 404 if there is no such course.

    Assumes the course_id is in a valid format.
    """
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    course = get_course_with_access(request.user, 'load', course_key)
    staff_access = has_access(request.user, 'staff', course)
    masq = setup_masquerade(
        request, staff_access)  # allow staff to toggle masquerade on info page
    reverifications = fetch_reverify_banner_info(request, course_key)
    studio_url = get_studio_url(course_key, 'course_info')

    context = {
        'request': request,
        'course_id': course_key.to_deprecated_string(),
        'cache': None,
        'course': course,
        'staff_access': staff_access,
        'masquerade': masq,
        'studio_url': studio_url,
        'reverifications': reverifications,
    }

    return render_to_response('courseware/info.html', context)
Esempio n. 4
0
def course_info(request, course_id):
    """
    Display the course's info.html, or 404 if there is no such course.

    Assumes the course_id is in a valid format.
    """
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    course = get_course_with_access(request.user, 'load', course_key)
    staff_access = has_access(request.user, 'staff', course)
    masq = setup_masquerade(request, staff_access)    # allow staff to toggle masquerade on info page
    reverifications = fetch_reverify_banner_info(request, course_key)
    studio_url = get_studio_url(course_key, 'course_info')

    context = {
        'request': request,
        'course_id': course_key.to_deprecated_string(),
        'cache': None,
        'course': course,
        'staff_access': staff_access,
        'masquerade': masq,
        'studio_url': studio_url,
        'reverifications': reverifications,
    }

    return render_to_response('courseware/info.html', context)
Esempio n. 5
0
def _progress(request, course_key, student_id):
    """
    Unwrapped version of "progress".

    User progress. We show the grade bar and every problem score.

    Course staff are allowed to see the progress of students in their class.
    """
    course = get_course_with_access(request.user,
                                    'load',
                                    course_key,
                                    depth=None,
                                    check_if_enrolled=True)

    # check to see if there is a required survey that must be taken before
    # the user can access the course.
    if survey.utils.must_answer_survey(course, request.user):
        return redirect(reverse('course_survey', args=[unicode(course.id)]))

    staff_access = has_access(request.user, 'staff', course)

    if student_id is None or student_id == request.user.id:
        # always allowed to see your own profile
        student = request.user
    else:
        # Requesting access to a different student's profile
        if not staff_access:
            raise Http404
        student = User.objects.get(id=int(student_id))

    # NOTE: To make sure impersonation by instructor works, use
    # student instead of request.user in the rest of the function.

    # The pre-fetching of groups is done to make auth checks not require an
    # additional DB lookup (this kills the Progress page in particular).
    student = User.objects.prefetch_related("groups").get(id=student.id)

    courseware_summary = grades.progress_summary(student, request, course)
    studio_url = get_studio_url(course, 'settings/grading')
    grade_summary = grades.grade(student, request, course)

    if courseware_summary is None:
        #This means the student didn't have access to the course (which the instructor requested)
        raise Http404

    context = {
        'course': course,
        'courseware_summary': courseware_summary,
        'studio_url': studio_url,
        'grade_summary': grade_summary,
        'staff_access': staff_access,
        'student': student,
        'reverifications': fetch_reverify_banner_info(request, course_key)
    }

    with grades.manual_transaction():
        response = render_to_response('courseware/progress.html', context)

    return response
Esempio n. 6
0
def course_about(request, course_id):
    """
    Display the course's about page.

    Assumes the course_id is in a valid format.
    """

    if microsite.get_value('ENABLE_MKTG_SITE',
                           settings.FEATURES.get('ENABLE_MKTG_SITE', False)):
        raise Http404
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    course = get_course_with_access(request.user, 'see_exists', course_key)
    registered = registered_for_course(course, request.user)
    staff_access = has_access(request.user, 'staff', course)
    studio_url = get_studio_url(course_key, 'settings/details')

    if has_access(request.user, 'load', course):
        course_target = reverse('info',
                                args=[course.id.to_deprecated_string()])
    else:
        course_target = reverse('about_course',
                                args=[course.id.to_deprecated_string()])

    show_courseware_link = (has_access(request.user, 'load', course)
                            or settings.FEATURES.get('ENABLE_LMS_MIGRATION'))

    # Note: this is a flow for payment for course registration, not the Verified Certificate flow.
    registration_price = 0
    in_cart = False
    reg_then_add_to_cart_link = ""
    if (settings.FEATURES.get('ENABLE_SHOPPING_CART')
            and settings.FEATURES.get('ENABLE_PAID_COURSE_REGISTRATION')):
        registration_price = CourseMode.min_course_price_for_currency(
            course_key, settings.PAID_COURSE_REGISTRATION_CURRENCY[0])
        if request.user.is_authenticated():
            cart = shoppingcart.models.Order.get_cart_for_user(request.user)
            in_cart = shoppingcart.models.PaidCourseRegistration.contained_in_order(
                cart, course_key)

        reg_then_add_to_cart_link = "{reg_url}?course_id={course_id}&enrollment_action=add_to_cart".format(
            reg_url=reverse('register_user'),
            course_id=course.id.to_deprecated_string())

    # see if we have already filled up all allowed enrollments
    is_course_full = CourseEnrollment.is_course_full(course)

    return render_to_response(
        'courseware/course_about.html', {
            'course': course,
            'staff_access': staff_access,
            'studio_url': studio_url,
            'registered': registered,
            'course_target': course_target,
            'registration_price': registration_price,
            'in_cart': in_cart,
            'reg_then_add_to_cart_link': reg_then_add_to_cart_link,
            'show_courseware_link': show_courseware_link,
            'is_course_full': is_course_full
        })
Esempio n. 7
0
def course_info(request, course_id):
    """
    Display the course's info.html, or 404 if there is no such course.

    Assumes the course_id is in a valid format.
    """

    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)

    with modulestore().bulk_operations(course_key):
        course = get_course_with_access(request.user, 'load', course_key)

        # check to see if there is a required survey that must be taken before
        # the user can access the course.
        if request.user.is_authenticated() and survey.utils.must_answer_survey(
                course, request.user):
            return redirect(reverse('course_survey',
                                    args=[unicode(course.id)]))

        staff_access = has_access(request.user, 'staff', course)
        masq = setup_masquerade(
            request,
            staff_access)  # allow staff to toggle masquerade on info page
        reverifications = fetch_reverify_banner_info(request, course_key)
        studio_url = get_studio_url(course, 'course_info')

        # link to where the student should go to enroll in the course:
        # about page if there is not marketing site, SITE_NAME if there is
        url_to_enroll = reverse(course_about, args=[course_id])
        if settings.FEATURES.get('ENABLE_MKTG_SITE'):
            url_to_enroll = marketing_link('COURSES')

        show_enroll_banner = request.user.is_authenticated(
        ) and not CourseEnrollment.is_enrolled(request.user, course.id)

        context = {
            'request': request,
            'course_id': course_key.to_deprecated_string(),
            'cache': None,
            'course': course,
            'staff_access': staff_access,
            'masquerade': masq,
            'studio_url': studio_url,
            'reverifications': reverifications,
            'show_enroll_banner': show_enroll_banner,
            'url_to_enroll': url_to_enroll,
        }

        now = datetime.now(UTC())
        effective_start = _adjust_start_date_for_beta_testers(
            request.user, course, course_key)
        if staff_access and now < effective_start:
            # Disable student view button if user is staff and
            # course is not yet visible to students.
            context['disable_student_access'] = True

        return render_to_response('courseware/info.html', context)
Esempio n. 8
0
def course_about(request, course_id):
    """
    Display the course's about page.

    Assumes the course_id is in a valid format.
    """

    if microsite.get_value(
        'ENABLE_MKTG_SITE',
        settings.FEATURES.get('ENABLE_MKTG_SITE', False)
    ):
        raise Http404
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    course = get_course_with_access(request.user, 'see_exists', course_key)
    registered = registered_for_course(course, request.user)
    staff_access = has_access(request.user, 'staff', course)
    studio_url = get_studio_url(course_key, 'settings/details')

    if has_access(request.user, 'load', course):
        course_target = reverse('info', args=[course.id.to_deprecated_string()])
    else:
        course_target = reverse('about_course', args=[course.id.to_deprecated_string()])

    show_courseware_link = (has_access(request.user, 'load', course) or
                            settings.FEATURES.get('ENABLE_LMS_MIGRATION'))

    # Note: this is a flow for payment for course registration, not the Verified Certificate flow.
    registration_price = 0
    in_cart = False
    reg_then_add_to_cart_link = ""
    if (settings.FEATURES.get('ENABLE_SHOPPING_CART') and
        settings.FEATURES.get('ENABLE_PAID_COURSE_REGISTRATION')):
        registration_price = CourseMode.min_course_price_for_currency(course_key,
                                                                      settings.PAID_COURSE_REGISTRATION_CURRENCY[0])
        if request.user.is_authenticated():
            cart = shoppingcart.models.Order.get_cart_for_user(request.user)
            in_cart = shoppingcart.models.PaidCourseRegistration.contained_in_order(cart, course_key)

        reg_then_add_to_cart_link = "{reg_url}?course_id={course_id}&enrollment_action=add_to_cart".format(
            reg_url=reverse('register_user'), course_id=course.id.to_deprecated_string())

    # see if we have already filled up all allowed enrollments
    is_course_full = CourseEnrollment.is_course_full(course)

    return render_to_response('courseware/course_about.html', {
        'course': course,
        'staff_access': staff_access,
        'studio_url': studio_url,
        'registered': registered,
        'course_target': course_target,
        'registration_price': registration_price,
        'in_cart': in_cart,
        'reg_then_add_to_cart_link': reg_then_add_to_cart_link,
        'show_courseware_link': show_courseware_link,
        'is_course_full': is_course_full
    })
Esempio n. 9
0
def course_about(request, course_id):
    """
    Display the course's about page.

    Assumes the course_id is in a valid format.
    """

    if microsite.get_value("ENABLE_MKTG_SITE", settings.FEATURES.get("ENABLE_MKTG_SITE", False)):
        raise Http404

    course = get_course_with_access(request.user, course_id, "see_exists")
    registered = registered_for_course(course, request.user)
    staff_access = has_access(request.user, course, "staff")
    studio_url = get_studio_url(course_id, "settings/details")

    if has_access(request.user, course, "load"):
        course_target = reverse("info", args=[course.id])
    else:
        course_target = reverse("about_course", args=[course.id])

    show_courseware_link = has_access(request.user, course, "load") or settings.FEATURES.get("ENABLE_LMS_MIGRATION")

    # Note: this is a flow for payment for course registration, not the Verified Certificate flow.
    registration_price = 0
    in_cart = False
    reg_then_add_to_cart_link = ""
    if settings.FEATURES.get("ENABLE_SHOPPING_CART") and settings.FEATURES.get("ENABLE_PAID_COURSE_REGISTRATION"):
        registration_price = CourseMode.min_course_price_for_currency(
            course_id, settings.PAID_COURSE_REGISTRATION_CURRENCY[0]
        )
        if request.user.is_authenticated():
            cart = shoppingcart.models.Order.get_cart_for_user(request.user)
            in_cart = shoppingcart.models.PaidCourseRegistration.contained_in_order(cart, course_id)

        reg_then_add_to_cart_link = "{reg_url}?course_id={course_id}&enrollment_action=add_to_cart".format(
            reg_url=reverse("register_user"), course_id=course.id
        )

    # see if we have already filled up all allowed enrollments
    is_course_full = CourseEnrollment.is_course_full(course)

    return render_to_response(
        "courseware/course_about.html",
        {
            "course": course,
            "staff_access": staff_access,
            "studio_url": studio_url,
            "registered": registered,
            "course_target": course_target,
            "registration_price": registration_price,
            "in_cart": in_cart,
            "reg_then_add_to_cart_link": reg_then_add_to_cart_link,
            "show_courseware_link": show_courseware_link,
            "is_course_full": is_course_full,
        },
    )
Esempio n. 10
0
def _progress(request, course_key, student_id):
    """
    Unwrapped version of "progress".

    User progress. We show the grade bar and every problem score.

    Course staff are allowed to see the progress of students in their class.
    """
    course = get_course_with_access(request.user, 'load', course_key, depth=None, check_if_enrolled=True)

    # check to see if there is a required survey that must be taken before
    # the user can access the course.
    if survey.utils.must_answer_survey(course, request.user):
        return redirect(reverse('course_survey', args=[unicode(course.id)]))

    staff_access = has_access(request.user, 'staff', course)

    if student_id is None or student_id == request.user.id:
        # always allowed to see your own profile
        student = request.user
    else:
        # Requesting access to a different student's profile
        if not staff_access:
            raise Http404
        student = User.objects.get(id=int(student_id))

    # NOTE: To make sure impersonation by instructor works, use
    # student instead of request.user in the rest of the function.

    # The pre-fetching of groups is done to make auth checks not require an
    # additional DB lookup (this kills the Progress page in particular).
    student = User.objects.prefetch_related("groups").get(id=student.id)

    courseware_summary = grades.progress_summary(student, request, course)
    studio_url = get_studio_url(course, 'settings/grading')
    grade_summary = grades.grade(student, request, course)

    if courseware_summary is None:
        #This means the student didn't have access to the course (which the instructor requested)
        raise Http404

    context = {
        'course': course,
        'courseware_summary': courseware_summary,
        'studio_url': studio_url,
        'grade_summary': grade_summary,
        'staff_access': staff_access,
        'student': student,
        'reverifications': fetch_reverify_banner_info(request, course_key)
    }

    with grades.manual_transaction():
        response = render_to_response('courseware/progress.html', context)

    return response
Esempio n. 11
0
def course_info(request, course_id):
    """
    Display the course's info.html, or 404 if there is no such course.

    Assumes the course_id is in a valid format.
    """

    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)

    with modulestore().bulk_operations(course_key):
        course = get_course_with_access(request.user, "load", course_key)

        # check to see if there is a required survey that must be taken before
        # the user can access the course.
        if request.user.is_authenticated() and survey.utils.must_answer_survey(course, request.user):
            return redirect(reverse("course_survey", args=[unicode(course.id)]))

        staff_access = has_access(request.user, "staff", course)
        masquerade = setup_masquerade(request, course_key, staff_access)  # allow staff to masquerade on the info page
        reverifications = fetch_reverify_banner_info(request, course_key)
        studio_url = get_studio_url(course, "course_info")

        # link to where the student should go to enroll in the course:
        # about page if there is not marketing site, SITE_NAME if there is
        url_to_enroll = reverse(course_about, args=[course_id])
        if settings.FEATURES.get("ENABLE_MKTG_SITE"):
            url_to_enroll = marketing_link("COURSES")

        show_enroll_banner = request.user.is_authenticated() and not CourseEnrollment.is_enrolled(
            request.user, course.id
        )

        context = {
            "request": request,
            "course_id": course_key.to_deprecated_string(),
            "cache": None,
            "course": course,
            "staff_access": staff_access,
            "masquerade": masquerade,
            "studio_url": studio_url,
            "reverifications": reverifications,
            "show_enroll_banner": show_enroll_banner,
            "url_to_enroll": url_to_enroll,
        }

        now = datetime.now(UTC())
        effective_start = _adjust_start_date_for_beta_testers(request.user, course, course_key)
        if staff_access and now < effective_start:
            # Disable student view button if user is staff and
            # course is not yet visible to students.
            context["disable_student_access"] = True

        return render_to_response("courseware/info.html", context)
Esempio n. 12
0
def _progress(request, course_id, student_id):
    """
    Unwrapped version of "progress".

    User progress. We show the grade bar and every problem score.

    Course staff are allowed to see the progress of students in their class.
    """
    course = get_course_with_access(request.user, course_id, "load", depth=None)
    staff_access = has_access(request.user, course, "staff")

    if student_id is None or student_id == request.user.id:
        # always allowed to see your own profile
        student = request.user
    else:
        # Requesting access to a different student's profile
        if not staff_access:
            raise Http404
        student = User.objects.get(id=int(student_id))

    # NOTE: To make sure impersonation by instructor works, use
    # student instead of request.user in the rest of the function.

    # The pre-fetching of groups is done to make auth checks not require an
    # additional DB lookup (this kills the Progress page in particular).
    student = User.objects.prefetch_related("groups").get(id=student.id)

    courseware_summary = grades.progress_summary(student, request, course)
    studio_url = get_studio_url(course_id, "settings/grading")
    grade_summary = grades.grade(student, request, course)

    if courseware_summary is None:
        # This means the student didn't have access to the course (which the instructor requested)
        raise Http404

    context = {
        "course": course,
        "courseware_summary": courseware_summary,
        "studio_url": studio_url,
        "grade_summary": grade_summary,
        "staff_access": staff_access,
        "student": student,
        "reverifications": fetch_reverify_banner_info(request, course_id),
    }

    with grades.manual_transaction():
        response = render_to_response("courseware/progress.html", context)

    return response
Esempio n. 13
0
def course_info(request, course_id):
    """
    Display the course's info.html, or 404 if there is no such course.

    Assumes the course_id is in a valid format.
    """

    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)

    with modulestore().bulk_operations(course_key):
        course = get_course_with_access(request.user, 'load', course_key)
        staff_access = has_access(request.user, 'staff', course)
        masq = setup_masquerade(request, staff_access)    # allow staff to toggle masquerade on info page
        reverifications = fetch_reverify_banner_info(request, course_key)
        studio_url = get_studio_url(course, 'course_info')

        # link to where the student should go to enroll in the course:
        # about page if there is not marketing site, SITE_NAME if there is
        url_to_enroll = reverse(course_about, args=[course_id])
        if settings.FEATURES.get('ENABLE_MKTG_SITE'):
            url_to_enroll = marketing_link('COURSES')

        show_enroll_banner = request.user.is_authenticated() and not CourseEnrollment.is_enrolled(request.user, course.id)

        context = {
            'request': request,
            'course_id': course_key.to_deprecated_string(),
            'cache': None,
            'course': course,
            'staff_access': staff_access,
            'masquerade': masq,
            'studio_url': studio_url,
            'reverifications': reverifications,
            'show_enroll_banner': show_enroll_banner,
            'url_to_enroll': url_to_enroll,
        }

        now = datetime.now(UTC())
        effective_start = _adjust_start_date_for_beta_testers(request.user, course, course_key)
        if staff_access and now < effective_start:
            # Disable student view button if user is staff and
            # course is not yet visible to students.
            context['disable_student_access'] = True

        return render_to_response('courseware/info.html', context)
def _section_membership(course, access):
    """ Provide data for the corresponding dashboard section """
    course_key = course.id
    section_data = {
        'section_key': 'membership',
        'section_display_name': _('Membership'),
        'access': access,
        'enroll_button_url': reverse('students_update_enrollment', kwargs={'course_id': course_key.to_deprecated_string()}),
        'unenroll_button_url': reverse('students_update_enrollment', kwargs={'course_id': course_key.to_deprecated_string()}),
        'modify_beta_testers_button_url': reverse('bulk_beta_modify_access', kwargs={'course_id': course_key.to_deprecated_string()}),
        'list_course_role_members_url': reverse('list_course_role_members', kwargs={'course_id': course_key.to_deprecated_string()}),
        'modify_access_url': reverse('modify_access', kwargs={'course_id': course_key.to_deprecated_string()}),
        'list_forum_members_url': reverse('list_forum_members', kwargs={'course_id': course_key.to_deprecated_string()}),
        'update_forum_role_membership_url': reverse('update_forum_role_membership', kwargs={'course_id': course_key.to_deprecated_string()}),
        'cohorts_ajax_url': reverse('cohorts', kwargs={'course_key_string': course_key.to_deprecated_string()}),
        'advanced_settings_url': get_studio_url(course, 'settings/advanced'),
    }
    return section_data
Esempio n. 15
0
def _section_membership(course, access):
    """ Provide data for the corresponding dashboard section """
    course_key = course.id
    section_data = {
        'section_key': 'membership',
        'section_display_name': _('Membership'),
        'access': access,
        'enroll_button_url': reverse('students_update_enrollment', kwargs={'course_id': course_key.to_deprecated_string()}),
        'unenroll_button_url': reverse('students_update_enrollment', kwargs={'course_id': course_key.to_deprecated_string()}),
        'upload_student_csv_button_url': reverse('register_and_enroll_students', kwargs={'course_id': course_key.to_deprecated_string()}),
        'modify_beta_testers_button_url': reverse('bulk_beta_modify_access', kwargs={'course_id': course_key.to_deprecated_string()}),
        'list_course_role_members_url': reverse('list_course_role_members', kwargs={'course_id': course_key.to_deprecated_string()}),
        'modify_access_url': reverse('modify_access', kwargs={'course_id': course_key.to_deprecated_string()}),
        'list_forum_members_url': reverse('list_forum_members', kwargs={'course_id': course_key.to_deprecated_string()}),
        'update_forum_role_membership_url': reverse('update_forum_role_membership', kwargs={'course_id': course_key.to_deprecated_string()}),
        'cohorts_ajax_url': reverse('cohorts', kwargs={'course_key_string': course_key.to_deprecated_string()}),
        'advanced_settings_url': get_studio_url(course, 'settings/advanced'),
    }
    return section_data
Esempio n. 16
0
def course_info(request, course_id):
    """
    Display the course's info.html, or 404 if there is no such course.

    Assumes the course_id is in a valid format.
    """

    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)

    course = get_course_with_access(request.user, 'load', course_key)
    staff_access = has_access(request.user, 'staff', course)
    masq = setup_masquerade(
        request, staff_access)  # allow staff to toggle masquerade on info page
    reverifications = fetch_reverify_banner_info(request, course_key)
    studio_url = get_studio_url(course, 'course_info')

    # link to where the student should go to enroll in the course:
    # about page if there is not marketing site, SITE_NAME if there is
    url_to_enroll = reverse(course_about, args=[course_id])
    if settings.FEATURES.get('ENABLE_MKTG_SITE'):
        url_to_enroll = marketing_link('COURSES')

    show_enroll_banner = request.user.is_authenticated(
    ) and not CourseEnrollment.is_enrolled(request.user, course.id)

    context = {
        'request': request,
        'course_id': course_key.to_deprecated_string(),
        'cache': None,
        'course': course,
        'staff_access': staff_access,
        'masquerade': masq,
        'studio_url': studio_url,
        'reverifications': reverifications,
        'show_enroll_banner': show_enroll_banner,
        'url_to_enroll': url_to_enroll,
    }

    return render_to_response('courseware/info.html', context)
Esempio n. 17
0
def course_info(request, course_id):
    """
    Display the course's info.html, or 404 if there is no such course.

    Assumes the course_id is in a valid format.
    """

    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)

    course = get_course_with_access(request.user, 'load', course_key)
    staff_access = has_access(request.user, 'staff', course)
    masq = setup_masquerade(request, staff_access)    # allow staff to toggle masquerade on info page
    reverifications = fetch_reverify_banner_info(request, course_key)
    studio_url = get_studio_url(course, 'course_info')

    # link to where the student should go to enroll in the course:
    # about page if there is not marketing site, SITE_NAME if there is
    url_to_enroll = reverse(course_about, args=[course_id])
    if settings.FEATURES.get('ENABLE_MKTG_SITE'):
        url_to_enroll = marketing_link('COURSES')

    show_enroll_banner = request.user.is_authenticated() and not CourseEnrollment.is_enrolled(request.user, course.id)

    context = {
        'request': request,
        'course_id': course_key.to_deprecated_string(),
        'cache': None,
        'course': course,
        'staff_access': staff_access,
        'masquerade': masq,
        'studio_url': studio_url,
        'reverifications': reverifications,
        'show_enroll_banner': show_enroll_banner,
        'url_to_enroll': url_to_enroll,
    }

    return render_to_response('courseware/info.html', context)
Esempio n. 18
0
def index(request, course_id):
   
    # Request data
    course_key = get_course_key(course_id)
    course = get_course_module(course_key)
    user = request.user
    staff_access = has_access(request.user, 'staff', course)
    instructor_access = has_access(request.user, 'instructor', course)
    masq = setup_masquerade(request, staff_access)  # allow staff to toggle masquerade on info page
    studio_url = get_studio_url(course, 'course_info')
    reverifications = fetch_reverify_banner_info(request, course_key)
    
    #course = get_course_with_access(request.user, action='load', course_key=course_key, depth=None, check_if_enrolled=False)
    
    # Proficiency and pass limit
    pass_limit = get_course_grade_cutoff(course)
    proficiency_limit = (1 - pass_limit) / 2 + pass_limit
    
    usernames_in = []
    for student in CourseEnrollment.users_enrolled_in(course_key):
        usernames_in.append(student.username.encode('utf-8'))
              
  
    # Data for visualization in JSON
    user_for_charts = '#average' if (staff_access or instructor_access) else user
    kwargs = {
        'qualifiers': {'category': 'video', },
    }
          
    # This returns video descriptors in the order they appear on the course
    video_descriptors = videos_problems_in(course)[0]
    video_durations = get_info_videos_descriptors(video_descriptors)[2]
      
    video_ids_str = []
    course_video_names = []
    for descriptor in video_descriptors:
        video_ids_str.append((course_key.make_usage_key('video', descriptor.location.name))._to_string())
        course_video_names.append(descriptor.display_name_with_default)
  
    if len(video_descriptors) > 0:
        first_video_id = course_key.make_usage_key('video', video_descriptors[0].location.name)
        # Video progress visualization. Video percentage seen total and non-overlapped.
        video_names, avg_video_time, video_percentages = get_module_consumption(user_for_charts, course_key, 'video', 'video_progress')  
        if avg_video_time != []:
            all_video_time_percent = map(truediv, avg_video_time, video_durations)
            all_video_time_percent = [int(round(x*100,0)) for x in all_video_time_percent]
        else:
            all_video_time_percent = avg_video_time
            
        column_headers = ['Video', 'Different video time', 'Total video time']
        video_prog_json = ready_for_arraytodatatable(column_headers, video_names, video_percentages, all_video_time_percent)
        
        video_names, all_video_time = get_module_consumption(user_for_charts, course_key, 'video', 'total_time_vid_prob')[0:2]
        # Time spent on every video resource
        column_headers = ['Video', 'Time watched']
        video_distrib_json = ready_for_arraytodatatable(column_headers, video_names, all_video_time)
  
        # Video events dispersion within video length
        scatter_array = get_video_events_info(user_for_charts, first_video_id)    
  
        # Repetitions per video intervals
        user_for_vid_intervals = '#class_total_times' if user_for_charts == '#average' else user_for_charts
        video_intervals_array = get_user_video_intervals(user_for_vid_intervals, first_video_id)        
          
    # Case no videos in course
    else:
        video_names = None
        video_prog_json = simplejson.dumps(None)
        video_distrib_json = simplejson.dumps(None)
        scatter_array = simplejson.dumps(None)
        video_intervals_array = simplejson.dumps(None)
          
    # Time spent on every problem resource
    problem_names, time_x_problem = get_module_consumption(user_for_charts, course_key, 'problem', 'total_time_vid_prob')[0:2]    
    column_headers = ['Problem', 'Time on problem']
    problem_distrib_json = ready_for_arraytodatatable(column_headers, problem_names, time_x_problem)
      
    # Daily time spent on video and/or problem resources
    video_days, video_daily_time = get_daily_consumption(user_for_charts, course_key, 'video')
    problem_days, problem_daily_time = get_daily_consumption(user_for_charts, course_key, 'problem')    
    vid_and_prob_daily_time = join_video_problem_time(video_days, video_daily_time, problem_days, problem_daily_time) 
    
    #Analytics visualizations
    if staff_access or instructor_access:
        # Instructor access
        std_sort = get_DB_sort_course_homework(course_key)
        # Chapter time
        cs, st = get_DB_course_spent_time(course_key, student_id=ALL_STUDENTS)
        students_spent_time = chapter_time_to_js(cs, st)
        students_grades = get_DB_student_grades(course_key, student_id=ALL_STUDENTS) 
        cs, sa = course_accesses = get_DB_course_section_accesses(course_key, student_id=ALL_STUDENTS)
        students_course_accesses = course_accesses_to_js(cs, sa)
        students_prob_vid_progress = get_DB_course_video_problem_progress(course_key, student_id=ALL_STUDENTS)
        students_time_schedule = get_DB_time_schedule(course_key, student_id=ALL_STUDENTS)
    else:
        # Sort homework                    
        # Chapter time
        std_sort = None
        cs, st = get_DB_course_spent_time(course_key, user.id) 
        students_spent_time = chapter_time_to_js(cs, st) 
        students_grades = get_DB_student_grades(course_key, user.id) 
        cs, sa = course_accesses = get_DB_course_section_accesses(course_key, user.id)
        students_course_accesses = course_accesses_to_js(cs, sa) 
        students_time_schedule = get_DB_time_schedule(course_key, user.id) 
        students_prob_vid_progress = get_DB_course_video_problem_progress(course_key, user.id) 
                    
    context = {'course': course,
               'request': request,
               'user': user,
               'user_id': user.id,
               'staff_access': staff_access,
               'instructor_access': instructor_access,
               'masquerade': masq,
               'studio_url': studio_url,
               'reverifications': reverifications,
               'course_id': course_id,
               'students': students_to_js(get_course_students(course_key)),
               'visualizations_id': VISUALIZATIONS_ID,
               'std_grades_dump': dumps(students_grades),
               'sort_std_dump': dumps(std_sort),
               'time_dump': dumps(students_spent_time),
               'accesses_dump': dumps(students_course_accesses),
               'std_time_schedule_dumb': dumps(students_time_schedule),
               'vid_prob_prog_dump': dumps(students_prob_vid_progress),
               'pass_limit': pass_limit,
               'prof_limit': proficiency_limit,
               'usernames_in' : usernames_in,
               'video_names' : course_video_names,
               'video_ids' : video_ids_str,
               'video_prog_json' : video_prog_json,
               'video_distrib_json' : video_distrib_json,
               'problem_distrib_json' : problem_distrib_json,
               'video_intervals_array' : video_intervals_array,
               'vid_and_prob_daily_time' : vid_and_prob_daily_time,
               'scatter_array' : scatter_array, }                                
        
    return render_to_response('learning_analytics/learning_analytics.html', context)    
Esempio n. 19
0
def course_about(request, course_id):
    """
    Display the course's about page.

    Assumes the course_id is in a valid format.
    """

    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)

    with modulestore().bulk_operations(course_key):
        permission_name = microsite.get_value(
            "COURSE_ABOUT_VISIBILITY_PERMISSION", settings.COURSE_ABOUT_VISIBILITY_PERMISSION
        )
        course = get_course_with_access(request.user, permission_name, course_key)

        if microsite.get_value("ENABLE_MKTG_SITE", settings.FEATURES.get("ENABLE_MKTG_SITE", False)):
            return redirect(reverse("info", args=[course.id.to_deprecated_string()]))

        registered = registered_for_course(course, request.user)

        staff_access = has_access(request.user, "staff", course)
        studio_url = get_studio_url(course, "settings/details")

        if has_access(request.user, "load", course):
            course_target = reverse("info", args=[course.id.to_deprecated_string()])
        else:
            course_target = reverse("about_course", args=[course.id.to_deprecated_string()])

        show_courseware_link = (
            has_access(request.user, "load", course)
            and has_access(request.user, "view_courseware_with_prerequisites", course)
        ) or settings.FEATURES.get("ENABLE_LMS_MIGRATION")

        # Note: this is a flow for payment for course registration, not the Verified Certificate flow.
        registration_price = 0
        in_cart = False
        reg_then_add_to_cart_link = ""

        _is_shopping_cart_enabled = is_shopping_cart_enabled()
        if _is_shopping_cart_enabled:
            registration_price = CourseMode.min_course_price_for_currency(
                course_key, settings.PAID_COURSE_REGISTRATION_CURRENCY[0]
            )
            if request.user.is_authenticated():
                cart = shoppingcart.models.Order.get_cart_for_user(request.user)
                in_cart = shoppingcart.models.PaidCourseRegistration.contained_in_order(
                    cart, course_key
                ) or shoppingcart.models.CourseRegCodeItem.contained_in_order(cart, course_key)

            reg_then_add_to_cart_link = "{reg_url}?course_id={course_id}&enrollment_action=add_to_cart".format(
                reg_url=reverse("register_user"), course_id=course.id.to_deprecated_string()
            )

        course_price = get_cosmetic_display_price(course, registration_price)

        # Used to provide context to message to student if enrollment not allowed
        can_enroll = has_access(request.user, "enroll", course)
        invitation_only = course.invitation_only
        is_course_full = CourseEnrollment.is_course_full(course)

        # Register button should be disabled if one of the following is true:
        # - Student is already registered for course
        # - Course is already full
        # - Student cannot enroll in course
        active_reg_button = not (registered or is_course_full or not can_enroll)

        is_shib_course = uses_shib(course)

        # get prerequisite courses display names
        pre_requisite_courses = get_prerequisite_courses_display(course)

        return render_to_response(
            "courseware/course_about.html",
            {
                "course": course,
                "staff_access": staff_access,
                "studio_url": studio_url,
                "registered": registered,
                "course_target": course_target,
                "is_cosmetic_price_enabled": settings.FEATURES.get("ENABLE_COSMETIC_DISPLAY_PRICE"),
                "course_price": course_price,
                "in_cart": in_cart,
                "reg_then_add_to_cart_link": reg_then_add_to_cart_link,
                "show_courseware_link": show_courseware_link,
                "is_course_full": is_course_full,
                "can_enroll": can_enroll,
                "invitation_only": invitation_only,
                "active_reg_button": active_reg_button,
                "is_shib_course": is_shib_course,
                # We do not want to display the internal courseware header, which is used when the course is found in the
                # context. This value is therefor explicitly set to render the appropriate header.
                "disable_courseware_header": True,
                "is_shopping_cart_enabled": _is_shopping_cart_enabled,
                "cart_link": reverse("shoppingcart.views.show_cart"),
                "pre_requisite_courses": pre_requisite_courses,
            },
        )
def instructor_dashboard_2(request, course_id):
    """ Display the instructor dashboard for a course. """
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    course = get_course_by_id(course_key, depth=None)

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

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

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

    #check if there is corresponding entry in the CourseMode Table related to the Instructor Dashboard course
    course_honor_mode = CourseMode.mode_for_course(course_key, 'honor')
    course_mode_has_price = False
    if course_honor_mode and course_honor_mode.min_price > 0:
        course_mode_has_price = True

    if (settings.FEATURES.get('INDIVIDUAL_DUE_DATES') and access['instructor']):
        sections.insert(3, _section_extensions(course))

    # Gate access to course email by feature flag & by course-specific authorization
    if bulk_email_is_enabled_for_course(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:
        sections.append(_section_e_commerce(course, access))

    enrollment_count = sections[0]['enrollment_count']['total']
    disable_buttons = False
    max_enrollment_for_buttons = settings.FEATURES.get("MAX_ENROLLMENT_INSTR_BUTTONS")
    if max_enrollment_for_buttons is not None:
        disable_buttons = enrollment_count > max_enrollment_for_buttons

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

    context = {
        'course': course,
        'old_dashboard_url': reverse('instructor_dashboard_legacy', kwargs={'course_id': course_key.to_deprecated_string()}),
        'studio_url': get_studio_url(course, 'course'),
        'sections': sections,
        'disable_buttons': disable_buttons,
        'analytics_dashboard_message': analytics_dashboard_message
    }

    return render_to_response('instructor/instructor_dashboard_2/instructor_dashboard_2.html', context)
Esempio n. 21
0
def course_about(request, course_id):
    """
    Display the course's about page.

    Assumes the course_id is in a valid format.
    """

    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    course = get_course_with_access(request.user, 'see_exists', course_key)

    if microsite.get_value('ENABLE_MKTG_SITE',
                           settings.FEATURES.get('ENABLE_MKTG_SITE', False)):
        return redirect(
            reverse('info', args=[course.id.to_deprecated_string()]))

    registered = registered_for_course(course, request.user)
    staff_access = has_access(request.user, 'staff', course)
    studio_url = get_studio_url(course, 'settings/details')

    if has_access(request.user, 'load', course):
        course_target = reverse('info',
                                args=[course.id.to_deprecated_string()])
    else:
        course_target = reverse('about_course',
                                args=[course.id.to_deprecated_string()])

    show_courseware_link = (has_access(request.user, 'load', course)
                            or settings.FEATURES.get('ENABLE_LMS_MIGRATION'))

    # Note: this is a flow for payment for course registration, not the Verified Certificate flow.
    registration_price = 0
    in_cart = False
    reg_then_add_to_cart_link = ""
    if (settings.FEATURES.get('ENABLE_SHOPPING_CART')
            and settings.FEATURES.get('ENABLE_PAID_COURSE_REGISTRATION')):
        registration_price = CourseMode.min_course_price_for_currency(
            course_key, settings.PAID_COURSE_REGISTRATION_CURRENCY[0])
        if request.user.is_authenticated():
            cart = shoppingcart.models.Order.get_cart_for_user(request.user)
            in_cart = shoppingcart.models.PaidCourseRegistration.contained_in_order(
                cart, course_key)

        reg_then_add_to_cart_link = "{reg_url}?course_id={course_id}&enrollment_action=add_to_cart".format(
            reg_url=reverse('register_user'),
            course_id=course.id.to_deprecated_string())

    # Used to provide context to message to student if enrollment not allowed
    can_enroll = has_access(request.user, 'enroll', course)
    invitation_only = course.invitation_only
    is_course_full = CourseEnrollment.is_course_full(course)

    # Register button should be disabled if one of the following is true:
    # - Student is already registered for course
    # - Course is already full
    # - Student cannot enroll in course
    active_reg_button = not (registered or is_course_full or not can_enroll)

    is_shib_course = uses_shib(course)

    return render_to_response(
        'courseware/course_about.html', {
            'course': course,
            'staff_access': staff_access,
            'studio_url': studio_url,
            'registered': registered,
            'course_target': course_target,
            'registration_price': registration_price,
            'in_cart': in_cart,
            'reg_then_add_to_cart_link': reg_then_add_to_cart_link,
            'show_courseware_link': show_courseware_link,
            'is_course_full': is_course_full,
            'can_enroll': can_enroll,
            'invitation_only': invitation_only,
            'active_reg_button': active_reg_button,
            'is_shib_course': is_shib_course,
        })
Esempio n. 22
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),
    }

    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 is_bulk_email_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)
Esempio n. 23
0
def course_about(request, course_id):
    """
    Display the course's about page.

    Assumes the course_id is in a valid format.
    """

    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)

    with modulestore().bulk_operations(course_key):
        permission_name = microsite.get_value(
            'COURSE_ABOUT_VISIBILITY_PERMISSION',
            settings.COURSE_ABOUT_VISIBILITY_PERMISSION
        )
        course = get_course_with_access(request.user, permission_name, course_key)

        if microsite.get_value('ENABLE_MKTG_SITE', settings.FEATURES.get('ENABLE_MKTG_SITE', False)):
            return redirect(reverse('info', args=[course.id.to_deprecated_string()]))

        registered = registered_for_course(course, request.user)

        staff_access = has_access(request.user, 'staff', course)
        studio_url = get_studio_url(course, 'settings/details')

        if has_access(request.user, 'load', course):
            course_target = reverse('info', args=[course.id.to_deprecated_string()])
        else:
            course_target = reverse('about_course', args=[course.id.to_deprecated_string()])

        show_courseware_link = (
            (
                has_access(request.user, 'load', course)
                and has_access(request.user, 'view_courseware_with_prerequisites', course)
            )
            or settings.FEATURES.get('ENABLE_LMS_MIGRATION')
        )

        # Note: this is a flow for payment for course registration, not the Verified Certificate flow.
        registration_price = 0
        in_cart = False
        reg_then_add_to_cart_link = ""

        _is_shopping_cart_enabled = is_shopping_cart_enabled()
        if _is_shopping_cart_enabled:
            registration_price = CourseMode.min_course_price_for_currency(course_key,
                                                                          settings.PAID_COURSE_REGISTRATION_CURRENCY[0])
            if request.user.is_authenticated():
                cart = shoppingcart.models.Order.get_cart_for_user(request.user)
                in_cart = shoppingcart.models.PaidCourseRegistration.contained_in_order(cart, course_key) or \
                    shoppingcart.models.CourseRegCodeItem.contained_in_order(cart, course_key)

            reg_then_add_to_cart_link = "{reg_url}?course_id={course_id}&enrollment_action=add_to_cart".format(
                reg_url=reverse('register_user'), course_id=course.id.to_deprecated_string())

        # Used to provide context to message to student if enrollment not allowed
        can_enroll = has_access(request.user, 'enroll', course)
        invitation_only = course.invitation_only
        is_course_full = CourseEnrollment.is_course_full(course)

        # Register button should be disabled if one of the following is true:
        # - Student is already registered for course
        # - Course is already full
        # - Student cannot enroll in course
        active_reg_button = not(registered or is_course_full or not can_enroll)

        is_shib_course = uses_shib(course)

        # get prerequisite courses display names
        pre_requisite_courses = get_prerequisite_courses_display(course)

        return render_to_response('courseware/course_about.html', {
            'course': course,
            'staff_access': staff_access,
            'studio_url': studio_url,
            'registered': registered,
            'course_target': course_target,
            'registration_price': registration_price,
            'currency_symbol': settings.PAID_COURSE_REGISTRATION_CURRENCY[1],
            'in_cart': in_cart,
            'reg_then_add_to_cart_link': reg_then_add_to_cart_link,
            'show_courseware_link': show_courseware_link,
            'is_course_full': is_course_full,
            'can_enroll': can_enroll,
            'invitation_only': invitation_only,
            'active_reg_button': active_reg_button,
            'is_shib_course': is_shib_course,
            # We do not want to display the internal courseware header, which is used when the course is found in the
            # context. This value is therefor explicitly set to render the appropriate header.
            'disable_courseware_header': True,
            'is_shopping_cart_enabled': _is_shopping_cart_enabled,
            'cart_link': reverse('shoppingcart.views.show_cart'),
            'pre_requisite_courses': pre_requisite_courses
        })
Esempio n. 24
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':
        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':
        has_access(request.user, 'staff', course),
        'forum_admin':
        has_forum_access(request.user, course_key, FORUM_ROLE_ADMINISTRATOR),
    }

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

    sections = [
        _section_course_info(course, access),
        _section_membership(course, access),
        _section_student_admin(course, access),
        _section_data_download(course, access),
        _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))

    is_white_label = CourseMode.is_white_label(course_key)

    if (settings.FEATURES.get('INDIVIDUAL_DUE_DATES')
            and access['instructor']):
        sections.insert(3, _section_extensions(course))

    # Gate access to course email by feature flag & by course-specific authorization
    if bulk_email_is_enabled_for_course(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))

    disable_buttons = not _is_small_course(course_key)

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

    context = {
        'course':
        course,
        'old_dashboard_url':
        reverse('instructor_dashboard_legacy',
                kwargs={'course_id': unicode(course_key)}),
        'studio_url':
        get_studio_url(course, 'course'),
        'sections':
        sections,
        'disable_buttons':
        disable_buttons,
        'analytics_dashboard_message':
        analytics_dashboard_message
    }

    return render_to_response(
        'instructor/instructor_dashboard_2/instructor_dashboard_2.html',
        context)
Esempio n. 25
0
def course_about(request, course_id):
    """
    Display the course's about page.

    Assumes the course_id is in a valid format.
    """

    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    course = get_course_with_access(request.user, 'see_exists', course_key)

    if microsite.get_value(
        'ENABLE_MKTG_SITE',
        settings.FEATURES.get('ENABLE_MKTG_SITE', False)
    ):
        return redirect(reverse('info', args=[course.id.to_deprecated_string()]))

    registered = registered_for_course(course, request.user)
    staff_access = has_access(request.user, 'staff', course)
    studio_url = get_studio_url(course, 'settings/details')

    if has_access(request.user, 'load', course):
        course_target = reverse('info', args=[course.id.to_deprecated_string()])
    else:
        course_target = reverse('about_course', args=[course.id.to_deprecated_string()])

    show_courseware_link = (has_access(request.user, 'load', course) or
                            settings.FEATURES.get('ENABLE_LMS_MIGRATION'))

    # Note: this is a flow for payment for course registration, not the Verified Certificate flow.
    registration_price = 0
    in_cart = False
    reg_then_add_to_cart_link = ""
    if (settings.FEATURES.get('ENABLE_SHOPPING_CART') and
        settings.FEATURES.get('ENABLE_PAID_COURSE_REGISTRATION')):
        registration_price = CourseMode.min_course_price_for_currency(course_key,
                                                                      settings.PAID_COURSE_REGISTRATION_CURRENCY[0])
        if request.user.is_authenticated():
            cart = shoppingcart.models.Order.get_cart_for_user(request.user)
            in_cart = shoppingcart.models.PaidCourseRegistration.contained_in_order(cart, course_key)

        reg_then_add_to_cart_link = "{reg_url}?course_id={course_id}&enrollment_action=add_to_cart".format(
            reg_url=reverse('register_user'), course_id=course.id.to_deprecated_string())

    # Used to provide context to message to student if enrollment not allowed
    can_enroll = has_access(request.user, 'enroll', course)
    invitation_only = course.invitation_only
    is_course_full = CourseEnrollment.is_course_full(course)

    # Register button should be disabled if one of the following is true:
    # - Student is already registered for course
    # - Course is already full
    # - Student cannot enroll in course
    active_reg_button = not(registered or is_course_full or not can_enroll)

    is_shib_course = uses_shib(course)

    return render_to_response('courseware/course_about.html', {
        'course': course,
        'staff_access': staff_access,
        'studio_url': studio_url,
        'registered': registered,
        'course_target': course_target,
        'registration_price': registration_price,
        'in_cart': in_cart,
        'reg_then_add_to_cart_link': reg_then_add_to_cart_link,
        'show_courseware_link': show_courseware_link,
        'is_course_full': is_course_full,
        'can_enroll': can_enroll,
        'invitation_only': invitation_only,
        'active_reg_button': active_reg_button,
        'is_shib_course': is_shib_course,
    })
Esempio n. 26
0
def index(request, course_id, chapter=None, section=None, position=None):
    """
    Displays courseware accordion and associated content.  If course, chapter,
    and section are all specified, renders the page, or returns an error if they
    are invalid.

    If section is not specified, displays the accordion opened to the right chapter.

    If neither chapter or section are specified, redirects to user's most recent
    chapter, or the first chapter if this is the user's first visit.

    Arguments:

     - request    : HTTP request
     - course_id  : course id (str: ORG/course/URL_NAME)
     - chapter    : chapter url_name (str)
     - section    : section url_name (str)
     - position   : position in module, eg of <sequential> module (str)

    Returns:

     - HTTPresponse
    """
    user = User.objects.prefetch_related("groups").get(id=request.user.id)
    request.user = user  # keep just one instance of User
    course = get_course_with_access(user, course_id, "load", depth=2)
    staff_access = has_access(user, course, "staff")
    registered = registered_for_course(course, user)
    if not registered:
        # TODO (vshnayder): do course instructors need to be registered to see course?
        log.debug(u"User %s tried to view course %s but is not enrolled", user, course.location.url())
        return redirect(reverse("about_course", args=[course.id]))

    masq = setup_masquerade(request, staff_access)

    try:
        field_data_cache = FieldDataCache.cache_for_descriptor_descendents(course.id, user, course, depth=2)

        course_module = get_module_for_descriptor(user, request, course, field_data_cache, course.id)
        if course_module is None:
            log.warning(
                u"If you see this, something went wrong: if we got this"
                u" far, should have gotten a course module for this user"
            )
            return redirect(reverse("about_course", args=[course.id]))

        studio_url = get_studio_url(course_id, "course")

        if chapter is None:
            return redirect_to_course_position(course_module)

        context = {
            "csrf": csrf(request)["csrf_token"],
            "accordion": render_accordion(request, course, chapter, section, field_data_cache),
            "COURSE_TITLE": course.display_name_with_default,
            "course": course,
            "init": "",
            "fragment": Fragment(),
            "staff_access": staff_access,
            "studio_url": studio_url,
            "masquerade": masq,
            "xqa_server": settings.FEATURES.get("USE_XQA_SERVER", "http://*****:*****@content-qa.mitx.mit.edu/xqa"),
            "reverifications": fetch_reverify_banner_info(request, course_id),
        }

        # Only show the chat if it's enabled by the course and in the
        # settings.
        show_chat = course.show_chat and settings.FEATURES["ENABLE_CHAT"]
        if show_chat:
            context["chat"] = chat_settings(course, user)
            # If we couldn't load the chat settings, then don't show
            # the widget in the courseware.
            if context["chat"] is None:
                show_chat = False

        context["show_chat"] = show_chat

        chapter_descriptor = course.get_child_by(lambda m: m.url_name == chapter)
        if chapter_descriptor is not None:
            save_child_position(course_module, chapter)
        else:
            raise Http404("No chapter descriptor found with name {}".format(chapter))

        chapter_module = course_module.get_child_by(lambda m: m.url_name == chapter)
        if chapter_module is None:
            # User may be trying to access a chapter that isn't live yet
            if masq == "student":  # if staff is masquerading as student be kinder, don't 404
                log.debug("staff masq as student: no chapter %s" % chapter)
                return redirect(reverse("courseware", args=[course.id]))
            raise Http404

        if section is not None:
            section_descriptor = chapter_descriptor.get_child_by(lambda m: m.url_name == section)
            if section_descriptor is None:
                # Specifically asked-for section doesn't exist
                if masq == "student":  # if staff is masquerading as student be kinder, don't 404
                    log.debug("staff masq as student: no section %s" % section)
                    return redirect(reverse("courseware", args=[course.id]))
                raise Http404

            # cdodge: this looks silly, but let's refetch the section_descriptor with depth=None
            # which will prefetch the children more efficiently than doing a recursive load
            section_descriptor = modulestore().get_instance(course.id, section_descriptor.location, depth=None)

            # Load all descendants of the section, because we're going to display its
            # html, which in general will need all of its children
            section_field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
                course_id, user, section_descriptor, depth=None
            )

            section_module = get_module_for_descriptor(
                request.user, request, section_descriptor, section_field_data_cache, course_id, position
            )

            if section_module is None:
                # User may be trying to be clever and access something
                # they don't have access to.
                raise Http404

            # Save where we are in the chapter
            save_child_position(chapter_module, section)
            context["fragment"] = section_module.render("student_view")
            context["section_title"] = section_descriptor.display_name_with_default
        else:
            # section is none, so display a message
            studio_url = get_studio_url(course_id, "course")
            prev_section = get_current_child(chapter_module)
            if prev_section is None:
                # Something went wrong -- perhaps this chapter has no sections visible to the user
                raise Http404
            prev_section_url = reverse(
                "courseware_section",
                kwargs={
                    "course_id": course_id,
                    "chapter": chapter_descriptor.url_name,
                    "section": prev_section.url_name,
                },
            )
            context["fragment"] = Fragment(
                content=render_to_string(
                    "courseware/welcome-back.html",
                    {
                        "course": course,
                        "studio_url": studio_url,
                        "chapter_module": chapter_module,
                        "prev_section": prev_section,
                        "prev_section_url": prev_section_url,
                    },
                )
            )

        result = render_to_response("courseware/courseware.html", context)
    except Exception as e:
        if isinstance(e, Http404):
            # let it propagate
            raise

        # In production, don't want to let a 500 out for any reason
        if settings.DEBUG:
            raise
        else:
            log.exception(
                u"Error in index view: user={user}, course={course}, chapter={chapter}"
                u" section={section} position={position}".format(
                    user=user, course=course, chapter=chapter, section=section, position=position
                )
            )
            try:
                result = render_to_response(
                    "courseware/courseware-error.html", {"staff_access": staff_access, "course": course}
                )
            except:
                # Let the exception propagate, relying on global config to at
                # at least return a nice error message
                log.exception("Error while rendering courseware-error page")
                raise

    return result
Esempio n. 27
0
def _progress(request, course_key, student_id):
    """
    Unwrapped version of "progress".

    User progress. We show the grade bar and every problem score.

    Course staff are allowed to see the progress of students in their class.
    """
    course = get_course_with_access(request.user, 'load', course_key, depth=None)
    staff_access = has_access(request.user, 'staff', course)

    if student_id is None or student_id == request.user.id:
        # always allowed to see your own profile
        student = request.user
    else:
        # Requesting access to a different student's profile
        if not staff_access:
            raise Http404
        student = User.objects.get(id=int(student_id))

    # NOTE: To make sure impersonation by instructor works, use
    # student instead of request.user in the rest of the function.

    # The pre-fetching of groups is done to make auth checks not require an
    # additional DB lookup (this kills the Progress page in particular).
    student = User.objects.prefetch_related("groups").get(id=student.id)

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

    if courseware_summary is None:
        #This means the student didn't have access to the course (which the instructor requested)
        raise Http404
    else:
        i=0

        while i < len(courseware_summary):
            need = NeedThread(request.user, course)

            if need:
                print "Precisa de thread"
                mythread = CadVersao(courseware_summary[i]['url_name'], request.user)
                mythread.start()
                mythread.join()
                imprimir = mythread.getResult()
            else:
                print "Nao precisa de thread"
                imprimir = VerABprint(courseware_summary[i]['url_name'], request.user)

            if imprimir == False:
                del courseware_summary[i]
            else:
                i += 1

    studio_url = get_studio_url(course_key, 'settings/grading')
    grade_summary = grades.grade(student, request, course)

    context = {
        'course': course,
        'courseware_summary': courseware_summary,
        'studio_url': studio_url,
        'grade_summary': grade_summary,
        'staff_access': staff_access,
        'student': student,
        'reverifications': fetch_reverify_banner_info(request, course_key)
    }

    with grades.manual_transaction():
        response = render_to_response('courseware/progress.html', context)

    return response
Esempio n. 28
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': 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': 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)

    sections = [
        _section_course_info(course, access),
        _section_membership(course, access, is_white_label),
        _section_cohort_management(course, access),
        _section_student_admin(course, access),
        _section_data_download(course, access),
        _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 (settings.FEATURES.get('INDIVIDUAL_DUE_DATES') and access['instructor']):
        sections.insert(3, _section_extensions(course))

    # Gate access to course email by feature flag & by course-specific authorization
    if bulk_email_is_enabled_for_course(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, is_white_label))

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

    disable_buttons = not _is_small_course(course_key)

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

    context = {
        'course': course,
        'old_dashboard_url': reverse('instructor_dashboard_legacy', kwargs={'course_id': unicode(course_key)}),
        'studio_url': get_studio_url(course, 'course'),
        'sections': sections,
        'disable_buttons': disable_buttons,
        'analytics_dashboard_message': analytics_dashboard_message
    }

    return render_to_response('instructor/instructor_dashboard_2/instructor_dashboard_2.html', context)
Esempio n. 29
0
def index(request, course_id, chapter=None, section=None, position=None):
    """
    Displays courseware accordion and associated content.  If course, chapter,
    and section are all specified, renders the page, or returns an error if they
    are invalid.

    If section is not specified, displays the accordion opened to the right chapter.

    If neither chapter or section are specified, redirects to user's most recent
    chapter, or the first chapter if this is the user's first visit.

    Arguments:

     - request    : HTTP request
     - course_id  : course id (str: ORG/course/URL_NAME)
     - chapter    : chapter url_name (str)
     - section    : section url_name (str)
     - position   : position in module, eg of <sequential> module (str)

    Returns:

     - HTTPresponse
    """
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    user = User.objects.prefetch_related("groups").get(id=request.user.id)
    request.user = user  # keep just one instance of User
    course = get_course_with_access(user, 'load', course_key, depth=2)
    staff_access = has_access(user, 'staff', course)
    registered = registered_for_course(course, user)
    if not registered:
        # TODO (vshnayder): do course instructors need to be registered to see course?
        log.debug(u'User %s tried to view course %s but is not enrolled', user,
                  course.location.to_deprecated_string())
        return redirect(
            reverse('about_course', args=[course_key.to_deprecated_string()]))

    masq = setup_masquerade(request, staff_access)

    try:
        field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
            course_key, user, course, depth=2)

        course_module = get_module_for_descriptor(user, request, course,
                                                  field_data_cache, course_key)
        if course_module is None:
            log.warning(
                u'If you see this, something went wrong: if we got this'
                u' far, should have gotten a course module for this user')
            return redirect(
                reverse('about_course',
                        args=[course_key.to_deprecated_string()]))

        studio_url = get_studio_url(course_key, 'course')

        context = {
            'csrf':
            csrf(request)['csrf_token'],
            'accordion':
            render_accordion(request, course, chapter, section,
                             field_data_cache),
            'COURSE_TITLE':
            course.display_name_with_default,
            'course':
            course,
            'init':
            '',
            'fragment':
            Fragment(),
            'staff_access':
            staff_access,
            'studio_url':
            studio_url,
            'masquerade':
            masq,
            'xqa_server':
            settings.FEATURES.get(
                'USE_XQA_SERVER',
                'http://*****:*****@content-qa.mitx.mit.edu/xqa'),
            'reverifications':
            fetch_reverify_banner_info(request, course_key),
        }

        has_content = course.has_children_at_depth(CONTENT_DEPTH)
        if not has_content:
            # Show empty courseware for a course with no units
            return render_to_response('courseware/courseware.html', context)
        elif chapter is None:
            # passing CONTENT_DEPTH avoids returning 404 for a course with an
            # empty first section and a second section with content
            return redirect_to_course_position(course_module, CONTENT_DEPTH)

        # Only show the chat if it's enabled by the course and in the
        # settings.
        show_chat = course.show_chat and settings.FEATURES['ENABLE_CHAT']
        if show_chat:
            context['chat'] = chat_settings(course, user)
            # If we couldn't load the chat settings, then don't show
            # the widget in the courseware.
            if context['chat'] is None:
                show_chat = False

        context['show_chat'] = show_chat

        chapter_descriptor = course.get_child_by(
            lambda m: m.location.name == chapter)
        if chapter_descriptor is not None:
            save_child_position(course_module, chapter)
        else:
            raise Http404(
                'No chapter descriptor found with name {}'.format(chapter))

        chapter_module = course_module.get_child_by(
            lambda m: m.location.name == chapter)
        if chapter_module is None:
            # User may be trying to access a chapter that isn't live yet
            if masq == 'student':  # if staff is masquerading as student be kinder, don't 404
                log.debug('staff masq as student: no chapter %s' % chapter)
                return redirect(
                    reverse('courseware',
                            args=[course.id.to_deprecated_string()]))
            raise Http404

        if section is not None:
            section_descriptor = chapter_descriptor.get_child_by(
                lambda m: m.location.name == section)

            if section_descriptor is None:
                # Specifically asked-for section doesn't exist
                if masq == 'student':  # if staff is masquerading as student be kinder, don't 404
                    log.debug('staff masq as student: no section %s' % section)
                    return redirect(
                        reverse('courseware',
                                args=[course.id.to_deprecated_string()]))
                raise Http404

            ## Allow chromeless operation
            if section_descriptor.chrome:
                chrome = [
                    s.strip()
                    for s in section_descriptor.chrome.lower().split(",")
                ]
                if 'accordion' not in chrome:
                    context['disable_accordion'] = True
                if 'tabs' not in chrome:
                    context['disable_tabs'] = True

            if section_descriptor.default_tab:
                context['default_tab'] = section_descriptor.default_tab

            # cdodge: this looks silly, but let's refetch the section_descriptor with depth=None
            # which will prefetch the children more efficiently than doing a recursive load
            section_descriptor = modulestore().get_item(
                section_descriptor.location, depth=None)

            # Load all descendants of the section, because we're going to display its
            # html, which in general will need all of its children
            section_field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
                course_key, user, section_descriptor, depth=None)

            # Verify that position a string is in fact an int
            if position is not None:
                try:
                    int(position)
                except ValueError:
                    raise Http404(
                        "Position {} is not an integer!".format(position))

            section_module = get_module_for_descriptor(
                request.user, request, section_descriptor,
                section_field_data_cache, course_key, position)

            if section_module is None:
                # User may be trying to be clever and access something
                # they don't have access to.
                raise Http404

            # Save where we are in the chapter
            save_child_position(chapter_module, section)
            context['fragment'] = section_module.render(STUDENT_VIEW)
            context[
                'section_title'] = section_descriptor.display_name_with_default
        else:
            # section is none, so display a message
            studio_url = get_studio_url(course_key, 'course')
            prev_section = get_current_child(chapter_module)
            if prev_section is None:
                # Something went wrong -- perhaps this chapter has no sections visible to the user
                raise Http404
            prev_section_url = reverse('courseware_section',
                                       kwargs={
                                           'course_id':
                                           course_key.to_deprecated_string(),
                                           'chapter':
                                           chapter_descriptor.url_name,
                                           'section':
                                           prev_section.url_name
                                       })
            context['fragment'] = Fragment(content=render_to_string(
                'courseware/welcome-back.html', {
                    'course': course,
                    'studio_url': studio_url,
                    'chapter_module': chapter_module,
                    'prev_section': prev_section,
                    'prev_section_url': prev_section_url
                }))

        result = render_to_response('courseware/courseware.html', context)
    except Exception as e:

        # Doesn't bar Unicode characters from URL, but if Unicode characters do
        # cause an error it is a graceful failure.
        if isinstance(e, UnicodeEncodeError):
            raise Http404("URL contains Unicode characters")

        if isinstance(e, Http404):
            # let it propagate
            raise

        # In production, don't want to let a 500 out for any reason
        if settings.DEBUG:
            raise
        else:
            log.exception(
                u"Error in index view: user={user}, course={course}, chapter={chapter}"
                u" section={section} position={position}".format(
                    user=user,
                    course=course,
                    chapter=chapter,
                    section=section,
                    position=position))
            try:
                result = render_to_response('courseware/courseware-error.html',
                                            {
                                                'staff_access': staff_access,
                                                'course': course
                                            })
            except:
                # Let the exception propagate, relying on global config to at
                # at least return a nice error message
                log.exception("Error while rendering courseware-error page")
                raise

    return result
Esempio n. 30
0
def index(request, course_id):

    # Request data
    course_key = get_course_key(course_id)
    course = get_course_module(course_key)
    user = request.user
    staff_access = has_access(request.user, 'staff', course)
    instructor_access = has_access(request.user, 'instructor', course)
    masq = setup_masquerade(
        request, staff_access)  # allow staff to toggle masquerade on info page
    studio_url = get_studio_url(course, 'course_info')
    reverifications = fetch_reverify_banner_info(request, course_key)

    #course = get_course_with_access(request.user, action='load', course_key=course_key, depth=None, check_if_enrolled=False)

    # Proficiency and pass limit
    pass_limit = get_course_grade_cutoff(course)
    proficiency_limit = (1 - pass_limit) / 2 + pass_limit

    usernames_in = []
    for student in CourseEnrollment.users_enrolled_in(course_key):
        usernames_in.append(student.username.encode('utf-8'))

    # Data for visualization in JSON
    user_for_charts = '#average' if (staff_access
                                     or instructor_access) else user
    kwargs = {
        'qualifiers': {
            'category': 'video',
        },
    }

    # This returns video descriptors in the order they appear on the course
    video_descriptors = videos_problems_in(course)[0]
    video_durations = get_info_videos_descriptors(video_descriptors)[2]

    video_ids_str = []
    course_video_names = []
    for descriptor in video_descriptors:
        video_ids_str.append(
            (course_key.make_usage_key('video',
                                       descriptor.location.name))._to_string())
        course_video_names.append(descriptor.display_name_with_default)

    if len(video_descriptors) > 0:
        first_video_id = course_key.make_usage_key(
            'video', video_descriptors[0].location.name)
        # Video progress visualization. Video percentage seen total and non-overlapped.
        video_names, avg_video_time, video_percentages = get_module_consumption(
            user_for_charts, course_key, 'video', 'video_progress')
        if avg_video_time != []:
            all_video_time_percent = map(truediv, avg_video_time,
                                         video_durations)
            all_video_time_percent = [
                int(round(x * 100, 0)) for x in all_video_time_percent
            ]
        else:
            all_video_time_percent = avg_video_time

        column_headers = ['Video', 'Different video time', 'Total video time']
        video_prog_json = ready_for_arraytodatatable(column_headers,
                                                     video_names,
                                                     video_percentages,
                                                     all_video_time_percent)

        video_names, all_video_time = get_module_consumption(
            user_for_charts, course_key, 'video', 'total_time_vid_prob')[0:2]
        # Time spent on every video resource
        column_headers = ['Video', 'Time watched']
        video_distrib_json = ready_for_arraytodatatable(
            column_headers, video_names, all_video_time)

        # Video events dispersion within video length
        scatter_array = get_video_events_info(user_for_charts, first_video_id)

        # Repetitions per video intervals
        user_for_vid_intervals = '#class_total_times' if user_for_charts == '#average' else user_for_charts
        video_intervals_array = get_user_video_intervals(
            user_for_vid_intervals, first_video_id)

    # Case no videos in course
    else:
        video_names = None
        video_prog_json = simplejson.dumps(None)
        video_distrib_json = simplejson.dumps(None)
        scatter_array = simplejson.dumps(None)
        video_intervals_array = simplejson.dumps(None)

    # Time spent on every problem resource
    problem_names, time_x_problem = get_module_consumption(
        user_for_charts, course_key, 'problem', 'total_time_vid_prob')[0:2]
    column_headers = ['Problem', 'Time on problem']
    problem_distrib_json = ready_for_arraytodatatable(column_headers,
                                                      problem_names,
                                                      time_x_problem)

    # Daily time spent on video and/or problem resources
    video_days, video_daily_time = get_daily_consumption(
        user_for_charts, course_key, 'video')
    problem_days, problem_daily_time = get_daily_consumption(
        user_for_charts, course_key, 'problem')
    vid_and_prob_daily_time = join_video_problem_time(video_days,
                                                      video_daily_time,
                                                      problem_days,
                                                      problem_daily_time)

    #Analytics visualizations
    if staff_access or instructor_access:
        # Instructor access
        std_sort = get_DB_sort_course_homework(course_key)
        # Chapter time
        cs, st = get_DB_course_spent_time(course_key, student_id=ALL_STUDENTS)
        students_spent_time = chapter_time_to_js(cs, st)
        students_grades = get_DB_student_grades(course_key,
                                                student_id=ALL_STUDENTS)
        cs, sa = course_accesses = get_DB_course_section_accesses(
            course_key, student_id=ALL_STUDENTS)
        students_course_accesses = course_accesses_to_js(cs, sa)
        students_prob_vid_progress = get_DB_course_video_problem_progress(
            course_key, student_id=ALL_STUDENTS)
        students_time_schedule = get_DB_time_schedule(course_key,
                                                      student_id=ALL_STUDENTS)
    else:
        # Sort homework
        # Chapter time
        std_sort = None
        cs, st = get_DB_course_spent_time(course_key, user.id)
        students_spent_time = chapter_time_to_js(cs, st)
        students_grades = get_DB_student_grades(course_key, user.id)
        cs, sa = course_accesses = get_DB_course_section_accesses(
            course_key, user.id)
        students_course_accesses = course_accesses_to_js(cs, sa)
        students_time_schedule = get_DB_time_schedule(course_key, user.id)
        students_prob_vid_progress = get_DB_course_video_problem_progress(
            course_key, user.id)

    context = {
        'course': course,
        'request': request,
        'user': user,
        'user_id': user.id,
        'staff_access': staff_access,
        'instructor_access': instructor_access,
        'masquerade': masq,
        'studio_url': studio_url,
        'reverifications': reverifications,
        'course_id': course_id,
        'students': students_to_js(get_course_students(course_key)),
        'visualizations_id': VISUALIZATIONS_ID,
        'std_grades_dump': dumps(students_grades),
        'sort_std_dump': dumps(std_sort),
        'time_dump': dumps(students_spent_time),
        'accesses_dump': dumps(students_course_accesses),
        'std_time_schedule_dumb': dumps(students_time_schedule),
        'vid_prob_prog_dump': dumps(students_prob_vid_progress),
        'pass_limit': pass_limit,
        'prof_limit': proficiency_limit,
        'usernames_in': usernames_in,
        'video_names': course_video_names,
        'video_ids': video_ids_str,
        'video_prog_json': video_prog_json,
        'video_distrib_json': video_distrib_json,
        'problem_distrib_json': problem_distrib_json,
        'video_intervals_array': video_intervals_array,
        'vid_and_prob_daily_time': vid_and_prob_daily_time,
        'scatter_array': scatter_array,
    }

    return render_to_response('learning_analytics/learning_analytics.html',
                              context)
Esempio n. 31
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
        or has_admin_access(request, course_key),  # [COLARAZ_CUSTOM]
        '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("<a href=\"{}\" target=\"_blank\">").format(
            analytics_dashboard_url)
        analytics_dashboard_message = _(
            "To gain insights into student enrollment and participation {link_start}"
            "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 settings.FEATURES.get('INDIVIDUAL_DUE_DATES') and access['instructor']:
        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)
Esempio n. 32
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),
    }

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

    is_white_label = CourseMode.is_white_label(course_key)

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

    analytics_dashboard_message = None
    if settings.ANALYTICS_DASHBOARD_URL:
        # Construct a URL to the external analytics dashboard
        analytics_dashboard_url = '{0}/courses/{1}'.format(
            settings.ANALYTICS_DASHBOARD_URL, unicode(course_key))
        link_start = "<a href=\"{}\" target=\"_blank\">".format(
            analytics_dashboard_url)
        analytics_dashboard_message = _(
            "To gain insights into student enrollment and participation {link_start}"
            "visit {analytics_dashboard_name}, our new course analytics product{link_end}."
        )
        analytics_dashboard_message = analytics_dashboard_message.format(
            link_start=link_start,
            link_end="</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 settings.FEATURES.get('INDIVIDUAL_DUE_DATES') and access['instructor']:
        sections.insert(3, _section_extensions(course))

    # Gate access to course email by feature flag & by course-specific authorization
    if bulk_email_is_enabled_for_course(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,
                                is_white_label))

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

    # NOTE: For now, if we only have procotred exams enabled, then only platform Staff
    # (user.is_staff) will be able to view the special exams tab. This may
    # change in the future
    can_see_special_exams = (
        ((course.enable_proctored_exams and request.user.is_staff)
         or course.enable_timed_exams)
        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.
    certs_enabled = CertificateGenerationConfiguration.current().enabled
    if certs_enabled and access['admin']:
        sections.append(_section_certificates(course))

    disable_buttons = not _is_small_course(course_key)

    certificate_white_list = CertificateWhitelist.get_certificate_white_list(
        course_key)
    generate_certificate_exceptions_url = reverse(  # pylint: disable=invalid-name
        'generate_certificate_exceptions',
        kwargs={
            'course_id': unicode(course_key),
            'generate_for': ''
        })
    generate_bulk_certificate_exceptions_url = reverse(  # pylint: disable=invalid-name
        '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(  # pylint: disable=invalid-name
        '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)
Esempio n. 33
0
def _index_bulk_op(request, course_key, chapter, section, position):
    """
    Render the index page for the specified course.
    """
    user = request.user
    course = get_course_with_access(user, 'load', course_key, depth=2)

    staff_access = has_access(user, 'staff', course)
    registered = registered_for_course(course, user)
    if not registered:
        # TODO (vshnayder): do course instructors need to be registered to see course?
        log.debug(u'User %s tried to view course %s but is not enrolled', user, course.location.to_deprecated_string())
        return redirect(reverse('about_course', args=[course_key.to_deprecated_string()]))

    # see if all pre-requisites (as per the milestones app feature) have been fulfilled
    # Note that if the pre-requisite feature flag has been turned off (default) then this check will
    # always pass
    if not has_access(user, 'view_courseware_with_prerequisites', course):
        # prerequisites have not been fulfilled therefore redirect to the Dashboard
        log.info(
            u'User %d tried to view course %s '
            u'without fulfilling prerequisites',
            user.id, unicode(course.id))
        return redirect(reverse('dashboard'))

    # check to see if there is a required survey that must be taken before
    # the user can access the course.
    if survey.utils.must_answer_survey(course, user):
        return redirect(reverse('course_survey', args=[unicode(course.id)]))

    masquerade = setup_masquerade(request, course_key, staff_access)

    try:
        field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
            course_key, user, course, depth=2)

        course_module = get_module_for_descriptor(user, request, course, field_data_cache, course_key)
        if course_module is None:
            log.warning(u'If you see this, something went wrong: if we got this'
                        u' far, should have gotten a course module for this user')
            return redirect(reverse('about_course', args=[course_key.to_deprecated_string()]))

        studio_url = get_studio_url(course, 'course')

        context = {
            'csrf': csrf(request)['csrf_token'],
            'accordion': render_accordion(request, course, chapter, section, field_data_cache),
            'COURSE_TITLE': course.display_name_with_default,
            'course': course,
            'init': '',
            'fragment': Fragment(),
            'staff_access': staff_access,
            'studio_url': studio_url,
            'masquerade': masquerade,
            'xqa_server': settings.FEATURES.get('USE_XQA_SERVER', 'http://*****:*****@content-qa.mitx.mit.edu/xqa'),
            'reverifications': fetch_reverify_banner_info(request, course_key),
        }

        now = datetime.now(UTC())
        effective_start = _adjust_start_date_for_beta_testers(user, course, course_key)
        if staff_access and now < effective_start:
            # Disable student view button if user is staff and
            # course is not yet visible to students.
            context['disable_student_access'] = True

        has_content = course.has_children_at_depth(CONTENT_DEPTH)
        if not has_content:
            # Show empty courseware for a course with no units
            return render_to_response('courseware/courseware.html', context)
        elif chapter is None:
            # passing CONTENT_DEPTH avoids returning 404 for a course with an
            # empty first section and a second section with content
            return redirect_to_course_position(course_module, CONTENT_DEPTH)

        # Only show the chat if it's enabled by the course and in the
        # settings.
        show_chat = course.show_chat and settings.FEATURES['ENABLE_CHAT']
        if show_chat:
            context['chat'] = chat_settings(course, user)
            # If we couldn't load the chat settings, then don't show
            # the widget in the courseware.
            if context['chat'] is None:
                show_chat = False

        context['show_chat'] = show_chat

        chapter_descriptor = course.get_child_by(lambda m: m.location.name == chapter)
        if chapter_descriptor is not None:
            save_child_position(course_module, chapter)
        else:
            raise Http404('No chapter descriptor found with name {}'.format(chapter))

        chapter_module = course_module.get_child_by(lambda m: m.location.name == chapter)
        if chapter_module is None:
            # User may be trying to access a chapter that isn't live yet
            if masquerade and masquerade.role == 'student':  # if staff is masquerading as student be kinder, don't 404
                log.debug('staff masquerading as student: no chapter %s', chapter)
                return redirect(reverse('courseware', args=[course.id.to_deprecated_string()]))
            raise Http404

        if section is not None:
            section_descriptor = chapter_descriptor.get_child_by(lambda m: m.location.name == section)

            if section_descriptor is None:
                # Specifically asked-for section doesn't exist
                if masquerade and masquerade.role == 'student':  # don't 404 if staff is masquerading as student
                    log.debug('staff masquerading as student: no section %s', section)
                    return redirect(reverse('courseware', args=[course.id.to_deprecated_string()]))
                raise Http404

            ## Allow chromeless operation
            if section_descriptor.chrome:
                chrome = [s.strip() for s in section_descriptor.chrome.lower().split(",")]
                if 'accordion' not in chrome:
                    context['disable_accordion'] = True
                if 'tabs' not in chrome:
                    context['disable_tabs'] = True

            if section_descriptor.default_tab:
                context['default_tab'] = section_descriptor.default_tab

            # cdodge: this looks silly, but let's refetch the section_descriptor with depth=None
            # which will prefetch the children more efficiently than doing a recursive load
            section_descriptor = modulestore().get_item(section_descriptor.location, depth=None)

            # Load all descendants of the section, because we're going to display its
            # html, which in general will need all of its children
            section_field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
                course_key, user, section_descriptor, depth=None, asides=XBlockAsidesConfig.possible_asides()
            )

            # Verify that position a string is in fact an int
            if position is not None:
                try:
                    int(position)
                except ValueError:
                    raise Http404("Position {} is not an integer!".format(position))

            section_module = get_module_for_descriptor(
                request.user,
                request,
                section_descriptor,
                section_field_data_cache,
                course_key,
                position
            )

            if section_module is None:
                # User may be trying to be clever and access something
                # they don't have access to.
                raise Http404

            # Save where we are in the chapter
            save_child_position(chapter_module, section)
            context['fragment'] = section_module.render(STUDENT_VIEW)
            context['section_title'] = section_descriptor.display_name_with_default
        else:
            # section is none, so display a message
            studio_url = get_studio_url(course, 'course')
            prev_section = get_current_child(chapter_module)
            if prev_section is None:
                # Something went wrong -- perhaps this chapter has no sections visible to the user.
                # Clearing out the last-visited state and showing "first-time" view by redirecting
                # to courseware.
                course_module.position = None
                course_module.save()
                return redirect(reverse('courseware', args=[course.id.to_deprecated_string()]))
            prev_section_url = reverse('courseware_section', kwargs={
                'course_id': course_key.to_deprecated_string(),
                'chapter': chapter_descriptor.url_name,
                'section': prev_section.url_name
            })
            context['fragment'] = Fragment(content=render_to_string(
                'courseware/welcome-back.html',
                {
                    'course': course,
                    'studio_url': studio_url,
                    'chapter_module': chapter_module,
                    'prev_section': prev_section,
                    'prev_section_url': prev_section_url
                }
            ))

        result = render_to_response('courseware/courseware.html', context)
    except Exception as e:

        # Doesn't bar Unicode characters from URL, but if Unicode characters do
        # cause an error it is a graceful failure.
        if isinstance(e, UnicodeEncodeError):
            raise Http404("URL contains Unicode characters")

        if isinstance(e, Http404):
            # let it propagate
            raise

        # In production, don't want to let a 500 out for any reason
        if settings.DEBUG:
            raise
        else:
            log.exception(
                u"Error in index view: user={user}, course={course}, chapter={chapter}"
                u" section={section} position={position}".format(
                    user=user,
                    course=course,
                    chapter=chapter,
                    section=section,
                    position=position
                ))
            try:
                result = render_to_response('courseware/courseware-error.html', {
                    'staff_access': staff_access,
                    'course': course
                })
            except:
                # Let the exception propagate, relying on global config to at
                # at least return a nice error message
                log.exception("Error while rendering courseware-error page")
                raise

    return result
Esempio n. 34
0
def index(request, course_id, chapter=None, section=None,
          position=None):
    """
    Displays courseware accordion and associated content.  If course, chapter,
    and section are all specified, renders the page, or returns an error if they
    are invalid.

    If section is not specified, displays the accordion opened to the right chapter.

    If neither chapter or section are specified, redirects to user's most recent
    chapter, or the first chapter if this is the user's first visit.

    Arguments:

     - request    : HTTP request
     - course_id  : course id (str: ORG/course/URL_NAME)
     - chapter    : chapter url_name (str)
     - section    : section url_name (str)
     - position   : position in module, eg of <sequential> module (str)

    Returns:

     - HTTPresponse
    """
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    user = User.objects.prefetch_related("groups").get(id=request.user.id)
    request.user = user  # keep just one instance of User
    course = get_course_with_access(user, 'load', course_key, depth=2)
    staff_access = has_access(user, 'staff', course)
    registered = registered_for_course(course, user)
    if not registered:
        # TODO (vshnayder): do course instructors need to be registered to see course?
        log.debug(u'User %s tried to view course %s but is not enrolled', user, course.location.to_deprecated_string())
        return redirect(reverse('about_course', args=[course_key.to_deprecated_string()]))

    masq = setup_masquerade(request, staff_access)

    try:
        field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
            course_key, user, course, depth=2)

        course_module = get_module_for_descriptor(user, request, course, field_data_cache, course_key)
        if course_module is None:
            log.warning(u'If you see this, something went wrong: if we got this'
                        u' far, should have gotten a course module for this user')
            return redirect(reverse('about_course', args=[course_key.to_deprecated_string()]))

        studio_url = get_studio_url(course_key, 'course')

        context = {
            'csrf': csrf(request)['csrf_token'],
            'accordion': render_accordion(request, course, chapter, section, field_data_cache),
            'COURSE_TITLE': course.display_name_with_default,
            'course': course,
            'init': '',
            'fragment': Fragment(),
            'staff_access': staff_access,
            'studio_url': studio_url,
            'masquerade': masq,
            'xqa_server': settings.FEATURES.get('USE_XQA_SERVER', 'http://*****:*****@content-qa.mitx.mit.edu/xqa'),
            'reverifications': fetch_reverify_banner_info(request, course_key),
        }

        has_content = course.has_children_at_depth(CONTENT_DEPTH)
        if not has_content:
            # Show empty courseware for a course with no units
            return render_to_response('courseware/courseware.html', context)
        elif chapter is None:
            # passing CONTENT_DEPTH avoids returning 404 for a course with an
            # empty first section and a second section with content
            return redirect_to_course_position(course_module, CONTENT_DEPTH)

        # Only show the chat if it's enabled by the course and in the
        # settings.
        show_chat = course.show_chat and settings.FEATURES['ENABLE_CHAT']
        if show_chat:
            context['chat'] = chat_settings(course, user)
            # If we couldn't load the chat settings, then don't show
            # the widget in the courseware.
            if context['chat'] is None:
                show_chat = False

        context['show_chat'] = show_chat

        chapter_descriptor = course.get_child_by(lambda m: m.location.name == chapter)
        if chapter_descriptor is not None:
            save_child_position(course_module, chapter)
        else:
            raise Http404('No chapter descriptor found with name {}'.format(chapter))

        chapter_module = course_module.get_child_by(lambda m: m.location.name == chapter)
        if chapter_module is None:
            # User may be trying to access a chapter that isn't live yet
            if masq == 'student':  # if staff is masquerading as student be kinder, don't 404
                log.debug('staff masq as student: no chapter %s' % chapter)
                return redirect(reverse('courseware', args=[course.id.to_deprecated_string()]))
            raise Http404

        if section is not None:
            section_descriptor = chapter_descriptor.get_child_by(lambda m: m.location.name == section)

            if section_descriptor is None:
                # Specifically asked-for section doesn't exist
                if masq == 'student':  # if staff is masquerading as student be kinder, don't 404
                    log.debug('staff masq as student: no section %s' % section)
                    return redirect(reverse('courseware', args=[course.id.to_deprecated_string()]))
                raise Http404

            ## Allow chromeless operation
            if section_descriptor.chrome:
                chrome = [s.strip() for s in section_descriptor.chrome.lower().split(",")]
                if 'accordion' not in chrome:
                    context['disable_accordion'] = True
                if 'tabs' not in chrome:
                    context['disable_tabs'] = True

            if section_descriptor.default_tab:
                context['default_tab'] = section_descriptor.default_tab

            # cdodge: this looks silly, but let's refetch the section_descriptor with depth=None
            # which will prefetch the children more efficiently than doing a recursive load
            section_descriptor = modulestore().get_item(section_descriptor.location, depth=None)

            # Load all descendants of the section, because we're going to display its
            # html, which in general will need all of its children
            section_field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
                course_key, user, section_descriptor, depth=None)

            # Verify that position a string is in fact an int
            if position is not None:
                try:
                    int(position)
                except ValueError:
                    raise Http404("Position {} is not an integer!".format(position))

            section_module = get_module_for_descriptor(
                request.user,
                request,
                section_descriptor,
                section_field_data_cache,
                course_key,
                position
            )

            if section_module is None:
                # User may be trying to be clever and access something
                # they don't have access to.
                raise Http404

            # Save where we are in the chapter
            save_child_position(chapter_module, section)
            context['fragment'] = section_module.render(STUDENT_VIEW)
            context['section_title'] = section_descriptor.display_name_with_default
        else:
            # section is none, so display a message
            studio_url = get_studio_url(course_key, 'course')
            prev_section = get_current_child(chapter_module)
            if prev_section is None:
                # Something went wrong -- perhaps this chapter has no sections visible to the user
                raise Http404
            prev_section_url = reverse('courseware_section', kwargs={
                'course_id': course_key.to_deprecated_string(),
                'chapter': chapter_descriptor.url_name,
                'section': prev_section.url_name
            })
            context['fragment'] = Fragment(content=render_to_string(
                'courseware/welcome-back.html',
                {
                    'course': course,
                    'studio_url': studio_url,
                    'chapter_module': chapter_module,
                    'prev_section': prev_section,
                    'prev_section_url': prev_section_url
                }
            ))

        result = render_to_response('courseware/courseware.html', context)
    except Exception as e:

        # Doesn't bar Unicode characters from URL, but if Unicode characters do
        # cause an error it is a graceful failure.
        if isinstance(e, UnicodeEncodeError):
            raise Http404("URL contains Unicode characters")

        if isinstance(e, Http404):
            # let it propagate
            raise

        # In production, don't want to let a 500 out for any reason
        if settings.DEBUG:
            raise
        else:
            log.exception(
                u"Error in index view: user={user}, course={course}, chapter={chapter}"
                u" section={section} position={position}".format(
                    user=user,
                    course=course,
                    chapter=chapter,
                    section=section,
                    position=position
                ))
            try:
                result = render_to_response('courseware/courseware-error.html', {
                    'staff_access': staff_access,
                    'course': course
                })
            except:
                # Let the exception propagate, relying on global config to at
                # at least return a nice error message
                log.exception("Error while rendering courseware-error page")
                raise

    return result
Esempio n. 35
0
def _index_bulk_op(request, course_key, chapter, section, position):
    """
    Render the index page for the specified course.
    """
    user = request.user
    course = get_course_with_access(user, 'load', course_key, depth=2)

    staff_access = has_access(user, 'staff', course)
    registered = registered_for_course(course, user)
    if not registered:
        # TODO (vshnayder): do course instructors need to be registered to see course?
        log.debug(u'User %s tried to view course %s but is not enrolled', user, course.location.to_deprecated_string())
        return redirect(reverse('about_course', args=[course_key.to_deprecated_string()]))

    # see if all pre-requisites (as per the milestones app feature) have been fulfilled
    # Note that if the pre-requisite feature flag has been turned off (default) then this check will
    # always pass
    if not has_access(user, 'view_courseware_with_prerequisites', course):
        # prerequisites have not been fulfilled therefore redirect to the Dashboard
        log.info(
            u'User %d tried to view course %s '
            u'without fulfilling prerequisites',
            user.id, unicode(course.id))
        return redirect(reverse('dashboard'))

    # check to see if there is a required survey that must be taken before
    # the user can access the course.
    if survey.utils.must_answer_survey(course, user):
        return redirect(reverse('course_survey', args=[unicode(course.id)]))

    masquerade = setup_masquerade(request, course_key, staff_access)

    try:
        field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
            course_key, user, course, depth=2)

        course_module = get_module_for_descriptor(user, request, course, field_data_cache, course_key)
        if course_module is None:
            log.warning(u'If you see this, something went wrong: if we got this'
                        u' far, should have gotten a course module for this user')
            return redirect(reverse('about_course', args=[course_key.to_deprecated_string()]))

        studio_url = get_studio_url(course, 'course')

        context = {
            'csrf': csrf(request)['csrf_token'],
            'accordion': render_accordion(request, course, chapter, section, field_data_cache),
            'COURSE_TITLE': course.display_name_with_default,
            'course': course,
            'init': '',
            'fragment': Fragment(),
            'staff_access': staff_access,
            'studio_url': studio_url,
            'masquerade': masquerade,
            'xqa_server': settings.FEATURES.get('USE_XQA_SERVER', 'http://*****:*****@content-qa.mitx.mit.edu/xqa'),
            'reverifications': fetch_reverify_banner_info(request, course_key),
        }

        now = datetime.now(UTC())
        effective_start = _adjust_start_date_for_beta_testers(user, course, course_key)
        if staff_access and now < effective_start:
            # Disable student view button if user is staff and
            # course is not yet visible to students.
            context['disable_student_access'] = True

        has_content = course.has_children_at_depth(CONTENT_DEPTH)
        if not has_content:
            # Show empty courseware for a course with no units
            return render_to_response('courseware/courseware.html', context)
        elif chapter is None:
            # passing CONTENT_DEPTH avoids returning 404 for a course with an
            # empty first section and a second section with content
            return redirect_to_course_position(course_module, CONTENT_DEPTH)

        # Only show the chat if it's enabled by the course and in the
        # settings.
        show_chat = course.show_chat and settings.FEATURES['ENABLE_CHAT']
        if show_chat:
            context['chat'] = chat_settings(course, user)
            # If we couldn't load the chat settings, then don't show
            # the widget in the courseware.
            if context['chat'] is None:
                show_chat = False

        context['show_chat'] = show_chat

        chapter_descriptor = course.get_child_by(lambda m: m.location.name == chapter)
        if chapter_descriptor is not None:
            save_child_position(course_module, chapter)
        else:
            raise Http404('No chapter descriptor found with name {}'.format(chapter))

        chapter_module = course_module.get_child_by(lambda m: m.location.name == chapter)
        if chapter_module is None:
            # User may be trying to access a chapter that isn't live yet
            if masquerade and masquerade.role == 'student':  # if staff is masquerading as student be kinder, don't 404
                log.debug('staff masquerading as student: no chapter %s', chapter)
                return redirect(reverse('courseware', args=[course.id.to_deprecated_string()]))
            raise Http404

        if section is not None:
            section_descriptor = chapter_descriptor.get_child_by(lambda m: m.location.name == section)

            if section_descriptor is None:
                # Specifically asked-for section doesn't exist
                if masquerade and masquerade.role == 'student':  # don't 404 if staff is masquerading as student
                    log.debug('staff masquerading as student: no section %s', section)
                    return redirect(reverse('courseware', args=[course.id.to_deprecated_string()]))
                raise Http404

            ## Allow chromeless operation
            if section_descriptor.chrome:
                chrome = [s.strip() for s in section_descriptor.chrome.lower().split(",")]
                if 'accordion' not in chrome:
                    context['disable_accordion'] = True
                if 'tabs' not in chrome:
                    context['disable_tabs'] = True

            if section_descriptor.default_tab:
                context['default_tab'] = section_descriptor.default_tab

            # cdodge: this looks silly, but let's refetch the section_descriptor with depth=None
            # which will prefetch the children more efficiently than doing a recursive load
            section_descriptor = modulestore().get_item(section_descriptor.location, depth=None)

            # Load all descendants of the section, because we're going to display its
            # html, which in general will need all of its children
            section_field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
                course_key, user, section_descriptor, depth=None, asides=XBlockAsidesConfig.possible_asides()
            )

            # Verify that position a string is in fact an int
            if position is not None:
                try:
                    int(position)
                except ValueError:
                    raise Http404("Position {} is not an integer!".format(position))

            section_module = get_module_for_descriptor(
                request.user,
                request,
                section_descriptor,
                section_field_data_cache,
                course_key,
                position
            )

            if section_module is None:
                # User may be trying to be clever and access something
                # they don't have access to.
                raise Http404

            # Save where we are in the chapter
            save_child_position(chapter_module, section)
            context['fragment'] = section_module.render(STUDENT_VIEW)
            context['section_title'] = section_descriptor.display_name_with_default
        else:
            # section is none, so display a message
            studio_url = get_studio_url(course, 'course')
            prev_section = get_current_child(chapter_module)
            if prev_section is None:
                # Something went wrong -- perhaps this chapter has no sections visible to the user.
                # Clearing out the last-visited state and showing "first-time" view by redirecting
                # to courseware.
                course_module.position = None
                course_module.save()
                return redirect(reverse('courseware', args=[course.id.to_deprecated_string()]))
            prev_section_url = reverse('courseware_section', kwargs={
                'course_id': course_key.to_deprecated_string(),
                'chapter': chapter_descriptor.url_name,
                'section': prev_section.url_name
            })
            context['fragment'] = Fragment(content=render_to_string(
                'courseware/welcome-back.html',
                {
                    'course': course,
                    'studio_url': studio_url,
                    'chapter_module': chapter_module,
                    'prev_section': prev_section,
                    'prev_section_url': prev_section_url
                }
            ))

        result = render_to_response('courseware/courseware.html', context)
    except Exception as e:

        # Doesn't bar Unicode characters from URL, but if Unicode characters do
        # cause an error it is a graceful failure.
        if isinstance(e, UnicodeEncodeError):
            raise Http404("URL contains Unicode characters")

        if isinstance(e, Http404):
            # let it propagate
            raise

        # In production, don't want to let a 500 out for any reason
        if settings.DEBUG:
            raise
        else:
            log.exception(
                u"Error in index view: user={user}, course={course}, chapter={chapter}"
                u" section={section} position={position}".format(
                    user=user,
                    course=course,
                    chapter=chapter,
                    section=section,
                    position=position
                ))
            try:
                result = render_to_response('courseware/courseware-error.html', {
                    'staff_access': staff_access,
                    'course': course
                })
            except:
                # Let the exception propagate, relying on global config to at
                # at least return a nice error message
                log.exception("Error while rendering courseware-error page")
                raise

    return result
Esempio n. 36
0
def index(request, course_id):
    # Palette
    color_not = '#CCCCCC'
    color_fail = '#e41a1c'
    color_ok = '#F2F20D'
    color_prof = '#4daf4a'
    problem_activity='#377eb8'
    video_activity='#ff7f00'
    video_repetition='#fdbf6f'
    course_activity='#984ea3'
    graded_time='#88419d'
    ungraded_time='#8c6bb1'
    chapter_time='#8c96c6'
    play_event='#1b9e77'
    pause_event='#d95f02'
    seek_from_event='#7570b3'
    seek_to_event='#e7298a'
    change_speed_event='#66a61e'
    morning_time='#C9C96C'
    afternoon_time ='#7F7160'
    night_time ='#50587C'
    # Request data
    course_key = get_course_key(course_id)
    course = get_course_module(course_key)
    #course2= get_course_by_id(SlashSeparatedCourseKey.from_deprecated_string(course_id))
    #user = request.user #Codigo Jose A. Gascon
    staff_access = has_access(request.user, 'staff', course).has_access#Codigo Jose A. Gascon
    instructor_access = has_access(request.user, 'instructor', course).has_access#Codigo Jose A. Gascon
    #Codigo Jose A. Gascon
    masq, user = setup_masquerade(request, course_key,staff_access, reset_masquerade_data=True)  # allow staff to toggle masquerade on info page
    user = request.user
    studio_url = get_studio_url(course, 'course_info')
    
    #reverifications = fetch_reverify_banner_info(request, course_key)
    #course = get_course_with_access(request.user, action='load', course_key=course_key, depth=None, check_if_enrolled=False)
    #user = User.objects.get(request.user.email)
    # Proficiency and pass limit
    pass_limit = get_course_grade_cutoff(course)
    proficiency_limit = (1 - pass_limit) / 2 + pass_limit
    usernames_in = []
    for student in CourseEnrollment.objects.users_enrolled_in(course_key):#Codigo Jose A. Gascon, se cambia la forma de llamar al metode users_enrolled_in
        usernames_in.append(student.username.encode('utf-8'))


    # Data for visualization in JSON
    user_for_charts = '#average' if (staff_access or instructor_access) else user
    kwargs = {
        'qualifiers': {'category': 'video', },
    }     
    # This returns video descriptors in the order they appear on the course
    video_descriptors = videos_problems_in(course)[0]
    #WARNINIG 
    #video_durations = get_info_videos_descriptors(video_descriptors)[2]
    #video_names, video_module_keys, video_durations = get_info_videos_descriptors(video_descriptors) # NO SE USAN LAS OTRAS VARIABLES
    video_names, video_module_keys, video_durations =get_DB_infovideos(course_key)
    video_names_sorted = video_names
    video_ids_sort = video_names_sorted

    #course_name = get_course_by_id(course_key, depth=None)
    names_students=[]
    only_students = []
    students_names = get_course_students(course_key)
    print students_names
    for student in students_names:
        staff_access_user = has_access(student, 'staff', course).has_access
        instructor_access_user = has_access(student, 'instructor', course).has_access
        if not (staff_access_user or instructor_access_user):
            names_students.append(student.username.encode('utf-8'))
            only_students.append(student)

    video_ids_str = []
    course_video_names = []
    problem_ids_str=[]
    for descriptor in video_descriptors:
        video_ids_str.append((course_key.make_usage_key('video', descriptor.location.name))._to_string())
        course_video_names.append(unicodedata.normalize('NFKD', descriptor.display_name_with_default).encode('ASCII', 'ignore'))
    if len(video_descriptors) > 0:
        first_video_id = course_key.make_usage_key('video', video_descriptors[0].location.name)
        # Video progress visualization. Video percentage seen total and non-overlapped.
        video_names, avg_video_time, video_percentages = get_video_time_watched(user_for_charts, course_key)  
        if avg_video_time != []:
            all_video_time_percent = map(truediv, avg_video_time, video_durations)
            all_video_time_percent = [int(round(x*100,0)) for x in all_video_time_percent]
        else:
            all_video_time_percent = avg_video_time


        column_headers = ['Video', 'Different video time', 'Total video time']
        # Codigo Javier Orcoyen
        video_prog_json = ready_for_arraytodatatable(column_headers, video_names, video_percentages, all_video_time_percent)
        video_names, all_video_time = get_module_consumption(user_for_charts, course_key, 'video')
        # Time spent on every video resource
        column_headers = ['Video', 'Time watched']
        video_distrib_json = ready_for_arraytodatatable(column_headers, video_names, all_video_time)
  
        # Video events dispersion within video length
        scatter_array = get_video_events_info(user_for_charts, first_video_id)    
  
        # Repetitions per video intervals
        user_for_vid_intervals = '#class_total_times' if user_for_charts == '#average' else user_for_charts
        video_intervals_array = get_user_video_intervals(user_for_vid_intervals, first_video_id)        

    # Case no videos in course
    else:
        video_names = None
        video_prog_json = json.dumps(None)
        video_distrib_json = json.dumps(None)
        scatter_array = json.dumps(None)
        video_intervals_array = json.dumps(None)
          
    # Time spent on every problem resource
    # Codigo Javier Orcoyen
    problem_names, time_x_problem = get_module_consumption(user_for_charts, course_key, 'problem')
    column_headers = ['Problem', 'Time on problem']
    problem_distrib_json = ready_for_arraytodatatable(column_headers, problem_names, time_x_problem)
    print 'USER'
    print user
    problems_in = videos_problems_in(course)[1]
    problem_names_sorted = [x.display_name_with_default.encode('utf-8') for x in problems_in]
    orden=[]
    orden.append(i for i, x in enumerate(problem_names_sorted))
    problem_ids_str=list(problem_names_sorted)
    for n in range(len(problem_names_sorted)):
        problem_names_sorted[n]= unicodedata.normalize('NFKD', unicode(problem_names_sorted[n],'utf-8')).encode('ASCII', 'ignore')
        problem_ids_str[n]= unicodedata.normalize('NFKD', unicode(problem_ids_str[n],'utf-8')).encode('ASCII', 'ignore')
    user_val=1
    # Daily time spent on video and/or problem resources
    video_days, video_daily_time = get_daily_consumption(user_for_charts, course_key, 'video')
    problem_days, problem_daily_time = get_daily_consumption(user_for_charts, course_key, 'problem')    
    vid_and_prob_daily_time = join_video_problem_time(video_days, video_daily_time, problem_days, problem_daily_time) 
    #Analytics visualizations
    if staff_access or instructor_access:
        # Instructor access
        std_sort = get_DB_sort_course_homework(course_key)
        # Chapter time
        cs, st = get_DB_course_spent_time(course_key, student_id=ALL_STUDENTS)
        students_spent_time = chapter_time_to_js(cs, st)
        students_grades = get_DB_student_grades(course_key, student_id=ALL_STUDENTS) 
        cs, sa = course_accesses = get_DB_course_section_accesses(course_key, student_id=ALL_STUDENTS)
        students_course_accesses = course_accesses_to_js(cs, sa)
        #students_prob_vid_progress = get_DB_course_video_problem_progress(course_key, student_id=ALL_STUDENTS)# C. J. A. Gascon ERROR
        students_time_schedule = get_DB_time_schedule(course_key, student_id=ALL_STUDENTS)
    else:
        # Sort homework                    
        # Chapter time
        std_sort = None
        cs, st = get_DB_course_spent_time(course_key, user.id)
        students_spent_time = chapter_time_to_js(cs, st) 
        students_grades = get_DB_student_grades(course_key, user.id) 
        cs, sa = course_accesses = get_DB_course_section_accesses(course_key, user.id)
        students_course_accesses = course_accesses_to_js(cs, sa) 
        students_time_schedule = get_DB_time_schedule(course_key, user.id)  
        #students_prob_vid_progress = get_DB_course_video_problem_progress(course_key, user.id)  #C. J. A. Gascon ERROR

    context = {'course': course,
               'request': request,
               'user': user,
               'user_id': user.id,
               'staff_access': staff_access,
               'instructor_access': instructor_access,
               'masquerade': masq,
               'studio_url': studio_url,
               #'reverifications': reverifications,
               'course_id': course_id,
               'students': students_to_js(only_students),
               'visualizations_id': VISUALIZATIONS_ID,
               'std_grades_dump': dumps(students_grades),
               'sort_std_dump': dumps(std_sort),
               'time_dump': dumps(students_spent_time),
               'accesses_dump': dumps(students_course_accesses),
               'std_time_schedule_dumb': dumps(students_time_schedule), 
               #'vid_prob_prog_dump': dumps(students_prob_vid_progress), #C. J. A. Gascon ERROR
               'pass_limit': pass_limit,
               'prof_limit': proficiency_limit,
               'usernames_in' : usernames_in,
               'video_names' : course_video_names,
               'video_ids' : video_ids_str,
               'video_prog_json' : video_prog_json,
               'video_distrib_json' : video_distrib_json,
               'problem_distrib_json' : problem_distrib_json,
               'video_intervals_array' : video_intervals_array,
               'vid_and_prob_daily_time' : vid_and_prob_daily_time,
               'scatter_array' : scatter_array,
               'problem_names' : problem_names,
               'problem_ids' : problem_ids_str,
               'color_not' : color_not,
               'color_ok' : color_ok,
               'color_prof' : color_prof,
               'color_fail' : color_fail,
               'problem_activity' : problem_activity,
               'video_activity' : video_activity,
               'course_activity' : course_activity,
               'video_repetition' : video_repetition,
               'graded_time' : graded_time,
               'ungraded_time' : ungraded_time,
               'chapter_time' : chapter_time,
               'user_for_charts' : user_for_charts,
               'video_ids_sort' : video_ids_sort,
               'video_names_sorted' : video_names_sorted,
               'problem_names_sorted' : problem_names_sorted,
               'play_event' : play_event,
               'pause_event' : pause_event,
               'seek_from_event' : seek_from_event,
               'seek_to_event' : seek_to_event,
               'change_speed_event' : change_speed_event,
               'morning_time' : morning_time,
               'afternoon_time' : afternoon_time,
               'night_time' : night_time,
               'names_students' : names_students,
               'user_val' : user_val,}
        
    return render_to_response('learning_analytics/learning_analytics.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)

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

    analytics_dashboard_message = None
    if settings.ANALYTICS_DASHBOARD_URL:
        # 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("<a href=\"{}\" target=\"_blank\">").format(analytics_dashboard_url)
        analytics_dashboard_message = _(
            "To gain insights into student enrollment and participation {link_start}"
            "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 settings.FEATURES.get('INDIVIDUAL_DUE_DATES') and access['instructor']:
        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, is_white_label))

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

    # NOTE: For now, if we only have procotred exams enabled, then only platform Staff
    # (user.is_staff) will be able to view the special exams tab. This may
    # change in the future
    can_see_special_exams = (
        ((course.enable_proctored_exams and request.user.is_staff) or course.enable_timed_exams) 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.
    certs_enabled = CertificateGenerationConfiguration.current().enabled
    if certs_enabled and access['admin']:
        sections.append(_section_certificates(course))

    disable_buttons = not _is_small_course(course_key)

    certificate_white_list = CertificateWhitelist.get_certificate_white_list(course_key)
    generate_certificate_exceptions_url = reverse(  # pylint: disable=invalid-name
        'generate_certificate_exceptions',
        kwargs={'course_id': unicode(course_key), 'generate_for': ''}
    )
    generate_bulk_certificate_exceptions_url = reverse(  # pylint: disable=invalid-name
        '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(  # pylint: disable=invalid-name
        '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)
Esempio n. 38
0
def instructor_dashboard_2(request, course_id):
    """ Display the instructor dashboard for a course. """
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    course = get_course_by_id(course_key, depth=None)

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

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

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

    # check if there is corresponding entry in the CourseMode Table related to the Instructor Dashboard course
    course_honor_mode = CourseMode.mode_for_course(course_key, "honor")
    course_mode_has_price = False
    if course_honor_mode and course_honor_mode.min_price > 0:
        course_mode_has_price = True

    if settings.FEATURES.get("INDIVIDUAL_DUE_DATES") and access["instructor"]:
        sections.insert(3, _section_extensions(course))

    # Gate access to course email by feature flag & by course-specific authorization
    if bulk_email_is_enabled_for_course(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:
        sections.append(_section_e_commerce(course, access))

    disable_buttons = not _is_small_course(course_key)

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

    context = {
        "course": course,
        "old_dashboard_url": reverse("instructor_dashboard_legacy", kwargs={"course_id": unicode(course_key)}),
        "studio_url": get_studio_url(course, "course"),
        "sections": sections,
        "disable_buttons": disable_buttons,
        "analytics_dashboard_message": analytics_dashboard_message,
    }

    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. """
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    course = get_course_by_id(course_key, depth=None)

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

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

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

    #check if there is corresponding entry in the CourseMode Table related to the Instructor Dashboard course
    course_honor_mode = CourseMode.mode_for_course(course_key, 'honor')
    course_mode_has_price = False
    if course_honor_mode and course_honor_mode.min_price > 0:
        course_mode_has_price = True

    if (settings.FEATURES.get('INDIVIDUAL_DUE_DATES')
            and access['instructor']):
        sections.insert(3, _section_extensions(course))

    # Gate access to course email by feature flag & by course-specific authorization
    if bulk_email_is_enabled_for_course(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:
        sections.append(_section_e_commerce(course, access))

    enrollment_count = sections[0]['enrollment_count']['total']
    disable_buttons = False
    max_enrollment_for_buttons = settings.FEATURES.get(
        "MAX_ENROLLMENT_INSTR_BUTTONS")
    if max_enrollment_for_buttons is not None:
        disable_buttons = enrollment_count > max_enrollment_for_buttons

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

    context = {
        'course':
        course,
        'old_dashboard_url':
        reverse('instructor_dashboard_legacy',
                kwargs={'course_id': course_key.to_deprecated_string()}),
        'studio_url':
        get_studio_url(course, 'course'),
        'sections':
        sections,
        'disable_buttons':
        disable_buttons,
        'analytics_dashboard_message':
        analytics_dashboard_message
    }

    return render_to_response(
        'instructor/instructor_dashboard_2/instructor_dashboard_2.html',
        context)
Esempio n. 40
0
    def _create_courseware_context(self, request):
        """
        Returns and creates the rendering context for the courseware.
        Also returns the table of contents for the courseware.
        """
        course_url_name = default_course_url_name(self.course.id)
        course_url = reverse(course_url_name,
                             kwargs={'course_id': unicode(self.course.id)})
        courseware_context = {
            'csrf':
            csrf(self.request)['csrf_token'],
            'course':
            self.course,
            'course_url':
            course_url,
            'chapter':
            self.chapter,
            'section':
            self.section,
            'init':
            '',
            'fragment':
            Fragment(),
            'staff_access':
            self.is_staff,
            'masquerade':
            self.masquerade,
            'supports_preview_menu':
            True,
            'studio_url':
            get_studio_url(self.course, 'course'),
            'xqa_server':
            settings.FEATURES.get('XQA_SERVER', "http://your_xqa_server.com"),
            'bookmarks_api_url':
            reverse('bookmarks'),
            'language_preference':
            self._get_language_preference(),
            'disable_optimizely':
            not WaffleSwitchNamespace('RET').is_enabled(
                'enable_optimizely_in_courseware'),
            'section_title':
            None,
            'sequence_title':
            None,
            'disable_accordion':
            COURSE_OUTLINE_PAGE_FLAG.is_enabled(self.course.id),
            # TODO: (Experimental Code). See https://openedx.atlassian.net/wiki/display/RET/2.+In-course+Verification+Prompts
            'upgrade_link':
            check_and_get_upgrade_link(request, self.effective_user,
                                       self.course.id),
            'upgrade_price':
            get_cosmetic_verified_display_price(self.course),
            # ENDTODO
        }
        table_of_contents = toc_for_course(
            self.effective_user,
            self.request,
            self.course,
            self.chapter_url_name,
            self.section_url_name,
            self.field_data_cache,
        )
        courseware_context['accordion_json'] = table_of_contents

        courseware_context['accordion'] = render_accordion(
            self.request,
            self.course,
            table_of_contents['chapters'],
        )

        courseware_context['course_sock_fragment'] = CourseSockFragmentView(
        ).render_to_fragment(request, course=self.course)

        # entrance exam data
        self._add_entrance_exam_to_context(courseware_context)

        # staff masquerading data
        if not is_course_open_for_learner(self.effective_user, self.course):
            # Disable student view button if user is staff and
            # course is not yet visible to students.
            courseware_context['disable_student_access'] = True
            courseware_context['supports_preview_menu'] = False

        if self.section:
            # chromeless data
            if self.section.chrome:
                chrome = [
                    s.strip() for s in self.section.chrome.lower().split(",")
                ]
                if 'accordion' not in chrome:
                    courseware_context['disable_accordion'] = True
                if 'tabs' not in chrome:
                    courseware_context['disable_tabs'] = True

            # default tab
            if self.section.default_tab:
                courseware_context['default_tab'] = self.section.default_tab

            # section data
            courseware_context[
                'section_title'] = self.section.display_name_with_default
            section_context = self._create_section_context(
                table_of_contents['previous_of_active_section'],
                table_of_contents['next_of_active_section'],
            )
            courseware_context['fragment'] = self.section.render(
                STUDENT_VIEW, section_context)
            if self.section.position and self.section.has_children:
                display_items = self.section.get_display_items()
                if display_items:
                    try:
                        courseware_context['sequence_title'] = display_items[self.section.position - 1] \
                            .display_name_with_default
                    except IndexError:
                        log.exception(
                            "IndexError loading courseware for user %s, course %s, section %s, position %d. Total items: %d. URL: %s",
                            self.real_user.username,
                            self.course.id,
                            self.section.display_name_with_default,
                            self.section.position,
                            len(display_items),
                            self.url,
                        )
                        raise

        return courseware_context
Esempio n. 41
0
def course_about(request, course_id):
    """
    Display the course's about page.

    Assumes the course_id is in a valid format.
    """

    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)

    with modulestore().bulk_operations(course_key):
        permission_name = microsite.get_value(
            'COURSE_ABOUT_VISIBILITY_PERMISSION',
            settings.COURSE_ABOUT_VISIBILITY_PERMISSION
        )
        course = get_course_with_access(request.user, permission_name, course_key)

        if microsite.get_value('ENABLE_MKTG_SITE', settings.FEATURES.get('ENABLE_MKTG_SITE', False)):
            return redirect(reverse('info', args=[course.id.to_deprecated_string()]))

        registered = registered_for_course(course, request.user)

        staff_access = has_access(request.user, 'staff', course)
        studio_url = get_studio_url(course, 'settings/details')

        if has_access(request.user, 'load', course):
            course_target = reverse('info', args=[course.id.to_deprecated_string()])
        else:
            course_target = reverse('about_course', args=[course.id.to_deprecated_string()])

        show_courseware_link = (
            (
                has_access(request.user, 'load', course)
                and has_access(request.user, 'view_courseware_with_prerequisites', course)
            )
            or settings.FEATURES.get('ENABLE_LMS_MIGRATION')
        )

        # Note: this is a flow for payment for course registration, not the Verified Certificate flow.
        registration_price = 0
        in_cart = False
        reg_then_add_to_cart_link = ""

        _is_shopping_cart_enabled = is_shopping_cart_enabled()
        if _is_shopping_cart_enabled:
            registration_price = CourseMode.min_course_price_for_currency(course_key,
                                                                          settings.PAID_COURSE_REGISTRATION_CURRENCY[0])
            if request.user.is_authenticated():
                cart = shoppingcart.models.Order.get_cart_for_user(request.user)
                in_cart = shoppingcart.models.PaidCourseRegistration.contained_in_order(cart, course_key) or \
                    shoppingcart.models.CourseRegCodeItem.contained_in_order(cart, course_key)

            reg_then_add_to_cart_link = "{reg_url}?course_id={course_id}&enrollment_action=add_to_cart".format(
                reg_url=reverse('register_user'), course_id=course.id.to_deprecated_string())

        course_price = get_cosmetic_display_price(course, registration_price)
        can_add_course_to_cart = _is_shopping_cart_enabled and registration_price

        # Used to provide context to message to student if enrollment not allowed
        can_enroll = has_access(request.user, 'enroll', course)
        invitation_only = course.invitation_only
        is_course_full = CourseEnrollment.is_course_full(course)

        # Register button should be disabled if one of the following is true:
        # - Student is already registered for course
        # - Course is already full
        # - Student cannot enroll in course
        active_reg_button = not(registered or is_course_full or not can_enroll)

        is_shib_course = uses_shib(course)

        # get prerequisite courses display names
        pre_requisite_courses = get_prerequisite_courses_display(course)

        return render_to_response('courseware/course_about.html', {
            'course': course,
            'staff_access': staff_access,
            'studio_url': studio_url,
            'registered': registered,
            'course_target': course_target,
            'is_cosmetic_price_enabled': settings.FEATURES.get('ENABLE_COSMETIC_DISPLAY_PRICE'),
            'course_price': course_price,
            'in_cart': in_cart,
            'reg_then_add_to_cart_link': reg_then_add_to_cart_link,
            'show_courseware_link': show_courseware_link,
            'is_course_full': is_course_full,
            'can_enroll': can_enroll,
            'invitation_only': invitation_only,
            'active_reg_button': active_reg_button,
            'is_shib_course': is_shib_course,
            # We do not want to display the internal courseware header, which is used when the course is found in the
            # context. This value is therefor explicitly set to render the appropriate header.
            'disable_courseware_header': True,
            'can_add_course_to_cart': can_add_course_to_cart,
            'cart_link': reverse('shoppingcart.views.show_cart'),
            'pre_requisite_courses': pre_requisite_courses
        })
Esempio n. 42
0
def index(request, course_id):
    # Palette
    color_not = '#CCCCCC'
    color_fail = '#e41a1c'
    color_ok = '#F2F20D'
    color_prof = '#4daf4a'
    problem_activity='#377eb8'
    video_activity='#ff7f00'
    video_repetition='#fdbf6f'
    course_activity='#984ea3'
    graded_time='#88419d'
    ungraded_time='#8c6bb1'
    chapter_time='#8c96c6'
    play_event='#1b9e77'
    pause_event='#d95f02'
    seek_from_event='#7570b3'
    seek_to_event='#e7298a'
    change_speed_event='#66a61e'
    morning_time='#C9C96C'
    afternoon_time ='#7F7160'
    night_time ='#50587C'
    # Request data
    course_key = get_course_key(course_id)
    course = get_course_module(course_key)
    #course2= get_course_by_id(SlashSeparatedCourseKey.from_deprecated_string(course_id))
    #user = request.user #Codigo Jose A. Gascon
    staff_access = has_access(request.user, 'staff', course).has_access#Codigo Jose A. Gascon
    instructor_access = has_access(request.user, 'instructor', course).has_access#Codigo Jose A. Gascon
    #Codigo Jose A. Gascon
    masq, user = setup_masquerade(request, course_key,staff_access, reset_masquerade_data=True)  # allow staff to toggle masquerade on info page
    user = request.user
    studio_url = get_studio_url(course, 'course_info')
    
    #reverifications = fetch_reverify_banner_info(request, course_key)
    
    #course = get_course_with_access(request.user, action='load', course_key=course_key, depth=None, check_if_enrolled=False)
    #user = User.objects.get(request.user.email)
    # Proficiency and pass limit
    pass_limit = get_course_grade_cutoff(course)
    proficiency_limit = (1 - pass_limit) / 2 + pass_limit
    usernames_in = []
    for student in CourseEnrollment.objects.users_enrolled_in(course_key):#Codigo Jose A. Gascon, se cambia la forma de llamar al metode users_enrolled_in
        usernames_in.append(student.username.encode('utf-8'))


    # Data for visualization in JSON
    user_for_charts = '#average' if (staff_access or instructor_access) else user
    kwargs = {
        'qualifiers': {'category': 'video', },
    }     
    # This returns video descriptors in the order they appear on the course
    video_descriptors = videos_problems_in(course)[0]
    #WARNINIG 
    #video_durations = get_info_videos_descriptors(video_descriptors)[2]
    #video_names, video_module_keys, video_durations = get_info_videos_descriptors(video_descriptors) # NO SE USAN LAS OTRAS VARIABLES
    video_names, video_module_keys, video_durations =get_DB_infovideos()
    video_names_sorted = video_names
    video_ids_sort = video_names_sorted

    #course_name = get_course_by_id(course_key, depth=None)
    names_students=[]
    only_students = []
    students_names = get_course_students(course_key)
    print students_names
    for student in students_names:
        staff_access_user = has_access(student, 'staff', course).has_access
        instructor_access_user = has_access(student, 'instructor', course).has_access
        if not (staff_access_user or instructor_access_user):
            names_students.append(student.username.encode('utf-8'))
            only_students.append(student)

    video_ids_str = []
    course_video_names = []
    problem_ids_str=[]
    for descriptor in video_descriptors:
        video_ids_str.append((course_key.make_usage_key('video', descriptor.location.name))._to_string())
        course_video_names.append(descriptor.display_name_with_default)
    if len(video_descriptors) > 0:
        first_video_id = course_key.make_usage_key('video', video_descriptors[0].location.name)
        # Video progress visualization. Video percentage seen total and non-overlapped.
        video_names, avg_video_time, video_percentages = get_video_time_watched(user_for_charts, course_key)  
        if avg_video_time != []:
            all_video_time_percent = map(truediv, avg_video_time, video_durations)
            all_video_time_percent = [int(round(x*100,0)) for x in all_video_time_percent]
        else:
            all_video_time_percent = avg_video_time


        column_headers = ['Video', 'Different video time', 'Total video time']
        # Codigo Javier Orcoyen
        video_prog_json = ready_for_arraytodatatable(column_headers, video_names, video_percentages, all_video_time_percent)
        video_names, all_video_time = get_module_consumption(user_for_charts, course_key, 'video')
        # Time spent on every video resource
        column_headers = ['Video', 'Time watched']
        video_distrib_json = ready_for_arraytodatatable(column_headers, video_names, all_video_time)
  
        # Video events dispersion within video length
        scatter_array = get_video_events_info(user_for_charts, first_video_id)    
  
        # Repetitions per video intervals
        user_for_vid_intervals = '#class_total_times' if user_for_charts == '#average' else user_for_charts
        video_intervals_array = get_user_video_intervals(user_for_vid_intervals, first_video_id)        

    # Case no videos in course
    else:
        video_names = None
        video_prog_json = json.dumps(None)
        video_distrib_json = json.dumps(None)
        scatter_array = json.dumps(None)
        video_intervals_array = json.dumps(None)
          
    # Time spent on every problem resource
    # Codigo Javier Orcoyen
    problem_names, time_x_problem = get_module_consumption(user_for_charts, course_key, 'problem')
    column_headers = ['Problem', 'Time on problem']
    problem_distrib_json = ready_for_arraytodatatable(column_headers, problem_names, time_x_problem)
    print 'USER'
    print user
    problems_in = videos_problems_in(course)[1]
    problem_names_sorted = [x.display_name_with_default.encode('utf-8') for x in problems_in]
    orden=[]
    orden.append(i for i, x in enumerate(problem_names_sorted))
    problem_ids_str=problem_names_sorted
    # Daily time spent on video and/or problem resources
    video_days, video_daily_time = get_daily_consumption(user_for_charts, course_key, 'video')
    problem_days, problem_daily_time = get_daily_consumption(user_for_charts, course_key, 'problem')    
    vid_and_prob_daily_time = join_video_problem_time(video_days, video_daily_time, problem_days, problem_daily_time) 
    #Analytics visualizations
    if staff_access or instructor_access:
        # Instructor access
        std_sort = get_DB_sort_course_homework(course_key)
        # Chapter time
        cs, st = get_DB_course_spent_time(course_key, student_id=ALL_STUDENTS)
        students_spent_time = chapter_time_to_js(cs, st)
        students_grades = get_DB_student_grades(course_key, student_id=ALL_STUDENTS) 
        cs, sa = course_accesses = get_DB_course_section_accesses(course_key, student_id=ALL_STUDENTS)
        students_course_accesses = course_accesses_to_js(cs, sa)
        #students_prob_vid_progress = get_DB_course_video_problem_progress(course_key, student_id=ALL_STUDENTS)# C. J. A. Gascon ERROR
        students_time_schedule = get_DB_time_schedule(course_key, student_id=ALL_STUDENTS)
    else:
        # Sort homework                    
        # Chapter time
        std_sort = None
        cs, st = get_DB_course_spent_time(course_key, user.id)
        students_spent_time = chapter_time_to_js(cs, st) 
        students_grades = get_DB_student_grades(course_key, user.id) 
        cs, sa = course_accesses = get_DB_course_section_accesses(course_key, user.id)
        students_course_accesses = course_accesses_to_js(cs, sa) 
        students_time_schedule = get_DB_time_schedule(course_key, user.id)  
        #students_prob_vid_progress = get_DB_course_video_problem_progress(course_key, user.id)  #C. J. A. Gascon ERROR

    context = {'course': course,
               'request': request,
               'user': user,
               'user_id': user.id,
               'staff_access': staff_access,
               'instructor_access': instructor_access,
               'masquerade': masq,
               'studio_url': studio_url,
               #'reverifications': reverifications,
               'course_id': course_id,
               'students': students_to_js(only_students),
               'visualizations_id': VISUALIZATIONS_ID,
               'std_grades_dump': dumps(students_grades),
               'sort_std_dump': dumps(std_sort),
               'time_dump': dumps(students_spent_time),
               'accesses_dump': dumps(students_course_accesses),
               'std_time_schedule_dumb': dumps(students_time_schedule), 
               #'vid_prob_prog_dump': dumps(students_prob_vid_progress), #C. J. A. Gascon ERROR
               'pass_limit': pass_limit,
               'prof_limit': proficiency_limit,
               'usernames_in' : usernames_in,
               'video_names' : course_video_names,
               'video_ids' : video_ids_str,
               'video_prog_json' : video_prog_json,
               'video_distrib_json' : video_distrib_json,
               'problem_distrib_json' : problem_distrib_json,
               'video_intervals_array' : video_intervals_array,
               'vid_and_prob_daily_time' : vid_and_prob_daily_time,
               'scatter_array' : scatter_array,
               'problem_names' : problem_names,
               'problem_ids' : problem_ids_str,
               'color_not' : color_not,
               'color_ok' : color_ok,
               'color_prof' : color_prof,
               'color_fail' : color_fail,
               'problem_activity' : problem_activity,
               'video_activity' : video_activity,
               'course_activity' : course_activity,
               'video_repetition' : video_repetition,
               'graded_time' : graded_time,
               'ungraded_time' : ungraded_time,
               'chapter_time' : chapter_time,
               'user_for_charts' : user_for_charts,
               'video_ids_sort' : video_ids_sort,
               'video_names_sorted' : video_names_sorted,
               'problem_names_sorted' : problem_names_sorted,
               'play_event' : play_event,
               'pause_event' : pause_event,
               'seek_from_event' : seek_from_event,
               'seek_to_event' : seek_to_event,
               'change_speed_event' : change_speed_event,
               'morning_time' : morning_time,
               'afternoon_time' : afternoon_time,
               'night_time' : night_time,
               'names_students' : names_students,}
        
    return render_to_response('learning_analytics/learning_analytics.html', context)