""" Progress Tab Views """ from django.http.response import Http404 from edx_django_utils import monitoring as monitoring_utils from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication from edx_rest_framework_extensions.auth.session.authentication import SessionAuthenticationAllowInactiveUser from opaque_keys.edx.keys import CourseKey from rest_framework.generics import RetrieveAPIView from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from xmodule.modulestore.django import modulestore from common.djangoapps.student.models import CourseEnrollment from lms.djangoapps.course_home_api.progress.v1.serializers import ProgressTabSerializer from lms.djangoapps.course_home_api.toggles import course_home_mfe_progress_tab_is_active from lms.djangoapps.courseware.access import has_access from lms.djangoapps.courseware.courses import get_course_blocks_completion_summary, get_course_with_access, get_studio_url from lms.djangoapps.courseware.masquerade import setup_masquerade from lms.djangoapps.courseware.views.views import get_cert_data from lms.djangoapps.grades.api import CourseGradeFactory from lms.djangoapps.verify_student.services import IDVerificationService from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiveUser class ProgressTabView(RetrieveAPIView): """ **Use Cases** Request details for the Progress Tab **Example Requests** GET api/course_home/v1/progress/{course_key} **Response Values** Body consists of the following fields: certificate_data: Object containing information about the user's certificate status cert_status: (str) the status of a user's certificate (full list of statuses are defined in lms/djangoapps/certificates/models.py) cert_web_view_url: (str) the url to view the certificate download_url: (str) the url to download the certificate completion_summary: Object containing unit completion counts with the following fields: complete_count: (float) number of complete units incomplete_count: (float) number of incomplete units locked_count: (float) number of units where contains_gated_content is True course_grade: Object containing the following fields: percent: (float) the user's total graded percent in the course is_passing: (bool) whether the user's grade is above the passing grade cutoff section_scores: List of serialized Chapters. Each Chapter has the following fields: display_name: (str) a str of what the name of the Chapter is for displaying on the site subsections: List of serialized Subsections, each has the following fields: assignment_type: (str) the format, if any, of the Subsection (Homework, Exam, etc) display_name: (str) a str of what the name of the Subsection is for displaying on the site has_graded_assignment: (bool) whether or not the Subsection is a graded assignment num_points_earned: (int) the amount of points the user has earned for the given subsection num_points_possible: (int) the total amount of points possible for the given subsection percent_graded: (float) the percentage of total points the user has received a grade for in a given subsection show_correctness: (str) a str representing whether to show the problem/practice scores based on due date ('always', 'never', 'past_due', values defined in common/lib/xmodule/xmodule/modulestore/inheritance.py) show_grades: (bool) a bool for whether to show grades based on the access the user has url: (str) the absolute path url to the Subsection enrollment_mode: (str) a str representing the enrollment the user has ('audit', 'verified', ...) grading_policy: assignment_policies: List of serialized assignment grading policy objects, each has the following fields: num_droppable: (int) the number of lowest scored assignments that will not be counted towards the final grade short_label: (str) the abbreviated name given to the assignment type type: (str) the assignment type weight: (float) the percent weight the given assigment type has on the overall grade grade_range: an object containing the grade range cutoffs. The exact keys in the object can vary, but they range from just 'Pass', to a combination of 'A', 'B', 'C', and 'D'. If a letter grade is present, 'Pass' is not included. studio_url: (str) a str of the link to the grading in studio for the course verification_data: an object containing link: (str) the link to either start or retry verification status: (str) the status of the verification status_date: (str) the date time string of when the verification status was set **Returns** * 200 on success with above fields. * 302 if the user is not enrolled. * 401 if the user is not authenticated. * 404 if the course is not available or cannot be seen. """ authentication_classes = ( JwtAuthentication, BearerAuthenticationAllowInactiveUser, SessionAuthenticationAllowInactiveUser, ) permission_classes = (IsAuthenticated,) serializer_class = ProgressTabSerializer def get(self, request, *args, **kwargs): course_key_string = kwargs.get('course_key_string') course_key = CourseKey.from_string(course_key_string) if not course_home_mfe_progress_tab_is_active(course_key): raise Http404 # Enable NR tracing for this view based on course monitoring_utils.set_custom_attribute('course_id', course_key_string) monitoring_utils.set_custom_attribute('user_id', request.user.id) monitoring_utils.set_custom_attribute('is_staff', request.user.is_staff) _, request.user = setup_masquerade( request, course_key, staff_access=has_access(request.user, 'staff', course_key), reset_masquerade_data=True ) course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True) enrollment_mode, _ = CourseEnrollment.enrollment_mode_for_user(request.user, course_key) course_grade = CourseGradeFactory().read(request.user, course)\ descriptor = modulestore().get_course(course_key) grading_policy = descriptor.grading_policy verification_status = IDVerificationService.user_status(request.user) verification_link = None if verification_status['status'] is None or verification_status['status'] == 'expired': verification_link = IDVerificationService.get_verify_location(course_id=course_key) elif verification_status['status'] == 'must_reverify': verification_link = IDVerificationService.get_verify_location(course_id=course_key) verification_data = { 'link': verification_link, 'status': verification_status['status'], 'status_date': verification_status['status_date'], } data = { 'certificate_data': get_cert_data(request.user, course, enrollment_mode, course_grade), 'completion_summary': get_course_blocks_completion_summary(course_key, request.user), 'course_grade': course_grade, 'section_scores': course_grade.chapter_grades.values(), 'enrollment_mode': enrollment_mode, 'grading_policy': grading_policy, 'studio_url': get_studio_url(course, 'settings/grading'), 'verification_data': verification_data, } context = self.get_serializer_context() context['staff_access'] = bool(has_access(request.user, 'staff', course)) context['course_key'] = course_key serializer = self.get_serializer_class()(data, context=context) return Response(serializer.data)