From 9bd85dc929d0186b6f9dade1ba23d01ab29263cb Mon Sep 17 00:00:00 2001 From: Waheed Ahmed Date: Thu, 13 Feb 2020 16:22:35 +0500 Subject: [PATCH] Fix certificates API for old deleted XML course certificates. Certificates API is retuning 500 error for old XML courses in which learners have a valid certificate. PROD-1247 --- .../certificates/apis/v0/tests/test_views.py | 26 +++++++++++++++++++ lms/djangoapps/certificates/apis/v0/views.py | 21 ++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/lms/djangoapps/certificates/apis/v0/tests/test_views.py b/lms/djangoapps/certificates/apis/v0/tests/test_views.py index 01c6fa0fc3..2a8fafd39e 100644 --- a/lms/djangoapps/certificates/apis/v0/tests/test_views.py +++ b/lms/djangoapps/certificates/apis/v0/tests/test_views.py @@ -384,3 +384,29 @@ class CertificatesListRestApiTest(AuthAndScopesTestMixin, SharedModuleStoreTestC kwargs = {"certificate_uuid": self.cert.verify_uuid} expected_download_url = reverse('certificates:render_cert_by_uuid', kwargs=kwargs) self.assert_success_response_for_student(response, download_url=expected_download_url) + + @patch('lms.djangoapps.certificates.apis.v0.views.get_course_run_details') + def test_certificate_without_course(self, mock_get_course_run_details): + """ + Verify that certificates are returned for deleted XML courses. + """ + expected_course_name = 'Test Course Title' + mock_get_course_run_details.return_value = {'title': expected_course_name} + xml_course_key = self.store.make_course_key('edX', 'testDeletedCourse', '2020') + cert_for_deleted_course = GeneratedCertificateFactory.create( + user=self.student, + course_id=xml_course_key, + status=CertificateStatuses.downloadable, + mode='honor', + download_url='www.edx.org/honor-cert-for-deleted-course.pdf', + grade="0.88" + ) + + response = self.get_response( + AuthType.jwt, + requesting_user=self.student, + requested_user=self.student, + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertContains(response, cert_for_deleted_course.download_url) + self.assertContains(response, expected_course_name) diff --git a/lms/djangoapps/certificates/apis/v0/views.py b/lms/djangoapps/certificates/apis/v0/views.py index b313fe0ed1..7704682a92 100644 --- a/lms/djangoapps/certificates/apis/v0/views.py +++ b/lms/djangoapps/certificates/apis/v0/views.py @@ -18,6 +18,7 @@ from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from lms.djangoapps.certificates.api import get_certificate_for_user, get_certificates_for_user +from openedx.core.djangoapps.catalog.utils import get_course_run_details from openedx.core.djangoapps.certificates.api import certificates_viewable_for_course from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from openedx.core.djangoapps.user_api.accounts.api import visible_fields @@ -270,14 +271,32 @@ class CertificatesListView(APIView): for course_key, course_overview in CourseOverview.get_from_ids( list(passing_certificates.keys()) ).items(): + if not course_overview: + # For deleted XML courses in which learners have a valid certificate. + # i.e. MITx/7.00x/2013_Spring + course_overview = self._get_pseudo_course_overview(course_key) if certificates_viewable_for_course(course_overview): course_certificate = passing_certificates[course_key] # add certificate into viewable certificate list only if it's a PDF certificate # or there is an active certificate configuration. if course_certificate['is_pdf_certificate'] or course_overview.has_any_active_web_certificate: - course_certificate['course_display_name'] = course_overview.display_name_with_default + course_display_name = course_overview.display_name + if not course_overview.pk: + course_display_name = course_overview.display_name_with_default + course_certificate['course_display_name'] = course_display_name course_certificate['course_organization'] = course_overview.display_org_with_default viewable_certificates.append(course_certificate) viewable_certificates.sort(key=lambda certificate: certificate['created']) return viewable_certificates + + def _get_pseudo_course_overview(self, course_key): + """ + Returns a pseudo course overview object for deleted courses. + """ + course_run = get_course_run_details(course_key, ['title']) + return CourseOverview( + display_name=course_run.get('title'), + display_org_with_default=course_key.org, + certificates_show_before_end=True + )