Commit 6fc4b38e by Omar Khan Committed by Braden MacDonald

Disallow free verified course modes

The verification workflow assumes that all verified courses will have a
price. Free verified course modes cause a 404 when the user attempts to
enroll or upgrade.
parent a2c686cf
...@@ -488,7 +488,8 @@ class TestCoursewareSearchIndexer(MixedWithOptionsTestCase): ...@@ -488,7 +488,8 @@ class TestCoursewareSearchIndexer(MixedWithOptionsTestCase):
verified_mode = CourseMode( verified_mode = CourseMode(
course_id=unicode(self.course.id), course_id=unicode(self.course.id),
mode_slug=CourseMode.VERIFIED, mode_slug=CourseMode.VERIFIED,
mode_display_name=CourseMode.VERIFIED mode_display_name=CourseMode.VERIFIED,
min_price=1
) )
verified_mode.save() verified_mode.save()
self.reindex_course(store) self.reindex_course(store)
......
...@@ -137,6 +137,8 @@ class CourseMode(models.Model): ...@@ -137,6 +137,8 @@ class CourseMode(models.Model):
raise ValidationError( raise ValidationError(
_(u"Professional education modes are not allowed to have expiration_datetime set.") _(u"Professional education modes are not allowed to have expiration_datetime set.")
) )
if self.is_verified_slug(self.mode_slug) and self.min_price <= 0:
raise ValidationError(_(u"Verified modes cannot be free."))
def save(self, force_insert=False, force_update=False, using=None): def save(self, force_insert=False, force_update=False, using=None):
# Ensure currency is always lowercase. # Ensure currency is always lowercase.
......
"""
Factories for course mode models.
"""
import random
from course_modes.models import CourseMode from course_modes.models import CourseMode
from factory.django import DjangoModelFactory from factory.django import DjangoModelFactory
from factory import lazy_attribute
from opaque_keys.edx.locations import SlashSeparatedCourseKey from opaque_keys.edx.locations import SlashSeparatedCourseKey
...@@ -11,8 +17,16 @@ class CourseModeFactory(DjangoModelFactory): ...@@ -11,8 +17,16 @@ class CourseModeFactory(DjangoModelFactory):
course_id = SlashSeparatedCourseKey('MITx', '999', 'Robot_Super_Course') course_id = SlashSeparatedCourseKey('MITx', '999', 'Robot_Super_Course')
mode_slug = 'audit' mode_slug = 'audit'
mode_display_name = 'audit course'
min_price = 0
currency = 'usd' currency = 'usd'
expiration_datetime = None expiration_datetime = None
suggested_prices = '' suggested_prices = ''
@lazy_attribute
def min_price(self):
if CourseMode.is_verified_slug(self.mode_slug):
return random.randint(1, 100)
return 0
@lazy_attribute
def mode_display_name(self):
return '{0} course'.format(self.mode_slug)
...@@ -16,6 +16,7 @@ from xmodule.modulestore.tests.factories import CourseFactory ...@@ -16,6 +16,7 @@ from xmodule.modulestore.tests.factories import CourseFactory
from student.tests.factories import UserFactory from student.tests.factories import UserFactory
from course_modes.models import CourseMode from course_modes.models import CourseMode
from course_modes.admin import CourseModeForm from course_modes.admin import CourseModeForm
from course_modes.tests.factories import CourseModeFactory
# Technically, we shouldn't be importing verify_student, since it's # Technically, we shouldn't be importing verify_student, since it's
# defined in the LMS and course_modes is in common. However, the benefits # defined in the LMS and course_modes is in common. However, the benefits
...@@ -178,7 +179,7 @@ class AdminCourseModeFormTest(ModuleStoreTestCase): ...@@ -178,7 +179,7 @@ class AdminCourseModeFormTest(ModuleStoreTestCase):
def _configure(self, mode, upgrade_deadline=None, verification_deadline=None): def _configure(self, mode, upgrade_deadline=None, verification_deadline=None):
"""Configure course modes and deadlines. """ """Configure course modes and deadlines. """
course_mode = CourseMode.objects.create( course_mode = CourseModeFactory.create(
mode_slug=mode, mode_slug=mode,
mode_display_name=mode, mode_display_name=mode,
) )
...@@ -193,7 +194,7 @@ class AdminCourseModeFormTest(ModuleStoreTestCase): ...@@ -193,7 +194,7 @@ class AdminCourseModeFormTest(ModuleStoreTestCase):
def _admin_form(self, mode, upgrade_deadline=None): def _admin_form(self, mode, upgrade_deadline=None):
"""Load the course mode admin form. """ """Load the course mode admin form. """
course_mode = CourseMode.objects.create( course_mode = CourseModeFactory.create(
course_id=self.course.id, course_id=self.course.id,
mode_slug=mode, mode_slug=mode,
) )
......
...@@ -17,6 +17,7 @@ import pytz ...@@ -17,6 +17,7 @@ import pytz
from course_modes.helpers import enrollment_mode_display from course_modes.helpers import enrollment_mode_display
from course_modes.models import CourseMode, Mode from course_modes.models import CourseMode, Mode
from course_modes.tests.factories import CourseModeFactory
@ddt.ddt @ddt.ddt
...@@ -74,9 +75,9 @@ class CourseModeModelTest(TestCase): ...@@ -74,9 +75,9 @@ class CourseModeModelTest(TestCase):
Find the modes for a course with only one mode Find the modes for a course with only one mode
""" """
self.create_mode('verified', 'Verified Certificate') self.create_mode('verified', 'Verified Certificate', 10)
modes = CourseMode.modes_for_course(self.course_key) modes = CourseMode.modes_for_course(self.course_key)
mode = Mode(u'verified', u'Verified Certificate', 0, '', 'usd', None, None, None) mode = Mode(u'verified', u'Verified Certificate', 10, '', 'usd', None, None, None)
self.assertEqual([mode], modes) self.assertEqual([mode], modes)
modes_dict = CourseMode.modes_for_course_dict(self.course_key) modes_dict = CourseMode.modes_for_course_dict(self.course_key)
...@@ -89,7 +90,7 @@ class CourseModeModelTest(TestCase): ...@@ -89,7 +90,7 @@ class CourseModeModelTest(TestCase):
Finding the modes when there's multiple modes Finding the modes when there's multiple modes
""" """
mode1 = Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd', None, None, None) mode1 = Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd', None, None, None)
mode2 = Mode(u'verified', u'Verified Certificate', 0, '', 'usd', None, None, None) mode2 = Mode(u'verified', u'Verified Certificate', 10, '', 'usd', None, None, None)
set_modes = [mode1, mode2] set_modes = [mode1, mode2]
for mode in set_modes: for mode in set_modes:
self.create_mode(mode.slug, mode.name, mode.min_price, mode.suggested_prices) self.create_mode(mode.slug, mode.name, mode.min_price, mode.suggested_prices)
...@@ -119,7 +120,7 @@ class CourseModeModelTest(TestCase): ...@@ -119,7 +120,7 @@ class CourseModeModelTest(TestCase):
self.assertEqual(80, CourseMode.min_course_price_for_currency(self.course_key, 'cny')) self.assertEqual(80, CourseMode.min_course_price_for_currency(self.course_key, 'cny'))
def test_modes_for_course_expired(self): def test_modes_for_course_expired(self):
expired_mode, _status = self.create_mode('verified', 'Verified Certificate') expired_mode, _status = self.create_mode('verified', 'Verified Certificate', 10)
expired_mode.expiration_datetime = datetime.now(pytz.UTC) + timedelta(days=-1) expired_mode.expiration_datetime = datetime.now(pytz.UTC) + timedelta(days=-1)
expired_mode.save() expired_mode.save()
modes = CourseMode.modes_for_course(self.course_key) modes = CourseMode.modes_for_course(self.course_key)
...@@ -133,7 +134,7 @@ class CourseModeModelTest(TestCase): ...@@ -133,7 +134,7 @@ class CourseModeModelTest(TestCase):
expiration_datetime = datetime.now(pytz.UTC) + timedelta(days=1) expiration_datetime = datetime.now(pytz.UTC) + timedelta(days=1)
expired_mode.expiration_datetime = expiration_datetime expired_mode.expiration_datetime = expiration_datetime
expired_mode.save() expired_mode.save()
expired_mode_value = Mode(u'verified', u'Verified Certificate', 0, '', 'usd', expiration_datetime, None, None) expired_mode_value = Mode(u'verified', u'Verified Certificate', 10, '', 'usd', expiration_datetime, None, None)
modes = CourseMode.modes_for_course(self.course_key) modes = CourseMode.modes_for_course(self.course_key)
self.assertEqual([expired_mode_value, mode1], modes) self.assertEqual([expired_mode_value, mode1], modes)
...@@ -141,14 +142,14 @@ class CourseModeModelTest(TestCase): ...@@ -141,14 +142,14 @@ class CourseModeModelTest(TestCase):
self.assertEqual([CourseMode.DEFAULT_MODE], modes) self.assertEqual([CourseMode.DEFAULT_MODE], modes)
def test_verified_mode_for_course(self): def test_verified_mode_for_course(self):
self.create_mode('verified', 'Verified Certificate') self.create_mode('verified', 'Verified Certificate', 10)
mode = CourseMode.verified_mode_for_course(self.course_key) mode = CourseMode.verified_mode_for_course(self.course_key)
self.assertEqual(mode.slug, 'verified') self.assertEqual(mode.slug, 'verified')
# verify that the professional mode is preferred # verify that the professional mode is preferred
self.create_mode('professional', 'Professional Education Verified Certificate') self.create_mode('professional', 'Professional Education Verified Certificate', 10)
mode = CourseMode.verified_mode_for_course(self.course_key) mode = CourseMode.verified_mode_for_course(self.course_key)
...@@ -163,9 +164,8 @@ class CourseModeModelTest(TestCase): ...@@ -163,9 +164,8 @@ class CourseModeModelTest(TestCase):
verified, _ = self.create_mode('verified', 'Verified', min_price=5) verified, _ = self.create_mode('verified', 'Verified', min_price=5)
self.assertTrue(CourseMode.has_payment_options(self.course_key)) self.assertTrue(CourseMode.has_payment_options(self.course_key))
# Unset verified's minimum price. # Remove the verified option.
verified.min_price = 0 verified.delete()
verified.save()
self.assertFalse(CourseMode.has_payment_options(self.course_key)) self.assertFalse(CourseMode.has_payment_options(self.course_key))
# Finally, give the honor mode payment options # Finally, give the honor mode payment options
...@@ -215,7 +215,7 @@ class CourseModeModelTest(TestCase): ...@@ -215,7 +215,7 @@ class CourseModeModelTest(TestCase):
past = now - timedelta(days=1) past = now - timedelta(days=1)
# Unexpired, no expiration date # Unexpired, no expiration date
CourseMode.objects.create( CourseModeFactory.create(
course_id=self.course_key, course_id=self.course_key,
mode_display_name="Honor No Expiration", mode_display_name="Honor No Expiration",
mode_slug="honor_no_expiration", mode_slug="honor_no_expiration",
...@@ -223,7 +223,7 @@ class CourseModeModelTest(TestCase): ...@@ -223,7 +223,7 @@ class CourseModeModelTest(TestCase):
) )
# Unexpired, expiration date in future # Unexpired, expiration date in future
CourseMode.objects.create( CourseModeFactory.create(
course_id=self.course_key, course_id=self.course_key,
mode_display_name="Honor Not Expired", mode_display_name="Honor Not Expired",
mode_slug="honor_not_expired", mode_slug="honor_not_expired",
...@@ -231,7 +231,7 @@ class CourseModeModelTest(TestCase): ...@@ -231,7 +231,7 @@ class CourseModeModelTest(TestCase):
) )
# Expired # Expired
CourseMode.objects.create( CourseModeFactory.create(
course_id=self.course_key, course_id=self.course_key,
mode_display_name="Verified Expired", mode_display_name="Verified Expired",
mode_slug="verified_expired", mode_slug="verified_expired",
...@@ -306,9 +306,9 @@ class CourseModeModelTest(TestCase): ...@@ -306,9 +306,9 @@ class CourseModeModelTest(TestCase):
def test_invalid_mode_expiration(self, mode_slug, exp_dt): def test_invalid_mode_expiration(self, mode_slug, exp_dt):
is_error_expected = CourseMode.is_professional_slug(mode_slug) and exp_dt is not None is_error_expected = CourseMode.is_professional_slug(mode_slug) and exp_dt is not None
try: try:
self.create_mode(mode_slug=mode_slug, mode_name=mode_slug.title(), expiration_datetime=exp_dt) self.create_mode(mode_slug=mode_slug, mode_name=mode_slug.title(), expiration_datetime=exp_dt, min_price=10)
self.assertFalse(is_error_expected, "Expected a ValidationError to be thrown.") self.assertFalse(is_error_expected, "Expected a ValidationError to be thrown.")
except ValidationError, exc: except ValidationError as exc:
self.assertTrue(is_error_expected, "Did not expect a ValidationError to be thrown.") self.assertTrue(is_error_expected, "Did not expect a ValidationError to be thrown.")
self.assertEqual( self.assertEqual(
exc.messages, exc.messages,
...@@ -367,7 +367,7 @@ class CourseModeModelTest(TestCase): ...@@ -367,7 +367,7 @@ class CourseModeModelTest(TestCase):
def test_hide_credit_modes(self, available_modes, expected_selectable_modes): def test_hide_credit_modes(self, available_modes, expected_selectable_modes):
# Create the course modes # Create the course modes
for mode in available_modes: for mode in available_modes:
CourseMode.objects.create( CourseModeFactory.create(
course_id=self.course_key, course_id=self.course_key,
mode_display_name=mode, mode_display_name=mode,
mode_slug=mode, mode_slug=mode,
...@@ -406,7 +406,7 @@ class CourseModeModelTest(TestCase): ...@@ -406,7 +406,7 @@ class CourseModeModelTest(TestCase):
def test_expiration_datetime_explicitly_set(self): def test_expiration_datetime_explicitly_set(self):
""" Verify that setting the expiration_date property sets the explicit flag. """ """ Verify that setting the expiration_date property sets the explicit flag. """
verified_mode, __ = self.create_mode('verified', 'Verified Certificate') verified_mode, __ = self.create_mode('verified', 'Verified Certificate', 10)
now = datetime.now() now = datetime.now()
verified_mode.expiration_datetime = now verified_mode.expiration_datetime = now
...@@ -415,7 +415,7 @@ class CourseModeModelTest(TestCase): ...@@ -415,7 +415,7 @@ class CourseModeModelTest(TestCase):
def test_expiration_datetime_not_explicitly_set(self): def test_expiration_datetime_not_explicitly_set(self):
""" Verify that setting the _expiration_date property does not set the explicit flag. """ """ Verify that setting the _expiration_date property does not set the explicit flag. """
verified_mode, __ = self.create_mode('verified', 'Verified Certificate') verified_mode, __ = self.create_mode('verified', 'Verified Certificate', 10)
now = datetime.now() now = datetime.now()
verified_mode._expiration_datetime = now # pylint: disable=protected-access verified_mode._expiration_datetime = now # pylint: disable=protected-access
...@@ -424,7 +424,7 @@ class CourseModeModelTest(TestCase): ...@@ -424,7 +424,7 @@ class CourseModeModelTest(TestCase):
def test_expiration_datetime_explicitly_set_to_none(self): def test_expiration_datetime_explicitly_set_to_none(self):
""" Verify that setting the _expiration_date property does not set the explicit flag. """ """ Verify that setting the _expiration_date property does not set the explicit flag. """
verified_mode, __ = self.create_mode('verified', 'Verified Certificate') verified_mode, __ = self.create_mode('verified', 'Verified Certificate', 10)
self.assertFalse(verified_mode.expiration_datetime_is_explicit) self.assertFalse(verified_mode.expiration_datetime_is_explicit)
verified_mode.expiration_datetime = None verified_mode.expiration_datetime = None
...@@ -443,3 +443,21 @@ class CourseModeModelTest(TestCase): ...@@ -443,3 +443,21 @@ class CourseModeModelTest(TestCase):
def test_eligible_for_cert(self, mode_slug, expected_eligibility): def test_eligible_for_cert(self, mode_slug, expected_eligibility):
"""Verify that non-audit modes are eligible for a cert.""" """Verify that non-audit modes are eligible for a cert."""
self.assertEqual(CourseMode.is_eligible_for_certificate(mode_slug), expected_eligibility) self.assertEqual(CourseMode.is_eligible_for_certificate(mode_slug), expected_eligibility)
@ddt.data(
(CourseMode.AUDIT, False),
(CourseMode.HONOR, False),
(CourseMode.VERIFIED, True),
(CourseMode.CREDIT_MODE, False),
(CourseMode.PROFESSIONAL, True),
(CourseMode.NO_ID_PROFESSIONAL_MODE, False),
)
@ddt.unpack
def test_verified_min_price(self, mode_slug, is_error_expected):
"""Verify that verified modes have a price."""
try:
self.create_mode(mode_slug=mode_slug, mode_name=mode_slug.title(), min_price=0)
except ValidationError:
self.assertTrue(is_error_expected, "Did not expect a ValidationError to be thrown.")
else:
self.assertFalse(is_error_expected, "Expected a ValidationError to be thrown.")
...@@ -60,7 +60,7 @@ class CourseModeSignalTest(ModuleStoreTestCase): ...@@ -60,7 +60,7 @@ class CourseModeSignalTest(ModuleStoreTestCase):
@ddt.data(1, 14, 30) @ddt.data(1, 14, 30)
def test_verified_mode(self, verification_window): def test_verified_mode(self, verification_window):
""" Verify signal updates expiration to configured time period before course end for verified mode. """ """ Verify signal updates expiration to configured time period before course end for verified mode. """
course_mode, __ = self.create_mode('verified', 'verified') course_mode, __ = self.create_mode('verified', 'verified', 10)
self.assertIsNone(course_mode.expiration_datetime) self.assertIsNone(course_mode.expiration_datetime)
with patch('course_modes.models.CourseModeExpirationConfig.current') as config: with patch('course_modes.models.CourseModeExpirationConfig.current') as config:
...@@ -75,7 +75,7 @@ class CourseModeSignalTest(ModuleStoreTestCase): ...@@ -75,7 +75,7 @@ class CourseModeSignalTest(ModuleStoreTestCase):
@ddt.data(1, 14, 30) @ddt.data(1, 14, 30)
def test_verified_mode_explicitly_set(self, verification_window): def test_verified_mode_explicitly_set(self, verification_window):
""" Verify signal does not update expiration for verified mode with explicitly set expiration. """ """ Verify signal does not update expiration for verified mode with explicitly set expiration. """
course_mode, __ = self.create_mode('verified', 'verified') course_mode, __ = self.create_mode('verified', 'verified', 10)
course_mode.expiration_datetime_is_explicit = True course_mode.expiration_datetime_is_explicit = True
self.assertIsNone(course_mode.expiration_datetime) self.assertIsNone(course_mode.expiration_datetime)
......
...@@ -50,7 +50,7 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase): ...@@ -50,7 +50,7 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase):
def test_redirect_to_dashboard(self, is_active, enrollment_mode, redirect): def test_redirect_to_dashboard(self, is_active, enrollment_mode, redirect):
# Create the course modes # Create the course modes
for mode in ('audit', 'honor', 'verified'): for mode in ('audit', 'honor', 'verified'):
CourseModeFactory(mode_slug=mode, course_id=self.course.id) CourseModeFactory.create(mode_slug=mode, course_id=self.course.id)
# Enroll the user in the test course # Enroll the user in the test course
if enrollment_mode is not None: if enrollment_mode is not None:
...@@ -73,7 +73,7 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase): ...@@ -73,7 +73,7 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase):
def test_no_id_redirect(self): def test_no_id_redirect(self):
# Create the course modes # Create the course modes
CourseModeFactory(mode_slug=CourseMode.NO_ID_PROFESSIONAL_MODE, course_id=self.course.id, min_price=100) CourseModeFactory.create(mode_slug=CourseMode.NO_ID_PROFESSIONAL_MODE, course_id=self.course.id, min_price=100)
# Enroll the user in the test course # Enroll the user in the test course
CourseEnrollmentFactory( CourseEnrollmentFactory(
...@@ -112,7 +112,7 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase): ...@@ -112,7 +112,7 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase):
def test_no_enrollment(self): def test_no_enrollment(self):
# Create the course modes # Create the course modes
for mode in ('audit', 'honor', 'verified'): for mode in ('audit', 'honor', 'verified'):
CourseModeFactory(mode_slug=mode, course_id=self.course.id) CourseModeFactory.create(mode_slug=mode, course_id=self.course.id)
# User visits the track selection page directly without ever enrolling # User visits the track selection page directly without ever enrolling
url = reverse('course_modes_choose', args=[unicode(self.course.id)]) url = reverse('course_modes_choose', args=[unicode(self.course.id)])
...@@ -130,9 +130,9 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase): ...@@ -130,9 +130,9 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase):
# Create the course modes # Create the course modes
for mode in ('audit', 'honor'): for mode in ('audit', 'honor'):
CourseModeFactory(mode_slug=mode, course_id=self.course.id) CourseModeFactory.create(mode_slug=mode, course_id=self.course.id)
CourseModeFactory( CourseModeFactory.create(
mode_slug='verified', mode_slug='verified',
course_id=self.course.id, course_id=self.course.id,
suggested_prices=price_list suggested_prices=price_list
...@@ -164,7 +164,7 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase): ...@@ -164,7 +164,7 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase):
def test_credit_upsell_message(self, available_modes, show_upsell): def test_credit_upsell_message(self, available_modes, show_upsell):
# Create the course modes # Create the course modes
for mode in available_modes: for mode in available_modes:
CourseModeFactory(mode_slug=mode, course_id=self.course.id) CourseModeFactory.create(mode_slug=mode, course_id=self.course.id)
# Check whether credit upsell is shown on the page # Check whether credit upsell is shown on the page
# This should *only* be shown when a credit mode is available # This should *only* be shown when a credit mode is available
...@@ -179,7 +179,7 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase): ...@@ -179,7 +179,7 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase):
@ddt.data('professional', 'no-id-professional') @ddt.data('professional', 'no-id-professional')
def test_professional_enrollment(self, mode): def test_professional_enrollment(self, mode):
# The only course mode is professional ed # The only course mode is professional ed
CourseModeFactory(mode_slug=mode, course_id=self.course.id, min_price=1) CourseModeFactory.create(mode_slug=mode, course_id=self.course.id, min_price=1)
# Go to the "choose your track" page # Go to the "choose your track" page
choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)]) choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)])
...@@ -219,8 +219,8 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase): ...@@ -219,8 +219,8 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase):
def test_choose_mode_redirect(self, course_mode, expected_redirect): def test_choose_mode_redirect(self, course_mode, expected_redirect):
# Create the course modes # Create the course modes
for mode in ('audit', 'honor', 'verified'): for mode in ('audit', 'honor', 'verified'):
min_price = 0 if course_mode in ["honor", "audit"] else 1 min_price = 0 if mode in ["honor", "audit"] else 1
CourseModeFactory(mode_slug=mode, course_id=self.course.id, min_price=min_price) CourseModeFactory.create(mode_slug=mode, course_id=self.course.id, min_price=min_price)
# Choose the mode (POST request) # Choose the mode (POST request)
choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)]) choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)])
...@@ -241,8 +241,8 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase): ...@@ -241,8 +241,8 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase):
def test_remember_donation_for_course(self): def test_remember_donation_for_course(self):
# Create the course modes # Create the course modes
for mode in ('honor', 'verified'): CourseModeFactory.create(mode_slug='honor', course_id=self.course.id)
CourseModeFactory(mode_slug=mode, course_id=self.course.id) CourseModeFactory.create(mode_slug='verified', course_id=self.course.id, min_price=1)
# Choose the mode (POST request) # Choose the mode (POST request)
choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)]) choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)])
...@@ -259,7 +259,7 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase): ...@@ -259,7 +259,7 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase):
def test_successful_default_enrollment(self): def test_successful_default_enrollment(self):
# Create the course modes # Create the course modes
for mode in (CourseMode.DEFAULT_MODE_SLUG, 'verified'): for mode in (CourseMode.DEFAULT_MODE_SLUG, 'verified'):
CourseModeFactory(mode_slug=mode, course_id=self.course.id) CourseModeFactory.create(mode_slug=mode, course_id=self.course.id)
# Enroll the user in the default mode (honor) to emulate # Enroll the user in the default mode (honor) to emulate
# automatic enrollment # automatic enrollment
...@@ -281,7 +281,7 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase): ...@@ -281,7 +281,7 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase):
def test_unsupported_enrollment_mode_failure(self): def test_unsupported_enrollment_mode_failure(self):
# Create the supported course modes # Create the supported course modes
for mode in ('honor', 'verified'): for mode in ('honor', 'verified'):
CourseModeFactory(mode_slug=mode, course_id=self.course.id) CourseModeFactory.create(mode_slug=mode, course_id=self.course.id)
# Choose an unsupported mode (POST request) # Choose an unsupported mode (POST request)
choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)]) choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)])
...@@ -356,7 +356,7 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase): ...@@ -356,7 +356,7 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase):
def test_hide_nav(self): def test_hide_nav(self):
# Create the course modes # Create the course modes
for mode in ["honor", "verified"]: for mode in ["honor", "verified"]:
CourseModeFactory(mode_slug=mode, course_id=self.course.id) CourseModeFactory.create(mode_slug=mode, course_id=self.course.id)
# Load the track selection page # Load the track selection page
url = reverse('course_modes_choose', args=[unicode(self.course.id)]) url = reverse('course_modes_choose', args=[unicode(self.course.id)])
...@@ -393,8 +393,8 @@ class TrackSelectionEmbargoTest(UrlResetMixin, ModuleStoreTestCase): ...@@ -393,8 +393,8 @@ class TrackSelectionEmbargoTest(UrlResetMixin, ModuleStoreTestCase):
# Create a course and course modes # Create a course and course modes
self.course = CourseFactory.create() self.course = CourseFactory.create()
CourseModeFactory(mode_slug='honor', course_id=self.course.id) CourseModeFactory.create(mode_slug='honor', course_id=self.course.id)
CourseModeFactory(mode_slug='verified', course_id=self.course.id, min_price=10) CourseModeFactory.create(mode_slug='verified', course_id=self.course.id, min_price=10)
# Create a user and log in # Create a user and log in
self.user = UserFactory.create(username="Bob", email="bob@example.com", password="edx") self.user = UserFactory.create(username="Bob", email="bob@example.com", password="edx")
......
"""Provides factories for student models.""" """Provides factories for student models."""
import random
from student.models import (User, UserProfile, Registration, from student.models import (User, UserProfile, Registration,
CourseEnrollmentAllowed, CourseEnrollment, CourseEnrollmentAllowed, CourseEnrollment,
PendingEmailChange, UserStanding, PendingEmailChange, UserStanding,
...@@ -7,6 +9,7 @@ from course_modes.models import CourseMode ...@@ -7,6 +9,7 @@ from course_modes.models import CourseMode
from django.contrib.auth.models import Group, AnonymousUser from django.contrib.auth.models import Group, AnonymousUser
from datetime import datetime from datetime import datetime
import factory import factory
from factory import lazy_attribute
from factory.django import DjangoModelFactory from factory.django import DjangoModelFactory
from uuid import uuid4 from uuid import uuid4
from pytz import UTC from pytz import UTC
...@@ -54,11 +57,16 @@ class CourseModeFactory(DjangoModelFactory): ...@@ -54,11 +57,16 @@ class CourseModeFactory(DjangoModelFactory):
course_id = None course_id = None
mode_display_name = CourseMode.DEFAULT_MODE.name mode_display_name = CourseMode.DEFAULT_MODE.name
mode_slug = CourseMode.DEFAULT_MODE_SLUG mode_slug = CourseMode.DEFAULT_MODE_SLUG
min_price = 0
suggested_prices = '' suggested_prices = ''
currency = 'usd' currency = 'usd'
expiration_datetime = None expiration_datetime = None
@lazy_attribute
def min_price(self):
if CourseMode.is_verified_slug(self.mode_slug):
return random.randint(1, 100)
return 0
class RegistrationFactory(DjangoModelFactory): class RegistrationFactory(DjangoModelFactory):
class Meta(object): class Meta(object):
......
...@@ -182,7 +182,7 @@ class TestRecentEnrollments(ModuleStoreTestCase, XssTestMixin): ...@@ -182,7 +182,7 @@ class TestRecentEnrollments(ModuleStoreTestCase, XssTestMixin):
# Create the course mode(s) # Create the course mode(s)
for mode, min_price in course_modes: for mode, min_price in course_modes:
CourseModeFactory(mode_slug=mode, course_id=self.course.id, min_price=min_price) CourseModeFactory.create(mode_slug=mode, course_id=self.course.id, min_price=min_price)
self.enrollment.mode = enrollment_mode self.enrollment.mode = enrollment_mode
self.enrollment.save() self.enrollment.save()
...@@ -203,7 +203,7 @@ class TestRecentEnrollments(ModuleStoreTestCase, XssTestMixin): ...@@ -203,7 +203,7 @@ class TestRecentEnrollments(ModuleStoreTestCase, XssTestMixin):
# Create a white-label course mode # Create a white-label course mode
# (honor mode with a price set) # (honor mode with a price set)
CourseModeFactory(mode_slug="honor", course_id=self.course.id, min_price=100) CourseModeFactory.create(mode_slug="honor", course_id=self.course.id, min_price=100)
# Check that the donate button is NOT displayed # Check that the donate button is NOT displayed
self.client.login(username=self.student.username, password=self.PASSWORD) self.client.login(username=self.student.username, password=self.PASSWORD)
......
...@@ -245,7 +245,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase): ...@@ -245,7 +245,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
# Adding another verification with different course. # Adding another verification with different course.
# Its created_at is greater than course deadline. # Its created_at is greater than course deadline.
course2 = CourseFactory.create() course2 = CourseFactory.create()
CourseModeFactory( CourseModeFactory.create(
course_id=course2.id, course_id=course2.id,
mode_slug="verified", mode_slug="verified",
expiration_datetime=self.PAST expiration_datetime=self.PAST
...@@ -277,7 +277,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase): ...@@ -277,7 +277,7 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
enrollment_mode (str): The mode of the enrollment. enrollment_mode (str): The mode of the enrollment.
""" """
CourseModeFactory( CourseModeFactory.create(
course_id=self.course.id, course_id=self.course.id,
mode_slug="verified", mode_slug="verified",
expiration_datetime=deadline expiration_datetime=deadline
......
...@@ -226,7 +226,7 @@ class DashboardTest(ModuleStoreTestCase): ...@@ -226,7 +226,7 @@ class DashboardTest(ModuleStoreTestCase):
""" """
Check that the css class and the status message are in the dashboard html. Check that the css class and the status message are in the dashboard html.
""" """
CourseModeFactory(mode_slug=mode, course_id=self.course.id) CourseModeFactory.create(mode_slug=mode, course_id=self.course.id)
CourseEnrollment.enroll(self.user, self.course.location.course_key, mode=mode) CourseEnrollment.enroll(self.user, self.course.location.course_key, mode=mode)
if mode == 'verified': if mode == 'verified':
...@@ -263,7 +263,7 @@ class DashboardTest(ModuleStoreTestCase): ...@@ -263,7 +263,7 @@ class DashboardTest(ModuleStoreTestCase):
""" """
Check that the css class and the status message are not in the dashboard html. Check that the css class and the status message are not in the dashboard html.
""" """
CourseModeFactory(mode_slug=mode, course_id=self.course.id) CourseModeFactory.create(mode_slug=mode, course_id=self.course.id)
CourseEnrollment.enroll(self.user, self.course.location.course_key, mode=mode) CourseEnrollment.enroll(self.user, self.course.location.course_key, mode=mode)
if mode == 'verified': if mode == 'verified':
......
...@@ -369,8 +369,8 @@ class GenerateExampleCertificatesTest(TestCase): ...@@ -369,8 +369,8 @@ class GenerateExampleCertificatesTest(TestCase):
def test_generate_example_certs_with_verified_mode(self): def test_generate_example_certs_with_verified_mode(self):
# Create verified and honor modes for the course # Create verified and honor modes for the course
CourseModeFactory(course_id=self.COURSE_KEY, mode_slug='honor') CourseModeFactory.create(course_id=self.COURSE_KEY, mode_slug='honor')
CourseModeFactory(course_id=self.COURSE_KEY, mode_slug='verified') CourseModeFactory.create(course_id=self.COURSE_KEY, mode_slug='verified')
# Generate certificates for the course # Generate certificates for the course
with self._mock_xqueue() as mock_queue: with self._mock_xqueue() as mock_queue:
......
...@@ -649,9 +649,13 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -649,9 +649,13 @@ class ViewsTestCase(ModuleStoreTestCase):
(verified_course_deadline_passed, CourseMode.AUDIT, datetime.now(UTC) - timedelta(days=1)) (verified_course_deadline_passed, CourseMode.AUDIT, datetime.now(UTC) - timedelta(days=1))
) )
for course, mode, expiration in enrollments: for course, mode, expiration in enrollments:
CourseModeFactory(mode_slug=CourseMode.AUDIT, course_id=course) CourseModeFactory.create(mode_slug=CourseMode.AUDIT, course_id=course)
if course != non_verified_course: if course != non_verified_course:
CourseModeFactory(mode_slug=CourseMode.VERIFIED, course_id=course, expiration_datetime=expiration) CourseModeFactory.create(
mode_slug=CourseMode.VERIFIED,
course_id=course,
expiration_datetime=expiration
)
CourseEnrollmentFactory(course_id=course, user=self.user, mode=mode) CourseEnrollmentFactory(course_id=course, user=self.user, mode=mode)
self.client.login(username=self.user.username, password=self.password) self.client.login(username=self.user.username, password=self.password)
......
...@@ -403,7 +403,7 @@ class TestInstructorAPIBulkAccountCreationAndEnrollment(SharedModuleStoreTestCas ...@@ -403,7 +403,7 @@ class TestInstructorAPIBulkAccountCreationAndEnrollment(SharedModuleStoreTestCas
# Create a course with mode 'audit' # Create a course with mode 'audit'
cls.audit_course = CourseFactory.create() cls.audit_course = CourseFactory.create()
CourseModeFactory(course_id=cls.audit_course.id, mode_slug=CourseMode.AUDIT) CourseModeFactory.create(course_id=cls.audit_course.id, mode_slug=CourseMode.AUDIT)
cls.url = reverse( cls.url = reverse(
'register_and_enroll_students', kwargs={'course_id': unicode(cls.course.id)} 'register_and_enroll_students', kwargs={'course_id': unicode(cls.course.id)}
...@@ -417,7 +417,7 @@ class TestInstructorAPIBulkAccountCreationAndEnrollment(SharedModuleStoreTestCas ...@@ -417,7 +417,7 @@ class TestInstructorAPIBulkAccountCreationAndEnrollment(SharedModuleStoreTestCas
# Create a course with mode 'honor' and with price # Create a course with mode 'honor' and with price
self.white_label_course = CourseFactory.create() self.white_label_course = CourseFactory.create()
self.white_label_course_mode = CourseModeFactory( self.white_label_course_mode = CourseModeFactory.create(
course_id=self.white_label_course.id, course_id=self.white_label_course.id,
mode_slug=CourseMode.HONOR, mode_slug=CourseMode.HONOR,
min_price=10, min_price=10,
......
...@@ -29,7 +29,7 @@ class UserCartContextProcessorUnitTest(ModuleStoreTestCase): ...@@ -29,7 +29,7 @@ class UserCartContextProcessorUnitTest(ModuleStoreTestCase):
Adds content to self.user's cart Adds content to self.user's cart
""" """
course = CourseFactory.create(org='MITx', number='999', display_name='Robot Super Course') course = CourseFactory.create(org='MITx', number='999', display_name='Robot Super Course')
CourseModeFactory(course_id=course.id) CourseModeFactory.create(course_id=course.id)
cart = Order.get_cart_for_user(self.user) cart = Order.get_cart_for_user(self.user)
PaidCourseRegistration.add_to_order(cart, course.id) PaidCourseRegistration.add_to_order(cart, course.id)
......
...@@ -44,7 +44,11 @@ class RefundTests(ModuleStoreTestCase): ...@@ -44,7 +44,11 @@ class RefundTests(ModuleStoreTestCase):
username='student', username='student',
email='student+refund@edx.org' email='student+refund@edx.org'
) )
self.course_mode = CourseMode.objects.get_or_create(course_id=self.course_id, mode_slug='verified')[0] self.course_mode = CourseMode.objects.get_or_create(
course_id=self.course_id,
mode_slug='verified',
min_price=1
)[0]
self.order = None self.order = None
self.form_pars = {'course_id': str(self.course_id), 'user': self.student.email} self.form_pars = {'course_id': str(self.course_id), 'user': self.student.email}
......
...@@ -26,7 +26,7 @@ class TestProfEdVerification(ModuleStoreTestCase): ...@@ -26,7 +26,7 @@ class TestProfEdVerification(ModuleStoreTestCase):
self.client.login(username="rusty", password="test") self.client.login(username="rusty", password="test")
course = CourseFactory.create(org='Robot', number='999', display_name='Test Course') course = CourseFactory.create(org='Robot', number='999', display_name='Test Course')
self.course_key = course.id self.course_key = course.id
CourseModeFactory( CourseModeFactory.create(
mode_slug="professional", mode_slug="professional",
course_id=self.course_key, course_id=self.course_key,
min_price=self.MIN_PRICE, min_price=self.MIN_PRICE,
......
...@@ -31,7 +31,7 @@ class TestReverificationService(ModuleStoreTestCase): ...@@ -31,7 +31,7 @@ class TestReverificationService(ModuleStoreTestCase):
self.user = UserFactory.create(username="rusty", password="test") self.user = UserFactory.create(username="rusty", password="test")
self.course = CourseFactory.create(org='Robot', number='999', display_name='Test Course') self.course = CourseFactory.create(org='Robot', number='999', display_name='Test Course')
self.course_id = self.course.id self.course_id = self.course.id
CourseModeFactory( CourseModeFactory.create(
mode_slug="verified", mode_slug="verified",
course_id=self.course_id, course_id=self.course_id,
min_price=100, min_price=100,
......
...@@ -822,7 +822,7 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin): ...@@ -822,7 +822,7 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin):
for course_mode in course_modes: for course_mode in course_modes:
min_price = (0 if course_mode in ["honor", "audit"] else self.MIN_PRICE) min_price = (0 if course_mode in ["honor", "audit"] else self.MIN_PRICE)
CourseModeFactory( CourseModeFactory.create(
course_id=course.id, course_id=course.id,
mode_slug=course_mode, mode_slug=course_mode,
mode_display_name=course_mode, mode_display_name=course_mode,
...@@ -1012,7 +1012,7 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin): ...@@ -1012,7 +1012,7 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin):
course = CourseFactory.create(display_name=mode_display_name) course = CourseFactory.create(display_name=mode_display_name)
for course_mode in [CourseMode.DEFAULT_MODE_SLUG, "verified"]: for course_mode in [CourseMode.DEFAULT_MODE_SLUG, "verified"]:
min_price = (self.MIN_PRICE if course_mode != CourseMode.DEFAULT_MODE_SLUG else 0) min_price = (self.MIN_PRICE if course_mode != CourseMode.DEFAULT_MODE_SLUG else 0)
CourseModeFactory( CourseModeFactory.create(
course_id=course.id, course_id=course.id,
mode_slug=course_mode, mode_slug=course_mode,
mode_display_name=mode_display_name, mode_display_name=mode_display_name,
...@@ -1074,7 +1074,7 @@ class CheckoutTestMixin(object): ...@@ -1074,7 +1074,7 @@ class CheckoutTestMixin(object):
self.user = UserFactory.create(username="test", password="test") self.user = UserFactory.create(username="test", password="test")
self.course = CourseFactory.create() self.course = CourseFactory.create()
for mode, min_price in (('audit', 0), ('honor', 0), ('verified', 100)): for mode, min_price in (('audit', 0), ('honor', 0), ('verified', 100)):
CourseModeFactory(mode_slug=mode, course_id=self.course.id, min_price=min_price, sku=self.make_sku()) CourseModeFactory.create(mode_slug=mode, course_id=self.course.id, min_price=min_price, sku=self.make_sku())
self.client.login(username="test", password="test") self.client.login(username="test", password="test")
def _assert_checked_out( def _assert_checked_out(
...@@ -1119,7 +1119,7 @@ class CheckoutTestMixin(object): ...@@ -1119,7 +1119,7 @@ class CheckoutTestMixin(object):
def test_create_order_prof_ed(self, patched_create_order): def test_create_order_prof_ed(self, patched_create_order):
# Create a prof ed course # Create a prof ed course
course = CourseFactory.create() course = CourseFactory.create()
CourseModeFactory(mode_slug="professional", course_id=course.id, min_price=10, sku=self.make_sku()) CourseModeFactory.create(mode_slug="professional", course_id=course.id, min_price=10, sku=self.make_sku())
# Create an order for a prof ed course # Create an order for a prof ed course
params = {'course_id': unicode(course.id)} params = {'course_id': unicode(course.id)}
self._assert_checked_out(params, patched_create_order, course.id, 'professional') self._assert_checked_out(params, patched_create_order, course.id, 'professional')
...@@ -1127,7 +1127,7 @@ class CheckoutTestMixin(object): ...@@ -1127,7 +1127,7 @@ class CheckoutTestMixin(object):
def test_create_order_no_id_professional(self, patched_create_order): def test_create_order_no_id_professional(self, patched_create_order):
# Create a no-id-professional ed course # Create a no-id-professional ed course
course = CourseFactory.create() course = CourseFactory.create()
CourseModeFactory(mode_slug="no-id-professional", course_id=course.id, min_price=10, sku=self.make_sku()) CourseModeFactory.create(mode_slug="no-id-professional", course_id=course.id, min_price=10, sku=self.make_sku())
# Create an order for a prof ed course # Create an order for a prof ed course
params = {'course_id': unicode(course.id)} params = {'course_id': unicode(course.id)}
self._assert_checked_out(params, patched_create_order, course.id, 'no-id-professional') self._assert_checked_out(params, patched_create_order, course.id, 'no-id-professional')
...@@ -1135,8 +1135,8 @@ class CheckoutTestMixin(object): ...@@ -1135,8 +1135,8 @@ class CheckoutTestMixin(object):
def test_create_order_for_multiple_paid_modes(self, patched_create_order): def test_create_order_for_multiple_paid_modes(self, patched_create_order):
# Create a no-id-professional ed course # Create a no-id-professional ed course
course = CourseFactory.create() course = CourseFactory.create()
CourseModeFactory(mode_slug="no-id-professional", course_id=course.id, min_price=10, sku=self.make_sku()) CourseModeFactory.create(mode_slug="no-id-professional", course_id=course.id, min_price=10, sku=self.make_sku())
CourseModeFactory(mode_slug="professional", course_id=course.id, min_price=10, sku=self.make_sku()) CourseModeFactory.create(mode_slug="professional", course_id=course.id, min_price=10, sku=self.make_sku())
# Create an order for a prof ed course # Create an order for a prof ed course
params = {'course_id': unicode(course.id)} params = {'course_id': unicode(course.id)}
# TODO jsa - is this the intended behavior? # TODO jsa - is this the intended behavior?
...@@ -1227,7 +1227,7 @@ class TestCheckoutWithEcommerceService(ModuleStoreTestCase): ...@@ -1227,7 +1227,7 @@ class TestCheckoutWithEcommerceService(ModuleStoreTestCase):
ecommerce api, we correctly call to that api to create a basket. ecommerce api, we correctly call to that api to create a basket.
""" """
user = UserFactory.create(username="test-username") user = UserFactory.create(username="test-username")
course_mode = CourseModeFactory(sku="test-sku").to_tuple() # pylint: disable=no-member course_mode = CourseModeFactory.create(sku="test-sku").to_tuple() # pylint: disable=no-member
expected_payment_data = {'foo': 'bar'} expected_payment_data = {'foo': 'bar'}
# mock out the payment processors endpoint # mock out the payment processors endpoint
httpretty.register_uri( httpretty.register_uri(
...@@ -2079,7 +2079,7 @@ class TestInCourseReverifyView(ModuleStoreTestCase): ...@@ -2079,7 +2079,7 @@ class TestInCourseReverifyView(ModuleStoreTestCase):
# Create the course modes # Create the course modes
for mode in ('audit', 'honor', 'verified'): for mode in ('audit', 'honor', 'verified'):
min_price = 0 if mode in ["honor", "audit"] else 1 min_price = 0 if mode in ["honor", "audit"] else 1
CourseModeFactory(mode_slug=mode, course_id=self.course_key, min_price=min_price) CourseModeFactory.create(mode_slug=mode, course_id=self.course_key, min_price=min_price)
# Create the 'edx-reverification-block' in course tree # Create the 'edx-reverification-block' in course tree
section = ItemFactory.create(parent=self.course, category='chapter', display_name='Test Section') section = ItemFactory.create(parent=self.course, category='chapter', display_name='Test Section')
...@@ -2280,7 +2280,7 @@ class TestEmailMessageWithCustomICRVBlock(ModuleStoreTestCase): ...@@ -2280,7 +2280,7 @@ class TestEmailMessageWithCustomICRVBlock(ModuleStoreTestCase):
# Create the course modes # Create the course modes
for mode in ('audit', 'honor', 'verified'): for mode in ('audit', 'honor', 'verified'):
min_price = 0 if mode in ["honor", "audit"] else 1 min_price = 0 if mode in ["honor", "audit"] else 1
CourseModeFactory(mode_slug=mode, course_id=self.course_key, min_price=min_price) CourseModeFactory.create(mode_slug=mode, course_id=self.course_key, min_price=min_price)
# Create the 'edx-reverification-block' in course tree # Create the 'edx-reverification-block' in course tree
section = ItemFactory.create(parent=self.course, category='chapter', display_name='Test Section') section = ItemFactory.create(parent=self.course, category='chapter', display_name='Test Section')
...@@ -2483,7 +2483,7 @@ class TestEmailMessageWithDefaultICRVBlock(ModuleStoreTestCase): ...@@ -2483,7 +2483,7 @@ class TestEmailMessageWithDefaultICRVBlock(ModuleStoreTestCase):
# Create the course modes # Create the course modes
for mode in ('audit', 'honor', 'verified'): for mode in ('audit', 'honor', 'verified'):
min_price = 0 if mode in ["honor", "audit"] else 1 min_price = 0 if mode in ["honor", "audit"] else 1
CourseModeFactory(mode_slug=mode, course_id=self.course_key, min_price=min_price) CourseModeFactory.create(mode_slug=mode, course_id=self.course_key, min_price=min_price)
# Create the 'edx-reverification-block' in course tree # Create the 'edx-reverification-block' in course tree
section = ItemFactory.create(parent=self.course, category='chapter', display_name='Test Section') section = ItemFactory.create(parent=self.course, category='chapter', display_name='Test Section')
......
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