diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py index a4a444b13e..113f021664 100644 --- a/lms/djangoapps/courseware/tests/test_views.py +++ b/lms/djangoapps/courseware/tests/test_views.py @@ -876,7 +876,6 @@ class GenerateUserCertTests(ModuleStoreTestCase): mock_send_to_queue.return_value = (0, "Successfully queued") resp = self.client.post(self.url) self.assertEqual(resp.status_code, 200) - self.assertIn("Creating certificate", resp.content) #Verify Google Analytics event fired after generating certificate mock_tracker.track.assert_called_once_with( # pylint: disable=no-member @@ -906,7 +905,7 @@ class GenerateUserCertTests(ModuleStoreTestCase): ) resp = self.client.post(self.url) self.assertEqual(resp.status_code, HttpResponseBadRequest.status_code) - self.assertIn("Creating certificate", resp.content) + self.assertIn("Certificate is already being created.", resp.content) @patch('courseware.grades.grade', Mock(return_value={'grade': 'Pass', 'percent': 0.75})) def test_user_with_passing_existing_downloadable_cert(self): @@ -920,7 +919,7 @@ class GenerateUserCertTests(ModuleStoreTestCase): ) resp = self.client.post(self.url) self.assertEqual(resp.status_code, HttpResponseBadRequest.status_code) - self.assertIn("Creating certificate", resp.content) + self.assertIn("Certificate has already been created.", resp.content) def test_user_with_non_existing_course(self): # If try to access a course with valid key pattern then it will return diff --git a/lms/djangoapps/courseware/views.py b/lms/djangoapps/courseware/views.py index ad5064eefb..7b19c24c51 100644 --- a/lms/djangoapps/courseware/views.py +++ b/lms/djangoapps/courseware/views.py @@ -1302,18 +1302,27 @@ def is_course_passed(course, grade_summary=None, student=None, request=None): return success_cutoff and grade_summary['percent'] > success_cutoff -@ensure_csrf_cookie @require_POST def generate_user_cert(request, course_id): - """ - It will check all validation and on clearance will add the new-certificate request into the xqueue. + """Start generating a new certificate for the user. - Args: - request (django request object): the HTTP request object that triggered this view function - course_id (unicode): id associated with the course + Certificate generation is allowed if: + * The user has passed the course, and + * The user does not already have a pending/completed certificate. + + Note that if an error occurs during certificate generation + (for example, if the queue is down), then we simply mark the + certificate generation task status as "error" and re-run + the task with a management command. To students, the certificate + will appear to be "generating" until it is re-run. + + Args: + request (HttpRequest): The POST request to this view. + course_id (unicode): The identifier for the course. Returns: - returns json response + HttpResponse: 200 on success, 400 if a new certificate cannot be generated. + """ if not request.user.is_authenticated(): @@ -1325,7 +1334,6 @@ def generate_user_cert(request, course_id): ) student = request.user - course_key = CourseKey.from_string(course_id) course = modulestore().get_course(course_key, depth=2) @@ -1337,17 +1345,20 @@ def generate_user_cert(request, course_id): certificate_status = certs_api.certificate_downloadable_status(student, course.id) - if not certificate_status["is_downloadable"] and not certificate_status["is_generating"]: + if certificate_status["is_downloadable"]: + return HttpResponseBadRequest(_("Certificate has already been created.")) + elif certificate_status["is_generating"]: + return HttpResponseBadRequest(_("Certificate is already being created.")) + else: + # If the certificate is not already in-process or completed, + # then create a new certificate generation task. + # If the certificate cannot be added to the queue, this will + # mark the certificate with "error" status, so it can be re-run + # with a management command. From the user's perspective, + # it will appear that the certificate task was submitted successfully. certs_api.generate_user_certificates(student, course.id) _track_successful_certificate_generation(student.id, course.id) - return HttpResponse(_("Creating certificate")) - - # if certificate_status is not is_downloadable and is_generating or - # if any error appears during certificate generation return the message cert is generating. - # with badrequest - # at backend debug the issue and re-submit the task. - - return HttpResponseBadRequest(_("Creating certificate")) + return HttpResponse() def _track_successful_certificate_generation(user_id, course_id): # pylint: disable=invalid-name @@ -1355,7 +1366,7 @@ def _track_successful_certificate_generation(user_id, course_id): # pylint: dis Arguments: user_id (str): The ID of the user generting the certificate. - course_id (unicode): id associated with the course + course_id (CourseKey): Identifier for the course. Returns: None diff --git a/lms/static/js/courseware/certificates_api.js b/lms/static/js/courseware/certificates_api.js index 3efaaec7c5..4027bf05ff 100644 --- a/lms/static/js/courseware/certificates_api.js +++ b/lms/static/js/courseware/certificates_api.js @@ -1,4 +1,6 @@ $(document).ready(function() { + 'use strict'; + $("#btn_generate_cert").click(function(e){ e.preventDefault(); var post_url = $("#btn_generate_cert").data("endpoint");