Commit 0137e38e by Alex Dusenbery Committed by Alex Dusenbery

EDUCATOR-1241 | make a separate file to make decisions about auto generated certs.

parent 29f6d5d6
......@@ -9,7 +9,7 @@
import urllib
from django.utils.translation import ugettext as _
from contentstore import utils
from openedx.core.djangoapps.certificates.config import waffle
from openedx.core.djangoapps.certificates.api import can_show_certificate_available_date_field
from openedx.core.djangolib.js_utils import (
dump_js_escaped_json, js_escaped_string
)
......@@ -214,7 +214,7 @@ CMS.URL.UPLOAD_ASSET = '${upload_asset_url | n, js_escaped_string}'
</li>
</ol>
% if waffle.waffle().is_enabled(waffle.INSTRUCTOR_PACED_ONLY) and not context_course.self_paced:
% if can_show_certificate_available_date_field(context_course):
<ol class="list-input">
<li class="field-group field-group-certificate-available" id="certificate-available">
<div class="field date" id="field-certificate-available-date">
......
......@@ -13,9 +13,13 @@ from certificates.models import (
GeneratedCertificate
)
from certificates.tasks import generate_certificate
from courseware import courses
from lms.djangoapps.grades.new.course_grade_factory import CourseGradeFactory
from openedx.core.djangoapps.certificates.api import (
auto_certificate_generation_enabled,
auto_certificate_generation_enabled_for_course,
)
from openedx.core.djangoapps.certificates.config import waffle
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 student.models import CourseEnrollment
......@@ -25,21 +29,10 @@ 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()
# No flags enabled
if (
not switches.is_enabled(waffle.SELF_PACED_ONLY) and
not switches.is_enabled(waffle.INSTRUCTOR_PACED_ONLY)
):
course = CourseOverview.get_from_id(instance.course_id)
if not auto_certificate_generation_enabled_for_course(course):
return
if courses.get_course_by_id(instance.course_id, depth=0).self_paced:
if not switches.is_enabled(waffle.SELF_PACED_ONLY):
return
else:
if not switches.is_enabled(waffle.INSTRUCTOR_PACED_ONLY):
return
fire_ungenerated_certificate_task(instance.user, instance.course_id)
log.info(u'Certificate generation task initiated for {user} : {course} via whitelist'.format(
user=instance.user.id,
......@@ -53,20 +46,10 @@ def _listen_for_passing_grade(sender, user, course_id, **kwargs): # pylint: dis
Listen for a learner passing a course, send cert generation task,
downstream signal from COURSE_GRADE_CHANGED
"""
# No flags enabled
if (
not waffle.waffle().is_enabled(waffle.SELF_PACED_ONLY) and
not waffle.waffle().is_enabled(waffle.INSTRUCTOR_PACED_ONLY)
):
course = CourseOverview.get_from_id(course_id)
if not auto_certificate_generation_enabled_for_course(course):
return
if courses.get_course_by_id(course_id, depth=0).self_paced:
if not waffle.waffle().is_enabled(waffle.SELF_PACED_ONLY):
return
else:
if not waffle.waffle().is_enabled(waffle.INSTRUCTOR_PACED_ONLY):
return
if fire_ungenerated_certificate_task(user, course_id):
log.info(u'Certificate generation task initiated for {user} : {course} via passing grade'.format(
user=user.id,
......@@ -80,11 +63,9 @@ def _listen_for_track_change(sender, user, **kwargs): # pylint: disable=unused-
Catches a track change signal, determines user status,
calls fire_ungenerated_certificate_task for passing grades
"""
if (
not waffle.waffle().is_enabled(waffle.SELF_PACED_ONLY) and
not waffle.waffle().is_enabled(waffle.INSTRUCTOR_PACED_ONLY)
):
if not auto_certificate_generation_enabled():
return
user_enrollments = CourseEnrollment.enrollments_for_user(user=user)
grade_factory = CourseGradeFactory()
for enrollment in user_enrollments:
......
......@@ -16,7 +16,7 @@ from pytz import timezone, utc
from course_modes.models import CourseMode
from lms.djangoapps.commerce.utils import EcommerceService
from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification, VerificationDeadline
from openedx.core.djangoapps.certificates.config import waffle
from openedx.core.djangoapps.certificates.api import can_show_certificate_available_date_field
from student.models import CourseEnrollment
......@@ -198,8 +198,8 @@ class CourseEndDate(DateSummary):
class CertificateAvailableDate(DateSummary):
"""
Displays the end date of the course.
"""
Displays the certificate available date of the course.
"""
css_class = 'certificate-available-date'
title = ugettext_lazy('Certificate Available')
......@@ -213,10 +213,9 @@ class CertificateAvailableDate(DateSummary):
@property
def is_enabled(self):
return (
can_show_certificate_available_date_field(self.course) and
self.date is not None and
datetime.datetime.now(utc) <= self.date and
not self.course.self_paced and
waffle.waffle().is_enabled(waffle.INSTRUCTOR_PACED_ONLY) and
len(self.active_certificates) > 0
)
......
"""
The public API for certificates.
"""
from openedx.core.djangoapps.certificates.config import waffle
SWITCHES = waffle.waffle()
def auto_certificate_generation_enabled():
return (
SWITCHES.is_enabled(waffle.SELF_PACED_ONLY) or
SWITCHES.is_enabled(waffle.INSTRUCTOR_PACED_ONLY)
)
def auto_certificate_generation_enabled_for_course(course):
if not 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 False
def can_show_certificate_available_date_field(course):
return _enabled_and_self_paced(course)
......@@ -8,6 +8,7 @@ from openedx.core.djangoapps.waffle_utils import WaffleSwitchNamespace
WAFFLE_NAMESPACE = u'certificates'
# Switches
AUTO_CERTIFICATE_GENERATION = u'auto_certificate_generation'
SELF_PACED_ONLY = u'self_paced_only'
INSTRUCTOR_PACED_ONLY = u'instructor_paced_only'
......
from contextlib import contextmanager
import itertools
from unittest import TestCase
import ddt
import waffle
from openedx.core.djangoapps.certificates import api
from openedx.core.djangoapps.certificates.config import waffle as certs_waffle
from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory
@contextmanager
def configure_waffle_namespace(self_paced_enabled, instructor_paced_enabled):
namespace = certs_waffle.waffle()
with namespace.override(certs_waffle.SELF_PACED_ONLY, active=self_paced_enabled):
with namespace.override(certs_waffle.INSTRUCTOR_PACED_ONLY, active=instructor_paced_enabled):
yield
@ddt.ddt
class FeatureEnabledTestCase(TestCase):
def setUp(self):
super(FeatureEnabledTestCase, self).setUp()
self.course = CourseOverviewFactory.create()
def tearDown(self):
super(FeatureEnabledTestCase, self).tearDown()
self.course.self_paced = False
@ddt.data(*itertools.product((True, False), (True, False)))
@ddt.unpack
def test_auto_certificate_generation_enabled(self, self_paced_enabled, instructor_paced_enabled):
expected_value = self_paced_enabled or instructor_paced_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(
(True, False, True, False), # feature enabled and self-paced should return False
(False, 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, False, False, False), # feature not enabled and instructor-paced should return False
)
@ddt.unpack
def test_can_show_certificate_available_date_field(
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.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