Auto setting of verification deadlines with manual overrides

This commit is contained in:
Bill DeRusha
2015-11-13 15:40:10 -05:00
parent ef4f39fea5
commit 522095e112
16 changed files with 369 additions and 30 deletions

View File

@@ -58,8 +58,9 @@ class Course(object):
def save(self, *args, **kwargs): # pylint: disable=unused-argument
""" Save the CourseMode objects to the database. """
# Update the verification deadline for the course (not the individual modes)
VerificationDeadline.set_deadline(self.id, self.verification_deadline)
# Override the verification deadline for the course (not the individual modes)
if self.verification_deadline is not None:
VerificationDeadline.set_deadline(self.id, self.verification_deadline, is_explicit=True)
for mode in self.modes:
mode.course_id = self.id
@@ -87,7 +88,8 @@ class Course(object):
merged_mode.min_price = posted_mode.min_price
merged_mode.currency = posted_mode.currency
merged_mode.sku = posted_mode.sku
merged_mode.expiration_datetime = posted_mode.expiration_datetime
if posted_mode.expiration_datetime is not None:
merged_mode.expiration_datetime = posted_mode.expiration_datetime
merged_mode.save()
merged_modes.add(merged_mode)

View File

@@ -1531,7 +1531,7 @@ def financial_assistance_form(request):
{'name': enrollment.course_overview.display_name, 'value': unicode(enrollment.course_id)}
for enrollment in CourseEnrollment.enrollments_for_user(user).order_by('-created')
if CourseMode.objects.filter(
Q(expiration_datetime__isnull=True) | Q(expiration_datetime__gt=datetime.now(UTC())),
Q(_expiration_datetime__isnull=True) | Q(_expiration_datetime__gt=datetime.now(UTC())),
course_id=enrollment.course_id,
mode_slug=CourseMode.VERIFIED
).exists()

View File

@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('verify_student', '0002_auto_20151124_1024'),
]
operations = [
migrations.AlterField(
model_name='historicalverificationdeadline',
name='deadline_is_explicit',
field=models.BooleanField(default=False),
),
migrations.AlterField(
model_name='verificationdeadline',
name='deadline_is_explicit',
field=models.BooleanField(default=False),
),
]

View File

@@ -958,7 +958,7 @@ class VerificationDeadline(TimeStampedModel):
# The system prefers to set this automatically based on default settings. But
# if the field is set manually we want a way to indicate that so we don't
# overwrite the manual setting of the field.
deadline_is_explicit = models.BooleanField(default=True)
deadline_is_explicit = models.BooleanField(default=False)
# Maintain a history of changes to deadlines for auditing purposes
history = HistoricalRecords()
@@ -966,7 +966,7 @@ class VerificationDeadline(TimeStampedModel):
ALL_DEADLINES_CACHE_KEY = "verify_student.all_verification_deadlines"
@classmethod
def set_deadline(cls, course_key, deadline):
def set_deadline(cls, course_key, deadline, is_explicit=False):
"""
Configure the verification deadline for a course.
@@ -984,11 +984,12 @@ class VerificationDeadline(TimeStampedModel):
else:
record, created = VerificationDeadline.objects.get_or_create(
course_key=course_key,
defaults={"deadline": deadline}
defaults={"deadline": deadline, "deadline_is_explicit": is_explicit}
)
if not created:
record.deadline = deadline
record.deadline_is_explicit = is_explicit
record.save()
@classmethod

View File

@@ -0,0 +1,24 @@
"""
Signal handler for setting default course verification dates
"""
from django.core.exceptions import ObjectDoesNotExist
from django.dispatch.dispatcher import receiver
from xmodule.modulestore.django import SignalHandler, modulestore
from .models import VerificationDeadline
@receiver(SignalHandler.course_published)
def _listen_for_course_publish(sender, course_key, **kwargs): # pylint: disable=unused-argument
"""
Catches the signal that a course has been published in Studio and
sets the verification deadline date to a default.
"""
try:
deadline = VerificationDeadline.objects.get(course_key=course_key)
if deadline and not deadline.deadline_is_explicit:
course = modulestore().get_course(course_key)
if course and deadline.deadline != course.end:
VerificationDeadline.set_deadline(course_key, course.end)
except ObjectDoesNotExist:
pass

View File

@@ -0,0 +1,4 @@
"""
Setup the signals on startup.
"""
import lms.djangoapps.verify_student.signals # pylint: disable=unused-import

View File

@@ -0,0 +1,49 @@
"""
Unit tests for the VerificationDeadline signals
"""
from datetime import datetime, timedelta
from pytz import UTC
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
from lms.djangoapps.verify_student.models import VerificationDeadline
from lms.djangoapps.verify_student.signals import _listen_for_course_publish
class VerificationDeadlineSignalTest(ModuleStoreTestCase):
"""
Tests for the VerificationDeadline signal
"""
def setUp(self):
super(VerificationDeadlineSignalTest, self).setUp()
self.end = datetime.now(tz=UTC).replace(microsecond=0) + timedelta(days=7)
self.course = CourseFactory.create(end=self.end)
VerificationDeadline.objects.all().delete()
def test_no_deadline(self):
""" Verify the signal does not raise error when no deadlines found. """
_listen_for_course_publish('store', self.course.id)
self.assertIsNone(_listen_for_course_publish('store', self.course.id))
def test_deadline(self):
""" Verify deadline is set to course end date by signal. """
deadline = datetime.now(tz=UTC) - timedelta(days=7)
VerificationDeadline.set_deadline(self.course.id, deadline)
_listen_for_course_publish('store', self.course.id)
self.assertEqual(VerificationDeadline.deadline_for_course(self.course.id), self.course.end)
def test_deadline_explicit(self):
""" Verify deadline is unchanged by signal when explicitly set. """
deadline = datetime.now(tz=UTC) - timedelta(days=7)
VerificationDeadline.set_deadline(self.course.id, deadline, is_explicit=True)
_listen_for_course_publish('store', self.course.id)
actual_deadline = VerificationDeadline.deadline_for_course(self.course.id)
self.assertNotEqual(actual_deadline, self.course.end)
self.assertEqual(actual_deadline, deadline)