fix: Allow cert generation if enrollment mode is now eligible (#28153)

MICROBA-1380
This commit is contained in:
Christie Rice
2021-07-13 09:51:15 -04:00
committed by GitHub
parent b3ac914a58
commit f42b36869e
2 changed files with 86 additions and 25 deletions

View File

@@ -164,7 +164,7 @@ def _can_generate_certificate_common(user, course_key):
log.info(f'{user.id} does not have a verified id. Certificate cannot be generated for {course_key}.')
return False
if not _can_generate_certificate_for_status(user, course_key):
if not _can_generate_certificate_for_status(user, course_key, enrollment_mode):
return False
course_overview = get_course_overview_or_none(course_key)
@@ -295,7 +295,7 @@ def is_on_certificate_allowlist(user, course_key):
return CertificateAllowlist.objects.filter(user=user, course_id=course_key, allowlist=True).exists()
def _can_generate_certificate_for_status(user, course_key):
def _can_generate_certificate_for_status(user, course_key, enrollment_mode):
"""
Check if the user's certificate status can handle regular (non-allowlist) certificate generation
"""
@@ -304,12 +304,14 @@ def _can_generate_certificate_for_status(user, course_key):
return True
if cert.status == CertificateStatuses.downloadable:
log.info(f'Certificate with status {cert.status} already exists for {user.id} : {course_key}, and is not '
f'eligible for generation. Certificate cannot be generated as it is already in a final state.')
return False
if not _is_mode_now_eligible(enrollment_mode, cert):
log.info(f'Certificate with status {cert.status} already exists for {user.id} : {course_key}, and is not '
f'eligible for generation. Certificate cannot be generated as it is already in a final state. The '
f'current enrollment mode is {enrollment_mode} and the existing cert mode is {cert.mode}')
return False
log.info(f'Certificate with status {cert.status} already exists for {user.id} : {course_key}, and is eligible for '
f'generation')
f'generation. The current enrollment mode is {enrollment_mode} and the existing cert mode is {cert.mode}')
return True
@@ -367,3 +369,12 @@ def _is_cert_downloadable(user, course_key):
return False
return True
def _is_mode_now_eligible(enrollment_mode, cert):
"""
Check if the current enrollment mode is now eligible, while the enrollment mode on the cert is NOT eligible
"""
if modes_api.is_eligible_for_certificate(enrollment_mode) and not modes_api.is_eligible_for_certificate(cert.mode):
return True
return False

View File

