Merge pull request #15389 from edx/yro/fire_generate_certs_onwhitelist
Add cert task fire on whitelist append
This commit is contained in:
@@ -1,3 +0,0 @@
|
|||||||
""" Certificates app """
|
|
||||||
# this is here to support registering the signals in signals.py
|
|
||||||
from . import signals
|
|
||||||
|
|||||||
22
lms/djangoapps/certificates/apps.py
Normal file
22
lms/djangoapps/certificates/apps.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
"""
|
||||||
|
Certificates Application Configuration
|
||||||
|
|
||||||
|
Signal handlers are connected here.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class CertificatesConfig(AppConfig):
|
||||||
|
"""
|
||||||
|
Application Configuration for Certificates.
|
||||||
|
"""
|
||||||
|
name = u'certificates'
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
"""
|
||||||
|
Connect handlers to signals.
|
||||||
|
"""
|
||||||
|
# Can't import models at module level in AppConfigs, and models get
|
||||||
|
# included from the signal handlers
|
||||||
|
from . import signals # pylint: disable=unused-variable
|
||||||
@@ -1,14 +1,53 @@
|
|||||||
"""
|
"""
|
||||||
Signal handler for enabling/disabling self-generated certificates based on the course-pacing.
|
Signal handler for enabling/disabling self-generated certificates based on the course-pacing.
|
||||||
"""
|
"""
|
||||||
|
import logging
|
||||||
|
|
||||||
from celery.task import task
|
from celery.task import task
|
||||||
|
from django.db.models.signals import post_save
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from opaque_keys.edx.keys import CourseKey
|
from opaque_keys.edx.keys import CourseKey
|
||||||
|
|
||||||
from certificates.models import CertificateGenerationCourseSetting
|
from .config import waffle
|
||||||
|
from certificates.models import CertificateGenerationCourseSetting, CertificateWhitelist
|
||||||
|
from certificates.tasks import generate_certificate
|
||||||
|
from courseware import courses
|
||||||
from openedx.core.djangoapps.models.course_details import COURSE_PACING_CHANGE
|
from openedx.core.djangoapps.models.course_details import COURSE_PACING_CHANGE
|
||||||
|
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_save, sender=CertificateWhitelist, dispatch_uid="append_certificate_whitelist")
|
||||||
|
def _listen_for_certificate_whitelist_append(sender, instance, **kwargs): # pylint: disable=unused-argument
|
||||||
|
switches = waffle.waffle()
|
||||||
|
# All flags enabled
|
||||||
|
if (
|
||||||
|
not switches.is_enabled(waffle.SELF_PACED_ONLY) and
|
||||||
|
not switches.is_enabled(waffle.INSTRUCTOR_PACED_ONLY)
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Only SELF_PACED_ONLY flag enabled
|
||||||
|
if not switches.is_enabled(waffle.INSTRUCTOR_PACED_ONLY):
|
||||||
|
if not courses.get_course_by_id(instance.course_id, depth=0).self_paced:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Only INSTRUCTOR_PACED_ONLY flag enabled
|
||||||
|
if not switches.is_enabled(waffle.SELF_PACED_ONLY):
|
||||||
|
if courses.get_course_by_id(instance.course_id, depth=0).self_paced:
|
||||||
|
return
|
||||||
|
|
||||||
|
generate_certificate.apply_async(
|
||||||
|
student=instance.user,
|
||||||
|
course_key=instance.course_id,
|
||||||
|
)
|
||||||
|
log.info(u'Certificate generation task initiated for {user} : {course} via whitelist'.format(
|
||||||
|
user=instance.user.id,
|
||||||
|
course=instance.course_id
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
@receiver(COURSE_PACING_CHANGE, dispatch_uid="course_pacing_changed")
|
@receiver(COURSE_PACING_CHANGE, dispatch_uid="course_pacing_changed")
|
||||||
def _listen_for_course_pacing_changed(sender, course_key, course_self_paced, **kwargs): # pylint: disable=unused-argument
|
def _listen_for_course_pacing_changed(sender, course_key, course_self_paced, **kwargs): # pylint: disable=unused-argument
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -2,10 +2,14 @@
|
|||||||
Unit tests for enabling self-generated certificates for self-paced courses
|
Unit tests for enabling self-generated certificates for self-paced courses
|
||||||
and disabling for instructor-paced courses.
|
and disabling for instructor-paced courses.
|
||||||
"""
|
"""
|
||||||
|
import mock
|
||||||
|
|
||||||
from certificates import api as certs_api
|
from certificates import api as certs_api
|
||||||
from certificates.models import CertificateGenerationConfiguration
|
from certificates.config import waffle
|
||||||
|
from certificates.models import CertificateGenerationConfiguration, CertificateWhitelist
|
||||||
from certificates.signals import _listen_for_course_pacing_changed
|
from certificates.signals import _listen_for_course_pacing_changed
|
||||||
from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration
|
from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration
|
||||||
|
from student.tests.factories import UserFactory
|
||||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||||
from xmodule.modulestore.tests.factories import CourseFactory
|
from xmodule.modulestore.tests.factories import CourseFactory
|
||||||
|
|
||||||
@@ -40,3 +44,59 @@ class SelfGeneratedCertsSignalTest(ModuleStoreTestCase):
|
|||||||
_listen_for_course_pacing_changed('store', self.course.id, self.course.self_paced)
|
_listen_for_course_pacing_changed('store', self.course.id, self.course.self_paced)
|
||||||
# verify that self-generation of cert is disabled for instructor-paced course
|
# verify that self-generation of cert is disabled for instructor-paced course
|
||||||
self.assertFalse(certs_api.cert_generation_enabled(self.course.id))
|
self.assertFalse(certs_api.cert_generation_enabled(self.course.id))
|
||||||
|
|
||||||
|
|
||||||
|
class WhitelistGeneratedCertificatesTest(ModuleStoreTestCase):
|
||||||
|
"""
|
||||||
|
Tests for whitelisted student auto-certificate generation
|
||||||
|
"""
|
||||||
|
def setUp(self):
|
||||||
|
super(WhitelistGeneratedCertificatesTest, self).setUp()
|
||||||
|
self.course = CourseFactory.create(self_paced=True)
|
||||||
|
self.user = UserFactory.create()
|
||||||
|
self.ip_course = CourseFactory.create(self_paced=False)
|
||||||
|
|
||||||
|
def test_cert_generation_on_whitelist_append(self):
|
||||||
|
"""
|
||||||
|
Verify that signal is sent, received, and fires task based on various flag configs
|
||||||
|
"""
|
||||||
|
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.SELF_PACED_ONLY, active=False):
|
||||||
|
CertificateWhitelist.objects.create(
|
||||||
|
user=self.user,
|
||||||
|
course_id=self.course.id
|
||||||
|
)
|
||||||
|
mock_generate_certificate_apply_async.assert_not_called(
|
||||||
|
student=self.user,
|
||||||
|
course_key=self.course.id
|
||||||
|
)
|
||||||
|
with waffle.waffle().override(waffle.SELF_PACED_ONLY, active=True):
|
||||||
|
CertificateWhitelist.objects.create(
|
||||||
|
user=self.user,
|
||||||
|
course_id=self.course.id
|
||||||
|
)
|
||||||
|
mock_generate_certificate_apply_async.assert_called_with(
|
||||||
|
student=self.user,
|
||||||
|
course_key=self.course.id,
|
||||||
|
)
|
||||||
|
with waffle.waffle().override(waffle.INSTRUCTOR_PACED_ONLY, active=False):
|
||||||
|
CertificateWhitelist.objects.create(
|
||||||
|
user=self.user,
|
||||||
|
course_id=self.ip_course.id
|
||||||
|
)
|
||||||
|
mock_generate_certificate_apply_async.assert_not_called(
|
||||||
|
student=self.user,
|
||||||
|
course_key=self.ip_course.id
|
||||||
|
)
|
||||||
|
with waffle.waffle().override(waffle.INSTRUCTOR_PACED_ONLY, active=True):
|
||||||
|
CertificateWhitelist.objects.create(
|
||||||
|
user=self.user,
|
||||||
|
course_id=self.ip_course.id
|
||||||
|
)
|
||||||
|
mock_generate_certificate_apply_async.assert_called_with(
|
||||||
|
student=self.user,
|
||||||
|
course_key=self.ip_course.id
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user