fix: [MICROBA-1594] fix cert generation logic for eligible modes that don't require IDV

[MICROBA-1594]

* Update course certificate generation logic when ID verification fails to check if the enrollment mode requires IDV.

This change fixes an issue where Honor certificates could not be generated in an Open edX installation unless a manual IDV override was added for the student.
This commit is contained in:
Justin Hynes
2021-11-22 14:52:17 -05:00
parent 0bf9a0e0ce
commit df71aebdcf
3 changed files with 67 additions and 4 deletions

View File

@@ -9,6 +9,7 @@ cannot be generated, a message is logged and no further action is taken.
import logging
from common.djangoapps.course_modes import api as modes_api
from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.student.models import CourseEnrollment
from lms.djangoapps.certificates.data import CertificateStatuses
from lms.djangoapps.certificates.models import (
@@ -170,14 +171,21 @@ def _can_generate_certificate_common(user, course_key, enrollment_mode):
log.info(f'{user.id} : {course_key} does not have an enrollment. Certificate cannot be generated.')
return False
if not modes_api.is_eligible_for_certificate(enrollment_mode):
is_eligible_for_cert = modes_api.is_eligible_for_certificate(enrollment_mode)
if not is_eligible_for_cert:
log.info(f'{user.id} : {course_key} has an enrollment mode of {enrollment_mode}, which is not eligible for a '
f'certificate. Certificate cannot be generated.')
return False
# If the IDV check fails we then check if the course-run requires ID verification. Honor and Professional-No-ID
# modes do not require IDV for certificate generation.
if _required_verification_missing(course_key, user):
log.info(f'{user.id} does not have a verified id. Certificate cannot be generated for {course_key}.')
return False
if enrollment_mode not in CourseMode.NON_VERIFIED_MODES:
log.info(f'{user.id} does not have a verified id. Certificate cannot be generated for {course_key}.')
return False
log.info(f'{user.id} : {course_key} is eligible for a certificate without requiring a verified ID. '
'Skipping results of the ID verification check.')
if not _can_generate_certificate_for_status(user, course_key, enrollment_mode):
return False

View File

@@ -5,6 +5,8 @@ import logging
from unittest import mock
import ddt
from django.conf import settings
from django.test import override_settings
from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
@@ -330,6 +332,31 @@ class AllowlistTests(ModuleStoreTestCase):
assert _set_allowlist_cert_status(u, key, self.enrollment_mode, self.grade) is None
def test_generate_allowlist_honor_cert(self):
"""
Test that verifies we can generate an Honor cert for an Open edX installation configured to support Honor
certificates.
"""
course_run = CourseFactory()
course_run_key = course_run.id # pylint: disable=no-member
enrollment_mode = CourseMode.HONOR
CourseEnrollmentFactory(
user=self.user,
course_id=course_run_key,
is_active=True,
mode=enrollment_mode,
)
CertificateAllowlistFactory.create(course_id=course_run_key, user=self.user)
# Enable Honor Certificates and verify we can generate an AllowList certificate
with override_settings(FEATURES={**settings.FEATURES, 'DISABLE_HONOR_CERTIFICATES': False}):
assert _can_generate_allowlist_certificate(self.user, course_run_key, enrollment_mode)
# Disable Honor Certificates and verify we cannot generate an AllowList certificate
with override_settings(FEATURES={**settings.FEATURES, 'DISABLE_HONOR_CERTIFICATES': True}):
assert not _can_generate_allowlist_certificate(self.user, course_run_key, enrollment_mode)
@mock.patch(INTEGRITY_ENABLED_METHOD, mock.Mock(return_value=False))
@mock.patch(ID_VERIFIED_METHOD, mock.Mock(return_value=True))
@@ -741,3 +768,31 @@ class CertificateTests(ModuleStoreTestCase):
)
assert _set_regular_cert_status(u, key, self.enrollment_mode, self.grade) is None
def test_can_generate_honor_cert(self):
"""
Test that verifies we can generate an Honor cert for an Open edX installation configured to support Honor
certificates.
"""
course_run = CourseFactory()
course_run_key = course_run.id # pylint: disable=no-member
enrollment_mode = CourseMode.HONOR
grade = CourseGradeFactory().read(self.user, course_run)
CourseEnrollmentFactory(
user=self.user,
course_id=course_run_key,
is_active=True,
mode=enrollment_mode,
)
# Enable Honor Certificates and verify we can generate a certificate
with mock.patch(ID_VERIFIED_METHOD, return_value=False), \
mock.patch(PASSING_GRADE_METHOD, return_value=True), \
override_settings(FEATURES={**settings.FEATURES, 'DISABLE_HONOR_CERTIFICATES': False}):
assert _can_generate_regular_certificate(self.user, course_run_key, enrollment_mode, grade)
# Disable Honor Certificates and verify we cannot generate a certificate
with mock.patch(ID_VERIFIED_METHOD, return_value=False), \
mock.patch(PASSING_GRADE_METHOD, return_value=True), \
override_settings(FEATURES={**settings.FEATURES, 'DISABLE_HONOR_CERTIFICATES': True}):
assert not _can_generate_regular_certificate(self.user, course_run_key, enrollment_mode, grade)

View File

@@ -2081,7 +2081,7 @@ class TestCertificateGeneration(InstructorTaskModuleTestCase):
'failed': 0,
'skipped': 2
}
with self.assertNumQueries(77):
with self.assertNumQueries(82):
self.assertCertificatesGenerated(task_input, expected_results)
@ddt.data(