@@ -6,6 +6,7 @@ from unittest import mock
import ddt
from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
from lms.djangoapps.certificates.data import CertificateStatuses
from lms.djangoapps.certificates.generation_handler import (
@@ -57,7 +58,7 @@ class AllowlistTests(ModuleStoreTestCase):
user=self.user,
course_id=self.course_run_key,
is_active=True,
mode=GeneratedCertificate.MODES.verified,
mode=CourseMode.VERIFIED,
)
# Add user to the allowlist
@@ -78,7 +79,7 @@ class AllowlistTests(ModuleStoreTestCase):
user=u,
course_id=self.course_run_key,
is_active=True,
mode=GeneratedCertificate.MODES.verified,
mode=CourseMode.VERIFIED,
)
CertificateAllowlistFactory.create(course_id=self.course_run_key, user=u, allowlist=False)
assert not is_on_certificate_allowlist(u, self.course_run_key)
@@ -113,13 +114,62 @@ class AllowlistTests(ModuleStoreTestCase):
status=status,
)
assert _can_generate_certificate_for_status(u, key) == expected_response
assert _can_generate_certificate_for_status(u, key, CourseMode.VERIFIED) == expected_response
def test_generation_status_mode_changed_from_verified(self):
"""
Test handling of certificate statuses when the mode has changed from verified to audit
"""
u = UserFactory()
cr = CourseFactory()
key = cr.id # pylint: disable=no-member
GeneratedCertificateFactory(
user=u,
course_id=key,
mode=GeneratedCertificate.MODES.verified,
status=CertificateStatuses.downloadable,
)
assert not _can_generate_certificate_for_status(u, key, CourseMode.AUDIT)
def test_generation_status_mode_changed_from_audit(self):
"""
Test handling of certificate statuses when the mode has changed from audit to verified
"""
u = UserFactory()
cr = CourseFactory()
key = cr.id # pylint: disable=no-member
GeneratedCertificateFactory(
user=u,
course_id=key,
mode=GeneratedCertificate.MODES.audit,
status=CertificateStatuses.downloadable,
)
assert _can_generate_certificate_for_status(u, key, CourseMode.VERIFIED)
def test_generation_status_mode_changed_from_audit_not_downloadable(self):
"""
Test handling of certificate statuses when the mode has changed from audit to verified but the cert is not
downloadable
"""
u = UserFactory()
cr = CourseFactory()
key = cr.id # pylint: disable=no-member
GeneratedCertificateFactory(
user=u,
course_id=key,
mode=GeneratedCertificate.MODES.audit,
status=CertificateStatuses.unverified,
)
assert _can_generate_certificate_for_status(u, key, CourseMode.VERIFIED)
def test_generation_status_for_none(self):
"""
Test handling of certificate statuses for a non-existent cert
"""
assert _can_generate_certificate_for_status(None, None)
assert _can_generate_certificate_for_status(None, None, None)
def test_handle_invalid(self):
"""
@@ -193,7 +243,7 @@ class AllowlistTests(ModuleStoreTestCase):
user=u,
course_id=key,
is_active=True,
mode=GeneratedCertificate.MODES.verified,
mode=CourseMode.VERIFIED,
)
assert not _can_generate_allowlist_certificate(u, key)
assert _set_allowlist_cert_status(u, key) is None
@@ -209,7 +259,7 @@ class AllowlistTests(ModuleStoreTestCase):
user=u,
course_id=key,
is_active=True,
mode=GeneratedCertificate.MODES.verified,
mode=CourseMode.VERIFIED,
)
cert = GeneratedCertificateFactory(
user=u,
@@ -254,7 +304,7 @@ class AllowlistTests(ModuleStoreTestCase):
user=u,
course_id=key,
is_active=True,
mode=GeneratedCertificate.MODES.verified,
mode=CourseMode.VERIFIED,
)
GeneratedCertificateFactory(
user=u,
@@ -287,7 +337,7 @@ class CertificateTests(ModuleStoreTestCase):
user=self.user,
course_id=self.course_run_key,
is_active=True,
mode=GeneratedCertificate.MODES.verified,
mode=CourseMode.VERIFIED,
)
def test_handle_valid(self):
@@ -339,7 +389,7 @@ class CertificateTests(ModuleStoreTestCase):
user=different_user,
course_id=self.course_run_key,
is_active=True,
mode=GeneratedCertificate.MODES.verified,
mode=CourseMode.VERIFIED,
)
with mock.patch(PASSING_GRADE_METHOD, return_value=False):
@@ -355,7 +405,7 @@ class CertificateTests(ModuleStoreTestCase):
user=different_user,
course_id=self.course_run_key,
is_active=True,
mode=GeneratedCertificate.MODES.verified,
mode=CourseMode.VERIFIED,
)
GeneratedCertificateFactory(
user=different_user,
@@ -399,13 +449,13 @@ class CertificateTests(ModuleStoreTestCase):
status=status,
)
assert _can_generate_certificate_for_status(u, key) == expected_response
assert _can_generate_certificate_for_status(u, key, CourseMode.VERIFIED) == expected_response
def test_generation_status_for_none(self):
"""
Test handling of certificate statuses for a non-existent cert
"""
assert _can_generate_certificate_for_status(None, None)
assert _can_generate_certificate_for_status(None, None, None)
def test_can_generate_not_verified_cert(self):
"""
@@ -416,7 +466,7 @@ class CertificateTests(ModuleStoreTestCase):
user=u,
course_id=self.course_run_key,
is_active=True,
mode=GeneratedCertificate.MODES.verified,
mode=CourseMode.VERIFIED,
)
GeneratedCertificateFactory(
user=u,
@@ -438,7 +488,7 @@ class CertificateTests(ModuleStoreTestCase):
user=u,
course_id=self.course_run_key,
is_active=True,
mode=GeneratedCertificate.MODES.verified,
mode=CourseMode.VERIFIED,
)
with mock.patch(ID_VERIFIED_METHOD, return_value=False):
@@ -454,7 +504,7 @@ class CertificateTests(ModuleStoreTestCase):
user=u,
course_id=self.course_run_key,
is_active=True,
mode=GeneratedCertificate.MODES.verified,
mode=CourseMode.VERIFIED,
)
GeneratedCertificateFactory(
user=u,
@@ -477,7 +527,7 @@ class CertificateTests(ModuleStoreTestCase):
user=u,
course_id=self.course_run_key,
is_active=True,
mode=GeneratedCertificate.MODES.verified,
mode=CourseMode.VERIFIED,
)
GeneratedCertificateFactory(
user=u,
@@ -525,7 +575,7 @@ class CertificateTests(ModuleStoreTestCase):
user=u,
course_id=self.course_run_key,
is_active=True,
mode=GeneratedCertificate.MODES.verified,
mode=CourseMode.VERIFIED,
)
GeneratedCertificateFactory(
user=u,
@@ -576,7 +626,7 @@ class CertificateTests(ModuleStoreTestCase):
user=u,
course_id=key,
is_active=True,
mode=GeneratedCertificate.MODES.verified,
mode=CourseMode.VERIFIED,
)
cert = GeneratedCertificateFactory(
user=u,
@@ -620,7 +670,7 @@ class CertificateTests(ModuleStoreTestCase):
user=u,
course_id=key,
is_active=True,
mode=GeneratedCertificate.MODES.verified,
mode=CourseMode.VERIFIED,
)
GeneratedCertificateFactory(
user=u,