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
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)
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)
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)
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
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 })
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)
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 })
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, }, )
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)
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
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
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
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)
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)
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)
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)
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, })
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)
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 })
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)
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, })
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
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
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)
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
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)
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)
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)
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
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
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)
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)
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
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 })
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)