Merge pull request #6864 from edx/will/country-access-messaging
ECOM-998: Country access messaging
This commit is contained in:
@@ -10,18 +10,31 @@ from collections import namedtuple
|
||||
BlockedMessage = namedtuple('BlockedMessage', [
|
||||
# A user-facing description of the message
|
||||
'description',
|
||||
|
||||
# The mako template used to render the message
|
||||
'template',
|
||||
])
|
||||
|
||||
|
||||
ENROLL_MESSAGES = {
|
||||
'default': BlockedMessage(
|
||||
description='Default',
|
||||
template='static_templates/enrollment_access_block.html'
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
ACCESS_MESSAGES = {
|
||||
'default': BlockedMessage(
|
||||
description='Default',
|
||||
'embargo': BlockedMessage(
|
||||
description='Embargo',
|
||||
template='static_templates/embargo.html'
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
COURSEWARE_MESSAGES = {
|
||||
'default': BlockedMessage(
|
||||
description='Default',
|
||||
template='static_templates/courseware_access_block.html'
|
||||
),
|
||||
'embargo': BlockedMessage(
|
||||
description='Embargo',
|
||||
template='static_templates/embargo.html'
|
||||
)
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ class Migration(DataMigration):
|
||||
orm.CountryAccessRule.objects.get_or_create(
|
||||
country=country_model,
|
||||
rule_type='blacklist',
|
||||
enroll_msg_key='embargo',
|
||||
access_msg_key='embargo',
|
||||
restricted_course=new_course
|
||||
)
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ from django_countries.fields import CountryField
|
||||
from config_models.models import ConfigurationModel
|
||||
from xmodule_django.models import CourseKeyField, NoneToEmptyManager
|
||||
|
||||
from embargo.messages import ENROLL_MESSAGES, ACCESS_MESSAGES
|
||||
from embargo.messages import ENROLL_MESSAGES, COURSEWARE_MESSAGES
|
||||
|
||||
|
||||
class EmbargoedCourse(models.Model):
|
||||
@@ -99,9 +99,9 @@ class RestrictedCourse(models.Model):
|
||||
for msg_key, msg in ENROLL_MESSAGES.iteritems()
|
||||
])
|
||||
|
||||
ACCESS_MSG_KEY_CHOICES = tuple([
|
||||
COURSEWARE_MSG_KEY_CHOICES = tuple([
|
||||
(msg_key, msg.description)
|
||||
for msg_key, msg in ACCESS_MESSAGES.iteritems()
|
||||
for msg_key, msg in COURSEWARE_MESSAGES.iteritems()
|
||||
])
|
||||
|
||||
course_key = CourseKeyField(
|
||||
@@ -118,7 +118,7 @@ class RestrictedCourse(models.Model):
|
||||
|
||||
access_msg_key = models.CharField(
|
||||
max_length=255,
|
||||
choices=ACCESS_MSG_KEY_CHOICES,
|
||||
choices=COURSEWARE_MSG_KEY_CHOICES,
|
||||
default='default',
|
||||
help_text=ugettext_lazy(u"The message to show when a user is blocked from accessing a course.")
|
||||
)
|
||||
|
||||
67
common/djangoapps/embargo/tests/test_views.py
Normal file
67
common/djangoapps/embargo/tests/test_views.py
Normal file
@@ -0,0 +1,67 @@
|
||||
"""Tests for embargo app views. """
|
||||
|
||||
import unittest
|
||||
from mock import patch
|
||||
from django.test import TestCase
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.conf import settings
|
||||
import ddt
|
||||
|
||||
from util.testing import UrlResetMixin
|
||||
from embargo import messages
|
||||
|
||||
|
||||
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
||||
@ddt.ddt
|
||||
class CourseAccessMessageViewTest(UrlResetMixin, TestCase):
|
||||
"""Tests for the courseware access message view.
|
||||
|
||||
These end-points serve static content.
|
||||
While we *could* check the text on each page,
|
||||
this will require changes to the test every time
|
||||
the text on the page changes.
|
||||
|
||||
Instead, we load each page we expect to be available
|
||||
(based on the configuration in `embargo.messages`)
|
||||
and verify that we get the correct status code.
|
||||
|
||||
This will catch errors in the message configuration
|
||||
(for example, moving a template and forgetting to
|
||||
update the configuration appropriately).
|
||||
|
||||
"""
|
||||
|
||||
@patch.dict(settings.FEATURES, {'ENABLE_COUNTRY_ACCESS': True})
|
||||
def setUp(self):
|
||||
super(CourseAccessMessageViewTest, self).setUp('embargo')
|
||||
|
||||
@ddt.data(*messages.ENROLL_MESSAGES.keys())
|
||||
def test_enrollment_messages(self, msg_key):
|
||||
self._load_page('enrollment', msg_key)
|
||||
|
||||
@ddt.data(*messages.COURSEWARE_MESSAGES.keys())
|
||||
def test_courseware_messages(self, msg_key):
|
||||
self._load_page('courseware', msg_key)
|
||||
|
||||
@ddt.data('enrollment', 'courseware')
|
||||
def test_invalid_message_key(self, access_point):
|
||||
self._load_page(access_point, 'invalid', expected_status=404)
|
||||
|
||||
def _load_page(self, access_point, message_key, expected_status=200):
|
||||
"""Load the message page and check the status code. """
|
||||
url = reverse('embargo_blocked_message', kwargs={
|
||||
'access_point': access_point,
|
||||
'message_key': message_key
|
||||
})
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(
|
||||
response.status_code, expected_status,
|
||||
msg=(
|
||||
u"Unexpected status code when loading '{url}': "
|
||||
u"expected {expected} but got {actual}"
|
||||
).format(
|
||||
url=url,
|
||||
expected=expected_status,
|
||||
actual=response.status_code
|
||||
)
|
||||
)
|
||||
15
common/djangoapps/embargo/urls.py
Normal file
15
common/djangoapps/embargo/urls.py
Normal file
@@ -0,0 +1,15 @@
|
||||
"""URLs served by the embargo app. """
|
||||
|
||||
from django.conf.urls import patterns, url
|
||||
|
||||
from embargo.views import CourseAccessMessageView
|
||||
|
||||
|
||||
urlpatterns = patterns(
|
||||
'embargo.views',
|
||||
url(
|
||||
r'^blocked-message/(?P<access_point>enrollment|courseware)/(?P<message_key>.+)/$',
|
||||
CourseAccessMessageView.as_view(),
|
||||
name='embargo_blocked_message',
|
||||
),
|
||||
)
|
||||
68
common/djangoapps/embargo/views.py
Normal file
68
common/djangoapps/embargo/views.py
Normal file
@@ -0,0 +1,68 @@
|
||||
"""Views served by the embargo app. """
|
||||
|
||||
from django.http import Http404
|
||||
from django.views.generic.base import View
|
||||
|
||||
from edxmako.shortcuts import render_to_response
|
||||
|
||||
from embargo import messages
|
||||
|
||||
|
||||
class CourseAccessMessageView(View):
|
||||
"""Show a message explaining that the user was blocked from a course. """
|
||||
|
||||
ENROLLMENT_ACCESS_POINT = 'enrollment'
|
||||
COURSEWARE_ACCESS_POINT = 'courseware'
|
||||
|
||||
def get(self, request, access_point=None, message_key=None):
|
||||
"""Show a message explaining that the user was blocked.
|
||||
|
||||
Arguments:
|
||||
request (HttpRequest)
|
||||
|
||||
Keyword Arguments:
|
||||
access_point (str): Either 'enrollment' or 'courseware',
|
||||
indicating how the user is trying to access the restricted
|
||||
content.
|
||||
|
||||
message_key (str): An identifier for which message to show.
|
||||
See `embargo.messages` for more information.
|
||||
|
||||
Returns:
|
||||
HttpResponse
|
||||
|
||||
Raises:
|
||||
Http404: If no message is configured for the specified message key.
|
||||
|
||||
"""
|
||||
blocked_message = self._message(access_point, message_key)
|
||||
|
||||
if blocked_message is None:
|
||||
raise Http404
|
||||
|
||||
return render_to_response(blocked_message.template, {})
|
||||
|
||||
def _message(self, access_point, message_key):
|
||||
"""Retrieve message information.
|
||||
|
||||
Arguments:
|
||||
access_point (str): Either 'enrollment' or 'courseware'
|
||||
message_key (str): The identifier for which message to show.
|
||||
|
||||
Returns:
|
||||
embargo.messages.BlockedMessage or None
|
||||
|
||||
"""
|
||||
message_dict = dict()
|
||||
|
||||
# The access point determines which set of messages to use.
|
||||
# This allows us to show different messages to students who
|
||||
# are enrolling in a course than we show to students
|
||||
# who are enrolled and accessing courseware.
|
||||
if access_point == self.ENROLLMENT_ACCESS_POINT:
|
||||
message_dict = messages.ENROLL_MESSAGES
|
||||
elif access_point == self.COURSEWARE_ACCESS_POINT:
|
||||
message_dict = messages.COURSEWARE_MESSAGES
|
||||
|
||||
# Return the message corresponding to the given key if one is available.
|
||||
return message_dict.get(message_key)
|
||||
@@ -252,6 +252,10 @@ FEATURES = {
|
||||
# Toggles the embargo site functionality, which enable embargoing for the whole site
|
||||
'SITE_EMBARGOED': False,
|
||||
|
||||
# Toggle whether to replace the current embargo implementation with
|
||||
# the more flexible "country access" feature.
|
||||
'ENABLE_COUNTRY_ACCESS': False,
|
||||
|
||||
# Whether the Wiki subsystem should be accessible via the direct /wiki/ paths. Setting this to True means
|
||||
# that people can submit content and modify the Wiki in any arbitrary manner. We're leaving this as True in the
|
||||
# defaults, so that we maintain current behavior
|
||||
|
||||
12
lms/templates/static_templates/courseware_access_block.html
Normal file
12
lms/templates/static_templates/courseware_access_block.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
<%inherit file="../main.html" />
|
||||
|
||||
<%block name="pagetitle">${_("This Course Unavailable In Your Country")}</%block>
|
||||
|
||||
<section class="outside-app">
|
||||
<p>
|
||||
${_("Our system indicates that you are trying to access this {platform_name} "
|
||||
"course from a country or region in which it is not currently available."
|
||||
).format(platform_name=settings.PLATFORM_NAME)}
|
||||
</p>
|
||||
</section>
|
||||
12
lms/templates/static_templates/enrollment_access_block.html
Normal file
12
lms/templates/static_templates/enrollment_access_block.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
<%inherit file="../main.html" />
|
||||
|
||||
<%block name="pagetitle">${_("This Course Unavailable In Your Country")}</%block>
|
||||
|
||||
<section class="outside-app">
|
||||
<p>
|
||||
${_("Our system indicates that you are trying to enroll in this {platform_name} "
|
||||
"course from a country or region in which it is not currently available."
|
||||
).format(platform_name=settings.PLATFORM_NAME)}
|
||||
</p>
|
||||
</section>
|
||||
@@ -484,6 +484,12 @@ urlpatterns += (
|
||||
url(r'^shoppingcart/', include('shoppingcart.urls')),
|
||||
)
|
||||
|
||||
# Country access (embargo)
|
||||
if settings.FEATURES.get('ENABLE_COUNTRY_ACCESS'):
|
||||
urlpatterns += (
|
||||
url(r'^embargo/', include('embargo.urls')),
|
||||
)
|
||||
|
||||
# Survey Djangoapp
|
||||
urlpatterns += (
|
||||
url(r'^survey/', include('survey.urls')),
|
||||
|
||||
Reference in New Issue
Block a user