From 6c6ba54e84c248fca71a4b89b6c54b8881ccef8a Mon Sep 17 00:00:00 2001 From: Diana Huang Date: Wed, 14 Aug 2013 11:57:26 -0400 Subject: [PATCH 1/3] Create Course Modes django app --- lms/djangoapps/course_modes/__init__.py | 0 lms/djangoapps/course_modes/models.py | 46 +++++++++++++++++++ lms/djangoapps/course_modes/tests.py | 61 +++++++++++++++++++++++++ lms/djangoapps/course_modes/views.py | 1 + lms/envs/common.py | 3 ++ 5 files changed, 111 insertions(+) create mode 100644 lms/djangoapps/course_modes/__init__.py create mode 100644 lms/djangoapps/course_modes/models.py create mode 100644 lms/djangoapps/course_modes/tests.py create mode 100644 lms/djangoapps/course_modes/views.py diff --git a/lms/djangoapps/course_modes/__init__.py b/lms/djangoapps/course_modes/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lms/djangoapps/course_modes/models.py b/lms/djangoapps/course_modes/models.py new file mode 100644 index 0000000000..44e096fa13 --- /dev/null +++ b/lms/djangoapps/course_modes/models.py @@ -0,0 +1,46 @@ +""" +Add and create new modes for running courses on this particular LMS +""" +from django.db import models +from collections import namedtuple +from django.utils.translation import ugettext as _ + +Mode = namedtuple('Mode', ['slug', 'name', 'min_price', 'suggested_prices']) + + +class CourseMode(models.Model): + """ + We would like to offer a course in a variety of modes. + + """ + # the course that this mode is attached to + course_id = models.CharField(max_length=255, db_index=True) + + # the reference to this mode that can be used by Enrollments to generate + # similar behavior for the same slug across courses + mode_slug = models.CharField(max_length=100) + + # The 'pretty' name that can be translated and displayed + mode_display_name = models.CharField(max_length=255) + + # minimum price in USD that we would like to charge for this mode of the course + min_price = models.IntegerField(default=0) + + # the suggested prices for this mode + suggested_prices = models.CommaSeparatedIntegerField(max_length=255, blank=True, default='') + + DEFAULT_MODE = Mode('honor', _('Honor Code Certificate'), 0, '') + + @classmethod + def modes_for_course(cls, course_id): + """ + Returns a list of the 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) + modes = ([Mode(mode.mode_slug, mode.mode_display_name, mode.min_price, mode.suggested_prices) + for mode in found_course_modes]) + if not modes: + modes = [cls.DEFAULT_MODE] + return modes diff --git a/lms/djangoapps/course_modes/tests.py b/lms/djangoapps/course_modes/tests.py new file mode 100644 index 0000000000..9f19d5e5bc --- /dev/null +++ b/lms/djangoapps/course_modes/tests.py @@ -0,0 +1,61 @@ +""" +This file demonstrates writing tests using the unittest module. These will pass +when you run "manage.py test". + +Replace this with more appropriate tests for your application. +""" + +from django.test import TestCase +from course_modes.models import CourseMode, Mode + + +class CourseModeModelTest(TestCase): + """ + Tests for the CourseMode model + """ + + def setUp(self): + self.course_id = 'TestCourse' + CourseMode.objects.all().delete() + + def create_mode(self, mode_slug, mode_name, min_price=0, suggested_prices=''): + """ + Create a new course mode + """ + CourseMode.objects.get_or_create( + course_id=self.course_id, + mode_display_name=mode_name, + mode_slug=mode_slug, + min_price=min_price, + suggested_prices=suggested_prices + ) + + def test_modes_for_course_empty(self): + """ + If we can't find any modes, we should get back the default mode + """ + # shouldn't be able to find a corresponding course + modes = CourseMode.modes_for_course(self.course_id) + self.assertEqual([CourseMode.DEFAULT_MODE], modes) + + def test_nodes_for_course_single(self): + """ + Find the modes for a course with only one mode + """ + + self.create_mode('verified', 'Verified Certificate') + modes = CourseMode.modes_for_course(self.course_id) + self.assertEqual([Mode(u'verified', u'Verified Certificate', 0, '')], modes) + + def test_modes_for_course_multiple(self): + """ + Finding the modes when there's multiple modes + """ + mode1 = Mode(u'honor', u'Honor Code Certificate', 0, '') + mode2 = Mode(u'verified', u'Verified Certificate', 0, '') + set_modes = [mode1, mode2] + for mode in set_modes: + self.create_mode(mode.slug, mode.name, mode.min_price, mode.suggested_prices) + + modes = CourseMode.modes_for_course(self.course_id) + self.assertEqual(modes, set_modes) diff --git a/lms/djangoapps/course_modes/views.py b/lms/djangoapps/course_modes/views.py new file mode 100644 index 0000000000..60f00ef0ef --- /dev/null +++ b/lms/djangoapps/course_modes/views.py @@ -0,0 +1 @@ +# Create your views here. diff --git a/lms/envs/common.py b/lms/envs/common.py index 0579fc94d6..0a96efd45d 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -771,6 +771,9 @@ INSTALLED_APPS = ( # Notification preferences setting 'notification_prefs', + + # Different Course Modes + 'course_modes' ) ######################### MARKETING SITE ############################### From 22b1ef34723bff7689b174b7a87b008ca90c1b81 Mon Sep 17 00:00:00 2001 From: Diana Huang Date: Wed, 14 Aug 2013 13:26:32 -0400 Subject: [PATCH 2/3] Initial migrations for course modes --- .../course_modes/migrations/0001_initial.py | 40 +++++++++++++++++++ .../course_modes/migrations/__init__.py | 0 2 files changed, 40 insertions(+) create mode 100644 lms/djangoapps/course_modes/migrations/0001_initial.py create mode 100644 lms/djangoapps/course_modes/migrations/__init__.py diff --git a/lms/djangoapps/course_modes/migrations/0001_initial.py b/lms/djangoapps/course_modes/migrations/0001_initial.py new file mode 100644 index 0000000000..83e53769a2 --- /dev/null +++ b/lms/djangoapps/course_modes/migrations/0001_initial.py @@ -0,0 +1,40 @@ +# -*- 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 model 'CourseMode' + db.create_table('course_modes_coursemode', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('course_id', self.gf('django.db.models.fields.CharField')(max_length=255, db_index=True)), + ('mode_slug', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('mode_display_name', self.gf('django.db.models.fields.CharField')(max_length=255)), + ('min_price', self.gf('django.db.models.fields.IntegerField')(default=0)), + ('suggested_prices', self.gf('django.db.models.fields.CommaSeparatedIntegerField')(default='', max_length=255, blank=True)), + )) + db.send_create_signal('course_modes', ['CourseMode']) + + + def backwards(self, orm): + # Deleting model 'CourseMode' + db.delete_table('course_modes_coursemode') + + + models = { + 'course_modes.coursemode': { + 'Meta': {'object_name': 'CourseMode'}, + 'course_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': '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/lms/djangoapps/course_modes/migrations/__init__.py b/lms/djangoapps/course_modes/migrations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 From 7d44379c9929ef2b3e329285f2f00218a2852a23 Mon Sep 17 00:00:00 2001 From: Diana Huang Date: Wed, 14 Aug 2013 15:13:11 -0400 Subject: [PATCH 3/3] Add admin site for CourseMode --- lms/djangoapps/course_modes/admin.py | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 lms/djangoapps/course_modes/admin.py diff --git a/lms/djangoapps/course_modes/admin.py b/lms/djangoapps/course_modes/admin.py new file mode 100644 index 0000000000..58c458236a --- /dev/null +++ b/lms/djangoapps/course_modes/admin.py @@ -0,0 +1,4 @@ +from ratelimitbackend import admin +from course_modes.models import CourseMode + +admin.site.register(CourseMode)