From 7ae64b4fb637d6324d5513f9b36b4f99e6947fb7 Mon Sep 17 00:00:00 2001 From: Awais Date: Thu, 16 Jun 2016 00:24:57 +0500 Subject: [PATCH] If support user re-generates the cert. Removes the invalidation entry if exists. ECOM-4199 --- .../certificates/tests/test_support_views.py | 69 ++++++++++++++++++- lms/djangoapps/certificates/views/support.py | 40 +++++++++-- 2 files changed, 101 insertions(+), 8 deletions(-) diff --git a/lms/djangoapps/certificates/tests/test_support_views.py b/lms/djangoapps/certificates/tests/test_support_views.py index e46698df5c..ba68f7ad29 100644 --- a/lms/djangoapps/certificates/tests/test_support_views.py +++ b/lms/djangoapps/certificates/tests/test_support_views.py @@ -9,13 +9,18 @@ from django.conf import settings from django.core.urlresolvers import reverse from django.test.utils import override_settings +from certificates.models import ( + CertificateInvalidation, + CertificateStatuses, + GeneratedCertificate +) +from certificates.tests.factories import CertificateInvalidationFactory from opaque_keys.edx.keys import CourseKey from student.tests.factories import UserFactory from student.models import CourseEnrollment from student.roles import GlobalStaff, SupportStaffRole from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory -from certificates.models import GeneratedCertificate, CertificateStatuses FEATURES_WITH_CERTS_ENABLED = settings.FEATURES.copy() FEATURES_WITH_CERTS_ENABLED['CERTIFICATES_HTML_VIEW'] = True @@ -326,6 +331,33 @@ class CertificateRegenerateTests(CertificateSupportTestCase): num_certs = GeneratedCertificate.eligible_certificates.filter(user=self.student).count() self.assertEqual(num_certs, 1) + def test_regenerate_cert_with_invalidated_record(self): + """ If the certificate is marked as invalid, regenerate the certificate + and verify the invalidate entry is deactivated. """ + + # mark certificate as invalid + self._invalidate_certificate(self.cert) + self.assertInvalidatedCertExists() + # after invalidation certificate status become un-available. + self.assertGeneratedCertExists( + user=self.student, status=CertificateStatuses.unavailable + ) + + # Should be able to regenerate + response = self._regenerate( + course_key=self.CERT_COURSE_KEY, + username=self.STUDENT_USERNAME + ) + self.assertEqual(response.status_code, 200) + self.assertInvalidatedCertDoesNotExist() + + # Check that the user's certificate was updated + # Since the student hasn't actually passed the course, + # we'd expect that the certificate status will be "notpassing" + self.assertGeneratedCertExists( + user=self.student, status=CertificateStatuses.notpassing + ) + def _regenerate(self, course_key=None, username=None): """Call the regeneration end-point and return the response. """ url = reverse("certificates:regenerate_certificate_for_user") @@ -339,6 +371,41 @@ class CertificateRegenerateTests(CertificateSupportTestCase): return self.client.post(url, params) + def _invalidate_certificate(self, certificate): + """ Dry method to mark certificate as invalid. """ + CertificateInvalidationFactory.create( + generated_certificate=certificate, + invalidated_by=self.support, + active=True + ) + # Invalidate user certificate + certificate.invalidate() + self.assertFalse(certificate.is_valid()) + + def assertInvalidatedCertExists(self): + """ Dry method to check certificate invalidated entry exists. """ + self.assertTrue( + CertificateInvalidation.objects.filter( + generated_certificate__user=self.student, active=True + ).exists() + ) + + def assertInvalidatedCertDoesNotExist(self): + """ Dry method to check certificate invalidated entry does not exists. """ + self.assertFalse( + CertificateInvalidation.objects.filter( + generated_certificate__user=self.student, active=True + ).exists() + ) + + def assertGeneratedCertExists(self, user, status): + """ Dry method to check if certificate exists. """ + self.assertTrue( + GeneratedCertificate.objects.filter( # pylint: disable=no-member + user=user, status=status + ).exists() + ) + @ddt.ddt class CertificateGenerateTests(CertificateSupportTestCase): diff --git a/lms/djangoapps/certificates/views/support.py b/lms/djangoapps/certificates/views/support.py index 89af213b74..e24476d454 100644 --- a/lms/djangoapps/certificates/views/support.py +++ b/lms/djangoapps/certificates/views/support.py @@ -19,15 +19,16 @@ from django.db import transaction from django.db.models import Q from django.utils.translation import ugettext as _ +from certificates import api +from certificates.models import CertificateInvalidation +from courseware.access import has_access +from instructor_task.api import generate_certificates_for_students from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey -from xmodule.modulestore.django import modulestore -from student.models import User, CourseEnrollment -from courseware.access import has_access -from util.json_request import JsonResponse -from certificates import api -from instructor_task.api import generate_certificates_for_students from openedx.core.djangoapps.content.course_overviews.models import CourseOverview +from student.models import User, CourseEnrollment +from util.json_request import JsonResponse +from xmodule.modulestore.django import modulestore log = logging.getLogger(__name__) @@ -196,7 +197,7 @@ def regenerate_certificate_for_user(request): # Attempt to regenerate certificates try: - api.regenerate_user_certificates(params["user"], params["course_key"], course=course) + certificate = api.regenerate_user_certificates(params["user"], params["course_key"], course=course) except: # pylint: disable=bare-except # We are pessimistic about the kinds of errors that might get thrown by the # certificates API. This may be overkill, but we're logging everything so we can @@ -208,6 +209,9 @@ def regenerate_certificate_for_user(request): ) return HttpResponseServerError(_("An unexpected error occurred while regenerating certificates.")) + # Deactivate certificate invalidation by setting active to False. + _deactivate_invalidation(certificate) + log.info( "Started regenerating certificates for user %s in course %s from the support page.", params["user"].id, params["course_key"] @@ -267,3 +271,25 @@ def generate_certificate_for_user(request): specific_student_id=params["user"].id ) return HttpResponse(200) + + +def _deactivate_invalidation(certificate): + """ + Deactivate certificate invalidation by setting active to False. + + Arguments: + certificate : The student certificate object + + Return: + None + """ + try: + # Fetch CertificateInvalidation object + certificate_invalidation = CertificateInvalidation.objects.get( + generated_certificate=certificate, + active=True + ) + # Deactivate certificate invalidation if it was fetched successfully. + certificate_invalidation.deactivate() + except CertificateInvalidation.DoesNotExist: # pylint: disable=bare-except + pass