Commit e4735a6a by Sanford Student

switch over to unified waffle switch

for EDUCATOR-1313
parent 14b8c12e
...@@ -14,10 +14,7 @@ from certificates.models import ( ...@@ -14,10 +14,7 @@ from certificates.models import (
) )
from certificates.tasks import generate_certificate from certificates.tasks import generate_certificate
from lms.djangoapps.grades.new.course_grade_factory import CourseGradeFactory from lms.djangoapps.grades.new.course_grade_factory import CourseGradeFactory
from openedx.core.djangoapps.certificates.api import ( from openedx.core.djangoapps.certificates.api import auto_certificate_generation_enabled
auto_certificate_generation_enabled,
auto_certificate_generation_enabled_for_course,
)
from openedx.core.djangoapps.certificates.config import waffle from openedx.core.djangoapps.certificates.config import waffle
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview 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 openedx.core.djangoapps.signals.signals import COURSE_GRADE_NOW_PASSED, LEARNER_NOW_VERIFIED
...@@ -30,7 +27,7 @@ log = logging.getLogger(__name__) ...@@ -30,7 +27,7 @@ log = logging.getLogger(__name__)
@receiver(post_save, sender=CertificateWhitelist, dispatch_uid="append_certificate_whitelist") @receiver(post_save, sender=CertificateWhitelist, dispatch_uid="append_certificate_whitelist")
def _listen_for_certificate_whitelist_append(sender, instance, **kwargs): # pylint: disable=unused-argument def _listen_for_certificate_whitelist_append(sender, instance, **kwargs): # pylint: disable=unused-argument
course = CourseOverview.get_from_id(instance.course_id) course = CourseOverview.get_from_id(instance.course_id)
if not auto_certificate_generation_enabled_for_course(course): if not auto_certificate_generation_enabled():
return return
fire_ungenerated_certificate_task(instance.user, instance.course_id) fire_ungenerated_certificate_task(instance.user, instance.course_id)
...@@ -47,7 +44,7 @@ def _listen_for_passing_grade(sender, user, course_id, **kwargs): # pylint: dis ...@@ -47,7 +44,7 @@ def _listen_for_passing_grade(sender, user, course_id, **kwargs): # pylint: dis
downstream signal from COURSE_GRADE_CHANGED downstream signal from COURSE_GRADE_CHANGED
""" """
course = CourseOverview.get_from_id(course_id) course = CourseOverview.get_from_id(course_id)
if not auto_certificate_generation_enabled_for_course(course): if not auto_certificate_generation_enabled():
return return
if fire_ungenerated_certificate_task(user, course_id): if fire_ungenerated_certificate_task(user, course_id):
......
...@@ -74,19 +74,19 @@ class WhitelistGeneratedCertificatesTest(ModuleStoreTestCase): ...@@ -74,19 +74,19 @@ class WhitelistGeneratedCertificatesTest(ModuleStoreTestCase):
def test_cert_generation_on_whitelist_append_self_paced(self): def test_cert_generation_on_whitelist_append_self_paced(self):
""" """
Verify that signal is sent, received, and fires task Verify that signal is sent, received, and fires task
based on 'SELF_PACED_ONLY' flag based on 'AUTO_CERTIFICATE_GENERATION' flag
""" """
with mock.patch( with mock.patch(
'lms.djangoapps.certificates.signals.generate_certificate.apply_async', 'lms.djangoapps.certificates.signals.generate_certificate.apply_async',
return_value=None return_value=None
) as mock_generate_certificate_apply_async: ) as mock_generate_certificate_apply_async:
with waffle.waffle().override(waffle.SELF_PACED_ONLY, active=False): with waffle.waffle().override(waffle.AUTO_CERTIFICATE_GENERATION, active=False):
CertificateWhitelist.objects.create( CertificateWhitelist.objects.create(
user=self.user, user=self.user,
course_id=self.course.id course_id=self.course.id
) )
mock_generate_certificate_apply_async.assert_not_called() mock_generate_certificate_apply_async.assert_not_called()
with waffle.waffle().override(waffle.SELF_PACED_ONLY, active=True): with waffle.waffle().override(waffle.AUTO_CERTIFICATE_GENERATION, active=True):
CertificateWhitelist.objects.create( CertificateWhitelist.objects.create(
user=self.user, user=self.user,
course_id=self.course.id course_id=self.course.id
...@@ -99,19 +99,19 @@ class WhitelistGeneratedCertificatesTest(ModuleStoreTestCase): ...@@ -99,19 +99,19 @@ class WhitelistGeneratedCertificatesTest(ModuleStoreTestCase):
def test_cert_generation_on_whitelist_append_instructor_paced(self): def test_cert_generation_on_whitelist_append_instructor_paced(self):
""" """
Verify that signal is sent, received, and fires task Verify that signal is sent, received, and fires task
based on 'INSTRUCTOR_PACED_ONLY' flag based on 'AUTO_CERTIFICATE_GENERATION' flag
""" """
with mock.patch( with mock.patch(
'lms.djangoapps.certificates.signals.generate_certificate.apply_async', 'lms.djangoapps.certificates.signals.generate_certificate.apply_async',
return_value=None return_value=None
) as mock_generate_certificate_apply_async: ) as mock_generate_certificate_apply_async:
with waffle.waffle().override(waffle.INSTRUCTOR_PACED_ONLY, active=False): with waffle.waffle().override(waffle.AUTO_CERTIFICATE_GENERATION, active=False):
CertificateWhitelist.objects.create( CertificateWhitelist.objects.create(
user=self.user, user=self.user,
course_id=self.ip_course.id course_id=self.ip_course.id
) )
mock_generate_certificate_apply_async.assert_not_called() mock_generate_certificate_apply_async.assert_not_called()
with waffle.waffle().override(waffle.INSTRUCTOR_PACED_ONLY, active=True): with waffle.waffle().override(waffle.AUTO_CERTIFICATE_GENERATION, active=True):
CertificateWhitelist.objects.create( CertificateWhitelist.objects.create(
user=self.user, user=self.user,
course_id=self.ip_course.id course_id=self.ip_course.id
...@@ -156,7 +156,7 @@ class PassingGradeCertsTest(ModuleStoreTestCase): ...@@ -156,7 +156,7 @@ class PassingGradeCertsTest(ModuleStoreTestCase):
'lms.djangoapps.certificates.signals.generate_certificate.apply_async', 'lms.djangoapps.certificates.signals.generate_certificate.apply_async',
return_value=None return_value=None
) as mock_generate_certificate_apply_async: ) as mock_generate_certificate_apply_async:
with waffle.waffle().override(waffle.SELF_PACED_ONLY, active=True): with waffle.waffle().override(waffle.AUTO_CERTIFICATE_GENERATION, active=True):
grade_factory = CourseGradeFactory() grade_factory = CourseGradeFactory()
# Not passing # Not passing
grade_factory.update(self.user, self.course) grade_factory.update(self.user, self.course)
...@@ -174,7 +174,7 @@ class PassingGradeCertsTest(ModuleStoreTestCase): ...@@ -174,7 +174,7 @@ class PassingGradeCertsTest(ModuleStoreTestCase):
'lms.djangoapps.certificates.signals.generate_certificate.apply_async', 'lms.djangoapps.certificates.signals.generate_certificate.apply_async',
return_value=None return_value=None
) as mock_generate_certificate_apply_async: ) as mock_generate_certificate_apply_async:
with waffle.waffle().override(waffle.INSTRUCTOR_PACED_ONLY, active=True): with waffle.waffle().override(waffle.AUTO_CERTIFICATE_GENERATION, active=True):
grade_factory = CourseGradeFactory() grade_factory = CourseGradeFactory()
# Not passing # Not passing
grade_factory.update(self.user, self.ip_course) grade_factory.update(self.user, self.ip_course)
...@@ -237,7 +237,7 @@ class LearnerTrackChangeCertsTest(ModuleStoreTestCase): ...@@ -237,7 +237,7 @@ class LearnerTrackChangeCertsTest(ModuleStoreTestCase):
'lms.djangoapps.certificates.signals.generate_certificate.apply_async', 'lms.djangoapps.certificates.signals.generate_certificate.apply_async',
return_value=None return_value=None
) as mock_generate_certificate_apply_async: ) as mock_generate_certificate_apply_async:
with waffle.waffle().override(waffle.SELF_PACED_ONLY, active=True): with waffle.waffle().override(waffle.AUTO_CERTIFICATE_GENERATION, active=True):
mock_generate_certificate_apply_async.assert_not_called() mock_generate_certificate_apply_async.assert_not_called()
attempt = SoftwareSecurePhotoVerification.objects.create( attempt = SoftwareSecurePhotoVerification.objects.create(
user=self.user_one, user=self.user_one,
...@@ -254,7 +254,7 @@ class LearnerTrackChangeCertsTest(ModuleStoreTestCase): ...@@ -254,7 +254,7 @@ class LearnerTrackChangeCertsTest(ModuleStoreTestCase):
'lms.djangoapps.certificates.signals.generate_certificate.apply_async', 'lms.djangoapps.certificates.signals.generate_certificate.apply_async',
return_value=None return_value=None
) as mock_generate_certificate_apply_async: ) as mock_generate_certificate_apply_async:
with waffle.waffle().override(waffle.INSTRUCTOR_PACED_ONLY, active=True): with waffle.waffle().override(waffle.AUTO_CERTIFICATE_GENERATION, active=True):
mock_generate_certificate_apply_async.assert_not_called() mock_generate_certificate_apply_async.assert_not_called()
attempt = SoftwareSecurePhotoVerification.objects.create( attempt = SoftwareSecurePhotoVerification.objects.create(
user=self.user_two, user=self.user_two,
......
...@@ -820,9 +820,8 @@ class CertificatesViewsTests(CommonCertificatesTestCase): ...@@ -820,9 +820,8 @@ class CertificatesViewsTests(CommonCertificatesTestCase):
expected_date = today expected_date = today
else: else:
expected_date = self.course.certificate_available_date expected_date = self.course.certificate_available_date
with waffle.waffle().override(waffle.SELF_PACED_ONLY, active=True): with waffle.waffle().override(waffle.AUTO_CERTIFICATE_GENERATION, active=True):
with waffle.waffle().override(waffle.INSTRUCTOR_PACED_ONLY, active=True): response = self.client.get(test_url)
response = self.client.get(test_url)
date = '{month} {day}, {year}'.format( date = '{month} {day}, {year}'.format(
month=strftime_localized(expected_date, "%B"), month=strftime_localized(expected_date, "%B"),
day=expected_date.day, day=expected_date.day,
......
...@@ -329,7 +329,7 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): ...@@ -329,7 +329,7 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
self.assertEqual(block.link, '{}?sku={}'.format(configuration.MULTIPLE_ITEMS_BASKET_PAGE_URL, sku)) self.assertEqual(block.link, '{}?sku={}'.format(configuration.MULTIPLE_ITEMS_BASKET_PAGE_URL, sku))
## CertificateAvailableDate ## CertificateAvailableDate
@waffle.testutils.override_switch('certificates.instructor_paced_only', True) @waffle.testutils.override_switch('certificates.auto_certificate_generation', True)
def test_no_certificate_available_date(self): def test_no_certificate_available_date(self):
course = create_course_run(days_till_start=-1) course = create_course_run(days_till_start=-1)
user = self.create_user() user = self.create_user()
...@@ -339,7 +339,7 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): ...@@ -339,7 +339,7 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
self.assertFalse(block.is_enabled) self.assertFalse(block.is_enabled)
## CertificateAvailableDate ## CertificateAvailableDate
@waffle.testutils.override_switch('certificates.instructor_paced_only', True) @waffle.testutils.override_switch('certificates.auto_certificate_generation', True)
def test_no_certificate_available_date_for_self_paced(self): def test_no_certificate_available_date_for_self_paced(self):
course = create_self_paced_course_run() course = create_self_paced_course_run()
verified_user = self.create_user() verified_user = self.create_user()
...@@ -350,7 +350,6 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): ...@@ -350,7 +350,6 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
self.assertNotEqual(block.date, None) self.assertNotEqual(block.date, None)
self.assertFalse(block.is_enabled) self.assertFalse(block.is_enabled)
# @waffle.testutils.override_switch('certificates.instructor_paced_only', True)
def test_no_certificate_available_date_for_audit_course(self): def test_no_certificate_available_date_for_audit_course(self):
""" """
Tests that Certificate Available Date is not visible in the course "Important Course Dates" section Tests that Certificate Available Date is not visible in the course "Important Course Dates" section
...@@ -374,7 +373,7 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): ...@@ -374,7 +373,7 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
self.assertFalse(block.is_enabled) self.assertFalse(block.is_enabled)
self.assertNotEqual(block.date, None) self.assertNotEqual(block.date, None)
@waffle.testutils.override_switch('certificates.instructor_paced_only', True) @waffle.testutils.override_switch('certificates.auto_certificate_generation', True)
def test_certificate_available_date_defined(self): def test_certificate_available_date_defined(self):
course = create_course_run() course = create_course_run()
audit_user = self.create_user() audit_user = self.create_user()
......
...@@ -933,9 +933,8 @@ def _get_cert_data(student, course, course_key, is_active, enrollment_mode, grad ...@@ -933,9 +933,8 @@ def _get_cert_data(student, course, course_key, is_active, enrollment_mode, grad
may_view_certificate = get_course_by_id(course_key).may_certify() may_view_certificate = get_course_by_id(course_key).may_certify()
switches = certificates_waffle.waffle() switches = certificates_waffle.waffle()
switches_enabled = (switches.is_enabled(certificates_waffle.SELF_PACED_ONLY) and switch_enabled = switches.is_enabled(certificates_waffle.AUTO_CERTIFICATE_GENERATION)
switches.is_enabled(certificates_waffle.INSTRUCTOR_PACED_ONLY)) student_cert_generation_enabled = switch_enabled or certs_api.cert_generation_enabled(course_key)
student_cert_generation_enabled = certs_api.cert_generation_enabled(course_key) if not switches_enabled else True
# Don't show certificate information if: # Don't show certificate information if:
# 1) the learner has not passed the course # 1) the learner has not passed the course
......
...@@ -10,39 +10,22 @@ SWITCHES = waffle.waffle() ...@@ -10,39 +10,22 @@ SWITCHES = waffle.waffle()
def auto_certificate_generation_enabled(): def auto_certificate_generation_enabled():
return ( return SWITCHES.is_enabled(waffle.AUTO_CERTIFICATE_GENERATION)
SWITCHES.is_enabled(waffle.SELF_PACED_ONLY) or
SWITCHES.is_enabled(waffle.INSTRUCTOR_PACED_ONLY)
)
def auto_certificate_generation_enabled_for_course(course): def _enabled_and_instructor_paced(course):
if not auto_certificate_generation_enabled(): if auto_certificate_generation_enabled():
return False
if course.self_paced:
if not SWITCHES.is_enabled(waffle.SELF_PACED_ONLY):
return False
else:
if not SWITCHES.is_enabled(waffle.INSTRUCTOR_PACED_ONLY):
return False
return True
def _enabled_and_self_paced(course):
if auto_certificate_generation_enabled_for_course(course):
return not course.self_paced return not course.self_paced
return False return False
def can_show_certificate_available_date_field(course): def can_show_certificate_available_date_field(course):
return _enabled_and_self_paced(course) return _enabled_and_instructor_paced(course)
def display_date_for_certificate(course, certificate): def display_date_for_certificate(course, certificate):
if ( if (
auto_certificate_generation_enabled_for_course(course) and auto_certificate_generation_enabled() and
not course.self_paced and not course.self_paced and
course.certificate_available_date and course.certificate_available_date and
course.certificate_available_date < datetime.now(UTC) course.certificate_available_date < datetime.now(UTC)
......
...@@ -9,8 +9,6 @@ WAFFLE_NAMESPACE = u'certificates' ...@@ -9,8 +9,6 @@ WAFFLE_NAMESPACE = u'certificates'
# Switches # Switches
AUTO_CERTIFICATE_GENERATION = u'auto_certificate_generation' AUTO_CERTIFICATE_GENERATION = u'auto_certificate_generation'
SELF_PACED_ONLY = u'self_paced_only'
INSTRUCTOR_PACED_ONLY = u'instructor_paced_only'
def waffle(): def waffle():
......
...@@ -11,11 +11,10 @@ from openedx.core.djangoapps.content.course_overviews.tests.factories import Cou ...@@ -11,11 +11,10 @@ from openedx.core.djangoapps.content.course_overviews.tests.factories import Cou
@contextmanager @contextmanager
def configure_waffle_namespace(self_paced_enabled, instructor_paced_enabled): def configure_waffle_namespace(feature_enabled):
namespace = certs_waffle.waffle() namespace = certs_waffle.waffle()
with namespace.override(certs_waffle.SELF_PACED_ONLY, active=self_paced_enabled): with namespace.override(certs_waffle.AUTO_CERTIFICATE_GENERATION, active=feature_enabled):
with namespace.override(certs_waffle.INSTRUCTOR_PACED_ONLY, active=instructor_paced_enabled):
yield yield
...@@ -29,38 +28,21 @@ class FeatureEnabledTestCase(TestCase): ...@@ -29,38 +28,21 @@ class FeatureEnabledTestCase(TestCase):
super(FeatureEnabledTestCase, self).tearDown() super(FeatureEnabledTestCase, self).tearDown()
self.course.self_paced = False self.course.self_paced = False
@ddt.data(*itertools.product((True, False), (True, False))) @ddt.data(True, False)
@ddt.unpack def test_auto_certificate_generation_enabled(self, feature_enabled):
def test_auto_certificate_generation_enabled(self, self_paced_enabled, instructor_paced_enabled): with configure_waffle_namespace(feature_enabled):
expected_value = self_paced_enabled or instructor_paced_enabled self.assertEqual(feature_enabled, api.auto_certificate_generation_enabled())
with configure_waffle_namespace(self_paced_enabled, instructor_paced_enabled):
self.assertEqual(expected_value, api.auto_certificate_generation_enabled())
@ddt.data(
(False, False, True, False), # feature not enabled should return False
(False, True, True, False), # self-paced feature enabled and self-paced course should return False
(True, False, True, True), # self-paced feature enabled and self-paced course should return True
(True, False, False, False), # instructor-paced feature enabled and self-paced course should return False
(False, True, False, True) # instructor-paced feature enabled and instructor-paced course should return True
)
@ddt.unpack
def test_auto_certificate_generation_enabled_for_course(
self, self_paced_enabled, instructor_paced_enabled, is_self_paced, expected_value
):
self.course.self_paced = is_self_paced
with configure_waffle_namespace(self_paced_enabled, instructor_paced_enabled):
self.assertEqual(expected_value, api.auto_certificate_generation_enabled_for_course(self.course))
@ddt.data( @ddt.data(
(True, False, True, False), # feature enabled and self-paced should return False (True, True, False), # feature enabled and self-paced should return False
(False, True, False, True), # feature enabled and instructor-paced should return True (True, False, True), # feature enabled and instructor-paced should return True
(False, False, True, False), # feature not enabled and self-paced should return False (False, True, False), # feature not enabled and self-paced should return False
(False, False, False, False), # feature not enabled and instructor-paced should return False (False, False, False), # feature not enabled and instructor-paced should return False
) )
@ddt.unpack @ddt.unpack
def test_can_show_certificate_available_date_field( def test_can_show_certificate_available_date_field(
self, self_paced_enabled, instructor_paced_enabled, is_self_paced, expected_value self, feature_enabled, is_self_paced, expected_value
): ):
self.course.self_paced = is_self_paced self.course.self_paced = is_self_paced
with configure_waffle_namespace(self_paced_enabled, instructor_paced_enabled): with configure_waffle_namespace(feature_enabled):
self.assertEqual(expected_value, api.can_show_certificate_available_date_field(self.course)) self.assertEqual(expected_value, api.can_show_certificate_available_date_field(self.course))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment