diff --git a/lms/djangoapps/course_home_api/progress/v1/serializers.py b/lms/djangoapps/course_home_api/progress/v1/serializers.py index 0260d8c4b8..375d9daa78 100644 --- a/lms/djangoapps/course_home_api/progress/v1/serializers.py +++ b/lms/djangoapps/course_home_api/progress/v1/serializers.py @@ -2,8 +2,8 @@ Progress Tab Serializers """ from rest_framework import serializers -from lms.djangoapps.course_home_api.outline.v1.serializers import CourseBlockSerializer from rest_framework.reverse import reverse +from lms.djangoapps.certificates.models import CertificateStatuses class GradedTotalSerializer(serializers.Serializer): @@ -51,11 +51,41 @@ class ChapterSerializer(serializers.Serializer): subsections = SubsectionSerializer(source='sections', many=True) +class CertificateDataSerializer(serializers.Serializer): + cert_web_view_url = serializers.CharField() + download_url = serializers.CharField() + is_downloadable = serializers.SerializerMethodField() + is_requestable = serializers.SerializerMethodField() + msg = serializers.CharField() + title = serializers.CharField() + + def get_is_downloadable(self, cert_data): + return cert_data.cert_status == CertificateStatuses.downloadable and cert_data.download_url is not None + + def get_is_requestable(self, cert_data): + return cert_data.cert_status == CertificateStatuses.requesting and cert_data.request_cert_url is not None + + +class CreditCourseRequirementsSerializer(serializers.Serializer): + """ + Serializer for credit_course_requirements + """ + display_name = serializers.CharField() + namespace = serializers.CharField() + min_grade = serializers.SerializerMethodField() + status = serializers.CharField() + status_date = serializers.DateTimeField() + + def get_min_grade(self, req): + return req['criteria']['min_grade'] * 100 + + class ProgressTabSerializer(serializers.Serializer): """ Serializer for progress tab """ - course_blocks = CourseBlockSerializer() + certificate_data = CertificateDataSerializer() courseware_summary = ChapterSerializer(many=True) enrollment_mode = serializers.CharField() + studio_url = serializers.CharField() user_timezone = serializers.CharField() diff --git a/lms/djangoapps/course_home_api/progress/v1/tests/test_views.py b/lms/djangoapps/course_home_api/progress/v1/tests/test_views.py index fa8bc87048..5e6e89c4c4 100644 --- a/lms/djangoapps/course_home_api/progress/v1/tests/test_views.py +++ b/lms/djangoapps/course_home_api/progress/v1/tests/test_views.py @@ -35,6 +35,7 @@ class ProgressTabTestViews(BaseCourseHomeTests): self.assertIsNotNone(response.data['courseware_summary']) for chapter in response.data['courseware_summary']: self.assertIsNotNone(chapter) + self.assertIn('settings/grading/' + str(self.course.id), response.data['studio_url']) def test_get_authenticated_user_not_enrolled(self): response = self.client.get(self.url) diff --git a/lms/djangoapps/course_home_api/progress/v1/views.py b/lms/djangoapps/course_home_api/progress/v1/views.py index 4d90533bc9..602c0977f7 100644 --- a/lms/djangoapps/course_home_api/progress/v1/views.py +++ b/lms/djangoapps/course_home_api/progress/v1/views.py @@ -14,13 +14,13 @@ from lms.djangoapps.course_home_api.progress.v1.serializers import ProgressTabSe from student.models import CourseEnrollment from lms.djangoapps.course_api.blocks.transformers.blocks_api import BlocksAPITransformer from lms.djangoapps.courseware.context_processor import user_timezone_locale_prefs -from lms.djangoapps.courseware.courses import get_course_with_access +from lms.djangoapps.courseware.courses import get_course_with_access, get_studio_url from lms.djangoapps.courseware.masquerade import setup_masquerade from lms.djangoapps.courseware.access import has_access from xmodule.modulestore.django import modulestore -from lms.djangoapps.course_blocks.api import get_course_blocks import lms.djangoapps.course_blocks.api as course_blocks_api +from lms.djangoapps.courseware.views.views import credit_course_requirements, get_cert_data from lms.djangoapps.grades.api import CourseGradeFactory from openedx.core.djangoapps.content.block_structure.transformers import BlockStructureTransformers @@ -39,18 +39,13 @@ class ProgressTabView(RetrieveAPIView): Body consists of the following fields: - course_blocks: - blocks: List of serialized Course Block objects. Each serialization has the following fields: - id: (str) The usage ID of the block. - type: (str) The type of block. Possible values the names of any - XBlock type in the system, including custom blocks. Examples are - course, chapter, sequential, vertical, html, problem, video, and - discussion. - display_name: (str) The display name of the block. - lms_web_url: (str) The URL to the navigational container of the - xBlock on the web LMS. - children: (list) If the block has child blocks, a list of IDs of - the child blocks. + certificate_data: Object containing information about the user's certificate status + cert_web_view_url: (str) the url to view the certificate + download_url: (str) the url to download the certificate + is_downloadable: (bool) true if the status is downloadable and the download url is not None + is_requestable: (bool) true if status is requesting and request_cert_url is not None + msg: (str) message for the certificate status + title: (str) title of the certificate status courseware_summary: 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: @@ -66,6 +61,7 @@ class ProgressTabView(RetrieveAPIView): 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', ...) + studio_url: (str) a str of the link to the grading in studio for the course user_timezone: (str) The user's preferred timezone @@ -107,7 +103,6 @@ class ProgressTabView(RetrieveAPIView): BlocksAPITransformer(None, None, depth=3), ] course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True) - course_blocks = get_course_blocks(request.user, course_usage_key, transformers, include_completion=True) enrollment_mode, _ = CourseEnrollment.enrollment_mode_for_user(request.user, course_key) @@ -115,9 +110,10 @@ class ProgressTabView(RetrieveAPIView): courseware_summary = course_grade.chapter_grades.values() data = { - 'course_blocks': course_blocks, + 'certificate_data': get_cert_data(request.user, course, enrollment_mode, course_grade), 'courseware_summary': courseware_summary, 'enrollment_mode': enrollment_mode, + 'studio_url': get_studio_url(course, 'settings/grading'), 'user_timezone': user_timezone, } context = self.get_serializer_context() diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py index 0ec4836e00..2125e0307a 100644 --- a/lms/djangoapps/courseware/tests/test_views.py +++ b/lms/djangoapps/courseware/tests/test_views.py @@ -1707,7 +1707,7 @@ class ProgressPageTests(ProgressPageBaseTests): ) # Invalidate user certificate generated_certificate.invalidate() - response = views._get_cert_data(self.user, self.course, CourseMode.HONOR, MagicMock(passed=True)) + response = views.get_cert_data(self.user, self.course, CourseMode.HONOR, MagicMock(passed=True)) self.assertEqual(response.cert_status, 'invalidated') self.assertEqual(response.title, 'Your certificate has been invalidated') @@ -1720,7 +1720,7 @@ class ProgressPageTests(ProgressPageBaseTests): self.generate_certificate( "http://www.example.com/certificate.pdf", "honor" ) - response = views._get_cert_data( + response = views.get_cert_data( self.user, self.course, CourseMode.HONOR, MagicMock(passed=True) ) @@ -1736,7 +1736,7 @@ class ProgressPageTests(ProgressPageBaseTests): ) with patch('lms.djangoapps.certificates.api.certificate_downloadable_status', return_value=self.mock_certificate_downloadable_status(is_generating=True)): - response = views._get_cert_data(self.user, self.course, CourseMode.HONOR, MagicMock(passed=True)) + response = views.get_cert_data(self.user, self.course, CourseMode.HONOR, MagicMock(passed=True)) self.assertEqual(response.cert_status, 'generating') self.assertEqual(response.title, "We're working on it...") @@ -1750,7 +1750,7 @@ class ProgressPageTests(ProgressPageBaseTests): ) with patch('lms.djangoapps.certificates.api.certificate_downloadable_status', return_value=self.mock_certificate_downloadable_status(is_unverified=True)): - response = views._get_cert_data(self.user, self.course, CourseMode.HONOR, MagicMock(passed=True)) + response = views.get_cert_data(self.user, self.course, CourseMode.HONOR, MagicMock(passed=True)) self.assertEqual(response.cert_status, 'unverified') self.assertEqual(response.title, "Certificate unavailable") @@ -1764,7 +1764,7 @@ class ProgressPageTests(ProgressPageBaseTests): ) with patch('lms.djangoapps.certificates.api.certificate_downloadable_status', return_value=self.mock_certificate_downloadable_status()): - response = views._get_cert_data(self.user, self.course, CourseMode.HONOR, MagicMock(passed=True)) + response = views.get_cert_data(self.user, self.course, CourseMode.HONOR, MagicMock(passed=True)) self.assertEqual(response.cert_status, 'requesting') self.assertEqual(response.title, "Congratulations, you qualified for a certificate!") diff --git a/lms/djangoapps/courseware/views/views.py b/lms/djangoapps/courseware/views/views.py index 9595a47e74..b23e60cf0c 100644 --- a/lms/djangoapps/courseware/views/views.py +++ b/lms/djangoapps/courseware/views/views.py @@ -1170,9 +1170,9 @@ def _progress(request, course_key, student_id): 'masquerade': masquerade, 'supports_preview_menu': True, 'student': student, - 'credit_course_requirements': _credit_course_requirements(course_key, student), + 'credit_course_requirements': credit_course_requirements(course_key, student), 'course_expiration_fragment': course_expiration_fragment, - 'certificate_data': _get_cert_data(student, course, enrollment_mode, course_grade) + 'certificate_data': get_cert_data(student, course, enrollment_mode, course_grade) } context.update( @@ -1230,7 +1230,7 @@ def _certificate_message(student, course, enrollment_mode): return REQUESTING_CERT_DATA -def _get_cert_data(student, course, enrollment_mode, course_grade=None): +def get_cert_data(student, course, enrollment_mode, course_grade=None): """Returns students course certificate related data. Arguments: student (User): Student for whom certificate to retrieve. @@ -1257,7 +1257,7 @@ def _get_cert_data(student, course, enrollment_mode, course_grade=None): return cert_data -def _credit_course_requirements(course_key, student): +def credit_course_requirements(course_key, student): """Return information about which credit requirements a user has satisfied. Arguments: course_key (CourseKey): Identifier for the course.