diff --git a/common/djangoapps/student/helpers.py b/common/djangoapps/student/helpers.py index a632dc46969141c967b6ac9a2bd1505c2873ea2e..80b65724e3291af3ca1a21ae9f19ac9ef72db7dc 100644 --- a/common/djangoapps/student/helpers.py +++ b/common/djangoapps/student/helpers.py @@ -37,6 +37,7 @@ from common.djangoapps.student.models import ( from common.djangoapps.util.password_policy_validators import normalize_password from lms.djangoapps.certificates.api import ( certificates_viewable_for_course, + cert_generation_enabled, get_certificate_url, has_html_certificates_enabled ) @@ -46,6 +47,7 @@ from lms.djangoapps.grades.api import CourseGradeFactory from lms.djangoapps.verify_student.models import VerificationDeadline from lms.djangoapps.verify_student.services import IDVerificationService from lms.djangoapps.verify_student.utils import is_verification_expiring_soon, verification_for_datetime +from openedx.core.djangoapps.certificates.api import auto_certificate_generation_enabled from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers from openedx.core.djangoapps.theming.helpers import get_themes from openedx.core.djangoapps.user_authn.utils import is_safe_login_or_logout_redirect @@ -592,6 +594,15 @@ def _cert_info(user, course_overview, cert_status): ) status_dict['grade'] = str(max_grade) + # If the grade is passing, the status is one of these statuses, and request certificate + # is enabled for a course then we need to provide the option to the learner + if ( + status_dict['status'] != CertificateStatuses.downloadable and + (cert_generation_enabled(course_overview.id) or auto_certificate_generation_enabled()) and + persisted_grade.passed + ): + status_dict['status'] = CertificateStatuses.requesting + return status_dict diff --git a/lms/static/js/learner_dashboard/certificate_api.js b/lms/static/js/learner_dashboard/certificate_api.js new file mode 100644 index 0000000000000000000000000000000000000000..1a5b3a27bfb069b9d47e1946106b0ce34f1670d0 --- /dev/null +++ b/lms/static/js/learner_dashboard/certificate_api.js @@ -0,0 +1,23 @@ +$(document).ready(() => { + 'use strict'; + + const requestButtons = document.getElementsByClassName('request-cert'); + + for (let i = 0; i < requestButtons.length; i++) { + requestButtons[i].addEventListener('click', (event) => { + event.preventDefault(); + const endpoint = !!event.target.dataset.endpoint && event.target.dataset.endpoint; + $.ajax({ + type: 'POST', + url: endpoint, + dataType: 'text', + success: () => { + location.reload(); + }, + error: (jqXHR, textStatus, errorThrown) => { + location.reload(); + }, + }); + }); + } +}); diff --git a/lms/templates/dashboard.html b/lms/templates/dashboard.html index 4f8a26272193559fd9e612efb540beeb463bbaa3..0543f827a0020341e1e8c24abdb58009eea21ecd 100644 --- a/lms/templates/dashboard.html +++ b/lms/templates/dashboard.html @@ -40,6 +40,7 @@ from common.djangoapps.student.models import CourseEnrollment <%block name="js_extra"> <script src="${static.url('js/commerce/credit.js')}"></script> + <script type="text/javascript" src="${static.url('js/learner_dashboard/certificate_api.js')}"></script> <%static:js group='dashboard'/> <script type="text/javascript"> $(document).ready(function() { diff --git a/lms/templates/dashboard/_dashboard_certificate_information.html b/lms/templates/dashboard/_dashboard_certificate_information.html index 56a9a06c51189835b871b64d63784f7b8deea850..5c48344611aaf5885506ef76632a634b984b67ff 100644 --- a/lms/templates/dashboard/_dashboard_certificate_information.html +++ b/lms/templates/dashboard/_dashboard_certificate_information.html @@ -1,6 +1,8 @@ <%page expression_filter="h" args="cert_status, course_overview, enrollment, reverify_link" /> <%! +from django.urls import reverse + from django.utils.translation import ugettext as _ from openedx.core.djangolib.markup import HTML, Text from common.djangoapps.course_modes.models import CourseMode @@ -21,15 +23,16 @@ from lms.djangoapps.certificates.data import CertificateStatuses <% if cert_status['status'] == 'certificate_earned_but_not_available': status_css_class = 'course-status-earned-not-available' -elif cert_status['status'] == 'generating': +elif cert_status['status'] == CertificateStatuses.generating: status_css_class = 'course-status-certrendering' -elif cert_status['status'] == 'downloadable': +elif cert_status['status'] == CertificateStatuses.downloadable or cert_status['status'] == CertificateStatuses.requesting: status_css_class = 'course-status-certavailable' -elif cert_status['status'] == 'notpassing': +elif cert_status['status'] == CertificateStatuses.notpassing: status_css_class = 'course-status-certnotavailable' else: status_css_class = 'course-status-processing' %> +<% requesting_post_url = reverse('generate_user_cert', args=[str(course_overview.id)]) %> % if cert_status['status'] != 'processing': % if cert_status['status'] == 'certificate_earned_but_not_available': @@ -46,7 +49,7 @@ else: % else: <div class="message message-status ${status_css_class} d-flex justify-content-between align-items-center"> <div class="message-copy"> - % if cert_status['status'] == CertificateStatuses.downloadable: + % if cert_status['status'] == CertificateStatuses.downloadable or cert_status['status'] == CertificateStatuses.requesting: ${_("Congratulations! Your certificate is ready.")} % elif cert_status['status'] == 'notpassing': % if enrollment.mode != 'audit': @@ -70,37 +73,43 @@ else: % endif </div> - % if cert_status['status'] == 'generating' or cert_status['status'] == 'downloadable' or cert_status['show_survey_button']: + % if cert_status['status'] == CertificateStatuses.generating or cert_status['status'] == CertificateStatuses.downloadable or cert_status['status'] == CertificateStatuses.requesting or cert_status['show_survey_button']: <div class="wrapper-message-primary"> <ul class="actions actions-primary"> - % if cert_status['status'] == 'generating': + % if cert_status['status'] == CertificateStatuses.generating: <li class="action"> <span class="disabled"> ${_("Your {cert_name_short} is Generating").format(cert_name_short=cert_name_short)} </span> </li> - % elif cert_status['status'] == 'downloadable' and cert_status.get('show_cert_web_view', False): + % elif cert_status['status'] == CertificateStatuses.requesting: + <li> + <button class="btn btn-primary request-cert" data-endpoint="${requesting_post_url}"> + ${_('Request Certificate')} + </button> + </li> + % elif cert_status['status'] == CertificateStatuses.downloadable and cert_status.get('show_cert_web_view', False): <li> <a class="btn btn-primary" href="${cert_status['cert_web_view_url']}" rel="noopener" target="_blank" title="${_('This link will open the certificate web view')}"> - ${_("View my {cert_name_short}").format(cert_name_short=cert_name_short,)} + ${_("View my {cert_name_short}").format(cert_name_short=cert_name_short)} </a> </li> - % elif cert_status['status'] == 'downloadable' and enrollment.mode in CourseMode.NON_VERIFIED_MODES: + % elif cert_status['status'] == CertificateStatuses.downloadable and enrollment.mode in CourseMode.NON_VERIFIED_MODES: <li> <a class="btn btn-primary" href="${cert_status['download_url']}" title="${_('This link will open/download a PDF document')}"> ${_("Download my {cert_name_short}").format(cert_name_short=cert_name_short,)} </a> </li> - % elif cert_status['status'] == 'downloadable' and enrollment.mode == 'verified' and cert_status['mode'] == 'honor': + % elif cert_status['status'] == CertificateStatuses.downloadable and enrollment.mode == 'verified' and cert_status['mode'] == 'honor': <li> <a class="btn btn-primary" href="${cert_status['download_url']}" title="${_('This link will open/download a PDF document')}"> ${_("Download my {cert_name_short}").format(cert_name_short=cert_name_short)} </a> </li> - % elif cert_status['status'] == 'downloadable' and enrollment.mode in CourseMode.VERIFIED_MODES: + % elif cert_status['status'] == CertificateStatuses.downloadable and enrollment.mode in CourseMode.VERIFIED_MODES: <li> <a class="btn btn-primary" href="${cert_status['download_url']}" title="${_('This link will open/download a PDF document of your verified {cert_name_long}.').format(cert_name_long=cert_name_long)}"> diff --git a/themes/edx.org/lms/templates/dashboard.html b/themes/edx.org/lms/templates/dashboard.html index 2406ae90b777f95b5703b0ff9dd641082bb89083..1594e4ad4cd62b8cd898a9479690827fb9b28627 100644 --- a/themes/edx.org/lms/templates/dashboard.html +++ b/themes/edx.org/lms/templates/dashboard.html @@ -45,6 +45,8 @@ from common.djangoapps.student.models import CourseEnrollment <%block name="js_extra"> <script src="${static.url('js/commerce/credit.js')}"></script> <script src="${static.url('js/demographics-collection.js')}"></script> + <script src="${static.url('js/learner_dashboard/certificate_api.js')}"></script> + <%static:js group='dashboard'/> <script type="text/javascript"> $(document).ready(function() {