diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py index 5cdf69af9b617734ceac6cba03c554a7f0aaf89d..6203de8e9e6bae5e154a00acd46a0bf16bab6ffa 100644 --- a/lms/djangoapps/courseware/tests/test_views.py +++ b/lms/djangoapps/courseware/tests/test_views.py @@ -1570,6 +1570,7 @@ class ProgressPageTests(ProgressPageBaseTests): 'lms.djangoapps.grades.new.course_grade.CourseGrade.summary', PropertyMock(return_value={'grade': 'Pass', 'percent': 0.75, 'section_breakdown': [], 'grade_breakdown': {}}) ) + @patch('courseware.views.views.is_course_passed', PropertyMock(return_value=True)) def test_message_for_audit_mode(self): """ Verify that message appears on progress page, if learner is enrolled in audit mode. @@ -1584,6 +1585,7 @@ class ProgressPageTests(ProgressPageBaseTests): u'You are enrolled in the audit track for this course. The audit track does not include a certificate.' ) + @patch('courseware.views.views.is_course_passed', PropertyMock(return_value=True)) def test_invalidated_cert_data(self): """ Verify that invalidated cert data is returned if cert is invalidated. @@ -1602,6 +1604,7 @@ class ProgressPageTests(ProgressPageBaseTests): self.assertEqual(response.cert_status, 'invalidated') self.assertEqual(response.title, 'Your certificate has been invalidated') + @patch('courseware.views.views.is_course_passed', PropertyMock(return_value=True)) def test_downloadable_get_cert_data(self): """ Verify that downloadable cert data is returned if cert is downloadable. @@ -1616,6 +1619,7 @@ class ProgressPageTests(ProgressPageBaseTests): self.assertEqual(response.cert_status, 'downloadable') self.assertEqual(response.title, 'Your certificate is available') + @patch('courseware.views.views.is_course_passed', PropertyMock(return_value=True)) def test_generating_get_cert_data(self): """ Verify that generating cert data is returned if cert is generating. @@ -1630,6 +1634,7 @@ class ProgressPageTests(ProgressPageBaseTests): self.assertEqual(response.cert_status, 'generating') self.assertEqual(response.title, "We're working on it...") + @patch('courseware.views.views.is_course_passed', PropertyMock(return_value=True)) def test_unverified_get_cert_data(self): """ Verify that unverified cert data is returned if cert is unverified. @@ -1644,6 +1649,7 @@ class ProgressPageTests(ProgressPageBaseTests): self.assertEqual(response.cert_status, 'unverified') self.assertEqual(response.title, "Certificate unavailable") + @patch('courseware.views.views.is_course_passed', PropertyMock(return_value=True)) def test_request_get_cert_data(self): """ Verify that requested cert data is returned if cert is to be requested. diff --git a/lms/djangoapps/courseware/views/views.py b/lms/djangoapps/courseware/views/views.py index 9b9f1e8184d91242a9751dc16c3cf29743626bf1..78f96c153de6f215852ee7bd27e1773278b2904f 100644 --- a/lms/djangoapps/courseware/views/views.py +++ b/lms/djangoapps/courseware/views/views.py @@ -77,6 +77,7 @@ from openedx.core.djangoapps.credit.api import ( is_credit_course, is_user_eligible_for_credit ) +from openedx.core.djangoapps.certificates.config import waffle as certificates_waffle from openedx.core.djangoapps.models.course_details import CourseDetails from openedx.core.djangoapps.monitoring_utils import set_custom_metrics_for_course_key from openedx.core.djangoapps.plugin_api.views import EdxFragmentView @@ -886,9 +887,8 @@ def _progress(request, course_key, student_id): 'masquerade': masquerade, 'supports_preview_menu': True, 'student': student, - 'passed': is_course_passed(course, grade_summary), 'credit_course_requirements': _credit_course_requirements(course_key, student), - 'certificate_data': _get_cert_data(student, course, course_key, is_active, enrollment_mode), + 'certificate_data': _get_cert_data(student, course, course_key, is_active, enrollment_mode, grade_summary), } context.update( get_experiment_user_metadata_context( @@ -903,7 +903,7 @@ def _progress(request, course_key, student_id): return response -def _get_cert_data(student, course, course_key, is_active, enrollment_mode): +def _get_cert_data(student, course, course_key, is_active, enrollment_mode, grade_summary=None): """Returns students course certificate related data. Arguments: @@ -912,13 +912,14 @@ def _get_cert_data(student, course, course_key, is_active, enrollment_mode): course_key (CourseKey): Course identifier for course. is_active (Bool): Boolean value to check if course is active. enrollment_mode (String): Course mode in which student is enrolled. + grade_summary (dict): Student grade details. Returns: returns dict if course certificate is available else None. """ from lms.djangoapps.courseware.courses import get_course_by_id - if enrollment_mode == CourseMode.AUDIT: + if not CourseMode.is_eligible_for_certificate(enrollment_mode): return CertData( CertificateStatuses.audit_passing, _('Your enrollment: Audit track'), @@ -931,14 +932,22 @@ def _get_cert_data(student, course, course_key, is_active, enrollment_mode): if course_key: may_view_certificate = get_course_by_id(course_key).may_certify() - show_message = all([ + switches = certificates_waffle.waffle() + switches_enabled = (switches.is_enabled(certificates_waffle.SELF_PACED_ONLY) and + switches.is_enabled(certificates_waffle.INSTRUCTOR_PACED_ONLY)) + student_cert_generation_enabled = certs_api.cert_generation_enabled(course_key) if not switches_enabled else True + + # Don't show certificate information if: + # 1) the learner has not passed the course + # 2) the course is not active + # 3) auto-generated certs flags are not enabled, but student cert generation is not enabled either + # 4) the learner may not view the certificate, based on the course's advanced course settings. + if not all([ + is_course_passed(course, grade_summary), is_active, - CourseMode.is_eligible_for_certificate(enrollment_mode), - certs_api.cert_generation_enabled(course_key), + student_cert_generation_enabled, may_view_certificate - ]) - - if not show_message: + ]): return None if certs_api.is_certificate_invalid(student, course_key): @@ -952,53 +961,44 @@ def _get_cert_data(student, course, course_key, is_active, enrollment_mode): cert_downloadable_status = certs_api.certificate_downloadable_status(student, course_key) + generating_certificate_message = CertData( + CertificateStatuses.generating, + _("We're working on it..."), + _( + "We're creating your certificate. You can keep working in your courses and a link " + "to it will appear here and on your Dashboard when it is ready." + ), + download_url=None, + cert_web_view_url=None + ) + if cert_downloadable_status['is_downloadable']: - cert_status = CertificateStatuses.downloadable - title = _('Your certificate is available') - msg = _("You've earned a certificate for this course.") if certs_api.has_html_certificates_enabled(course_key, course): if certs_api.get_active_web_certificate(course) is not None: - cert_web_view_url = certs_api.get_certificate_url( - course_id=course_key, uuid=cert_downloadable_status['uuid'] - ) return CertData( - cert_status, - title, - msg, + CertificateStatuses.downloadable, + _('Your certificate is available'), + _("You've earned a certificate for this course."), download_url=None, - cert_web_view_url=cert_web_view_url + cert_web_view_url=certs_api.get_certificate_url( + course_id=course_key, uuid=cert_downloadable_status['uuid'] + ) ) else: - return CertData( - CertificateStatuses.generating, - _("We're working on it..."), - _( - "We're creating your certificate. You can keep working in your courses and a link " - "to it will appear here and on your Dashboard when it is ready." - ), - download_url=None, - cert_web_view_url=None - ) + # If there is an error, the user should see the generating certificate message + # until a new certificate is generated. + return generating_certificate_message return CertData( - cert_status, - title, - msg, + CertificateStatuses.downloadable, + _('Your certificate is available'), + _("You've earned a certificate for this course."), download_url=cert_downloadable_status['download_url'], cert_web_view_url=None ) if cert_downloadable_status['is_generating']: - return CertData( - CertificateStatuses.generating, - _("We're working on it..."), - _( - "We're creating your certificate. You can keep working in your courses and a link to " - "it will appear here and on your Dashboard when it is ready." - ), - download_url=None, - cert_web_view_url=None - ) + return generating_certificate_message # If the learner is in verified modes and the student did not have # their ID verified, we need to show message to ask learner to verify their ID first diff --git a/lms/templates/courseware/progress.html b/lms/templates/courseware/progress.html index c60c2226ef23406f86606fdd4c0d15a312c37c1f..bf0dde66ade2ace2853a6e499b118158921b21cd 100644 --- a/lms/templates/courseware/progress.html +++ b/lms/templates/courseware/progress.html @@ -56,10 +56,9 @@ from django.utils.http import urlquote_plus ${_("Course Progress for Student '{username}' ({email})").format(username=student.username, email=student.email)} </h2> - %if certificate_data: <div class="wrapper-msg wrapper-auto-cert"> <div id="errors-info" class="errors-info"></div> - %if passed: + %if certificate_data: <div class="auto-cert-message" id="course-success"> <div class="has-actions"> <% post_url = reverse('generate_user_cert', args=[unicode(course.id)]) %> @@ -80,7 +79,6 @@ from django.utils.http import urlquote_plus </div> %endif </div> - %endif %if not course.disable_progress_graph: <div class="grade-detail-graph" id="grade-detail-graph"></div>