From 26678daf1feac2416e7d27346c687e86b1331f14 Mon Sep 17 00:00:00 2001
From: "Albert (AJ) St. Aubin" <astaubin@edx.org>
Date: Tue, 13 Jul 2021 17:59:45 -0400
Subject: [PATCH] feat: Add the Request Certificate button to a Course card

[MICROBA-678]

When a certificate is in an unexpected state (i.e. notpassing with a
passing grade) this alert will allow the user to attempt to resolve the
issue on their own. It will run the code that checks the certificates
status. It requires that the course is configured to allow users to
Request Certificates though.
---
 common/djangoapps/student/helpers.py          | 11 +++++++
 .../js/learner_dashboard/certificate_api.js   | 23 ++++++++++++++
 lms/templates/dashboard.html                  |  1 +
 .../_dashboard_certificate_information.html   | 31 ++++++++++++-------
 themes/edx.org/lms/templates/dashboard.html   |  2 ++
 5 files changed, 57 insertions(+), 11 deletions(-)
 create mode 100644 lms/static/js/learner_dashboard/certificate_api.js

diff --git a/common/djangoapps/student/helpers.py b/common/djangoapps/student/helpers.py
index a632dc46969..80b65724e32 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 00000000000..1a5b3a27bfb
--- /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 4f8a2627219..0543f827a00 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 56a9a06c511..5c48344611a 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 2406ae90b77..1594e4ad4cd 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() {
-- 
GitLab