@@ -31,6 +31,7 @@ the time the certificate is generated:
|
||||
* The user must be on the allowlist for the course run (see the *CertificateWhitelist* model)
|
||||
* The user must not have an invalidated certificate for the course run (see the *CertificateInvalidation* model)
|
||||
* Automatic certificate generation must be globally enabled
|
||||
* HTML (web) certificates must be globally enabled, and also enabled for the course run
|
||||
|
||||
Note: the above requirements were written for the allowlist, which assumes the
|
||||
CourseWaffleFlag *certificates_revamp.use_allowlist* has been enabled for the
|
||||
|
||||
@@ -52,7 +52,8 @@ CERTIFICATES_USE_ALLOWLIST = CourseWaffleFlag(
|
||||
# .. toggle_implementation: CourseWaffleFlag
|
||||
# .. toggle_default: False
|
||||
# .. toggle_description: Waffle flag to enable the updated regular (non-allowlist) course certificate logic on a
|
||||
# per-course run basis.
|
||||
# per-course run basis. Note that if this flag is enabled for a course run, certificates_revamp.use_allowlist
|
||||
# should also be enabled for that course run.
|
||||
# .. toggle_use_cases: temporary
|
||||
# .. toggle_creation_date: 2021-03-05
|
||||
# .. toggle_target_removal_date: 2022-03-05
|
||||
@@ -183,6 +184,12 @@ def _can_generate_allowlist_certificate(user, course_key):
|
||||
log.info(f'{user.id} does not have a verified id. Allowlist certificate cannot be generated for {course_key}.')
|
||||
return False
|
||||
|
||||
course = _get_course(course_key)
|
||||
if not has_html_certificates_enabled(course):
|
||||
log.info(f'{course_key} does not have HTML certificates enabled. Allowlist certificate cannot be generated for '
|
||||
f'{user.id}.')
|
||||
return False
|
||||
|
||||
log.info(f'{user.id} : {course_key} is on the certificate allowlist')
|
||||
return _can_generate_allowlist_certificate_for_status(user, course_key)
|
||||
|
||||
@@ -226,7 +233,7 @@ def _can_generate_v2_certificate(user, course_key):
|
||||
log.info(f'{course_key} is a CCX course. Certificate cannot be generated for {user.id}.')
|
||||
return False
|
||||
|
||||
course = modulestore().get_course(course_key, depth=0)
|
||||
course = _get_course(course_key)
|
||||
if _is_beta_tester(user, course):
|
||||
log.info(f'{user.id} is a beta tester in {course_key}. Certificate cannot be generated.')
|
||||
return False
|
||||
@@ -238,6 +245,12 @@ def _can_generate_v2_certificate(user, course_key):
|
||||
if not _can_generate_certificate_for_status(user, course_key):
|
||||
return False
|
||||
|
||||
course = _get_course(course_key)
|
||||
if not has_html_certificates_enabled(course):
|
||||
log.info(f'{course_key} does not have HTML certificates enabled. Certificate cannot be generated for '
|
||||
f'{user.id}.')
|
||||
return False
|
||||
|
||||
log.info(f'V2 certificate can be generated for {user.id} : {course_key}')
|
||||
return True
|
||||
|
||||
@@ -332,6 +345,13 @@ def _has_passing_grade(user, course):
|
||||
return course_grade.passed
|
||||
|
||||
|
||||
def _get_course(course_key):
|
||||
"""
|
||||
Get the course from the course key
|
||||
"""
|
||||
return modulestore().get_course(course_key, depth=0)
|
||||
|
||||
|
||||
def generate_user_certificates(student, course_key, course=None, insecure=False, generation_mode='batch',
|
||||
forced_grade=None):
|
||||
"""
|
||||
|
||||
@@ -41,6 +41,7 @@ BETA_TESTER_METHOD = 'lms.djangoapps.certificates.generation_handler._is_beta_te
|
||||
CCX_COURSE_METHOD = 'lms.djangoapps.certificates.generation_handler._is_ccx_course'
|
||||
ID_VERIFIED_METHOD = 'lms.djangoapps.verify_student.services.IDVerificationService.user_is_verified'
|
||||
PASSING_GRADE_METHOD = 'lms.djangoapps.certificates.generation_handler._has_passing_grade'
|
||||
WEB_CERTS_METHOD = 'lms.djangoapps.certificates.generation_handler.has_html_certificates_enabled'
|
||||
AUTO_GENERATION_NAMESPACE = waffle.WAFFLE_NAMESPACE
|
||||
AUTO_GENERATION_NAME = waffle.AUTO_CERTIFICATE_GENERATION
|
||||
AUTO_GENERATION_SWITCH_NAME = f'{AUTO_GENERATION_NAMESPACE}.{AUTO_GENERATION_NAME}'
|
||||
@@ -50,6 +51,7 @@ AUTO_GENERATION_SWITCH = LegacyWaffleSwitch(AUTO_GENERATION_NAMESPACE, AUTO_GENE
|
||||
@override_switch(AUTO_GENERATION_SWITCH_NAME, active=True)
|
||||
@override_waffle_flag(CERTIFICATES_USE_ALLOWLIST, active=True)
|
||||
@mock.patch(ID_VERIFIED_METHOD, mock.Mock(return_value=True))
|
||||
@mock.patch(WEB_CERTS_METHOD, mock.Mock(return_value=True))
|
||||
@ddt.ddt
|
||||
class AllowlistTests(ModuleStoreTestCase):
|
||||
"""
|
||||
@@ -259,12 +261,20 @@ class AllowlistTests(ModuleStoreTestCase):
|
||||
|
||||
assert not _can_generate_allowlist_certificate(u, key)
|
||||
|
||||
def test_can_generate_web_cert_disabled(self):
|
||||
"""
|
||||
Test handling when web certs are not enabled
|
||||
"""
|
||||
with mock.patch(WEB_CERTS_METHOD, return_value=False):
|
||||
assert not _can_generate_allowlist_certificate(self.user, self.course_run_key)
|
||||
|
||||
|
||||
@override_switch(AUTO_GENERATION_SWITCH_NAME, active=True)
|
||||
@override_waffle_flag(CERTIFICATES_USE_UPDATED, active=True)
|
||||
@mock.patch(ID_VERIFIED_METHOD, mock.Mock(return_value=True))
|
||||
@mock.patch(CCX_COURSE_METHOD, mock.Mock(return_value=False))
|
||||
@mock.patch(PASSING_GRADE_METHOD, mock.Mock(return_value=True))
|
||||
@mock.patch(WEB_CERTS_METHOD, mock.Mock(return_value=True))
|
||||
@ddt.ddt
|
||||
class CertificateTests(ModuleStoreTestCase):
|
||||
"""
|
||||
@@ -441,3 +451,10 @@ class CertificateTests(ModuleStoreTestCase):
|
||||
)
|
||||
|
||||
assert not _can_generate_v2_certificate(u, key)
|
||||
|
||||
def test_can_generate_web_cert_disabled(self):
|
||||
"""
|
||||
Test handling when web certs are not enabled
|
||||
"""
|
||||
with mock.patch(WEB_CERTS_METHOD, return_value=False):
|
||||
assert not _can_generate_v2_certificate(self.user, self.course_run_key)
|
||||
|
||||
Reference in New Issue
Block a user