diff --git a/common/djangoapps/course_modes/migrations/0004_auto__add_field_coursemode_expiration_date.py b/common/djangoapps/course_modes/migrations/0004_auto__add_field_coursemode_expiration_date.py new file mode 100644 index 0000000000000000000000000000000000000000..afd8207388f8a2075f8a2e58c543a508d1dfb72d --- /dev/null +++ b/common/djangoapps/course_modes/migrations/0004_auto__add_field_coursemode_expiration_date.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding field 'CourseMode.expiration_date' + db.add_column('course_modes_coursemode', 'expiration_date', + self.gf('django.db.models.fields.DateField')(default=None, null=True), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'CourseMode.expiration_date' + db.delete_column('course_modes_coursemode', 'expiration_date') + + + models = { + 'course_modes.coursemode': { + 'Meta': {'unique_together': "(('course_id', 'mode_slug', 'currency'),)", 'object_name': 'CourseMode'}, + 'course_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'currency': ('django.db.models.fields.CharField', [], {'default': "'usd'", 'max_length': '8'}), + 'expiration_date': ('django.db.models.fields.DateField', [], {'default': 'None', 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'min_price': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'mode_display_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'mode_slug': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'suggested_prices': ('django.db.models.fields.CommaSeparatedIntegerField', [], {'default': "''", 'max_length': '255', 'blank': 'True'}) + } + } + + complete_apps = ['course_modes'] \ No newline at end of file diff --git a/common/djangoapps/course_modes/models.py b/common/djangoapps/course_modes/models.py index 50399fcc646d67fa348b0ba9ff748e8a4a3dc310..cc25031935ff458d818a1760fa2b8ee9a2ae2d5b 100644 --- a/common/djangoapps/course_modes/models.py +++ b/common/djangoapps/course_modes/models.py @@ -1,9 +1,13 @@ """ Add and create new modes for running courses on this particular LMS """ +import pytz +from datetime import datetime + from django.db import models from collections import namedtuple from django.utils.translation import ugettext as _ +from django.db.models import Q Mode = namedtuple('Mode', ['slug', 'name', 'min_price', 'suggested_prices', 'currency']) @@ -32,6 +36,9 @@ class CourseMode(models.Model): # the currency these prices are in, using lower case ISO currency codes currency = models.CharField(default="usd", max_length=8) + # turn this mode off after the given expiration date + expiration_date = models.DateField(default=None, null=True) + DEFAULT_MODE = Mode('honor', _('Honor Code Certificate'), 0, '', 'usd') DEFAULT_MODE_SLUG = 'honor' @@ -42,11 +49,14 @@ class CourseMode(models.Model): @classmethod def modes_for_course(cls, course_id): """ - Returns a list of the modes for a given course id + Returns a list of the non-expired modes for a given course id If no modes have been set in the table, returns the default mode """ - found_course_modes = cls.objects.filter(course_id=course_id) + now = datetime.now(pytz.UTC) + found_course_modes = cls.objects.filter(Q(course_id=course_id) & + Q(expiration_date__isnull=True) | + Q(expiration_date__gte=now)) modes = ([Mode(mode.mode_slug, mode.mode_display_name, mode.min_price, mode.suggested_prices, mode.currency) for mode in found_course_modes]) if not modes: diff --git a/common/djangoapps/course_modes/tests/test_models.py b/common/djangoapps/course_modes/tests/test_models.py index 1fba5ca1979536d0243c237ae84d9341604ac346..72aa3f2464c88c84160456b93e29cf86f6b1ee22 100644 --- a/common/djangoapps/course_modes/tests/test_models.py +++ b/common/djangoapps/course_modes/tests/test_models.py @@ -5,6 +5,9 @@ when you run "manage.py test". Replace this with more appropriate tests for your application. """ +from datetime import datetime, timedelta +import pytz + from django.test import TestCase from course_modes.models import CourseMode, Mode @@ -22,7 +25,7 @@ class CourseModeModelTest(TestCase): """ Create a new course mode """ - CourseMode.objects.get_or_create( + return CourseMode.objects.get_or_create( course_id=self.course_id, mode_display_name=mode_name, mode_slug=mode_slug, @@ -46,7 +49,13 @@ class CourseModeModelTest(TestCase): self.create_mode('verified', 'Verified Certificate') modes = CourseMode.modes_for_course(self.course_id) - self.assertEqual([Mode(u'verified', u'Verified Certificate', 0, '', 'usd')], modes) + mode = Mode(u'verified', u'Verified Certificate', 0, '', 'usd') + self.assertEqual([mode], modes) + + modes_dict = CourseMode.modes_for_course_dict(self.course_id) + self.assertEqual(modes_dict['verified'], mode) + self.assertEqual(CourseMode.mode_for_course(self.course_id, 'verified'), + mode) def test_modes_for_course_multiple(self): """ @@ -63,3 +72,15 @@ class CourseModeModelTest(TestCase): self.assertEqual(mode1, CourseMode.mode_for_course(self.course_id, u'honor')) self.assertEqual(mode2, CourseMode.mode_for_course(self.course_id, u'verified')) self.assertIsNone(CourseMode.mode_for_course(self.course_id, 'DNE')) + + def test_modes_for_course_expired(self): + expired_mode, _status = self.create_mode('verified', 'Verified Certificate') + expired_mode.expiration_date = datetime.now(pytz.UTC) + timedelta(days=-1) + expired_mode.save() + modes = CourseMode.modes_for_course(self.course_id) + self.assertEqual([CourseMode.DEFAULT_MODE], modes) + + mode1 = Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd') + self.create_mode(mode1.slug, mode1.name, mode1.min_price, mode1.suggested_prices) + modes = CourseMode.modes_for_course(self.course_id) + self.assertEqual([mode1], modes) diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py index c3a18c56642bc06fbd9c89afb650adb5994f106c..486e32c465fce77f2001a666b682abded9d5c124 100644 --- a/common/djangoapps/student/views.py +++ b/common/djangoapps/student/views.py @@ -391,6 +391,8 @@ def change_enrollment(request): reverse("course_modes_choose", kwargs={'course_id': course_id}) ) + current_mode = available_modes[0] + org, course_num, run = course_id.split("/") dog_stats_api.increment( "common.student.enrollment", @@ -399,7 +401,7 @@ def change_enrollment(request): "run:{0}".format(run)] ) - CourseEnrollment.enroll(user, course.id) + CourseEnrollment.enroll(user, course.id, mode=current_mode.slug) return HttpResponse()