Switch ContentTypeGatingConfig.enabled_as_of and CourseDurationLimitConfig.enabled_as_of to datetimes

This commit is contained in:
Calen Pennington
2018-11-28 14:13:55 -05:00
parent af86f7856c
commit 31047260cc
20 changed files with 194 additions and 112 deletions

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.16 on 2018-11-28 19:07
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('course_duration_limits', '0002_auto_20181119_0959'),
]
operations = [
migrations.AlterField(
model_name='coursedurationlimitconfig',
name='enabled_as_of',
field=models.DateTimeField(blank=True, default=None, help_text='If the configuration is Enabled, then all enrollments created after this date (UTC) will be affected.', null=True, verbose_name='Enabled As Of'),
),
]

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.16 on 2018-11-28 20:21
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('course_duration_limits', '0003_auto_20181128_1407'),
]
operations = [
migrations.AlterField(
model_name='coursedurationlimitconfig',
name='enabled_as_of',
field=models.DateTimeField(blank=True, default=None, help_text='If the configuration is Enabled, then all enrollments created after this date and time (UTC) will be affected.', null=True, verbose_name='Enabled As Of'),
),
]

View File

@@ -5,11 +5,11 @@ Course Duration Limit Configuration Models
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from datetime import datetime
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
from experiments.models import ExperimentData
from student.models import CourseEnrollment
@@ -29,14 +29,14 @@ class CourseDurationLimitConfig(StackedConfigurationModel):
STACKABLE_FIELDS = ('enabled', 'enabled_as_of')
enabled_as_of = models.DateField(
enabled_as_of = models.DateTimeField(
default=None,
null=True,
verbose_name=_('Enabled As Of'),
blank=True,
help_text=_(
'If the configuration is Enabled, then all enrollments '
'created after this date (UTC) will be affected.'
'created after this date and time (UTC) will be affected.'
)
)
@@ -78,7 +78,7 @@ class CourseDurationLimitConfig(StackedConfigurationModel):
# enrollment might be None if the user isn't enrolled. In that case,
# return enablement as if the user enrolled today
if enrollment is None:
return cls.enabled_for_course(course_key=course_key, target_date=datetime.utcnow().date())
return cls.enabled_for_course(course_key=course_key, target_datetime=timezone.now())
else:
# TODO: clean up as part of REV-100
experiment_data_holdback_key = EXPERIMENT_DATA_HOLDBACK_KEY.format(user)
@@ -95,48 +95,48 @@ class CourseDurationLimitConfig(StackedConfigurationModel):
if is_in_holdback:
return False
current_config = cls.current(course_key=enrollment.course_id)
return current_config.enabled_as_of_date(target_date=enrollment.created.date())
return current_config.enabled_as_of_datetime(target_datetime=enrollment.created)
@classmethod
def enabled_for_course(cls, course_key, target_date=None):
def enabled_for_course(cls, course_key, target_datetime=None):
"""
Return whether Course Duration Limits are enabled for this course as of a particular date.
Course Duration Limits are enabled for a course on a date if they are enabled either specifically,
or via a containing context, such as the org, site, or globally, and if the configuration
is specified to be ``enabled_as_of`` before ``target_date``.
is specified to be ``enabled_as_of`` before ``target_datetime``.
Only one of enrollment and (user, course_key) may be specified at a time.
Arguments:
course_key: The CourseKey of the course being queried.
target_date: The date to checked enablement as of. Defaults to the current date.
target_datetime: The datetime to checked enablement as of. Defaults to the current date and time.
"""
if CONTENT_TYPE_GATING_FLAG.is_enabled():
return True
if target_date is None:
target_date = datetime.utcnow().date()
if target_datetime is None:
target_datetime = timezone.now()
current_config = cls.current(course_key=course_key)
return current_config.enabled_as_of_date(target_date=target_date)
return current_config.enabled_as_of_datetime(target_datetime=target_datetime)
def clean(self):
if self.enabled and self.enabled_as_of is None:
raise ValidationError({'enabled_as_of': _('enabled_as_of must be set when enabled is True')})
def enabled_as_of_date(self, target_date):
def enabled_as_of_datetime(self, target_datetime):
"""
Return whether this Course Duration Limit configuration context is enabled as of a date.
Return whether this Course Duration Limit configuration context is enabled as of a date and time.
Arguments:
target_date (:class:`datetime.date`): The date that ``enabled_as_of`` must be equal to or before
target_datetime (:class:`datetime.datetime`): The datetime that ``enabled_as_of`` must be equal to or before
"""
if CONTENT_TYPE_GATING_FLAG.is_enabled():
return True
# Explicitly cast this to bool, so that when self.enabled is None the method doesn't return None
return bool(self.enabled and self.enabled_as_of <= target_date)
return bool(self.enabled and self.enabled_as_of <= target_datetime)
def __str__(self):
return "CourseDurationLimits(enabled={!r}, enabled_as_of={!r})".format(

View File

@@ -2,12 +2,12 @@
Tests of CourseDurationLimitConfig.
"""
from datetime import timedelta, date
from datetime import timedelta, datetime
import itertools
import ddt
from django.utils import timezone
from mock import Mock
from openedx.core.djangoapps.site_configuration.tests.factories import SiteConfigurationFactory
from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory
from openedx.core.djangoapps.waffle_utils.testutils import override_waffle_flag
@@ -46,12 +46,12 @@ class TestCourseDurationLimitConfig(CacheIsolationTestCase):
enrolled_before_enabled,
):
# Tweak the day to enable the config so that it is either before
# or after today (which is when the enrollment will be created)
# Tweak the datetime to enable the config so that it is either before
# or after now (which is when the enrollment will be created)
if enrolled_before_enabled:
enabled_as_of = date.today() + timedelta(days=1)
enabled_as_of = timezone.now() + timedelta(days=1)
else:
enabled_as_of = date.today() - timedelta(days=1)
enabled_as_of = timezone.now() - timedelta(days=1)
CourseDurationLimitConfig.objects.create(
enabled=True,
@@ -130,15 +130,15 @@ class TestCourseDurationLimitConfig(CacheIsolationTestCase):
config = CourseDurationLimitConfig.objects.create(
enabled=True,
course=self.course_overview,
enabled_as_of=date.today(),
enabled_as_of=timezone.now(),
)
# Tweak the day to check for course enablement so it is either
# Tweak the datetime to check for course enablement so it is either
# before or after when the configuration was enabled
if before_enabled:
target_date = config.enabled_as_of - timedelta(days=1)
target_datetime = config.enabled_as_of - timedelta(days=1)
else:
target_date = config.enabled_as_of + timedelta(days=1)
target_datetime = config.enabled_as_of + timedelta(days=1)
course_key = self.course_overview.id
@@ -146,7 +146,7 @@ class TestCourseDurationLimitConfig(CacheIsolationTestCase):
not before_enabled,
CourseDurationLimitConfig.enabled_for_course(
course_key=course_key,
target_date=target_date,
target_datetime=target_datetime,
)
)
@@ -200,7 +200,7 @@ class TestCourseDurationLimitConfig(CacheIsolationTestCase):
self.assertEqual(expected_course_setting, CourseDurationLimitConfig.current(course_key=test_course.id).enabled)
def test_caching_global(self):
global_config = CourseDurationLimitConfig(enabled=True, enabled_as_of=date(2018, 1, 1))
global_config = CourseDurationLimitConfig(enabled=True, enabled_as_of=datetime(2018, 1, 1))
global_config.save()
# Check that the global value is not retrieved from cache after save
@@ -220,7 +220,7 @@ class TestCourseDurationLimitConfig(CacheIsolationTestCase):
def test_caching_site(self):
site_cfg = SiteConfigurationFactory()
site_config = CourseDurationLimitConfig(site=site_cfg.site, enabled=True, enabled_as_of=date(2018, 1, 1))
site_config = CourseDurationLimitConfig(site=site_cfg.site, enabled=True, enabled_as_of=datetime(2018, 1, 1))
site_config.save()
# Check that the site value is not retrieved from cache after save
@@ -238,7 +238,7 @@ class TestCourseDurationLimitConfig(CacheIsolationTestCase):
with self.assertNumQueries(1):
self.assertFalse(CourseDurationLimitConfig.current(site=site_cfg.site).enabled)
global_config = CourseDurationLimitConfig(enabled=True, enabled_as_of=date(2018, 1, 1))
global_config = CourseDurationLimitConfig(enabled=True, enabled_as_of=datetime(2018, 1, 1))
global_config.save()
# Check that the site value is not updated in cache by changing the global value
@@ -248,7 +248,7 @@ class TestCourseDurationLimitConfig(CacheIsolationTestCase):
def test_caching_org(self):
course = CourseOverviewFactory.create(org='test-org')
site_cfg = SiteConfigurationFactory.create(values={'course_org_filter': course.org})
org_config = CourseDurationLimitConfig(org=course.org, enabled=True, enabled_as_of=date(2018, 1, 1))
org_config = CourseDurationLimitConfig(org=course.org, enabled=True, enabled_as_of=datetime(2018, 1, 1))
org_config.save()
# Check that the org value is not retrieved from cache after save
@@ -266,14 +266,14 @@ class TestCourseDurationLimitConfig(CacheIsolationTestCase):
with self.assertNumQueries(2):
self.assertFalse(CourseDurationLimitConfig.current(org=course.org).enabled)
global_config = CourseDurationLimitConfig(enabled=True, enabled_as_of=date(2018, 1, 1))
global_config = CourseDurationLimitConfig(enabled=True, enabled_as_of=datetime(2018, 1, 1))
global_config.save()
# Check that the org value is not updated in cache by changing the global value
with self.assertNumQueries(0):
self.assertFalse(CourseDurationLimitConfig.current(org=course.org).enabled)
site_config = CourseDurationLimitConfig(site=site_cfg.site, enabled=True, enabled_as_of=date(2018, 1, 1))
site_config = CourseDurationLimitConfig(site=site_cfg.site, enabled=True, enabled_as_of=datetime(2018, 1, 1))
site_config.save()
# Check that the org value is not updated in cache by changing the site value
@@ -283,7 +283,7 @@ class TestCourseDurationLimitConfig(CacheIsolationTestCase):
def test_caching_course(self):
course = CourseOverviewFactory.create(org='test-org')
site_cfg = SiteConfigurationFactory.create(values={'course_org_filter': course.org})
course_config = CourseDurationLimitConfig(course=course, enabled=True, enabled_as_of=date(2018, 1, 1))
course_config = CourseDurationLimitConfig(course=course, enabled=True, enabled_as_of=datetime(2018, 1, 1))
course_config.save()
# Check that the org value is not retrieved from cache after save
@@ -301,21 +301,21 @@ class TestCourseDurationLimitConfig(CacheIsolationTestCase):
with self.assertNumQueries(2):
self.assertFalse(CourseDurationLimitConfig.current(course_key=course.id).enabled)
global_config = CourseDurationLimitConfig(enabled=True, enabled_as_of=date(2018, 1, 1))
global_config = CourseDurationLimitConfig(enabled=True, enabled_as_of=datetime(2018, 1, 1))
global_config.save()
# Check that the org value is not updated in cache by changing the global value
with self.assertNumQueries(0):
self.assertFalse(CourseDurationLimitConfig.current(course_key=course.id).enabled)
site_config = CourseDurationLimitConfig(site=site_cfg.site, enabled=True, enabled_as_of=date(2018, 1, 1))
site_config = CourseDurationLimitConfig(site=site_cfg.site, enabled=True, enabled_as_of=datetime(2018, 1, 1))
site_config.save()
# Check that the org value is not updated in cache by changing the site value
with self.assertNumQueries(0):
self.assertFalse(CourseDurationLimitConfig.current(course_key=course.id).enabled)
org_config = CourseDurationLimitConfig(org=course.org, enabled=True, enabled_as_of=date(2018, 1, 1))
org_config = CourseDurationLimitConfig(org=course.org, enabled=True, enabled_as_of=datetime(2018, 1, 1))
org_config.save()
# Check that the org value is not updated in cache by changing the site value