Prevent ordering closed courses, and give a good user message.

When Drupal attempts to enroll a user in a closed course, a 406 will
be returned. This causes the marketing site to redirect to the track
selection page for that course, which will then redirect to the
dashboard with a nice message.

ECOM-2317
This commit is contained in:
Peter Fogg
2016-03-08 13:18:42 -05:00
parent e6fcfae994
commit fd2f3b69ef
7 changed files with 147 additions and 3 deletions

View File

@@ -1,6 +1,12 @@
"""
Tests for course_modes views.
"""
from datetime import datetime
import unittest
import decimal
import ddt
import freezegun
from mock import patch
from django.conf import settings
from django.core.urlresolvers import reverse
@@ -9,6 +15,7 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from util.testing import UrlResetMixin
from embargo.test_utils import restrict_course
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.tests.factories import CourseFactory
from course_modes.tests.factories import CourseModeFactory
from student.tests.factories import CourseEnrollmentFactory, UserFactory
@@ -340,6 +347,21 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase):
self.assertNotContains(response, "Find courses")
self.assertNotContains(response, "Schools & Partners")
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
@freezegun.freeze_time('2015-01-02')
def test_course_closed(self):
for mode in ["honor", "verified"]:
CourseModeFactory(mode_slug=mode, course_id=self.course.id)
self.course.enrollment_end = datetime(2015, 01, 01)
modulestore().update_item(self.course, self.user.id)
url = reverse('course_modes_choose', args=[unicode(self.course.id)])
response = self.client.get(url)
# URL-encoded version of 1/1/15, 12:00 AM
redirect_url = reverse('dashboard') + '?course_closed=1%2F1%2F15%2C+12%3A00+AM'
self.assertRedirects(response, redirect_url)
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
class TrackSelectionEmbargoTest(UrlResetMixin, ModuleStoreTestCase):

View File

@@ -3,14 +3,16 @@ Views for the course_mode module
"""
import decimal
import urllib
from babel.dates import format_datetime
from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse
from django.db import transaction
from django.http import HttpResponse, HttpResponseBadRequest
from django.shortcuts import redirect
from django.utils.decorators import method_decorator
from django.utils.translation import ugettext as _
from django.utils.translation import get_language, to_locale, ugettext as _
from django.views.generic.base import View
from ipware.ip import get_ip
from opaque_keys.edx.keys import CourseKey
@@ -108,6 +110,11 @@ class ChooseModeView(View):
chosen_price = donation_for_course.get(unicode(course_key), None)
course = modulestore().get_course(course_key)
if CourseEnrollment.is_enrollment_closed(request.user, course):
locale = to_locale(get_language())
enrollment_end_date = format_datetime(course.enrollment_end, 'short', locale=locale)
params = urllib.urlencode({'course_closed': enrollment_end_date})
return redirect('{0}?{1}'.format(reverse('dashboard'), params))
# When a credit mode is available, students will be given the option
# to upgrade from a verified mode to a credit mode at the end of the course.

View File

@@ -701,6 +701,10 @@ def dashboard(request):
redirect_message = _("The course you are looking for does not start until {date}.").format(
date=request.GET['notlive']
)
elif 'course_closed' in request.GET:
redirect_message = _("The course you are looking for is closed for enrollment as of {date}.").format(
date=request.GET['course_closed']
)
else:
redirect_message = ''

View File

@@ -2,12 +2,13 @@
"""
End-to-end tests for the LMS.
"""
from datetime import datetime
from datetime import datetime, timedelta
from flaky import flaky
from textwrap import dedent
from unittest import skip
from nose.plugins.attrib import attr
import pytz
import urllib
from bok_choy.promise import EmptyPromise
from ..helpers import (
@@ -1156,6 +1157,95 @@ class NotLiveRedirectTest(UniqueCourseTest):
)
@attr('shard_1')
class EnrollmentClosedRedirectTest(UniqueCourseTest):
"""
Test that a banner is shown when the user is redirected to the
dashboard after trying to view the track selection page for a
course after enrollment has ended.
"""
def setUp(self):
"""Create a course that is closed for enrollment, and sign in as a user."""
super(EnrollmentClosedRedirectTest, self).setUp()
course = CourseFixture(
self.course_info['org'], self.course_info['number'],
self.course_info['run'], self.course_info['display_name']
)
now = datetime.now(pytz.UTC)
course.add_course_details({
'enrollment_start': (now - timedelta(days=30)).isoformat(),
'enrollment_end': (now - timedelta(days=1)).isoformat()
})
course.install()
# Add an honor mode to the course
ModeCreationPage(self.browser, self.course_id).visit()
# Add a verified mode to the course
ModeCreationPage(
self.browser,
self.course_id,
mode_slug=u'verified',
mode_display_name=u'Verified Certificate',
min_price=10,
suggested_prices='10,20'
).visit()
def _assert_dashboard_message(self):
"""
Assert that the 'closed for enrollment' text is present on the
dashboard.
"""
page = DashboardPage(self.browser)
page.wait_for_page()
self.assertIn(
'The course you are looking for is closed for enrollment',
page.banner_text
)
def test_redirect_banner(self):
"""
Navigate to the course info page, then check that we're on the
dashboard page with the appropriate message.
"""
AutoAuthPage(self.browser).visit()
url = BASE_URL + "/course_modes/choose/" + self.course_id
self.browser.get(url)
self._assert_dashboard_message()
def test_login_redirect(self):
"""
Test that the user is correctly redirected after logistration when
attempting to enroll in a closed course.
"""
url = '{base_url}/register?{params}'.format(
base_url=BASE_URL,
params=urllib.urlencode({
'course_id': self.course_id,
'enrollment_action': 'enroll',
'email_opt_in': 'false'
})
)
self.browser.get(url)
register_page = CombinedLoginAndRegisterPage(
self.browser,
start_page="register",
course_id=self.course_id
)
register_page.wait_for_page()
register_page.register(
email="email@example.com",
password="password",
username="username",
full_name="Test User",
country="US",
favorite_movie="Mad Max: Fury Road",
terms_of_service=True
)
self._assert_dashboard_message()
@attr('shard_1')
class LMSLanguageTest(UniqueCourseTest):
""" Test suite for the LMS Language """