Merge pull request #10741 from edx/peter-fogg/remove-default-honor-mode
Switch default course mode to 'audit'.
This commit is contained in:
@@ -360,7 +360,7 @@ def certificates_list_handler(request, course_key_string):
|
||||
certificate_web_view_url = get_lms_link_for_certificate_web_view(
|
||||
user_id=request.user.id,
|
||||
course_key=course_key,
|
||||
mode=course_modes[0] # CourseMode.modes_for_course returns default mode 'honor' if doesn't find anyone.
|
||||
mode=course_modes[0] # CourseMode.modes_for_course returns default mode if doesn't find anyone.
|
||||
)
|
||||
certificates = None
|
||||
is_active = False
|
||||
|
||||
@@ -94,8 +94,8 @@ class CourseMode(models.Model):
|
||||
NO_ID_PROFESSIONAL_MODE = "no-id-professional"
|
||||
CREDIT_MODE = "credit"
|
||||
|
||||
DEFAULT_MODE = Mode(HONOR, _('Honor Code Certificate'), 0, '', 'usd', None, None, None)
|
||||
DEFAULT_MODE_SLUG = HONOR
|
||||
DEFAULT_MODE = Mode(AUDIT, _('Audit'), 0, '', 'usd', None, None, None)
|
||||
DEFAULT_MODE_SLUG = AUDIT
|
||||
|
||||
# Modes that allow a student to pursue a verified certificate
|
||||
VERIFIED_MODES = [VERIFIED, PROFESSIONAL]
|
||||
@@ -107,7 +107,7 @@ class CourseMode(models.Model):
|
||||
CREDIT_MODES = [CREDIT_MODE]
|
||||
|
||||
# Modes that are allowed to upsell
|
||||
UPSELL_TO_VERIFIED_MODES = [HONOR]
|
||||
UPSELL_TO_VERIFIED_MODES = [HONOR, AUDIT]
|
||||
|
||||
class Meta(object):
|
||||
unique_together = ('course_id', 'mode_slug', 'currency')
|
||||
@@ -507,7 +507,7 @@ class CourseMode(models.Model):
|
||||
return False
|
||||
|
||||
# Check that the default mode is available.
|
||||
return cls.HONOR in modes_dict
|
||||
return cls.DEFAULT_MODE_SLUG in modes_dict
|
||||
|
||||
@classmethod
|
||||
def is_white_label(cls, course_id, modes_dict=None):
|
||||
|
||||
@@ -177,6 +177,7 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase):
|
||||
# Mapping of course modes to the POST parameters sent
|
||||
# when the user chooses that mode.
|
||||
POST_PARAMS_FOR_COURSE_MODE = {
|
||||
'audit': {},
|
||||
'honor': {'honor_mode': True},
|
||||
'verified': {'verified_mode': True, 'contribution': '1.23'},
|
||||
'unsupported': {'unsupported_mode': True},
|
||||
@@ -227,9 +228,9 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase):
|
||||
expected_amount = decimal.Decimal(self.POST_PARAMS_FOR_COURSE_MODE['verified']['contribution'])
|
||||
self.assertEqual(actual_amount, expected_amount)
|
||||
|
||||
def test_successful_honor_enrollment(self):
|
||||
def test_successful_default_enrollment(self):
|
||||
# Create the course modes
|
||||
for mode in ('honor', 'verified'):
|
||||
for mode in (CourseMode.DEFAULT_MODE_SLUG, 'verified'):
|
||||
CourseModeFactory(mode_slug=mode, course_id=self.course.id)
|
||||
|
||||
# Enroll the user in the default mode (honor) to emulate
|
||||
@@ -242,11 +243,11 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase):
|
||||
|
||||
# Explicitly select the honor mode (POST request)
|
||||
choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)])
|
||||
self.client.post(choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE['honor'])
|
||||
self.client.post(choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE[CourseMode.DEFAULT_MODE_SLUG])
|
||||
|
||||
# Verify that the user's enrollment remains unchanged
|
||||
mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id)
|
||||
self.assertEqual(mode, 'honor')
|
||||
self.assertEqual(mode, CourseMode.DEFAULT_MODE_SLUG)
|
||||
self.assertEqual(is_active, True)
|
||||
|
||||
def test_unsupported_enrollment_mode_failure(self):
|
||||
|
||||
@@ -7,6 +7,7 @@ import importlib
|
||||
import logging
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
from course_modes.models import CourseMode
|
||||
from enrollment import errors
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -132,10 +133,10 @@ def get_enrollment(user_id, course_id):
|
||||
return _data_api().get_course_enrollment(user_id, course_id)
|
||||
|
||||
|
||||
def add_enrollment(user_id, course_id, mode='honor', is_active=True):
|
||||
def add_enrollment(user_id, course_id, mode=CourseMode.DEFAULT_MODE_SLUG, is_active=True):
|
||||
"""Enrolls a user in a course.
|
||||
|
||||
Enrolls a user in a course. If the mode is not specified, this will default to 'honor'.
|
||||
Enrolls a user in a course. If the mode is not specified, this will default to `CourseMode.DEFAULT_MODE_SLUG`.
|
||||
|
||||
Arguments:
|
||||
user_id (str): The user to enroll.
|
||||
@@ -143,7 +144,7 @@ def add_enrollment(user_id, course_id, mode='honor', is_active=True):
|
||||
|
||||
Keyword Arguments:
|
||||
mode (str): Optional argument for the type of enrollment to create. Ex. 'audit', 'honor', 'verified',
|
||||
'professional'. If not specified, this defaults to 'honor'.
|
||||
'professional'. If not specified, this defaults to the default course mode.
|
||||
is_active (boolean): Optional argument for making the new enrollment inactive. If not specified, is_active
|
||||
defaults to True.
|
||||
|
||||
@@ -154,7 +155,7 @@ def add_enrollment(user_id, course_id, mode='honor', is_active=True):
|
||||
>>> add_enrollment("Bob", "edX/DemoX/2014T2", mode="audit")
|
||||
{
|
||||
"created": "2014-10-20T20:18:00Z",
|
||||
"mode": "honor",
|
||||
"mode": "audit",
|
||||
"is_active": True,
|
||||
"user": "Bob",
|
||||
"course": {
|
||||
@@ -165,8 +166,8 @@ def add_enrollment(user_id, course_id, mode='honor', is_active=True):
|
||||
"course_end": "2015-05-06T00:00:00Z",
|
||||
"course_modes": [
|
||||
{
|
||||
"slug": "honor",
|
||||
"name": "Honor Code Certificate",
|
||||
"slug": "audit",
|
||||
"name": "Audit",
|
||||
"min_price": 0,
|
||||
"suggested_prices": "",
|
||||
"currency": "usd",
|
||||
|
||||
@@ -47,7 +47,7 @@ class EnrollmentTestMixin(object):
|
||||
expected_status=status.HTTP_200_OK,
|
||||
email_opt_in=None,
|
||||
as_server=False,
|
||||
mode=CourseMode.HONOR,
|
||||
mode=CourseMode.DEFAULT_MODE_SLUG,
|
||||
is_active=None,
|
||||
enrollment_attributes=None,
|
||||
min_mongo_calls=0,
|
||||
@@ -169,13 +169,13 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase):
|
||||
|
||||
@ddt.data(
|
||||
# Default (no course modes in the database)
|
||||
# Expect that users are automatically enrolled as "honor".
|
||||
([], CourseMode.HONOR),
|
||||
# Expect that users are automatically enrolled as the default
|
||||
([], CourseMode.DEFAULT_MODE_SLUG),
|
||||
|
||||
# Audit / Verified / Honor
|
||||
# Audit / Verified
|
||||
# We should always go to the "choose your course" page.
|
||||
# We should also be enrolled as "honor" by default.
|
||||
([CourseMode.HONOR, CourseMode.VERIFIED, CourseMode.AUDIT], CourseMode.HONOR),
|
||||
# We should also be enrolled as the default.
|
||||
([CourseMode.VERIFIED, CourseMode.AUDIT], CourseMode.DEFAULT_MODE_SLUG),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_enroll(self, course_modes, enrollment_mode):
|
||||
@@ -198,8 +198,8 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase):
|
||||
def test_check_enrollment(self):
|
||||
CourseModeFactory.create(
|
||||
course_id=self.course.id,
|
||||
mode_slug=CourseMode.HONOR,
|
||||
mode_display_name=CourseMode.HONOR,
|
||||
mode_slug=CourseMode.DEFAULT_MODE_SLUG,
|
||||
mode_display_name=CourseMode.DEFAULT_MODE_SLUG,
|
||||
)
|
||||
# Create an enrollment
|
||||
self.assert_enrollment_status()
|
||||
@@ -209,7 +209,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase):
|
||||
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||
data = json.loads(resp.content)
|
||||
self.assertEqual(unicode(self.course.id), data['course_details']['course_id'])
|
||||
self.assertEqual(CourseMode.HONOR, data['mode'])
|
||||
self.assertEqual(CourseMode.DEFAULT_MODE_SLUG, data['mode'])
|
||||
self.assertTrue(data['is_active'])
|
||||
|
||||
@ddt.data(
|
||||
@@ -258,8 +258,8 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase):
|
||||
def test_user_not_specified(self):
|
||||
CourseModeFactory.create(
|
||||
course_id=self.course.id,
|
||||
mode_slug=CourseMode.HONOR,
|
||||
mode_display_name=CourseMode.HONOR,
|
||||
mode_slug=CourseMode.DEFAULT_MODE_SLUG,
|
||||
mode_display_name=CourseMode.DEFAULT_MODE_SLUG,
|
||||
)
|
||||
# Create an enrollment
|
||||
self.assert_enrollment_status()
|
||||
@@ -269,7 +269,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase):
|
||||
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||
data = json.loads(resp.content)
|
||||
self.assertEqual(unicode(self.course.id), data['course_details']['course_id'])
|
||||
self.assertEqual(CourseMode.HONOR, data['mode'])
|
||||
self.assertEqual(CourseMode.DEFAULT_MODE_SLUG, data['mode'])
|
||||
self.assertTrue(data['is_active'])
|
||||
|
||||
def test_user_not_authenticated(self):
|
||||
@@ -306,8 +306,8 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase):
|
||||
# Try to enroll a user that is not the authenticated user.
|
||||
CourseModeFactory.create(
|
||||
course_id=self.course.id,
|
||||
mode_slug=CourseMode.HONOR,
|
||||
mode_display_name=CourseMode.HONOR,
|
||||
mode_slug=CourseMode.DEFAULT_MODE_SLUG,
|
||||
mode_display_name=CourseMode.DEFAULT_MODE_SLUG,
|
||||
)
|
||||
self.assert_enrollment_status(username=self.other_user.username, expected_status=status.HTTP_404_NOT_FOUND)
|
||||
# Verify that the server still has access to this endpoint.
|
||||
@@ -340,8 +340,8 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase):
|
||||
for course in self.course, other_course:
|
||||
CourseModeFactory.create(
|
||||
course_id=unicode(course.id),
|
||||
mode_slug=CourseMode.HONOR,
|
||||
mode_display_name=CourseMode.HONOR,
|
||||
mode_slug=CourseMode.DEFAULT_MODE_SLUG,
|
||||
mode_display_name=CourseMode.DEFAULT_MODE_SLUG,
|
||||
)
|
||||
self.assert_enrollment_status(
|
||||
course_id=unicode(course.id),
|
||||
@@ -520,8 +520,8 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase):
|
||||
self.rate_limit_config.save()
|
||||
CourseModeFactory.create(
|
||||
course_id=self.course.id,
|
||||
mode_slug=CourseMode.HONOR,
|
||||
mode_display_name=CourseMode.HONOR,
|
||||
mode_slug=CourseMode.DEFAULT_MODE_SLUG,
|
||||
mode_display_name=CourseMode.DEFAULT_MODE_SLUG,
|
||||
)
|
||||
|
||||
for attempt in xrange(self.rate_limit + 10):
|
||||
@@ -534,8 +534,8 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase):
|
||||
self.rate_limit_config.save()
|
||||
CourseModeFactory.create(
|
||||
course_id=self.course.id,
|
||||
mode_slug=CourseMode.HONOR,
|
||||
mode_display_name=CourseMode.HONOR,
|
||||
mode_slug=CourseMode.DEFAULT_MODE_SLUG,
|
||||
mode_display_name=CourseMode.DEFAULT_MODE_SLUG,
|
||||
)
|
||||
|
||||
for attempt in xrange(self.rate_limit + 10):
|
||||
@@ -595,7 +595,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase):
|
||||
def test_update_enrollment_with_mode(self):
|
||||
"""With the right API key, update an existing enrollment with a new mode. """
|
||||
# Create an honor and verified mode for a course. This allows an update.
|
||||
for mode in [CourseMode.HONOR, CourseMode.VERIFIED]:
|
||||
for mode in [CourseMode.DEFAULT_MODE_SLUG, CourseMode.VERIFIED]:
|
||||
CourseModeFactory.create(
|
||||
course_id=self.course.id,
|
||||
mode_slug=mode,
|
||||
@@ -605,11 +605,11 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase):
|
||||
# Create an enrollment
|
||||
self.assert_enrollment_status(as_server=True)
|
||||
|
||||
# Check that the enrollment is honor.
|
||||
# Check that the enrollment is default.
|
||||
self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course.id))
|
||||
course_mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id)
|
||||
self.assertTrue(is_active)
|
||||
self.assertEqual(course_mode, CourseMode.HONOR)
|
||||
self.assertEqual(course_mode, CourseMode.DEFAULT_MODE_SLUG)
|
||||
|
||||
# Check that the enrollment upgraded to verified.
|
||||
self.assert_enrollment_status(as_server=True, mode=CourseMode.VERIFIED, expected_status=status.HTTP_200_OK)
|
||||
@@ -621,7 +621,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase):
|
||||
"""With the right API key, update an existing enrollment with credit
|
||||
mode and set enrollment attributes.
|
||||
"""
|
||||
for mode in [CourseMode.HONOR, CourseMode.CREDIT_MODE]:
|
||||
for mode in [CourseMode.DEFAULT_MODE_SLUG, CourseMode.CREDIT_MODE]:
|
||||
CourseModeFactory.create(
|
||||
course_id=self.course.id,
|
||||
mode_slug=mode,
|
||||
@@ -631,11 +631,11 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase):
|
||||
# Create an enrollment
|
||||
self.assert_enrollment_status(as_server=True)
|
||||
|
||||
# Check that the enrollment is honor.
|
||||
# Check that the enrollment is the default.
|
||||
self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course.id))
|
||||
course_mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id)
|
||||
self.assertTrue(is_active)
|
||||
self.assertEqual(course_mode, CourseMode.HONOR)
|
||||
self.assertEqual(course_mode, CourseMode.DEFAULT_MODE_SLUG)
|
||||
|
||||
# Check that the enrollment upgraded to credit.
|
||||
enrollment_attributes = [{
|
||||
@@ -657,7 +657,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase):
|
||||
"""Check response status is bad request when invalid enrollment
|
||||
attributes are passed
|
||||
"""
|
||||
for mode in [CourseMode.HONOR, CourseMode.CREDIT_MODE]:
|
||||
for mode in [CourseMode.DEFAULT_MODE_SLUG, CourseMode.CREDIT_MODE]:
|
||||
CourseModeFactory.create(
|
||||
course_id=self.course.id,
|
||||
mode_slug=mode,
|
||||
@@ -667,11 +667,11 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase):
|
||||
# Create an enrollment
|
||||
self.assert_enrollment_status(as_server=True)
|
||||
|
||||
# Check that the enrollment is honor.
|
||||
# Check that the enrollment is the default.
|
||||
self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course.id))
|
||||
course_mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id)
|
||||
self.assertTrue(is_active)
|
||||
self.assertEqual(course_mode, CourseMode.HONOR)
|
||||
self.assertEqual(course_mode, CourseMode.DEFAULT_MODE_SLUG)
|
||||
|
||||
# Check that the enrollment upgraded to credit.
|
||||
enrollment_attributes = [{
|
||||
@@ -687,12 +687,12 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase):
|
||||
)
|
||||
course_mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id)
|
||||
self.assertTrue(is_active)
|
||||
self.assertEqual(course_mode, CourseMode.HONOR)
|
||||
self.assertEqual(course_mode, CourseMode.DEFAULT_MODE_SLUG)
|
||||
|
||||
def test_downgrade_enrollment_with_mode(self):
|
||||
"""With the right API key, downgrade an existing enrollment with a new mode. """
|
||||
# Create an honor and verified mode for a course. This allows an update.
|
||||
for mode in [CourseMode.HONOR, CourseMode.VERIFIED]:
|
||||
for mode in [CourseMode.DEFAULT_MODE_SLUG, CourseMode.VERIFIED]:
|
||||
CourseModeFactory.create(
|
||||
course_id=self.course.id,
|
||||
mode_slug=mode,
|
||||
@@ -708,16 +708,20 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase):
|
||||
self.assertTrue(is_active)
|
||||
self.assertEqual(course_mode, CourseMode.VERIFIED)
|
||||
|
||||
# Check that the enrollment downgraded to honor.
|
||||
self.assert_enrollment_status(as_server=True, mode=CourseMode.HONOR, expected_status=status.HTTP_200_OK)
|
||||
# Check that the enrollment was downgraded to the default mode.
|
||||
self.assert_enrollment_status(
|
||||
as_server=True,
|
||||
mode=CourseMode.DEFAULT_MODE_SLUG,
|
||||
expected_status=status.HTTP_200_OK
|
||||
)
|
||||
course_mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id)
|
||||
self.assertTrue(is_active)
|
||||
self.assertEqual(course_mode, CourseMode.HONOR)
|
||||
self.assertEqual(course_mode, CourseMode.DEFAULT_MODE_SLUG)
|
||||
|
||||
@ddt.data(
|
||||
((CourseMode.HONOR, ), CourseMode.HONOR),
|
||||
((CourseMode.HONOR, CourseMode.VERIFIED), CourseMode.HONOR),
|
||||
((CourseMode.HONOR, CourseMode.VERIFIED), CourseMode.VERIFIED),
|
||||
((CourseMode.DEFAULT_MODE_SLUG, ), CourseMode.DEFAULT_MODE_SLUG),
|
||||
((CourseMode.DEFAULT_MODE_SLUG, CourseMode.VERIFIED), CourseMode.DEFAULT_MODE_SLUG),
|
||||
((CourseMode.DEFAULT_MODE_SLUG, CourseMode.VERIFIED), CourseMode.VERIFIED),
|
||||
((CourseMode.PROFESSIONAL, ), CourseMode.PROFESSIONAL),
|
||||
((CourseMode.NO_ID_PROFESSIONAL_MODE, ), CourseMode.NO_ID_PROFESSIONAL_MODE),
|
||||
((CourseMode.VERIFIED, CourseMode.CREDIT_MODE), CourseMode.VERIFIED),
|
||||
@@ -758,8 +762,12 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase):
|
||||
self.assert_enrollment_activation(False, selected_mode)
|
||||
|
||||
# Verify that omitting the mode returns 400 for course configurations
|
||||
# in which the default (honor) mode doesn't exist.
|
||||
expected_status = status.HTTP_200_OK if CourseMode.HONOR in configured_modes else status.HTTP_400_BAD_REQUEST
|
||||
# in which the default mode doesn't exist.
|
||||
expected_status = (
|
||||
status.HTTP_200_OK
|
||||
if CourseMode.DEFAULT_MODE_SLUG in configured_modes
|
||||
else status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
self.assert_enrollment_status(
|
||||
as_server=True,
|
||||
is_active=False,
|
||||
@@ -788,8 +796,8 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase):
|
||||
|
||||
def test_change_mode_from_user(self):
|
||||
"""Users should not be able to alter the enrollment mode on an enrollment. """
|
||||
# Create an honor and verified mode for a course. This allows an update.
|
||||
for mode in [CourseMode.HONOR, CourseMode.VERIFIED]:
|
||||
# Create a default and a verified mode for a course. This allows an update.
|
||||
for mode in [CourseMode.DEFAULT_MODE_SLUG, CourseMode.VERIFIED]:
|
||||
CourseModeFactory.create(
|
||||
course_id=self.course.id,
|
||||
mode_slug=mode,
|
||||
@@ -803,13 +811,13 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase):
|
||||
self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course.id))
|
||||
course_mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id)
|
||||
self.assertTrue(is_active)
|
||||
self.assertEqual(course_mode, CourseMode.HONOR)
|
||||
self.assertEqual(course_mode, CourseMode.DEFAULT_MODE_SLUG)
|
||||
|
||||
# Get a 403 response when trying to upgrade yourself.
|
||||
self.assert_enrollment_status(mode=CourseMode.VERIFIED, expected_status=status.HTTP_403_FORBIDDEN)
|
||||
course_mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id)
|
||||
self.assertTrue(is_active)
|
||||
self.assertEqual(course_mode, CourseMode.HONOR)
|
||||
self.assertEqual(course_mode, CourseMode.DEFAULT_MODE_SLUG)
|
||||
|
||||
@ddt.data(*itertools.product(
|
||||
(CourseMode.HONOR, CourseMode.VERIFIED),
|
||||
|
||||
@@ -287,9 +287,10 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
|
||||
|
||||
* Enroll the currently signed in user in a course.
|
||||
|
||||
Currently a user can use this command only to enroll the user in
|
||||
honor mode. If honor mode is not supported for the course, the
|
||||
request fails and returns the available modes.
|
||||
Currently a user can use this command only to enroll the
|
||||
user in the default course mode. If this is not
|
||||
supported for the course, the request fails and returns
|
||||
the available modes.
|
||||
|
||||
This command can use a server-to-server call to enroll a user in
|
||||
other modes, such as "verified", "professional", or "credit". If
|
||||
@@ -325,7 +326,7 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
|
||||
You cannot use the command to enroll a different user.
|
||||
|
||||
* mode: Optional. The course mode for the enrollment. Individual
|
||||
users cannot upgrade their enrollment mode from 'honor'. Only
|
||||
users cannot upgrade their enrollment mode from the default. Only
|
||||
server-to-server requests can enroll with other modes.
|
||||
|
||||
* is_active: Optional. A Boolean value indicating whether the
|
||||
@@ -353,7 +354,7 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
|
||||
deactivate an enrollment.
|
||||
|
||||
* mode: Optional. The course mode for the enrollment. Individual
|
||||
users cannot upgrade their enrollment mode from "honor". Only
|
||||
users cannot upgrade their enrollment mode from the default. Only
|
||||
server-to-server requests can enroll with other modes.
|
||||
|
||||
* user: Optional. The user ID of the currently logged in user. You
|
||||
@@ -519,7 +520,7 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
|
||||
}
|
||||
)
|
||||
|
||||
mode = request.data.get('mode', CourseMode.HONOR)
|
||||
mode = request.data.get('mode', CourseMode.DEFAULT_MODE_SLUG)
|
||||
|
||||
has_api_key_permissions = self.has_api_key_permissions(request)
|
||||
|
||||
@@ -531,7 +532,7 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
|
||||
# other users, do not let them deduce the existence of an enrollment.
|
||||
return Response(status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
if mode != CourseMode.HONOR and not has_api_key_permissions:
|
||||
if mode != CourseMode.DEFAULT_MODE_SLUG and not has_api_key_permissions:
|
||||
return Response(
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
data={
|
||||
|
||||
@@ -895,7 +895,7 @@ class CourseEnrollment(models.Model):
|
||||
|
||||
# Represents the modes that are possible. We'll update this later with a
|
||||
# list of possible values.
|
||||
mode = models.CharField(default="honor", max_length=100)
|
||||
mode = models.CharField(default=CourseMode.DEFAULT_MODE_SLUG, max_length=100)
|
||||
|
||||
objects = CourseEnrollmentManager()
|
||||
|
||||
@@ -957,7 +957,7 @@ class CourseEnrollment(models.Model):
|
||||
|
||||
# If we *did* just create a new enrollment, set some defaults
|
||||
if created:
|
||||
enrollment.mode = "honor"
|
||||
enrollment.mode = CourseMode.DEFAULT_MODE_SLUG
|
||||
enrollment.is_active = False
|
||||
enrollment.save()
|
||||
|
||||
@@ -1043,8 +1043,8 @@ class CourseEnrollment(models.Model):
|
||||
u"mode:{}".format(self.mode)]
|
||||
)
|
||||
if mode_changed:
|
||||
# the user's default mode is "honor" and disabled for a course
|
||||
# mode change events will only be emitted when the user's mode changes from this
|
||||
# Only emit mode change events when the user's enrollment
|
||||
# mode has changed from its previous setting
|
||||
self.emit_event(EVENT_NAME_ENROLLMENT_MODE_CHANGED)
|
||||
|
||||
def emit_event(self, event_name):
|
||||
@@ -1090,7 +1090,7 @@ class CourseEnrollment(models.Model):
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def enroll(cls, user, course_key, mode="honor", check_access=False):
|
||||
def enroll(cls, user, course_key, mode=CourseMode.DEFAULT_MODE_SLUG, check_access=False):
|
||||
"""
|
||||
Enroll a user in a course. This saves immediately.
|
||||
|
||||
@@ -1103,8 +1103,8 @@ class CourseEnrollment(models.Model):
|
||||
`course_key` is our usual course_id string (e.g. "edX/Test101/2013_Fall)
|
||||
|
||||
`mode` is a string specifying what kind of enrollment this is. The
|
||||
default is 'honor', meaning honor certificate. Other options
|
||||
include 'professional', 'verified', 'audit',
|
||||
default is the default course mode, 'audit'. Other options
|
||||
include 'professional', 'verified', 'honor',
|
||||
'no-id-professional' and 'credit'.
|
||||
See CourseMode in common/djangoapps/course_modes/models.py.
|
||||
|
||||
@@ -1165,7 +1165,7 @@ class CourseEnrollment(models.Model):
|
||||
return enrollment
|
||||
|
||||
@classmethod
|
||||
def enroll_by_email(cls, email, course_id, mode="honor", ignore_errors=True):
|
||||
def enroll_by_email(cls, email, course_id, mode=CourseMode.DEFAULT_MODE_SLUG, ignore_errors=True):
|
||||
"""
|
||||
Enroll a user in a course given their email. This saves immediately.
|
||||
|
||||
@@ -1181,9 +1181,10 @@ class CourseEnrollment(models.Model):
|
||||
`course_id` is our usual course_id string (e.g. "edX/Test101/2013_Fall)
|
||||
|
||||
`mode` is a string specifying what kind of enrollment this is. The
|
||||
default is "honor", meaning honor certificate. Future options
|
||||
may include "audit", "verified_id", etc. Please don't use it
|
||||
until we have these mapped out.
|
||||
default is the default course mode, 'audit'. Other options
|
||||
include 'professional', 'verified', 'honor',
|
||||
'no-id-professional' and 'credit'.
|
||||
See CourseMode in common/djangoapps/course_modes/models.py.
|
||||
|
||||
`ignore_errors` is a boolean indicating whether we should suppress
|
||||
`User.DoesNotExist` errors (returning None) or let it
|
||||
|
||||
@@ -52,8 +52,8 @@ class CourseModeFactory(DjangoModelFactory):
|
||||
model = CourseMode
|
||||
|
||||
course_id = None
|
||||
mode_display_name = u'Honor Code',
|
||||
mode_slug = 'honor'
|
||||
mode_display_name = CourseMode.DEFAULT_MODE.name
|
||||
mode_slug = CourseMode.DEFAULT_MODE_SLUG
|
||||
min_price = 0
|
||||
suggested_prices = ''
|
||||
currency = 'usd'
|
||||
|
||||
@@ -7,6 +7,7 @@ from mock import patch
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from course_modes.models import CourseMode
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from util.testing import UrlResetMixin
|
||||
@@ -41,13 +42,13 @@ class EnrollmentTest(UrlResetMixin, ModuleStoreTestCase):
|
||||
@ddt.data(
|
||||
# Default (no course modes in the database)
|
||||
# Expect that we're redirected to the dashboard
|
||||
# and automatically enrolled as "honor"
|
||||
([], '', 'honor'),
|
||||
# and automatically enrolled
|
||||
([], '', CourseMode.DEFAULT_MODE_SLUG),
|
||||
|
||||
# Audit / Verified / Honor
|
||||
# We should always go to the "choose your course" page.
|
||||
# We should also be enrolled as "honor" by default.
|
||||
(['honor', 'verified', 'audit'], 'course_modes_choose', 'honor'),
|
||||
# We should also be enrolled as the default mode.
|
||||
(['honor', 'verified', 'audit'], 'course_modes_choose', CourseMode.DEFAULT_MODE_SLUG),
|
||||
|
||||
# Professional ed
|
||||
# Expect that we're sent to the "choose your track" page
|
||||
|
||||
@@ -127,22 +127,21 @@ class TestRecentEnrollments(ModuleStoreTestCase):
|
||||
self.assertContains(response, "Thank you for enrolling in")
|
||||
|
||||
@ddt.data(
|
||||
#Register as an honor in any course modes with no payment option
|
||||
# Register as honor in any course modes with no payment option
|
||||
([('audit', 0), ('honor', 0)], 'honor', True),
|
||||
([('honor', 0)], 'honor', True),
|
||||
([], 'honor', True),
|
||||
#Register as an honor in any course modes which has payment option
|
||||
# Register as honor in any course modes which has payment option
|
||||
([('honor', 10)], 'honor', False), # This is a paid course
|
||||
([('audit', 0), ('honor', 0), ('professional', 20)], 'honor', True),
|
||||
([('audit', 0), ('honor', 0), ('verified', 20)], 'honor', True),
|
||||
([('audit', 0), ('honor', 0), ('verified', 20), ('professional', 20)], 'honor', True),
|
||||
([], 'honor', True),
|
||||
#Register as an audit in any course modes with no payment option
|
||||
# Register as audit in any course modes with no payment option
|
||||
([('audit', 0), ('honor', 0)], 'audit', True),
|
||||
([('audit', 0)], 'audit', True),
|
||||
#Register as an audit in any course modes which has no payment option
|
||||
([], 'audit', True),
|
||||
# Register as audit in any course modes which has no payment option
|
||||
([('audit', 0), ('honor', 0), ('verified', 10)], 'audit', True),
|
||||
#Register as a verified in any course modes which has payment option
|
||||
# Register as verified in any course modes which has payment option
|
||||
([('professional', 20)], 'professional', False),
|
||||
([('verified', 20)], 'verified', False),
|
||||
([('professional', 20), ('verified', 20)], 'verified', False),
|
||||
|
||||
@@ -18,6 +18,7 @@ from django.core.urlresolvers import reverse
|
||||
from django.test import TestCase
|
||||
from django.test.client import Client
|
||||
|
||||
from course_modes.models import CourseMode
|
||||
from student.models import (
|
||||
anonymous_id_for_user, user_by_anonymous_id, CourseEnrollment,
|
||||
unique_id_for_user, LinkedInAddToProfileConfiguration
|
||||
@@ -321,7 +322,12 @@ class DashboardTest(ModuleStoreTestCase):
|
||||
course_id=self.course.id
|
||||
)
|
||||
course_reg_code = shoppingcart.models.CourseRegistrationCode(
|
||||
code="abcde", course_id=self.course.id, created_by=self.user, invoice=sale_invoice_1, invoice_item=invoice_item, mode_slug='honor'
|
||||
code="abcde",
|
||||
course_id=self.course.id,
|
||||
created_by=self.user,
|
||||
invoice=sale_invoice_1,
|
||||
invoice_item=invoice_item,
|
||||
mode_slug=CourseMode.DEFAULT_MODE_SLUG
|
||||
)
|
||||
course_reg_code.save()
|
||||
|
||||
@@ -339,7 +345,6 @@ class DashboardTest(ModuleStoreTestCase):
|
||||
#now activate the user by enrolling him/her to the course
|
||||
response = self.client.post(redeem_url)
|
||||
self.assertEquals(response.status_code, 200)
|
||||
|
||||
response = self.client.get(reverse('dashboard'))
|
||||
self.assertIn('You can no longer access this course because payment has not yet been received', response.content)
|
||||
optout_object = Optout.objects.filter(user=self.user, course_id=self.course.id)
|
||||
@@ -566,7 +571,7 @@ class EnrollmentEventTestMixin(EventTestMixin):
|
||||
{
|
||||
'course_id': course_key.to_deprecated_string(),
|
||||
'user_id': user.pk,
|
||||
'mode': 'honor'
|
||||
'mode': CourseMode.DEFAULT_MODE_SLUG
|
||||
}
|
||||
)
|
||||
self.mock_tracker.reset_mock()
|
||||
@@ -578,7 +583,7 @@ class EnrollmentEventTestMixin(EventTestMixin):
|
||||
{
|
||||
'course_id': course_key.to_deprecated_string(),
|
||||
'user_id': user.pk,
|
||||
'mode': 'honor'
|
||||
'mode': CourseMode.DEFAULT_MODE_SLUG
|
||||
}
|
||||
)
|
||||
self.mock_tracker.reset_mock()
|
||||
@@ -754,19 +759,19 @@ class EnrollInCourseTest(EnrollmentEventTestMixin, TestCase):
|
||||
user = User.objects.create(username="justin", email="jh@fake.edx.org")
|
||||
course_id = SlashSeparatedCourseKey("edX", "Test101", "2013")
|
||||
|
||||
CourseEnrollment.enroll(user, course_id)
|
||||
CourseEnrollment.enroll(user, course_id, "audit")
|
||||
self.assert_enrollment_event_was_emitted(user, course_id)
|
||||
|
||||
CourseEnrollment.enroll(user, course_id, "audit")
|
||||
self.assert_enrollment_mode_change_event_was_emitted(user, course_id, "audit")
|
||||
|
||||
# same enrollment mode does not emit an event
|
||||
CourseEnrollment.enroll(user, course_id, "audit")
|
||||
self.assert_no_events_were_emitted()
|
||||
|
||||
CourseEnrollment.enroll(user, course_id, "honor")
|
||||
self.assert_enrollment_mode_change_event_was_emitted(user, course_id, "honor")
|
||||
|
||||
# same enrollment mode does not emit an event
|
||||
CourseEnrollment.enroll(user, course_id, "honor")
|
||||
self.assert_no_events_were_emitted()
|
||||
|
||||
CourseEnrollment.enroll(user, course_id, "audit")
|
||||
self.assert_enrollment_mode_change_event_was_emitted(user, course_id, "audit")
|
||||
|
||||
|
||||
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
||||
class ChangeEnrollmentViewTest(ModuleStoreTestCase):
|
||||
@@ -789,7 +794,7 @@ class ChangeEnrollmentViewTest(ModuleStoreTestCase):
|
||||
)
|
||||
return response
|
||||
|
||||
def test_enroll_as_honor(self):
|
||||
def test_enroll_as_default(self):
|
||||
"""Tests that a student can successfully enroll through this view"""
|
||||
response = self._enroll_through_view(self.course)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
@@ -797,7 +802,7 @@ class ChangeEnrollmentViewTest(ModuleStoreTestCase):
|
||||
self.user, self.course.id
|
||||
)
|
||||
self.assertTrue(is_active)
|
||||
self.assertEqual(enrollment_mode, u'honor')
|
||||
self.assertEqual(enrollment_mode, CourseMode.DEFAULT_MODE_SLUG)
|
||||
|
||||
def test_cannot_enroll_if_already_enrolled(self):
|
||||
"""
|
||||
@@ -810,14 +815,14 @@ class ChangeEnrollmentViewTest(ModuleStoreTestCase):
|
||||
response = self._enroll_through_view(self.course)
|
||||
self.assertEqual(response.status_code, 400)
|
||||
|
||||
def test_change_to_honor_if_verified(self):
|
||||
def test_change_to_default_if_verified(self):
|
||||
"""
|
||||
Tests that a student that is a currently enrolled verified student cannot
|
||||
accidentally change their enrollment to verified
|
||||
accidentally change their enrollment mode
|
||||
"""
|
||||
CourseEnrollment.enroll(self.user, self.course.id, mode=u'verified')
|
||||
self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course.id))
|
||||
# now try to enroll the student in the honor mode:
|
||||
# now try to enroll the student in the default mode:
|
||||
response = self._enroll_through_view(self.course)
|
||||
self.assertEqual(response.status_code, 400)
|
||||
enrollment_mode, is_active = CourseEnrollment.enrollment_mode_for_user(
|
||||
@@ -826,7 +831,7 @@ class ChangeEnrollmentViewTest(ModuleStoreTestCase):
|
||||
self.assertTrue(is_active)
|
||||
self.assertEqual(enrollment_mode, u'verified')
|
||||
|
||||
def test_change_to_honor_if_verified_not_active(self):
|
||||
def test_change_to_default_if_verified_not_active(self):
|
||||
"""
|
||||
Tests that one can renroll for a course if one has already unenrolled
|
||||
"""
|
||||
@@ -847,7 +852,7 @@ class ChangeEnrollmentViewTest(ModuleStoreTestCase):
|
||||
self.user, self.course.id
|
||||
)
|
||||
self.assertTrue(is_active)
|
||||
self.assertEqual(enrollment_mode, u'honor')
|
||||
self.assertEqual(enrollment_mode, CourseMode.DEFAULT_MODE_SLUG)
|
||||
|
||||
|
||||
class AnonymousLookupTable(ModuleStoreTestCase):
|
||||
|
||||
@@ -13,6 +13,7 @@ from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from student.models import CourseEnrollment
|
||||
from student.tests.factories import UserFactory
|
||||
from course_modes.models import CourseMode
|
||||
from course_modes.tests.factories import CourseModeFactory
|
||||
from config_models.models import cache
|
||||
from util.testing import EventTestMixin
|
||||
@@ -305,6 +306,7 @@ class GenerateExampleCertificatesTest(TestCase):
|
||||
|
||||
def test_generate_example_certs(self):
|
||||
# Generate certificates for the course
|
||||
CourseModeFactory.create(course_id=self.COURSE_KEY, mode_slug=CourseMode.HONOR)
|
||||
with self._mock_xqueue() as mock_queue:
|
||||
certs_api.generate_example_certificates(self.COURSE_KEY)
|
||||
|
||||
|
||||
@@ -197,7 +197,7 @@ class BasketsViewTests(EnrollmentEventTestMixin, UserMixin, ModuleStoreTestCase)
|
||||
with mock_create_basket(response=return_value):
|
||||
self._test_successful_ecommerce_api_call(False)
|
||||
|
||||
def _test_course_without_sku(self):
|
||||
def _test_course_without_sku(self, enrollment_mode=CourseMode.DEFAULT_MODE_SLUG):
|
||||
"""
|
||||
Validates the view bypasses the E-Commerce API when the course has no CourseModes with SKUs.
|
||||
"""
|
||||
@@ -207,13 +207,16 @@ class BasketsViewTests(EnrollmentEventTestMixin, UserMixin, ModuleStoreTestCase)
|
||||
|
||||
# Validate the response content
|
||||
self.assertEqual(response.status_code, 200)
|
||||
msg = Messages.NO_SKU_ENROLLED.format(enrollment_mode='honor', course_id=self.course.id,
|
||||
username=self.user.username)
|
||||
msg = Messages.NO_SKU_ENROLLED.format(
|
||||
enrollment_mode=enrollment_mode,
|
||||
course_id=self.course.id,
|
||||
username=self.user.username
|
||||
)
|
||||
self.assertResponseMessage(response, msg)
|
||||
|
||||
def test_course_without_sku(self):
|
||||
def test_course_without_sku_default(self):
|
||||
"""
|
||||
If the course does NOT have a SKU, the user should be enrolled in the course (under the honor mode) and
|
||||
If the course does NOT have a SKU, the user should be enrolled in the course (under the default mode) and
|
||||
redirected to the user dashboard.
|
||||
"""
|
||||
# Remove SKU from all course modes
|
||||
@@ -223,6 +226,24 @@ class BasketsViewTests(EnrollmentEventTestMixin, UserMixin, ModuleStoreTestCase)
|
||||
|
||||
self._test_course_without_sku()
|
||||
|
||||
def test_course_without_sku_honor(self):
|
||||
"""
|
||||
If the course does not have an SKU and has an honor mode, the user
|
||||
should be enrolled as honor. This ensures backwards
|
||||
compatibility with courses existing before the removal of
|
||||
honor certificates.
|
||||
"""
|
||||
# Remove all existing course modes
|
||||
CourseMode.objects.filter(course_id=self.course.id).delete()
|
||||
# Ensure that honor mode exists
|
||||
CourseMode(
|
||||
mode_slug=CourseMode.HONOR,
|
||||
mode_display_name="Honor Cert",
|
||||
course_id=self.course.id
|
||||
).save()
|
||||
# We should be enrolled in honor mode
|
||||
self._test_course_without_sku(enrollment_mode=CourseMode.HONOR)
|
||||
|
||||
@override_settings(ECOMMERCE_API_URL=None, ECOMMERCE_API_SIGNING_KEY=None)
|
||||
def test_ecommerce_service_not_configured(self):
|
||||
"""
|
||||
@@ -240,7 +261,7 @@ class BasketsViewTests(EnrollmentEventTestMixin, UserMixin, ModuleStoreTestCase)
|
||||
self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course.id))
|
||||
|
||||
def assertProfessionalModeBypassed(self):
|
||||
""" Verifies that the view returns HTTP 406 when a course with no honor mode is encountered. """
|
||||
""" Verifies that the view returns HTTP 406 when a course with no honor or audit mode is encountered. """
|
||||
|
||||
CourseMode.objects.filter(course_id=self.course.id).delete()
|
||||
mode = CourseMode.NO_ID_PROFESSIONAL_MODE
|
||||
@@ -252,7 +273,7 @@ class BasketsViewTests(EnrollmentEventTestMixin, UserMixin, ModuleStoreTestCase)
|
||||
|
||||
# The view should return an error status code
|
||||
self.assertEqual(response.status_code, 406)
|
||||
msg = Messages.NO_HONOR_MODE.format(course_id=self.course.id)
|
||||
msg = Messages.NO_DEFAULT_ENROLLMENT_MODE.format(course_id=self.course.id)
|
||||
self.assertResponseMessage(response, msg)
|
||||
|
||||
def test_course_with_professional_mode_only(self):
|
||||
|
||||
@@ -59,9 +59,9 @@ class BasketsView(APIView):
|
||||
|
||||
return True, course_key, None
|
||||
|
||||
def _enroll(self, course_key, user):
|
||||
def _enroll(self, course_key, user, mode=CourseMode.DEFAULT_MODE_SLUG):
|
||||
""" Enroll the user in the course. """
|
||||
add_enrollment(user.username, unicode(course_key))
|
||||
add_enrollment(user.username, unicode(course_key), mode)
|
||||
|
||||
def _handle_marketing_opt_in(self, request, course_key, user):
|
||||
"""
|
||||
@@ -100,19 +100,28 @@ class BasketsView(APIView):
|
||||
msg = Messages.ENROLLMENT_EXISTS.format(course_id=course_id, username=user.username)
|
||||
return DetailResponse(msg, status=HTTP_409_CONFLICT)
|
||||
|
||||
# If there is no honor course mode, this most likely a Prof-Ed course. Return an error so that the JS
|
||||
# redirects to track selection.
|
||||
# If there is no audit or honor course mode, this most likely
|
||||
# a Prof-Ed course. Return an error so that the JS redirects
|
||||
# to track selection.
|
||||
honor_mode = CourseMode.mode_for_course(course_key, CourseMode.HONOR)
|
||||
audit_mode = CourseMode.mode_for_course(course_key, CourseMode.AUDIT)
|
||||
|
||||
if not honor_mode:
|
||||
msg = Messages.NO_HONOR_MODE.format(course_id=course_id)
|
||||
# Accept either honor or audit as an enrollment mode to
|
||||
# maintain backwards compatibility with existing courses
|
||||
default_enrollment_mode = audit_mode or honor_mode
|
||||
|
||||
if not default_enrollment_mode:
|
||||
msg = Messages.NO_DEFAULT_ENROLLMENT_MODE.format(course_id=course_id)
|
||||
return DetailResponse(msg, status=HTTP_406_NOT_ACCEPTABLE)
|
||||
elif not honor_mode.sku:
|
||||
elif default_enrollment_mode and not default_enrollment_mode.sku:
|
||||
# If there are no course modes with SKUs, enroll the user without contacting the external API.
|
||||
msg = Messages.NO_SKU_ENROLLED.format(enrollment_mode=CourseMode.HONOR, course_id=course_id,
|
||||
username=user.username)
|
||||
msg = Messages.NO_SKU_ENROLLED.format(
|
||||
enrollment_mode=default_enrollment_mode.slug,
|
||||
course_id=course_id,
|
||||
username=user.username
|
||||
)
|
||||
log.info(msg)
|
||||
self._enroll(course_key, user)
|
||||
self._enroll(course_key, user, default_enrollment_mode.slug)
|
||||
self._handle_marketing_opt_in(request, course_key, user)
|
||||
return DetailResponse(msg)
|
||||
|
||||
@@ -131,7 +140,7 @@ class BasketsView(APIView):
|
||||
# Make the API call
|
||||
try:
|
||||
response_data = api.baskets.post({
|
||||
'products': [{'sku': honor_mode.sku}],
|
||||
'products': [{'sku': default_enrollment_mode.sku}],
|
||||
'checkout': True,
|
||||
})
|
||||
|
||||
@@ -158,7 +167,7 @@ class BasketsView(APIView):
|
||||
audit_log(
|
||||
'checkout_requested',
|
||||
course_id=course_id,
|
||||
mode=honor_mode.slug,
|
||||
mode=default_enrollment_mode.slug,
|
||||
processor_name=None,
|
||||
user_id=user.id
|
||||
)
|
||||
|
||||
@@ -285,7 +285,7 @@ class CourseRetrieveUpdateViewTests(CourseApiViewTestMixin, ModuleStoreTestCase)
|
||||
|
||||
expected_modes = [
|
||||
CourseMode(
|
||||
mode_slug=u'honor',
|
||||
mode_slug=CourseMode.DEFAULT_MODE_SLUG,
|
||||
min_price=150, currency=u'USD',
|
||||
sku=u'ABC123'
|
||||
)
|
||||
|
||||
@@ -15,4 +15,5 @@ class Messages(object):
|
||||
ORDER_COMPLETED = u'Order {order_number} was completed.'
|
||||
ORDER_INCOMPLETE_ENROLLED = u'Order {order_number} was created, but is not yet complete. User was enrolled.'
|
||||
NO_HONOR_MODE = u'Course {course_id} does not have an honor mode.'
|
||||
NO_DEFAULT_ENROLLMENT_MODE = u'Course {course_id} does not have an honor or audit mode.'
|
||||
ENROLLMENT_EXISTS = u'User {username} is already enrolled in {course_id}.'
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""
|
||||
Test helpers for testing course block transformers.
|
||||
"""
|
||||
from course_modes.models import CourseMode
|
||||
from student.tests.factories import CourseEnrollmentFactory, UserFactory
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
|
||||
@@ -221,7 +222,12 @@ class BlockParentsMapTestCase(ModuleStoreTestCase):
|
||||
self.password = 'test'
|
||||
self.student = UserFactory.create(is_staff=False, username='test_student', password=self.password)
|
||||
self.staff = UserFactory.create(is_staff=True, username='test_staff', password=self.password)
|
||||
CourseEnrollmentFactory.create(is_active=True, mode='honor', user=self.student, course_id=self.course.id)
|
||||
CourseEnrollmentFactory.create(
|
||||
is_active=True,
|
||||
mode=CourseMode.DEFAULT_MODE_SLUG,
|
||||
user=self.student,
|
||||
course_id=self.course.id
|
||||
)
|
||||
|
||||
def assert_transform_results(
|
||||
self,
|
||||
|
||||
@@ -58,10 +58,12 @@ class AboutTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, EventTrackingT
|
||||
)
|
||||
|
||||
self.purchase_course = CourseFactory.create(org='MITx', number='buyme', display_name='Course To Buy')
|
||||
self.course_mode = CourseMode(course_id=self.purchase_course.id,
|
||||
mode_slug="honor",
|
||||
mode_display_name="honor cert",
|
||||
min_price=10)
|
||||
self.course_mode = CourseMode(
|
||||
course_id=self.purchase_course.id,
|
||||
mode_slug=CourseMode.DEFAULT_MODE_SLUG,
|
||||
mode_display_name=CourseMode.DEFAULT_MODE_SLUG,
|
||||
min_price=10
|
||||
)
|
||||
self.course_mode.save()
|
||||
|
||||
def test_anonymous_user(self):
|
||||
@@ -248,8 +250,7 @@ class AboutWithCappedEnrollmentsTestCase(LoginEnrollmentTestCase, ModuleStoreTes
|
||||
self.email = 'foo_second@test.com'
|
||||
self.password = 'bar'
|
||||
self.username = 'test_second'
|
||||
self.create_account(self.username,
|
||||
self.email, self.password)
|
||||
self.create_account(self.username, self.email, self.password)
|
||||
self.activate_user(self.email)
|
||||
self.login(self.email, self.password)
|
||||
|
||||
@@ -417,8 +418,8 @@ class AboutPurchaseCourseTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase):
|
||||
"""
|
||||
course_mode = CourseMode(
|
||||
course_id=course.id,
|
||||
mode_slug="honor",
|
||||
mode_display_name="honor cert",
|
||||
mode_slug=CourseMode.DEFAULT_MODE_SLUG,
|
||||
mode_display_name=CourseMode.DEFAULT_MODE_SLUG,
|
||||
min_price=10,
|
||||
)
|
||||
course_mode.save()
|
||||
|
||||
@@ -201,8 +201,8 @@ class TestMicrosites(ModuleStoreTestCase, LoginEnrollmentTestCase):
|
||||
"""
|
||||
course_mode = CourseMode(
|
||||
course_id=self.course_with_visibility.id,
|
||||
mode_slug="honor",
|
||||
mode_display_name="honor cert",
|
||||
mode_slug=CourseMode.DEFAULT_MODE_SLUG,
|
||||
mode_display_name=CourseMode.DEFAULT_MODE_SLUG,
|
||||
min_price=10,
|
||||
)
|
||||
course_mode.save()
|
||||
|
||||
@@ -27,6 +27,7 @@ from xblock.core import XBlock
|
||||
from xblock.fragment import Fragment
|
||||
|
||||
from capa.tests.response_xml_factory import OptionResponseXMLFactory
|
||||
from course_modes.models import CourseMode
|
||||
from courseware import module_render as render
|
||||
from courseware.courses import get_course_with_access, course_image_url, get_course_info_section
|
||||
from courseware.field_overrides import OverrideFieldData
|
||||
@@ -724,9 +725,9 @@ class TestProctoringRendering(ModuleStoreTestCase):
|
||||
)
|
||||
|
||||
@ddt.data(
|
||||
('honor', False, None, None),
|
||||
(CourseMode.DEFAULT_MODE_SLUG, False, None, None),
|
||||
(
|
||||
'honor',
|
||||
CourseMode.DEFAULT_MODE_SLUG,
|
||||
True,
|
||||
'eligible',
|
||||
{
|
||||
@@ -737,7 +738,7 @@ class TestProctoringRendering(ModuleStoreTestCase):
|
||||
}
|
||||
),
|
||||
(
|
||||
'honor',
|
||||
CourseMode.DEFAULT_MODE_SLUG,
|
||||
True,
|
||||
'submitted',
|
||||
{
|
||||
@@ -748,7 +749,7 @@ class TestProctoringRendering(ModuleStoreTestCase):
|
||||
}
|
||||
),
|
||||
(
|
||||
'honor',
|
||||
CourseMode.DEFAULT_MODE_SLUG,
|
||||
True,
|
||||
'error',
|
||||
{
|
||||
@@ -759,7 +760,7 @@ class TestProctoringRendering(ModuleStoreTestCase):
|
||||
}
|
||||
),
|
||||
(
|
||||
'verified',
|
||||
CourseMode.VERIFIED,
|
||||
False,
|
||||
None,
|
||||
{
|
||||
@@ -770,7 +771,7 @@ class TestProctoringRendering(ModuleStoreTestCase):
|
||||
}
|
||||
),
|
||||
(
|
||||
'verified',
|
||||
CourseMode.VERIFIED,
|
||||
False,
|
||||
'declined',
|
||||
{
|
||||
@@ -781,7 +782,7 @@ class TestProctoringRendering(ModuleStoreTestCase):
|
||||
}
|
||||
),
|
||||
(
|
||||
'verified',
|
||||
CourseMode.VERIFIED,
|
||||
False,
|
||||
'submitted',
|
||||
{
|
||||
@@ -792,7 +793,7 @@ class TestProctoringRendering(ModuleStoreTestCase):
|
||||
}
|
||||
),
|
||||
(
|
||||
'verified',
|
||||
CourseMode.VERIFIED,
|
||||
False,
|
||||
'verified',
|
||||
{
|
||||
@@ -803,7 +804,7 @@ class TestProctoringRendering(ModuleStoreTestCase):
|
||||
}
|
||||
),
|
||||
(
|
||||
'verified',
|
||||
CourseMode.VERIFIED,
|
||||
False,
|
||||
'rejected',
|
||||
{
|
||||
@@ -814,7 +815,7 @@ class TestProctoringRendering(ModuleStoreTestCase):
|
||||
}
|
||||
),
|
||||
(
|
||||
'verified',
|
||||
CourseMode.VERIFIED,
|
||||
False,
|
||||
'error',
|
||||
{
|
||||
@@ -851,56 +852,56 @@ class TestProctoringRendering(ModuleStoreTestCase):
|
||||
|
||||
@ddt.data(
|
||||
(
|
||||
'honor',
|
||||
CourseMode.DEFAULT_MODE_SLUG,
|
||||
True,
|
||||
None,
|
||||
'Try a proctored exam',
|
||||
True
|
||||
),
|
||||
(
|
||||
'honor',
|
||||
CourseMode.DEFAULT_MODE_SLUG,
|
||||
True,
|
||||
'submitted',
|
||||
'You have submitted this practice proctored exam',
|
||||
False
|
||||
),
|
||||
(
|
||||
'honor',
|
||||
CourseMode.DEFAULT_MODE_SLUG,
|
||||
True,
|
||||
'error',
|
||||
'There was a problem with your practice proctoring session',
|
||||
True
|
||||
),
|
||||
(
|
||||
'verified',
|
||||
CourseMode.VERIFIED,
|
||||
False,
|
||||
None,
|
||||
'This exam is proctored',
|
||||
False
|
||||
),
|
||||
(
|
||||
'verified',
|
||||
CourseMode.VERIFIED,
|
||||
False,
|
||||
'submitted',
|
||||
'You have submitted this proctored exam for review',
|
||||
True
|
||||
),
|
||||
(
|
||||
'verified',
|
||||
CourseMode.VERIFIED,
|
||||
False,
|
||||
'verified',
|
||||
'Your proctoring session was reviewed and passed all requirements',
|
||||
False
|
||||
),
|
||||
(
|
||||
'verified',
|
||||
CourseMode.VERIFIED,
|
||||
False,
|
||||
'rejected',
|
||||
'Your proctoring session was reviewed and did not pass requirements',
|
||||
True
|
||||
),
|
||||
(
|
||||
'verified',
|
||||
CourseMode.VERIFIED,
|
||||
False,
|
||||
'error',
|
||||
'There was a problem with your proctoring session',
|
||||
|
||||
@@ -708,7 +708,7 @@ class ProgressPageTests(ModuleStoreTestCase):
|
||||
)
|
||||
|
||||
# Enroll student into course
|
||||
CourseEnrollment.enroll(self.user, self.course.id, mode='honor')
|
||||
CourseEnrollment.enroll(self.user, self.course.id)
|
||||
resp = views.progress(self.request, course_id=self.course.id.to_deprecated_string(), student_id=self.user.id)
|
||||
# Assert that valid 'student_id' returns 200 status
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
@@ -12,6 +12,7 @@ from django.core.urlresolvers import reverse
|
||||
from django.core.mail import send_mail
|
||||
from django.utils.translation import override as override_language
|
||||
|
||||
from course_modes.models import CourseMode
|
||||
from student.models import CourseEnrollment, CourseEnrollmentAllowed
|
||||
from courseware.models import StudentModule
|
||||
from edxmako.shortcuts import render_to_string
|
||||
@@ -110,7 +111,7 @@ def enroll_email(course_id, student_email, auto_enroll=False, email_students=Fal
|
||||
if previous_state.user:
|
||||
# if the student is currently unenrolled, don't enroll them in their
|
||||
# previous mode
|
||||
course_mode = u"honor"
|
||||
course_mode = CourseMode.DEFAULT_MODE_SLUG
|
||||
if previous_state.enrollment:
|
||||
course_mode = previous_state.mode
|
||||
|
||||
|
||||
@@ -1275,7 +1275,7 @@ class TestInstructorAPIEnrollment(SharedModuleStoreTestCase, LoginEnrollmentTest
|
||||
create paid course mode.
|
||||
"""
|
||||
paid_course = CourseFactory.create()
|
||||
CourseModeFactory.create(course_id=paid_course.id, min_price=50)
|
||||
CourseModeFactory.create(course_id=paid_course.id, min_price=50, mode_slug=CourseMode.HONOR)
|
||||
CourseInstructorRole(paid_course.id).add_users(self.instructor)
|
||||
return paid_course
|
||||
|
||||
@@ -1405,7 +1405,7 @@ class TestInstructorAPIEnrollment(SharedModuleStoreTestCase, LoginEnrollmentTest
|
||||
def test_unenroll_and_enroll_verified(self):
|
||||
"""
|
||||
Test that unenrolling and enrolling a student from a verified track
|
||||
results in that student being in an honor track
|
||||
results in that student being in the default track
|
||||
"""
|
||||
course_enrollment = CourseEnrollment.objects.get(
|
||||
user=self.enrolled_student, course_id=self.course.id
|
||||
@@ -1422,7 +1422,7 @@ class TestInstructorAPIEnrollment(SharedModuleStoreTestCase, LoginEnrollmentTest
|
||||
course_enrollment = CourseEnrollment.objects.get(
|
||||
user=self.enrolled_student, course_id=self.course.id
|
||||
)
|
||||
self.assertEqual(course_enrollment.mode, u'honor')
|
||||
self.assertEqual(course_enrollment.mode, CourseMode.DEFAULT_MODE_SLUG)
|
||||
|
||||
def _change_student_enrollment(self, user, course, action):
|
||||
"""
|
||||
@@ -2138,7 +2138,11 @@ class TestInstructorAPILevelsDataDump(SharedModuleStoreTestCase, LoginEnrollment
|
||||
company_contact_email='test@123', recipient_name='R1',
|
||||
recipient_email='', customer_reference_number='PO#23')
|
||||
|
||||
paid_course_reg_item = PaidCourseRegistration.add_to_order(self.cart, self.course.id)
|
||||
paid_course_reg_item = PaidCourseRegistration.add_to_order(
|
||||
self.cart,
|
||||
self.course.id,
|
||||
mode_slug=CourseMode.HONOR
|
||||
)
|
||||
# update the quantity of the cart item paid_course_reg_item
|
||||
resp = self.client.post(reverse('shoppingcart.views.update_user_cart'), {'ItemId': paid_course_reg_item.id, 'qty': '4'})
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""
|
||||
Test for the registration code status information.
|
||||
"""
|
||||
from course_modes.models import CourseMode
|
||||
from courseware.tests.factories import InstructorFactory
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from django.utils.translation import ugettext as _
|
||||
@@ -116,7 +117,7 @@ class TestCourseRegistrationCodeStatus(SharedModuleStoreTestCase):
|
||||
created_by=self.instructor,
|
||||
invoice=self.sale_invoice,
|
||||
invoice_item=self.invoice_item,
|
||||
mode_slug='honor'
|
||||
mode_slug=CourseMode.DEFAULT_MODE_SLUG
|
||||
)
|
||||
|
||||
reg_code = CourseRegistrationCode.objects.all()[0]
|
||||
@@ -247,7 +248,7 @@ class TestCourseRegistrationCodeStatus(SharedModuleStoreTestCase):
|
||||
created_by=self.instructor,
|
||||
invoice=self.sale_invoice,
|
||||
invoice_item=self.invoice_item,
|
||||
mode_slug='honor',
|
||||
mode_slug=CourseMode.DEFAULT_MODE_SLUG,
|
||||
is_valid=False
|
||||
)
|
||||
|
||||
@@ -278,7 +279,7 @@ class TestCourseRegistrationCodeStatus(SharedModuleStoreTestCase):
|
||||
created_by=self.instructor,
|
||||
invoice=self.sale_invoice,
|
||||
invoice_item=self.invoice_item,
|
||||
mode_slug='honor'
|
||||
mode_slug=CourseMode.DEFAULT_MODE_SLUG,
|
||||
)
|
||||
|
||||
reg_code = CourseRegistrationCode.objects.all()[0]
|
||||
|
||||
@@ -56,10 +56,12 @@ class TestInstructorDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase, XssT
|
||||
display_name='<script>alert("XSS")</script>'
|
||||
)
|
||||
|
||||
self.course_mode = CourseMode(course_id=self.course.id,
|
||||
mode_slug="honor",
|
||||
mode_display_name="honor cert",
|
||||
min_price=40)
|
||||
self.course_mode = CourseMode(
|
||||
course_id=self.course.id,
|
||||
mode_slug=CourseMode.DEFAULT_MODE_SLUG,
|
||||
mode_display_name=CourseMode.DEFAULT_MODE.name,
|
||||
min_price=40
|
||||
)
|
||||
self.course_mode.save()
|
||||
# Create instructor account
|
||||
self.instructor = AdminFactory.create()
|
||||
|
||||
@@ -476,7 +476,7 @@ class TestInstructorDetailedEnrollmentReport(TestReportMixin, InstructorTaskCour
|
||||
created_by=self.instructor,
|
||||
invoice=self.sale_invoice_1,
|
||||
invoice_item=self.invoice_item,
|
||||
mode_slug='honor'
|
||||
mode_slug=CourseMode.DEFAULT_MODE_SLUG
|
||||
)
|
||||
course_registration_code.save()
|
||||
|
||||
@@ -517,7 +517,7 @@ class TestInstructorDetailedEnrollmentReport(TestReportMixin, InstructorTaskCour
|
||||
created_by=self.instructor,
|
||||
invoice=self.sale_invoice_1,
|
||||
invoice_item=self.invoice_item,
|
||||
mode_slug='honor'
|
||||
mode_slug=CourseMode.DEFAULT_MODE_SLUG
|
||||
)
|
||||
course_registration_code.save()
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""
|
||||
Test utils for Facebook functionality
|
||||
Test utils for Facebook functionality
|
||||
"""
|
||||
|
||||
import httpretty
|
||||
@@ -10,6 +10,7 @@ from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from social.apps.django_app.default.models import UserSocialAuth
|
||||
|
||||
from course_modes.models import CourseMode
|
||||
from student.models import CourseEnrollment
|
||||
from student.views import login_oauth_token
|
||||
from openedx.core.djangoapps.user_api.preferences.api import get_user_preference, set_user_preference
|
||||
@@ -182,4 +183,4 @@ class SocialFacebookTestCase(ModuleStoreTestCase, APITestCase):
|
||||
self.assertTrue(CourseEnrollment.is_enrolled(user, course.id))
|
||||
course_mode, is_active = CourseEnrollment.enrollment_mode_for_user(user, course.id)
|
||||
self.assertTrue(is_active)
|
||||
self.assertEqual(course_mode, 'honor')
|
||||
self.assertEqual(course_mode, CourseMode.DEFAULT_MODE_SLUG)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
from tempfile import NamedTemporaryFile
|
||||
from django.core.management import call_command
|
||||
|
||||
from course_modes.models import CourseMode
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from shoppingcart.models import Order, CertificateItem
|
||||
@@ -16,6 +17,11 @@ class TestRetireOrder(ModuleStoreTestCase):
|
||||
|
||||
course = CourseFactory.create()
|
||||
self.course_key = course.id
|
||||
CourseMode.objects.create(
|
||||
course_id=self.course_key,
|
||||
mode_slug=CourseMode.HONOR,
|
||||
mode_display_name=CourseMode.HONOR
|
||||
)
|
||||
|
||||
# set up test carts
|
||||
self.cart, __ = self._create_cart()
|
||||
|
||||
@@ -56,7 +56,13 @@ class OrderTest(ModuleStoreTestCase):
|
||||
self.course_key = course.id
|
||||
self.other_course_keys = []
|
||||
for __ in xrange(1, 5):
|
||||
self.other_course_keys.append(CourseFactory.create().id)
|
||||
course_key = CourseFactory.create().id
|
||||
CourseMode.objects.create(
|
||||
course_id=course_key,
|
||||
mode_slug=CourseMode.HONOR,
|
||||
mode_display_name="Honor"
|
||||
)
|
||||
self.other_course_keys.append(course_key)
|
||||
self.cost = 40
|
||||
|
||||
# Add mock tracker for event testing.
|
||||
@@ -64,6 +70,12 @@ class OrderTest(ModuleStoreTestCase):
|
||||
self.mock_tracker = patcher.start()
|
||||
self.addCleanup(patcher.stop)
|
||||
|
||||
CourseMode.objects.create(
|
||||
course_id=self.course_key,
|
||||
mode_slug=CourseMode.HONOR,
|
||||
mode_display_name="Honor"
|
||||
)
|
||||
|
||||
def test_get_cart_for_user(self):
|
||||
# create a cart
|
||||
cart = Order.get_cart_for_user(user=self.user)
|
||||
@@ -479,10 +491,12 @@ class PaidCourseRegistrationTest(ModuleStoreTestCase):
|
||||
self.cost = 40
|
||||
self.course = CourseFactory.create()
|
||||
self.course_key = self.course.id
|
||||
self.course_mode = CourseMode(course_id=self.course_key,
|
||||
mode_slug="honor",
|
||||
mode_display_name="honor cert",
|
||||
min_price=self.cost)
|
||||
self.course_mode = CourseMode(
|
||||
course_id=self.course_key,
|
||||
mode_slug=CourseMode.HONOR,
|
||||
mode_display_name="honor cert",
|
||||
min_price=self.cost
|
||||
)
|
||||
self.course_mode.save()
|
||||
self.percentage_discount = 20.0
|
||||
self.cart = Order.get_cart_for_user(self.user)
|
||||
@@ -492,7 +506,7 @@ class PaidCourseRegistrationTest(ModuleStoreTestCase):
|
||||
Test to check the total amount of the
|
||||
purchased items.
|
||||
"""
|
||||
PaidCourseRegistration.add_to_order(self.cart, self.course_key)
|
||||
PaidCourseRegistration.add_to_order(self.cart, self.course_key, mode_slug=CourseMode.HONOR)
|
||||
self.cart.purchase()
|
||||
|
||||
total_amount = PaidCourseRegistration.get_total_amount_of_purchased_item(course_key=self.course_key)
|
||||
@@ -507,7 +521,7 @@ class PaidCourseRegistrationTest(ModuleStoreTestCase):
|
||||
self.assertEqual(total_amount, 0.00)
|
||||
|
||||
def test_add_to_order(self):
|
||||
reg1 = PaidCourseRegistration.add_to_order(self.cart, self.course_key)
|
||||
reg1 = PaidCourseRegistration.add_to_order(self.cart, self.course_key, mode_slug=CourseMode.HONOR)
|
||||
|
||||
self.assertEqual(reg1.unit_cost, self.cost)
|
||||
self.assertEqual(reg1.line_cost, self.cost)
|
||||
@@ -545,7 +559,7 @@ class PaidCourseRegistrationTest(ModuleStoreTestCase):
|
||||
|
||||
self.cart.order_type = 'business'
|
||||
self.cart.save()
|
||||
item = CourseRegCodeItem.add_to_order(self.cart, self.course_key, 2)
|
||||
item = CourseRegCodeItem.add_to_order(self.cart, self.course_key, 2, mode_slug=CourseMode.HONOR)
|
||||
self.cart.purchase()
|
||||
registration_codes = CourseRegistrationCode.order_generated_registration_codes(self.course_key)
|
||||
self.assertEqual(registration_codes.count(), item.qty)
|
||||
@@ -710,14 +724,15 @@ class PaidCourseRegistrationTest(ModuleStoreTestCase):
|
||||
|
||||
def test_add_with_default_mode(self):
|
||||
"""
|
||||
Tests add_to_cart where the mode specified in the argument is NOT in the database
|
||||
and NOT the default "honor". In this case it just adds the user in the CourseMode.DEFAULT_MODE, 0 price
|
||||
Tests add_to_cart where the mode specified in the argument is NOT
|
||||
in the database and NOT the default "audit". In this case it
|
||||
just adds the user in the CourseMode.DEFAULT_MODE for free.
|
||||
"""
|
||||
reg1 = PaidCourseRegistration.add_to_order(self.cart, self.course_key, mode_slug="DNE")
|
||||
|
||||
self.assertEqual(reg1.unit_cost, 0)
|
||||
self.assertEqual(reg1.line_cost, 0)
|
||||
self.assertEqual(reg1.mode, "honor")
|
||||
self.assertEqual(reg1.mode, CourseMode.DEFAULT_MODE_SLUG)
|
||||
self.assertEqual(reg1.user, self.user)
|
||||
self.assertEqual(reg1.status, "cart")
|
||||
self.assertEqual(self.cart.total_cost, 0)
|
||||
@@ -727,7 +742,7 @@ class PaidCourseRegistrationTest(ModuleStoreTestCase):
|
||||
|
||||
self.assertEqual(course_reg_code_item.unit_cost, 0)
|
||||
self.assertEqual(course_reg_code_item.line_cost, 0)
|
||||
self.assertEqual(course_reg_code_item.mode, "honor")
|
||||
self.assertEqual(course_reg_code_item.mode, CourseMode.DEFAULT_MODE_SLUG)
|
||||
self.assertEqual(course_reg_code_item.user, self.user)
|
||||
self.assertEqual(course_reg_code_item.status, "cart")
|
||||
self.assertEqual(self.cart.total_cost, 0)
|
||||
|
||||
@@ -184,7 +184,7 @@ class ItemizedPurchaseReportTest(ModuleStoreTestCase):
|
||||
self.course_reg_code_annotation = CourseRegCodeItemAnnotation(course_id=self.course_key, annotation=self.TEST_ANNOTATION)
|
||||
self.course_reg_code_annotation.save()
|
||||
self.cart = Order.get_cart_for_user(self.user)
|
||||
self.reg = PaidCourseRegistration.add_to_order(self.cart, self.course_key)
|
||||
self.reg = PaidCourseRegistration.add_to_order(self.cart, self.course_key, mode_slug=course_mode.mode_slug)
|
||||
self.cert_item = CertificateItem.add_to_order(self.cart, self.course_key, self.cost, 'verified')
|
||||
self.cart.purchase()
|
||||
self.now = datetime.datetime.now(pytz.UTC)
|
||||
|
||||
@@ -94,20 +94,41 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin):
|
||||
self.coupon_code = 'abcde'
|
||||
self.reg_code = 'qwerty'
|
||||
self.percentage_discount = 10
|
||||
self.course_mode = CourseMode(course_id=self.course_key,
|
||||
mode_slug="honor",
|
||||
mode_display_name="honor cert",
|
||||
min_price=self.cost)
|
||||
self.course_mode = CourseMode(
|
||||
course_id=self.course_key,
|
||||
mode_slug=CourseMode.HONOR,
|
||||
mode_display_name="honor cert",
|
||||
min_price=self.cost
|
||||
)
|
||||
self.course_mode.save()
|
||||
|
||||
# Saving another testing course mode
|
||||
self.testing_cost = 20
|
||||
self.testing_course_mode = CourseMode(course_id=self.testing_course.id,
|
||||
mode_slug="honor",
|
||||
mode_display_name="testing honor cert",
|
||||
min_price=self.testing_cost)
|
||||
self.testing_course_mode = CourseMode(
|
||||
course_id=self.testing_course.id,
|
||||
mode_slug=CourseMode.HONOR,
|
||||
mode_display_name="testing honor cert",
|
||||
min_price=self.testing_cost
|
||||
)
|
||||
self.testing_course_mode.save()
|
||||
|
||||
# And for the XSS course
|
||||
CourseMode(
|
||||
course_id=self.xss_course_key,
|
||||
mode_slug=CourseMode.HONOR,
|
||||
mode_display_name="honor cert",
|
||||
min_price=self.cost
|
||||
).save()
|
||||
|
||||
# And the verified course
|
||||
self.verified_course_mode = CourseMode(
|
||||
course_id=self.verified_course_key,
|
||||
mode_slug=CourseMode.HONOR,
|
||||
mode_display_name="honor cert",
|
||||
min_price=self.cost
|
||||
)
|
||||
self.verified_course_mode.save()
|
||||
|
||||
self.cart = Order.get_cart_for_user(self.user)
|
||||
|
||||
self.addCleanup(patcher.stop)
|
||||
@@ -131,10 +152,12 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin):
|
||||
percentage_discount=self.percentage_discount, created_by=self.user, is_active=is_active)
|
||||
coupon.save()
|
||||
|
||||
def add_reg_code(self, course_key, mode_slug='honor', is_valid=True):
|
||||
def add_reg_code(self, course_key, mode_slug=None, is_valid=True):
|
||||
"""
|
||||
add dummy registration code into models
|
||||
"""
|
||||
if mode_slug is None:
|
||||
mode_slug = self.course_mode.mode_slug
|
||||
course_reg_code = CourseRegistrationCode(
|
||||
code=self.reg_code, course_id=course_key,
|
||||
created_by=self.user, mode_slug=mode_slug,
|
||||
@@ -159,7 +182,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin):
|
||||
adding course to user cart
|
||||
"""
|
||||
self.login_user()
|
||||
reg_item = PaidCourseRegistration.add_to_order(self.cart, course_key)
|
||||
reg_item = PaidCourseRegistration.add_to_order(self.cart, course_key, mode_slug=self.course_mode.mode_slug)
|
||||
return reg_item
|
||||
|
||||
def login_user(self):
|
||||
@@ -224,9 +247,18 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin):
|
||||
test to check that that the same coupon code applied on multiple
|
||||
items in the cart.
|
||||
"""
|
||||
for course_key, cost in ((self.course_key, 40), (self.testing_course.id, 20)):
|
||||
CourseMode(
|
||||
course_id=course_key,
|
||||
mode_slug=CourseMode.DEFAULT_MODE_SLUG,
|
||||
mode_display_name=CourseMode.DEFAULT_MODE_SLUG,
|
||||
min_price=cost
|
||||
).save()
|
||||
self.login_user()
|
||||
# add first course to user cart
|
||||
resp = self.client.post(reverse('shoppingcart.views.add_course_to_cart', args=[self.course_key.to_deprecated_string()]))
|
||||
resp = self.client.post(
|
||||
reverse('shoppingcart.views.add_course_to_cart', args=[self.course_key.to_deprecated_string()])
|
||||
)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
# add and apply the coupon code to course in the cart
|
||||
self.add_coupon(self.course_key, True, self.coupon_code)
|
||||
@@ -237,7 +269,9 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin):
|
||||
self.add_coupon(self.testing_course.id, True, self.coupon_code)
|
||||
#now add the second course to cart, the coupon code should be
|
||||
# applied when adding the second course to the cart
|
||||
resp = self.client.post(reverse('shoppingcart.views.add_course_to_cart', args=[self.testing_course.id.to_deprecated_string()]))
|
||||
resp = self.client.post(
|
||||
reverse('shoppingcart.views.add_course_to_cart', args=[self.testing_course.id.to_deprecated_string()])
|
||||
)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
#now check the user cart and see that the discount has been applied on both the courses
|
||||
resp = self.client.get(reverse('shoppingcart.views.show_cart', args=[]))
|
||||
@@ -586,7 +620,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin):
|
||||
self.add_reg_code(course_key, mode_slug='verified')
|
||||
|
||||
# Enroll as honor in the course with the current user.
|
||||
CourseEnrollment.enroll(self.user, self.course_key)
|
||||
CourseEnrollment.enroll(self.user, self.course_key, mode=CourseMode.HONOR)
|
||||
self.login_user()
|
||||
current_enrollment, __ = CourseEnrollment.enrollment_mode_for_user(self.user, self.course_key)
|
||||
self.assertEquals('honor', current_enrollment)
|
||||
@@ -753,8 +787,17 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin):
|
||||
@patch('shoppingcart.views.render_to_response', render_mock)
|
||||
def test_show_cart(self):
|
||||
self.login_user()
|
||||
reg_item = PaidCourseRegistration.add_to_order(self.cart, self.course_key)
|
||||
cert_item = CertificateItem.add_to_order(self.cart, self.verified_course_key, self.cost, 'honor')
|
||||
reg_item = PaidCourseRegistration.add_to_order(
|
||||
self.cart,
|
||||
self.course_key,
|
||||
mode_slug=self.course_mode.mode_slug
|
||||
)
|
||||
cert_item = CertificateItem.add_to_order(
|
||||
self.cart,
|
||||
self.verified_course_key,
|
||||
self.cost,
|
||||
self.course_mode.mode_slug
|
||||
)
|
||||
resp = self.client.get(reverse('shoppingcart.views.show_cart', args=[]))
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
@@ -860,7 +903,6 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin):
|
||||
for __ in range(num_items):
|
||||
CertificateItem.add_to_order(self.cart, self.verified_course_key, self.cost, 'honor')
|
||||
self.cart.purchase()
|
||||
|
||||
self.login_user()
|
||||
url = reverse('shoppingcart.views.show_receipt', args=[self.cart.id])
|
||||
resp = self.client.get(url, HTTP_ACCEPT="application/json")
|
||||
@@ -891,7 +933,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin):
|
||||
'unit_cost': 40,
|
||||
'quantity': 1,
|
||||
'line_cost': 40,
|
||||
'line_desc': 'Honor Code Certificate for course Test Course',
|
||||
'line_desc': '{} for course Test Course'.format(self.verified_course_mode.mode_display_name),
|
||||
'course_key': unicode(self.verified_course_key)
|
||||
})
|
||||
|
||||
@@ -922,8 +964,17 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin):
|
||||
|
||||
def test_show_receipt_json_multiple_items(self):
|
||||
# Two different item types
|
||||
PaidCourseRegistration.add_to_order(self.cart, self.course_key)
|
||||
CertificateItem.add_to_order(self.cart, self.verified_course_key, self.cost, 'honor')
|
||||
PaidCourseRegistration.add_to_order(
|
||||
self.cart,
|
||||
self.course_key,
|
||||
mode_slug=self.course_mode.mode_slug
|
||||
)
|
||||
CertificateItem.add_to_order(
|
||||
self.cart,
|
||||
self.verified_course_key,
|
||||
self.cost,
|
||||
self.verified_course_mode.mode_slug
|
||||
)
|
||||
self.cart.purchase()
|
||||
|
||||
self.login_user()
|
||||
@@ -950,7 +1001,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin):
|
||||
'unit_cost': 40,
|
||||
'quantity': 1,
|
||||
'line_cost': 40,
|
||||
'line_desc': 'Honor Code Certificate for course Test Course',
|
||||
'line_desc': '{} for course Test Course'.format(self.verified_course_mode.mode_display_name),
|
||||
'course_key': unicode(self.verified_course_key)
|
||||
})
|
||||
|
||||
@@ -1011,7 +1062,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin):
|
||||
|
||||
self.client.login(username=self.instructor.username, password="test")
|
||||
cart = Order.get_cart_for_user(self.instructor)
|
||||
PaidCourseRegistration.add_to_order(cart, self.course_key)
|
||||
PaidCourseRegistration.add_to_order(cart, self.course_key, mode_slug=self.course_mode.mode_slug)
|
||||
cart.purchase(first='FirstNameTesting123', street1='StreetTesting123')
|
||||
|
||||
total_amount = PaidCourseRegistration.get_total_amount_of_purchased_item(self.course_key)
|
||||
@@ -1058,8 +1109,12 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin):
|
||||
|
||||
# Two courses in user shopping cart
|
||||
self.login_user()
|
||||
PaidCourseRegistration.add_to_order(self.cart, self.course_key)
|
||||
item2 = PaidCourseRegistration.add_to_order(self.cart, self.testing_course.id)
|
||||
PaidCourseRegistration.add_to_order(self.cart, self.course_key, mode_slug=self.course_mode.mode_slug)
|
||||
item2 = PaidCourseRegistration.add_to_order(
|
||||
self.cart,
|
||||
self.testing_course.id,
|
||||
mode_slug=self.course_mode.mode_slug
|
||||
)
|
||||
self.assertEquals(self.cart.orderitem_set.count(), 2)
|
||||
|
||||
resp = self.client.post(reverse('shoppingcart.views.use_code'), {'code': self.reg_code})
|
||||
@@ -1113,7 +1168,11 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin):
|
||||
|
||||
@patch('shoppingcart.views.render_to_response', render_mock)
|
||||
def test_show_receipt_success(self):
|
||||
reg_item = PaidCourseRegistration.add_to_order(self.cart, self.course_key)
|
||||
reg_item = PaidCourseRegistration.add_to_order(
|
||||
self.cart,
|
||||
self.course_key,
|
||||
mode_slug=self.course_mode.mode_slug
|
||||
)
|
||||
cert_item = CertificateItem.add_to_order(self.cart, self.verified_course_key, self.cost, 'honor')
|
||||
self.cart.purchase(first='FirstNameTesting123', street1='StreetTesting123')
|
||||
|
||||
@@ -1157,7 +1216,7 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin):
|
||||
def test_courseregcode_item_total_price(self):
|
||||
self.cart.order_type = 'business'
|
||||
self.cart.save()
|
||||
CourseRegCodeItem.add_to_order(self.cart, self.course_key, 2)
|
||||
CourseRegCodeItem.add_to_order(self.cart, self.course_key, 2, mode_slug=self.course_mode.mode_slug)
|
||||
self.cart.purchase(first='FirstNameTesting123', street1='StreetTesting123')
|
||||
self.assertEquals(CourseRegCodeItem.get_total_amount_of_purchased_item(self.course_key), 80)
|
||||
|
||||
@@ -1165,7 +1224,12 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin):
|
||||
def test_show_receipt_success_with_order_type_business(self):
|
||||
self.cart.order_type = 'business'
|
||||
self.cart.save()
|
||||
reg_item = CourseRegCodeItem.add_to_order(self.cart, self.course_key, 2)
|
||||
reg_item = CourseRegCodeItem.add_to_order(
|
||||
self.cart,
|
||||
self.course_key,
|
||||
2,
|
||||
mode_slug=self.course_mode.mode_slug
|
||||
)
|
||||
self.cart.add_billing_details(company_name='T1Omega', company_contact_name='C1',
|
||||
company_contact_email='test@t1.com', recipient_email='test@t2.com')
|
||||
self.cart.purchase(first='FirstNameTesting123', street1='StreetTesting123')
|
||||
@@ -1230,7 +1294,11 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin):
|
||||
@patch('shoppingcart.views.render_to_response', render_mock)
|
||||
def test_show_receipt_success_with_upgrade(self):
|
||||
|
||||
reg_item = PaidCourseRegistration.add_to_order(self.cart, self.course_key)
|
||||
reg_item = PaidCourseRegistration.add_to_order(
|
||||
self.cart,
|
||||
self.course_key,
|
||||
mode_slug=self.course_mode.mode_slug
|
||||
)
|
||||
cert_item = CertificateItem.add_to_order(self.cart, self.verified_course_key, self.cost, 'honor')
|
||||
self.cart.purchase(first='FirstNameTesting123', street1='StreetTesting123')
|
||||
|
||||
@@ -1255,7 +1323,11 @@ class ShoppingCartViewsTests(SharedModuleStoreTestCase, XssTestMixin):
|
||||
|
||||
@patch('shoppingcart.views.render_to_response', render_mock)
|
||||
def test_show_receipt_success_refund(self):
|
||||
reg_item = PaidCourseRegistration.add_to_order(self.cart, self.course_key)
|
||||
reg_item = PaidCourseRegistration.add_to_order(
|
||||
self.cart,
|
||||
self.course_key,
|
||||
mode_slug=self.course_mode.mode_slug
|
||||
)
|
||||
cert_item = CertificateItem.add_to_order(self.cart, self.verified_course_key, self.cost, 'honor')
|
||||
self.cart.purchase(first='FirstNameTesting123', street1='StreetTesting123')
|
||||
cert_item.status = "refunded"
|
||||
@@ -1493,10 +1565,12 @@ class ShoppingcartViewsClosedEnrollment(ModuleStoreTestCase):
|
||||
|
||||
self.course = CourseFactory.create(org='MITx', number='999', display_name='Robot Super Course')
|
||||
self.course_key = self.course.id
|
||||
self.course_mode = CourseMode(course_id=self.course_key,
|
||||
mode_slug="honor",
|
||||
mode_display_name="honor cert",
|
||||
min_price=self.cost)
|
||||
self.course_mode = CourseMode(
|
||||
course_id=self.course_key,
|
||||
mode_slug=CourseMode.HONOR,
|
||||
mode_display_name="honor cert",
|
||||
min_price=self.cost
|
||||
)
|
||||
self.course_mode.save()
|
||||
self.testing_course = CourseFactory.create(
|
||||
org='Edx',
|
||||
@@ -1504,6 +1578,13 @@ class ShoppingcartViewsClosedEnrollment(ModuleStoreTestCase):
|
||||
display_name='Testing Super Course',
|
||||
metadata={"invitation_only": False}
|
||||
)
|
||||
self.testing_course_mode = CourseMode(
|
||||
course_id=self.testing_course.id,
|
||||
mode_slug=CourseMode.HONOR,
|
||||
mode_display_name="honor cert",
|
||||
min_price=self.cost
|
||||
)
|
||||
self.course_mode.save()
|
||||
self.percentage_discount = 20.0
|
||||
self.coupon_code = 'asdsad'
|
||||
self.course_mode = CourseMode(course_id=self.testing_course.id,
|
||||
@@ -1570,8 +1651,16 @@ class ShoppingcartViewsClosedEnrollment(ModuleStoreTestCase):
|
||||
|
||||
def test_to_check_that_cart_item_enrollment_is_closed_when_clicking_the_payment_button(self):
|
||||
self.login_user()
|
||||
PaidCourseRegistration.add_to_order(self.cart, self.course_key)
|
||||
PaidCourseRegistration.add_to_order(self.cart, self.testing_course.id)
|
||||
PaidCourseRegistration.add_to_order(
|
||||
self.cart,
|
||||
self.course_key,
|
||||
mode_slug=self.course_mode.mode_slug
|
||||
)
|
||||
PaidCourseRegistration.add_to_order(
|
||||
self.cart,
|
||||
self.testing_course.id,
|
||||
mode_slug=self.testing_course_mode.mode_slug
|
||||
)
|
||||
|
||||
# update the testing_course enrollment dates
|
||||
self.testing_course.enrollment_start = self.tomorrow
|
||||
@@ -1593,8 +1682,8 @@ class ShoppingcartViewsClosedEnrollment(ModuleStoreTestCase):
|
||||
self.login_user()
|
||||
self.cart.order_type = 'business'
|
||||
self.cart.save()
|
||||
PaidCourseRegistration.add_to_order(self.cart, self.course_key)
|
||||
CourseRegCodeItem.add_to_order(self.cart, self.testing_course.id, 2)
|
||||
PaidCourseRegistration.add_to_order(self.cart, self.course_key, mode_slug=self.course_mode.mode_slug)
|
||||
CourseRegCodeItem.add_to_order(self.cart, self.testing_course.id, 2, mode_slug=self.course_mode.mode_slug)
|
||||
|
||||
# update the testing_course enrollment dates
|
||||
self.testing_course.enrollment_start = self.tomorrow
|
||||
@@ -2039,7 +2128,7 @@ class CSVReportViewsTest(SharedModuleStoreTestCase):
|
||||
report_type = 'itemized_purchase_report'
|
||||
start_date = '1970-01-01'
|
||||
end_date = '2100-01-01'
|
||||
PaidCourseRegistration.add_to_order(self.cart, self.course_key)
|
||||
PaidCourseRegistration.add_to_order(self.cart, self.course_key, mode_slug=self.course_mode.mode_slug)
|
||||
self.cart.purchase()
|
||||
self.login_user()
|
||||
self.add_to_download_group(self.user)
|
||||
|
||||
@@ -339,8 +339,11 @@ def register_code_redemption(request, registration_code):
|
||||
}
|
||||
return render_to_response(template_to_render, context)
|
||||
elif request.method == "POST":
|
||||
reg_code_is_valid, reg_code_already_redeemed, course_registration = get_reg_code_validity(registration_code,
|
||||
request, limiter)
|
||||
reg_code_is_valid, reg_code_already_redeemed, course_registration = get_reg_code_validity(
|
||||
registration_code,
|
||||
request,
|
||||
limiter
|
||||
)
|
||||
course = get_course_by_id(course_registration.course_id, depth=0)
|
||||
|
||||
# Restrict the user from enrolling based on country access rules
|
||||
|
||||
@@ -17,6 +17,7 @@ from django.test import TestCase
|
||||
from django.test.utils import override_settings
|
||||
from django.http import HttpRequest
|
||||
|
||||
from course_modes.models import CourseMode
|
||||
from openedx.core.djangoapps.user_api.accounts.api import activate_account, create_account
|
||||
from openedx.core.djangoapps.user_api.accounts import EMAIL_MAX_LENGTH
|
||||
from openedx.core.lib.js_utils import escape_json_dumps
|
||||
@@ -263,7 +264,7 @@ class StudentAccountLoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMi
|
||||
params = [
|
||||
('course_id', 'edX/DemoX/Demo_Course'),
|
||||
('enrollment_action', 'enroll'),
|
||||
('course_mode', 'honor'),
|
||||
('course_mode', CourseMode.DEFAULT_MODE_SLUG),
|
||||
('email_opt_in', 'true'),
|
||||
('next', '/custom/final/destination')
|
||||
]
|
||||
@@ -294,7 +295,7 @@ class StudentAccountLoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMi
|
||||
params = [
|
||||
('course_id', 'course-v1:Org+Course+Run'),
|
||||
('enrollment_action', 'enroll'),
|
||||
('course_mode', 'honor'),
|
||||
('course_mode', CourseMode.DEFAULT_MODE_SLUG),
|
||||
('email_opt_in', 'true'),
|
||||
('next', '/custom/final/destination'),
|
||||
]
|
||||
|
||||
@@ -472,6 +472,7 @@ class TestPhotoVerification(ModuleStoreTestCase):
|
||||
@ddt.unpack
|
||||
@ddt.data(
|
||||
{'enrollment_mode': 'honor', 'status': None, 'output': 'N/A'},
|
||||
{'enrollment_mode': 'audit', 'status': None, 'output': 'N/A'},
|
||||
{'enrollment_mode': 'verified', 'status': False, 'output': 'Not ID Verified'},
|
||||
{'enrollment_mode': 'verified', 'status': True, 'output': 'ID Verified'},
|
||||
)
|
||||
|
||||
@@ -105,7 +105,7 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin):
|
||||
@ddt.data("verified", "professional")
|
||||
def test_start_flow_not_verified(self, course_mode):
|
||||
course = self._create_course(course_mode)
|
||||
self._enroll(course.id, "honor")
|
||||
self._enroll(course.id)
|
||||
response = self._get_page('verify_student_start_flow', course.id)
|
||||
self._assert_displayed_mode(response, course_mode)
|
||||
self._assert_steps_displayed(
|
||||
@@ -123,8 +123,7 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin):
|
||||
@ddt.data("no-id-professional")
|
||||
def test_start_flow_with_no_id_professional(self, course_mode):
|
||||
course = self._create_course(course_mode)
|
||||
# by default enrollment is honor
|
||||
self._enroll(course.id, "honor")
|
||||
self._enroll(course.id)
|
||||
response = self._get_page('verify_student_start_flow', course.id)
|
||||
self._assert_displayed_mode(response, course_mode)
|
||||
self._assert_steps_displayed(
|
||||
@@ -164,7 +163,7 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin):
|
||||
@ddt.unpack
|
||||
def test_start_flow_already_verified(self, course_mode, verification_status):
|
||||
course = self._create_course(course_mode)
|
||||
self._enroll(course.id, "honor")
|
||||
self._enroll(course.id)
|
||||
self._set_verification_status(verification_status)
|
||||
response = self._get_page('verify_student_start_flow', course.id)
|
||||
self._assert_displayed_mode(response, course_mode)
|
||||
@@ -323,7 +322,7 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin):
|
||||
)
|
||||
def test_verify_now_not_paid(self, page_name):
|
||||
course = self._create_course("verified")
|
||||
self._enroll(course.id, "honor")
|
||||
self._enroll(course.id)
|
||||
response = self._get_page(page_name, course.id, expected_status_code=302)
|
||||
self._assert_redirects_to_upgrade(response, course.id)
|
||||
|
||||
@@ -440,7 +439,7 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin):
|
||||
@ddt.data("verified", "professional")
|
||||
def test_upgrade(self, course_mode):
|
||||
course = self._create_course(course_mode)
|
||||
self._enroll(course.id, "honor")
|
||||
self._enroll(course.id)
|
||||
|
||||
response = self._get_page('verify_student_upgrade_and_verify', course.id)
|
||||
self._assert_displayed_mode(response, course_mode)
|
||||
@@ -459,7 +458,7 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin):
|
||||
|
||||
def test_upgrade_already_verified(self):
|
||||
course = self._create_course("verified")
|
||||
self._enroll(course.id, "honor")
|
||||
self._enroll(course.id)
|
||||
self._set_verification_status("submitted")
|
||||
|
||||
response = self._get_page('verify_student_upgrade_and_verify', course.id)
|
||||
@@ -746,7 +745,7 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin):
|
||||
|
||||
return course
|
||||
|
||||
def _enroll(self, course_key, mode):
|
||||
def _enroll(self, course_key, mode=CourseMode.DEFAULT_MODE_SLUG):
|
||||
"""Enroll the user in a course. """
|
||||
CourseEnrollmentFactory.create(
|
||||
user=self.user,
|
||||
@@ -923,8 +922,8 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin):
|
||||
"""Check the course information on the page. """
|
||||
mode_display_name = u"Introduction à l'astrophysique"
|
||||
course = CourseFactory.create(display_name=mode_display_name)
|
||||
for course_mode in ["honor", "verified"]:
|
||||
min_price = (self.MIN_PRICE if course_mode != "honor" else 0)
|
||||
for course_mode in [CourseMode.DEFAULT_MODE_SLUG, "verified"]:
|
||||
min_price = (self.MIN_PRICE if course_mode != CourseMode.DEFAULT_MODE_SLUG else 0)
|
||||
CourseModeFactory(
|
||||
course_id=course.id,
|
||||
mode_slug=course_mode,
|
||||
@@ -932,7 +931,7 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin):
|
||||
min_price=min_price
|
||||
)
|
||||
|
||||
self._enroll(course.id, "honor")
|
||||
self._enroll(course.id)
|
||||
response_dict = self._get_page_data(self._get_page('verify_student_start_flow', course.id))
|
||||
|
||||
self.assertEqual(response_dict['course_name'], mode_display_name)
|
||||
@@ -948,7 +947,7 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin):
|
||||
# setting a nonempty sku on the course will a trigger calls to
|
||||
# the ecommerce api to get payment processors.
|
||||
course = self._create_course("verified", sku='nonempty-sku')
|
||||
self._enroll(course.id, "honor")
|
||||
self._enroll(course.id)
|
||||
|
||||
# mock out the payment processors endpoint
|
||||
httpretty.register_uri(
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
);
|
||||
});
|
||||
|
||||
it('sends the user to the payment flow when the course mode is not honor', function() {
|
||||
it('sends the user to the payment flow for a paid course mode', function() {
|
||||
// Simulate providing enrollment query string params
|
||||
// AND specifying a course mode.
|
||||
setFakeQueryParams({
|
||||
@@ -114,13 +114,13 @@
|
||||
);
|
||||
});
|
||||
|
||||
it('sends the user to the student dashboard when the course mode is honor', function() {
|
||||
it('sends the user to the student dashboard for an unpaid course mode', function() {
|
||||
// Simulate providing enrollment query string params
|
||||
// AND specifying a course mode.
|
||||
setFakeQueryParams({
|
||||
'?enrollment_action': 'enroll',
|
||||
'?course_id': COURSE_KEY,
|
||||
'?course_mode': 'honor'
|
||||
'?course_mode': 'audit'
|
||||
});
|
||||
|
||||
ajaxSpyAndInitialize(this);
|
||||
|
||||
@@ -26,7 +26,7 @@ var edx = edx || {};
|
||||
hasVisibleReqs: false,
|
||||
platformName: '',
|
||||
alreadyVerified: false,
|
||||
courseModeSlug: 'honor',
|
||||
courseModeSlug: 'audit',
|
||||
verificationGoodUntil: ''
|
||||
};
|
||||
},
|
||||
|
||||
@@ -22,7 +22,7 @@ from lms.djangoapps.verify_student.views import PayAndVerifyView
|
||||
${_(u"The verification deadline for {course_name} was {date}. Verification is no longer available.").format(
|
||||
course_name=course.display_name, date=deadline)}
|
||||
% elif deadline_name == PayAndVerifyView.UPGRADE_DEADLINE:
|
||||
${_(u"The deadline to upgrade to a verified certificate for this course has passed. You can still earn an honor code certificate.")}
|
||||
${_(u"The deadline to upgrade to a verified certificate for this course has passed.")}
|
||||
% endif
|
||||
</p>
|
||||
</section>
|
||||
|
||||
@@ -25,6 +25,15 @@ class CreditServiceTests(ModuleStoreTestCase):
|
||||
self.credit_course = CreditCourse.objects.create(course_key=self.course.id, enabled=True)
|
||||
self.profile = UserProfile.objects.create(user_id=self.user.id, name='Foo Bar')
|
||||
|
||||
def enroll(self, course_id=None):
|
||||
"""
|
||||
Enroll the test user in the given course's honor mode, or the test
|
||||
course if not provided.
|
||||
"""
|
||||
if course_id is None:
|
||||
course_id = self.course.id
|
||||
return CourseEnrollment.enroll(self.user, course_id, mode='honor')
|
||||
|
||||
def test_user_not_found(self):
|
||||
"""
|
||||
Makes sure that get_credit_state returns None if user_id cannot be found
|
||||
@@ -46,7 +55,7 @@ class CreditServiceTests(ModuleStoreTestCase):
|
||||
inactive
|
||||
"""
|
||||
|
||||
enrollment = CourseEnrollment.enroll(self.user, self.course.id)
|
||||
enrollment = self.enroll()
|
||||
enrollment.is_active = False
|
||||
enrollment.save()
|
||||
|
||||
@@ -58,7 +67,7 @@ class CreditServiceTests(ModuleStoreTestCase):
|
||||
Credit eligible
|
||||
"""
|
||||
|
||||
CourseEnrollment.enroll(self.user, self.course.id)
|
||||
self.enroll()
|
||||
|
||||
self.credit_course.enabled = False
|
||||
self.credit_course.save()
|
||||
@@ -86,7 +95,7 @@ class CreditServiceTests(ModuleStoreTestCase):
|
||||
|
||||
self.assertTrue(self.service.is_credit_course(self.course.id))
|
||||
|
||||
CourseEnrollment.enroll(self.user, self.course.id)
|
||||
self.enroll()
|
||||
|
||||
# set course requirements
|
||||
set_credit_requirements(
|
||||
@@ -127,7 +136,7 @@ class CreditServiceTests(ModuleStoreTestCase):
|
||||
"""
|
||||
self.assertTrue(self.service.is_credit_course(self.course.id))
|
||||
|
||||
CourseEnrollment.enroll(self.user, self.course.id)
|
||||
self.enroll()
|
||||
|
||||
# set course requirements
|
||||
set_credit_requirements(
|
||||
@@ -216,7 +225,7 @@ class CreditServiceTests(ModuleStoreTestCase):
|
||||
|
||||
self.assertFalse(self.service.is_credit_course(no_credit_course.id))
|
||||
|
||||
CourseEnrollment.enroll(self.user, no_credit_course.id)
|
||||
self.enroll(no_credit_course.id)
|
||||
|
||||
# this should be a no-op
|
||||
self.service.remove_credit_requirement_status(
|
||||
@@ -237,7 +246,7 @@ class CreditServiceTests(ModuleStoreTestCase):
|
||||
Make sure we can get back the optional course name
|
||||
"""
|
||||
|
||||
CourseEnrollment.enroll(self.user, self.course.id)
|
||||
self.enroll()
|
||||
|
||||
# make sure it is not returned by default
|
||||
credit_state = self.service.get_credit_state(self.user.id, self.course.id)
|
||||
@@ -258,7 +267,7 @@ class CreditServiceTests(ModuleStoreTestCase):
|
||||
|
||||
self.assertFalse(self.service.is_credit_course(no_credit_course.id))
|
||||
|
||||
CourseEnrollment.enroll(self.user, no_credit_course.id)
|
||||
self.enroll(no_credit_course.id)
|
||||
|
||||
# this should be a no-op
|
||||
self.service.set_credit_requirement_status(
|
||||
@@ -308,7 +317,7 @@ class CreditServiceTests(ModuleStoreTestCase):
|
||||
Make sure we can pass a course_id (string) and get back correct results as well
|
||||
"""
|
||||
|
||||
CourseEnrollment.enroll(self.user, self.course.id)
|
||||
self.enroll()
|
||||
|
||||
# set course requirements
|
||||
set_credit_requirements(
|
||||
|
||||
Reference in New Issue
Block a user