Merge pull request #17165 from edx/noraiz/EDUCATOR-1994
auto certs for professional and no-id-professional enrollment modes
This commit is contained in:
@@ -16,6 +16,7 @@ from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification
|
||||
from openedx.core.djangoapps.certificates.api import auto_certificate_generation_enabled
|
||||
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
|
||||
from openedx.core.djangoapps.signals.signals import COURSE_GRADE_NOW_PASSED, LEARNER_NOW_VERIFIED
|
||||
from course_modes.models import CourseMode
|
||||
from student.models import CourseEnrollment
|
||||
|
||||
|
||||
@@ -81,17 +82,40 @@ def _listen_for_id_verification_status_changed(sender, user, **kwargs): # pylin
|
||||
|
||||
def fire_ungenerated_certificate_task(user, course_key, expected_verification_status=None):
|
||||
"""
|
||||
Helper function to fire un-generated certificate tasks
|
||||
Helper function to fire certificate generation task.
|
||||
Auto-generation of certificates is available for following course modes:
|
||||
1- VERIFIED
|
||||
2- CREDIT_MODE
|
||||
3- PROFESSIONAL
|
||||
4- NO_ID_PROFESSIONAL_MODE
|
||||
|
||||
The 'mode_is_verified' query is copied from the GeneratedCertificate model,
|
||||
but is done here in an attempt to reduce traffic to the workers.
|
||||
If the learner is verified and their cert has the 'unverified' status,
|
||||
we regenerate the cert.
|
||||
Certificate generation task is fired to either generate a certificate
|
||||
when there is no generated certificate for user in a particular course or
|
||||
update a certificate if it has 'unverified' status.
|
||||
|
||||
Task is fired to attempt an update to a certificate
|
||||
with 'unverified' status as this method is called when a user is
|
||||
successfully verified, any certificate associated
|
||||
with such user can now be verified.
|
||||
|
||||
NOTE: Purpose of restricting other course modes (HONOR and AUDIT) from auto-generation is to reduce
|
||||
traffic to workers.
|
||||
"""
|
||||
|
||||
allowed_enrollment_modes_list = [
|
||||
CourseMode.VERIFIED,
|
||||
CourseMode.CREDIT_MODE,
|
||||
CourseMode.PROFESSIONAL,
|
||||
CourseMode.NO_ID_PROFESSIONAL_MODE,
|
||||
]
|
||||
enrollment_mode, __ = CourseEnrollment.enrollment_mode_for_user(user, course_key)
|
||||
mode_is_verified = enrollment_mode in GeneratedCertificate.VERIFIED_CERTS_MODES
|
||||
cert = GeneratedCertificate.certificate_for_student(user, course_key)
|
||||
if mode_is_verified and (cert is None or cert.status == 'unverified'):
|
||||
|
||||
generate_learner_certificate = (
|
||||
enrollment_mode in allowed_enrollment_modes_list and (cert is None or cert.status == 'unverified')
|
||||
)
|
||||
|
||||
if generate_learner_certificate:
|
||||
kwargs = {
|
||||
'student': unicode(user.id),
|
||||
'course_key': unicode(course_key)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
Unit tests for enabling self-generated certificates for self-paced courses
|
||||
and disabling for instructor-paced courses.
|
||||
"""
|
||||
import ddt
|
||||
import mock
|
||||
|
||||
from certificates import api as certs_api
|
||||
@@ -11,6 +12,7 @@ from certificates.models import (
|
||||
GeneratedCertificate,
|
||||
CertificateStatuses,
|
||||
)
|
||||
from certificates.signals import fire_ungenerated_certificate_task
|
||||
from lms.djangoapps.grades.course_grade_factory import CourseGradeFactory
|
||||
from lms.djangoapps.grades.tests.utils import mock_passing_grade
|
||||
from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification
|
||||
@@ -286,3 +288,44 @@ class LearnerTrackChangeCertsTest(ModuleStoreTestCase):
|
||||
'expected_verification_status': SoftwareSecurePhotoVerification.STATUS.approved
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class CertificateGenerationTaskTest(ModuleStoreTestCase):
|
||||
"""
|
||||
Tests for certificate generation task.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(CertificateGenerationTaskTest, self).setUp()
|
||||
self.course = CourseFactory.create()
|
||||
|
||||
@ddt.data(
|
||||
('professional', True),
|
||||
('verified', True),
|
||||
('no-id-professional', True),
|
||||
('credit', True),
|
||||
('audit', False),
|
||||
('honor', False),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_fire_ungenerated_certificate_task_allowed_modes(self, enrollment_mode, should_create):
|
||||
"""
|
||||
Test that certificate generation task is fired for only modes that are
|
||||
allowed to generate certificates automatically.
|
||||
"""
|
||||
self.user = UserFactory.create()
|
||||
self.enrollment = CourseEnrollmentFactory(
|
||||
user=self.user,
|
||||
course_id=self.course.id,
|
||||
is_active=True,
|
||||
mode=enrollment_mode
|
||||
)
|
||||
with mock.patch(
|
||||
'lms.djangoapps.certificates.signals.generate_certificate.apply_async',
|
||||
return_value=None
|
||||
) as mock_generate_certificate_apply_async:
|
||||
with waffle.waffle().override(waffle.AUTO_CERTIFICATE_GENERATION, active=True):
|
||||
fire_ungenerated_certificate_task(self.user, self.course.id)
|
||||
task_created = mock_generate_certificate_apply_async.called
|
||||
self.assertEqual(task_created, should_create)
|
||||
|
||||
Reference in New Issue
Block a user