diff --git a/cms/djangoapps/contentstore/views/course.py b/cms/djangoapps/contentstore/views/course.py
index 95229428ac..138e323d1c 100644
--- a/cms/djangoapps/contentstore/views/course.py
+++ b/cms/djangoapps/contentstore/views/course.py
@@ -55,7 +55,7 @@ from contentstore import utils
from student.roles import CourseInstructorRole, CourseStaffRole, CourseCreatorRole, GlobalStaff
from student import auth
-from microsite_configuration.middleware import MicrositeConfiguration
+from microsite_configuration import microsite
__all__ = ['course_info_handler', 'course_handler', 'course_info_update_handler',
'settings_handler',
@@ -535,7 +535,7 @@ def settings_handler(request, tag=None, package_id=None, branch=None, version_gu
# see if the ORG of this course can be attributed to a 'Microsite'. In that case, the
# course about page should be editable in Studio
- about_page_editable = not MicrositeConfiguration.get_microsite_configuration_value_for_org(
+ about_page_editable = not microsite.get_value_for_org(
course_module.location.org,
'ENABLE_MKTG_SITE',
settings.FEATURES.get('ENABLE_MKTG_SITE', False)
diff --git a/cms/djangoapps/contentstore/views/public.py b/cms/djangoapps/contentstore/views/public.py
index ef02445430..63f95084aa 100644
--- a/cms/djangoapps/contentstore/views/public.py
+++ b/cms/djangoapps/contentstore/views/public.py
@@ -10,7 +10,7 @@ from django.conf import settings
from edxmako.shortcuts import render_to_response
from external_auth.views import ssl_login_shortcut, ssl_get_cert_from_request
-from microsite_configuration.middleware import MicrositeConfiguration
+from microsite_configuration import microsite
__all__ = ['signup', 'login_page', 'howitworks']
@@ -49,7 +49,7 @@ def login_page(request):
{
'csrf': csrf_token,
'forgot_password_link': "//{base}/login#forgot-password-modal".format(base=settings.LMS_BASE),
- 'platform_name': MicrositeConfiguration.get_microsite_configuration_value('platform_name', settings.PLATFORM_NAME),
+ 'platform_name': microsite.get_value('platform_name', settings.PLATFORM_NAME),
}
)
diff --git a/cms/envs/aws.py b/cms/envs/aws.py
index 2bdd075218..3147ad3cd7 100644
--- a/cms/envs/aws.py
+++ b/cms/envs/aws.py
@@ -239,16 +239,8 @@ VIRTUAL_UNIVERSITIES = ENV_TOKENS.get('VIRTUAL_UNIVERSITIES', [])
MAX_FAILED_LOGIN_ATTEMPTS_ALLOWED = ENV_TOKENS.get("MAX_FAILED_LOGIN_ATTEMPTS_ALLOWED", 5)
MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS = ENV_TOKENS.get("MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS", 15 * 60)
-
MICROSITE_CONFIGURATION = ENV_TOKENS.get('MICROSITE_CONFIGURATION', {})
-MICROSITE_ROOT_DIR = ENV_TOKENS.get('MICROSITE_ROOT_DIR')
-if len(MICROSITE_CONFIGURATION.keys()) > 0:
- enable_microsites(
- MICROSITE_CONFIGURATION,
- SUBDOMAIN_BRANDING,
- VIRTUAL_UNIVERSITIES,
- microsites_root=path(MICROSITE_ROOT_DIR)
- )
+MICROSITE_ROOT_DIR = path(ENV_TOKENS.get('MICROSITE_ROOT_DIR', ''))
#### PASSWORD POLICY SETTINGS #####
PASSWORD_MIN_LENGTH = ENV_TOKENS.get("PASSWORD_MIN_LENGTH")
diff --git a/cms/envs/common.py b/cms/envs/common.py
index 94a4db86e7..588bdd7a41 100644
--- a/cms/envs/common.py
+++ b/cms/envs/common.py
@@ -27,7 +27,7 @@ Longer TODO:
import sys
import lms.envs.common
from lms.envs.common import (
- USE_TZ, TECH_SUPPORT_EMAIL, PLATFORM_NAME, BUGS_EMAIL, DOC_STORE_CONFIG, enable_microsites, ALL_LANGUAGES
+ USE_TZ, TECH_SUPPORT_EMAIL, PLATFORM_NAME, BUGS_EMAIL, DOC_STORE_CONFIG, ALL_LANGUAGES
)
from path import path
@@ -84,6 +84,9 @@ FEATURES = {
# Toggles embargo functionality
'EMBARGO': False,
+
+ # Turn on/off Microsites feature
+ 'USE_MICROSITES': False,
}
ENABLE_JASMINE = False
diff --git a/cms/envs/microsite_test.py b/cms/envs/microsite_test.py
index 5eb2079da8..b79e295226 100644
--- a/cms/envs/microsite_test.py
+++ b/cms/envs/microsite_test.py
@@ -6,10 +6,7 @@ This is a localdev test for the Microsite processing pipeline
# pylint: disable=W0401, W0614
from .dev import *
-from .dev import SUBDOMAIN_BRANDING, VIRTUAL_UNIVERSITIES
MICROSITE_NAMES = ['openedx']
MICROSITE_CONFIGURATION = {}
-
-if MICROSITE_NAMES and len(MICROSITE_NAMES) > 0:
- enable_microsites(MICROSITE_NAMES, MICROSITE_CONFIGURATION, SUBDOMAIN_BRANDING, VIRTUAL_UNIVERSITIES)
+FEATURES['USE_MICROSITES'] = True
diff --git a/cms/envs/test.py b/cms/envs/test.py
index 1e1adf49e4..8d60aff95c 100644
--- a/cms/envs/test.py
+++ b/cms/envs/test.py
@@ -199,3 +199,31 @@ FEATURES['DISABLE_RESET_EMAIL_TEST'] = True
# Toggles embargo on for testing
FEATURES['EMBARGO'] = True
+
+# set up some testing for microsites
+MICROSITE_CONFIGURATION = {
+ "test_microsite": {
+ "domain_prefix": "testmicrosite",
+ "university": "test_microsite",
+ "platform_name": "Test Microsite",
+ "logo_image_url": "test_microsite/images/header-logo.png",
+ "email_from_address": "test_microsite@edx.org",
+ "payment_support_email": "test_microsite@edx.org",
+ "ENABLE_MKTG_SITE": False,
+ "SITE_NAME": "test_microsite.localhost",
+ "course_org_filter": "TestMicrositeX",
+ "course_about_show_social_links": False,
+ "css_overrides_file": "test_microsite/css/test_microsite.css",
+ "show_partners": False,
+ "show_homepage_promo_video": False,
+ "course_index_overlay_text": "This is a Test Microsite Overlay Text.",
+ "course_index_overlay_logo_file": "test_microsite/images/header-logo.png",
+ "homepage_overlay_html": "
This is a Test Microsite Overlay HTML
"
+ },
+ "default": {
+ "university": "default_university",
+ "domain_prefix": "www",
+ }
+}
+MICROSITE_ROOT_DIR = COMMON_ROOT / 'test' / 'test_microsites'
+FEATURES['USE_MICROSITES'] = True
diff --git a/common/djangoapps/edxmako/shortcuts.py b/common/djangoapps/edxmako/shortcuts.py
index 73f76b8afd..b8d0c2a2c2 100644
--- a/common/djangoapps/edxmako/shortcuts.py
+++ b/common/djangoapps/edxmako/shortcuts.py
@@ -16,7 +16,7 @@ from django.template import Context
from django.http import HttpResponse
import logging
-from microsite_configuration.middleware import MicrositeConfiguration
+from microsite_configuration import microsite
from edxmako import lookup_template
import edxmako.middleware
@@ -37,7 +37,7 @@ def marketing_link(name):
# link_map maps URLs from the marketing site to the old equivalent on
# the Django site
link_map = settings.MKTG_URL_LINK_MAP
- enable_mktg_site = MicrositeConfiguration.get_microsite_configuration_value(
+ enable_mktg_site = microsite.get_value(
'ENABLE_MKTG_SITE',
settings.FEATURES.get('ENABLE_MKTG_SITE', False)
)
@@ -80,7 +80,7 @@ def marketing_link_context_processor(request):
def render_to_string(template_name, dictionary, context=None, namespace='main'):
# see if there is an override template defined in the microsite
- template_name = MicrositeConfiguration.get_microsite_template_path(template_name)
+ template_name = microsite.get_template_path(template_name)
context_instance = Context(dictionary)
# add dictionary to context_instance
@@ -111,7 +111,7 @@ def render_to_response(template_name, dictionary=None, context_instance=None, na
"""
# see if there is an override template defined in the microsite
- template_name = MicrositeConfiguration.get_microsite_template_path(template_name)
+ template_name = microsite.get_template_path(template_name)
dictionary = dictionary or {}
return HttpResponse(render_to_string(template_name, dictionary, context_instance, namespace), **kwargs)
diff --git a/common/djangoapps/edxmako/startup.py b/common/djangoapps/edxmako/startup.py
index 1783373239..2ecc8b231e 100644
--- a/common/djangoapps/edxmako/startup.py
+++ b/common/djangoapps/edxmako/startup.py
@@ -8,6 +8,9 @@ from . import add_lookup
def run():
"""
Setup mako lookup directories.
+
+ IMPORTANT: This method can be called multiple times during application startup. Any changes to this method
+ must be safe for multiple callers during startup phase.
"""
template_locations = settings.MAKO_TEMPLATES
for namespace, directories in template_locations.items():
diff --git a/common/djangoapps/microsite_configuration/microsite.py b/common/djangoapps/microsite_configuration/microsite.py
new file mode 100644
index 0000000000..91f8eaffa1
--- /dev/null
+++ b/common/djangoapps/microsite_configuration/microsite.py
@@ -0,0 +1,142 @@
+"""
+This file implements the Microsite support for the Open edX platform.
+A microsite enables the following features:
+
+1) Mapping of sub-domain name to a 'brand', e.g. foo-university.edx.org
+2) Present a landing page with a listing of courses that are specific to the 'brand'
+3) Ability to swap out some branding elements in the website
+"""
+import threading
+import os.path
+
+from django.conf import settings
+
+CURRENT_REQUEST_CONFIGURATION = threading.local()
+CURRENT_REQUEST_CONFIGURATION.data = {}
+
+
+def has_configuration_set():
+ """
+ Returns whether there is any Microsite configuration settings
+ """
+ return getattr(settings, "MICROSITE_CONFIGURATION", False)
+
+
+def get_configuration():
+ """
+ Returns the current request's microsite configuration
+ """
+ if not hasattr(CURRENT_REQUEST_CONFIGURATION, 'data'):
+ return {}
+
+ return CURRENT_REQUEST_CONFIGURATION.data
+
+
+def is_request_in_microsite():
+ """
+ This will return if current request is a request within a microsite
+ """
+ return get_configuration()
+
+
+def get_value(val_name, default=None):
+ """
+ Returns a value associated with the request's microsite, if present
+ """
+ configuration = get_configuration()
+ return configuration.get(val_name, default)
+
+
+def get_template_path(relative_path):
+ """
+ Returns a path (string) to a Mako template, which can either be in
+ a microsite directory (as an override) or will just return what is passed in which is
+ expected to be a string
+ """
+
+ if not is_request_in_microsite():
+ return relative_path
+
+ microsite_template_path = str(get_value('template_dir'))
+
+ if microsite_template_path:
+ search_path = os.path.join(microsite_template_path, relative_path)
+
+ if os.path.isfile(search_path):
+ path = '{0}/templates/{1}'.format(
+ get_value('microsite_name'),
+ relative_path
+ )
+ return path
+
+ return relative_path
+
+
+def get_value_for_org(org, val_name, default=None):
+ """
+ This returns a configuration value for a microsite which has an org_filter that matches
+ what is passed in
+ """
+ if not has_configuration_set():
+ return default
+
+ for value in settings.MICROSITE_CONFIGURATION.values():
+ org_filter = value.get('course_org_filter', None)
+ if org_filter == org:
+ return value.get(val_name, default)
+ return default
+
+
+def get_all_orgs():
+ """
+ This returns a set of orgs that are considered within a microsite. This can be used,
+ for example, to do filtering
+ """
+ org_filter_set = set()
+ if not has_configuration_set():
+ return org_filter_set
+
+ for value in settings.MICROSITE_CONFIGURATION.values():
+ org_filter = value.get('course_org_filter')
+ if org_filter:
+ org_filter_set.add(org_filter)
+
+ return org_filter_set
+
+
+def clear():
+ """
+ Clears out any microsite configuration from the current request/thread
+ """
+ CURRENT_REQUEST_CONFIGURATION.data = {}
+
+
+def _set_current_microsite(microsite_config_key, subdomain, domain):
+ """
+ Helper internal method to actually put a microsite on the threadlocal
+ """
+ config = settings.MICROSITE_CONFIGURATION[microsite_config_key].copy()
+ config['subdomain'] = subdomain
+ config['site_domain'] = domain
+ CURRENT_REQUEST_CONFIGURATION.data = config
+
+
+def set_by_domain(domain):
+ """
+ For a given request domain, find a match in our microsite configuration and then assign
+ it to the thread local so that it is available throughout the entire
+ Django request processing
+ """
+ if not has_configuration_set() or not domain:
+ return
+
+ for key, value in settings.MICROSITE_CONFIGURATION.items():
+ subdomain = value.get('domain_prefix')
+ if subdomain and domain.startswith(subdomain):
+ _set_current_microsite(key, subdomain, domain)
+ return
+
+ # if no match on subdomain then see if there is a 'default' microsite defined
+ # if so, then use that
+ if 'default' in settings.MICROSITE_CONFIGURATION:
+ _set_current_microsite('default', subdomain, domain)
diff --git a/common/djangoapps/microsite_configuration/middleware.py b/common/djangoapps/microsite_configuration/middleware.py
index 61d2cd9883..f9e1e0ba15 100644
--- a/common/djangoapps/microsite_configuration/middleware.py
+++ b/common/djangoapps/microsite_configuration/middleware.py
@@ -1,183 +1,36 @@
"""
-This file implements the initial Microsite support for the Open edX platform.
+This file implements the Middleware support for the Open edX platform.
A microsite enables the following features:
1) Mapping of sub-domain name to a 'brand', e.g. foo-university.edx.org
2) Present a landing page with a listing of courses that are specific to the 'brand'
3) Ability to swap out some branding elements in the website
"""
-import threading
-import os.path
-
-from django.conf import settings
-
-_microsite_configuration_threadlocal = threading.local()
-_microsite_configuration_threadlocal.data = {}
+from microsite_configuration import microsite
-def has_microsite_configuration_set():
- """
- Returns whether the MICROSITE_CONFIGURATION has been set in the configuration files
- """
- return getattr(settings, "MICROSITE_CONFIGURATION", False)
-
-
-class MicrositeConfiguration(object):
+class MicrositeMiddleware(object):
"""
Middleware class which will bind configuration information regarding 'microsites' on a per request basis.
The actual configuration information is taken from Django settings information
"""
- @classmethod
- def is_request_in_microsite(cls):
- """
- This will return if current request is a request within a microsite
- """
- return cls.get_microsite_configuration()
-
- @classmethod
- def get_microsite_configuration(cls):
- """
- Returns the current request's microsite configuration
- """
- if not hasattr(_microsite_configuration_threadlocal, 'data'):
- return {}
-
- return _microsite_configuration_threadlocal.data
-
- @classmethod
- def get_microsite_configuration_value(cls, val_name, default=None):
- """
- Returns a value associated with the request's microsite, if present
- """
- configuration = cls.get_microsite_configuration()
- return configuration.get(val_name, default)
-
- @classmethod
- def get_microsite_template_path(cls, relative_path):
- """
- Returns a path to a Mako template, which can either be in
- a microsite directory (as an override) or will just return what is passed in
- """
-
- if not cls.is_request_in_microsite():
- return relative_path
-
- microsite_template_path = cls.get_microsite_configuration_value('template_dir')
-
- if microsite_template_path:
- search_path = microsite_template_path / relative_path
-
- if os.path.isfile(search_path):
- path = '{0}/templates/{1}'.format(
- cls.get_microsite_configuration_value('microsite_name'),
- relative_path
- )
- return path
-
- return relative_path
-
- @classmethod
- def get_microsite_configuration_value_for_org(cls, org, val_name, default=None):
- """
- This returns a configuration value for a microsite which has an org_filter that matches
- what is passed in
- """
- if not has_microsite_configuration_set():
- return default
-
- for key in settings.MICROSITE_CONFIGURATION.keys():
- org_filter = settings.MICROSITE_CONFIGURATION[key].get('course_org_filter', None)
- if org_filter == org:
- return settings.MICROSITE_CONFIGURATION[key].get(val_name, default)
- return default
-
- @classmethod
- def get_all_microsite_orgs(cls):
- """
- This returns a set of orgs that are considered within a Microsite. This can be used,
- for example, to do filtering
- """
- org_filter_set = []
- if not has_microsite_configuration_set():
- return org_filter_set
-
- for key in settings.MICROSITE_CONFIGURATION:
- org_filter = settings.MICROSITE_CONFIGURATION[key].get('course_org_filter')
- if org_filter:
- org_filter_set.append(org_filter)
-
- return org_filter_set
-
- def clear_microsite_configuration(self):
- """
- Clears out any microsite configuration from the current request/thread
- """
- _microsite_configuration_threadlocal.data = {}
-
def process_request(self, request):
"""
Middleware entry point on every request processing. This will associate a request's domain name
with a 'University' and any corresponding microsite configuration information
"""
- self.clear_microsite_configuration()
+ microsite.clear()
domain = request.META.get('HTTP_HOST', None)
- if domain:
- subdomain = MicrositeConfiguration.pick_subdomain(domain, settings.SUBDOMAIN_BRANDING.keys())
- university = MicrositeConfiguration.match_university(subdomain)
- microsite_configuration = self.get_microsite_configuration_for_university(university)
- if microsite_configuration:
- microsite_configuration['university'] = university
- microsite_configuration['subdomain'] = subdomain
- microsite_configuration['site_domain'] = domain
- _microsite_configuration_threadlocal.data = microsite_configuration
+ microsite.set_by_domain(domain)
- # also put the configuration on the request itself to make it easier to dereference
- request.microsite_configuration = _microsite_configuration_threadlocal.data
return None
def process_response(self, request, response):
"""
Middleware entry point for request completion.
"""
- self.clear_microsite_configuration()
+ microsite.clear()
return response
-
- def get_microsite_configuration_for_university(self, university):
- """
- For a given university, return the microsite configuration which
- is in the Django settings
- """
- if not university:
- return None
-
- if not has_microsite_configuration_set():
- return None
-
- configuration = settings.MICROSITE_CONFIGURATION.get(university, None)
- return configuration
-
- @classmethod
- def match_university(cls, domain):
- """
- Return the university name specified for the domain, or None
- if no university was specified
- """
- if not settings.FEATURES['SUBDOMAIN_BRANDING'] or domain is None:
- return None
-
- subdomain = cls.pick_subdomain(domain, settings.SUBDOMAIN_BRANDING.keys())
- return settings.SUBDOMAIN_BRANDING.get(subdomain)
-
- @classmethod
- def pick_subdomain(cls, domain, options, default='default'):
- """
- Attempt to match the incoming request's HOST domain with a configuration map
- to see what subdomains are supported in Microsites.
- """
- for option in options:
- if domain.startswith(option):
- return option
- return default
diff --git a/common/djangoapps/microsite_configuration/templatetags/microsite.py b/common/djangoapps/microsite_configuration/templatetags/microsite.py
index 5e76c152a9..3b21dec7df 100644
--- a/common/djangoapps/microsite_configuration/templatetags/microsite.py
+++ b/common/djangoapps/microsite_configuration/templatetags/microsite.py
@@ -4,7 +4,7 @@ based on the current micro site.
"""
from django import template
from django.conf import settings
-from microsite_configuration.middleware import MicrositeConfiguration
+from microsite_configuration import microsite
register = template.Library()
@@ -37,4 +37,4 @@ def platform_name():
Django template tag that outputs the current platform name:
{% platform_name %}
"""
- return MicrositeConfiguration.get_microsite_configuration_value('platform_name', settings.PLATFORM_NAME)
+ return microsite.get_value('platform_name', settings.PLATFORM_NAME)
diff --git a/common/djangoapps/microsite_configuration/tests/__init__.py b/common/djangoapps/microsite_configuration/tests/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/common/djangoapps/microsite_configuration/tests/test_logic.py b/common/djangoapps/microsite_configuration/tests/test_logic.py
new file mode 100644
index 0000000000..2d0ad93fcb
--- /dev/null
+++ b/common/djangoapps/microsite_configuration/tests/test_logic.py
@@ -0,0 +1,26 @@
+"""
+Some additional unit tests for Microsite logic. The LMS covers some of the Microsite testing, this adds
+some additional coverage
+"""
+import django.test
+
+from microsite_configuration.microsite import get_value_for_org
+
+
+class TestMicrosites(django.test.TestCase):
+ """
+ Run through some Microsite logic
+ """
+
+ def test_get_value_for_org(self):
+ """
+ Make sure we can do lookups on Microsite configuration based on ORG fields
+ """
+
+ # first make sure default value is returned if there's no Microsite ORG match
+ value = get_value_for_org("BogusX", "university", "default_value")
+ self.assertEquals(value, "default_value")
+
+ # now test when we call in a value Microsite ORG, note this is defined in test.py configuration
+ value = get_value_for_org("TestMicrositeX", "university", "default_value")
+ self.assertEquals(value, "test_microsite")
diff --git a/common/djangoapps/microsite_configuration/test_microsites.py b/common/djangoapps/microsite_configuration/tests/test_microsites.py
similarity index 89%
rename from common/djangoapps/microsite_configuration/test_microsites.py
rename to common/djangoapps/microsite_configuration/tests/test_microsites.py
index b3bb21990a..01cf04aa8a 100644
--- a/common/djangoapps/microsite_configuration/test_microsites.py
+++ b/common/djangoapps/microsite_configuration/tests/test_microsites.py
@@ -4,10 +4,13 @@ Tests microsite_configuration templatetags and helper functions.
"""
from django.test import TestCase
from django.conf import settings
-from .templatetags import microsite
+from microsite_configuration.templatetags import microsite
class MicroSiteTests(TestCase):
+ """
+ Make sure some of the helper functions work
+ """
def test_breadcrumbs(self):
crumbs = ['my', 'less specific', 'Page']
expected = u'my | less specific | Page | edX'
@@ -23,10 +26,9 @@ class MicroSiteTests(TestCase):
def test_platform_name(self):
pname = microsite.platform_name()
self.assertEqual(pname, settings.PLATFORM_NAME)
-
+
def test_breadcrumb_tag(self):
crumbs = ['my', 'less specific', 'Page']
expected = u'my | less specific | Page | edX'
title = microsite.page_title_breadcrumbs_tag(None, *crumbs)
self.assertEqual(expected, title)
-
\ No newline at end of file
diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py
index 453ea03ca3..2c802d3f4f 100644
--- a/common/djangoapps/student/views.py
+++ b/common/djangoapps/student/views.py
@@ -74,7 +74,7 @@ from dogapi import dog_stats_api
from util.json_request import JsonResponse
from util.bad_request_rate_limiter import BadRequestRateLimiter
-from microsite_configuration.middleware import MicrositeConfiguration
+from microsite_configuration import microsite
from util.password_policy_validators import (
validate_password_length, validate_password_complexity,
@@ -350,7 +350,7 @@ def signin_user(request):
context = {
'course_id': request.GET.get('course_id'),
'enrollment_action': request.GET.get('enrollment_action'),
- 'platform_name': MicrositeConfiguration.get_microsite_configuration_value(
+ 'platform_name': microsite.get_value(
'platform_name',
settings.PLATFORM_NAME
),
@@ -373,7 +373,7 @@ def register_user(request, extra_context=None):
context = {
'course_id': request.GET.get('course_id'),
'enrollment_action': request.GET.get('enrollment_action'),
- 'platform_name': MicrositeConfiguration.get_microsite_configuration_value(
+ 'platform_name': microsite.get_value(
'platform_name',
settings.PLATFORM_NAME
),
@@ -416,11 +416,11 @@ def dashboard(request):
# for microsites, we want to filter and only show enrollments for courses within
# the microsites 'ORG'
- course_org_filter = MicrositeConfiguration.get_microsite_configuration_value('course_org_filter')
+ course_org_filter = microsite.get_value('course_org_filter')
# Let's filter out any courses in an "org" that has been declared to be
# in a Microsite
- org_filter_out_set = MicrositeConfiguration.get_all_microsite_orgs()
+ org_filter_out_set = microsite.get_all_orgs()
# remove our current Microsite from the "filter out" list, if applicable
if course_org_filter:
@@ -1160,7 +1160,7 @@ def create_account(request, post_override=None):
# don't send email if we are doing load testing or random user generation for some reason
if not (settings.FEATURES.get('AUTOMATIC_AUTH_FOR_TESTING')):
- from_address = MicrositeConfiguration.get_microsite_configuration_value(
+ from_address = microsite.get_value(
'email_from_address',
settings.DEFAULT_FROM_EMAIL
)
@@ -1502,7 +1502,7 @@ def change_email_request(request):
message = render_to_string('emails/email_change.txt', context)
- from_address = MicrositeConfiguration.get_microsite_configuration_value(
+ from_address = microsite.get_value(
'email_from_address',
settings.DEFAULT_FROM_EMAIL
)
diff --git a/common/djangoapps/util/request.py b/common/djangoapps/util/request.py
index a26059e8a7..813a3347d3 100644
--- a/common/djangoapps/util/request.py
+++ b/common/djangoapps/util/request.py
@@ -2,7 +2,7 @@
import re
from django.conf import settings
-from microsite_configuration.middleware import MicrositeConfiguration
+from microsite_configuration import microsite
COURSE_REGEX = re.compile(r'^.*?/courses/(?P[^/]+/[^/]+/[^/]+)')
@@ -19,7 +19,7 @@ def safe_get_host(request):
if isinstance(settings.ALLOWED_HOSTS, (list, tuple)) and '*' not in settings.ALLOWED_HOSTS:
return request.get_host()
else:
- return MicrositeConfiguration.get_microsite_configuration_value('site_domain', settings.SITE_NAME)
+ return microsite.get_value('site_domain', settings.SITE_NAME)
def course_id_from_url(url):
diff --git a/common/test/test_microsites/default/readme.txt b/common/test/test_microsites/default/readme.txt
new file mode 100644
index 0000000000..6515cbfb96
--- /dev/null
+++ b/common/test/test_microsites/default/readme.txt
@@ -0,0 +1,3 @@
+This directory is intentionally empty.
+
+We need to have a directory on disk for the corresponding Microsite configuration to be considered 'valid'. Therefore to execute some 'default' use-cases, we have this empty directory.
diff --git a/common/test/test_microsites/test_microsite/templates/footer.html b/common/test/test_microsites/test_microsite/templates/footer.html
index bb7dd0de28..de7e55e47c 100644
--- a/common/test/test_microsites/test_microsite/templates/footer.html
+++ b/common/test/test_microsites/test_microsite/templates/footer.html
@@ -1,7 +1,7 @@
## mako
<%! from django.core.urlresolvers import reverse %>
<%! from django.utils.translation import ugettext as _ %>
-<%! from microsite_configuration.middleware import MicrositeConfiguration %>
+<%! from microsite_configuration import microsite %>
<%namespace name='static' file='static_content.html'/>
diff --git a/lms/djangoapps/branding/__init__.py b/lms/djangoapps/branding/__init__.py
index 51645b824f..b6a0f3c11e 100644
--- a/lms/djangoapps/branding/__init__.py
+++ b/lms/djangoapps/branding/__init__.py
@@ -2,7 +2,7 @@ from xmodule.modulestore.django import modulestore
from xmodule.course_module import CourseDescriptor
from django.conf import settings
-from microsite_configuration.middleware import MicrositeConfiguration
+from microsite_configuration import microsite
def get_visible_courses():
@@ -15,7 +15,7 @@ def get_visible_courses():
if isinstance(c, CourseDescriptor)]
courses = sorted(courses, key=lambda course: course.number)
- subdomain = MicrositeConfiguration.get_microsite_configuration_value('subdomain', 'default')
+ subdomain = microsite.get_value('subdomain', 'default')
# See if we have filtered course listings in this domain
filtered_visible_ids = None
@@ -24,7 +24,7 @@ def get_visible_courses():
if hasattr(settings, 'COURSE_LISTINGS') and subdomain in settings.COURSE_LISTINGS and not settings.DEBUG:
filtered_visible_ids = frozenset(settings.COURSE_LISTINGS[subdomain])
- filtered_by_org = MicrositeConfiguration.get_microsite_configuration_value('course_org_filter')
+ filtered_by_org = microsite.get_value('course_org_filter')
if filtered_by_org:
return [course for course in courses if course.location.org == filtered_by_org]
@@ -33,7 +33,7 @@ def get_visible_courses():
else:
# Let's filter out any courses in an "org" that has been declared to be
# in a Microsite
- org_filter_out_set = MicrositeConfiguration.get_all_microsite_orgs()
+ org_filter_out_set = microsite.get_all_orgs()
return [course for course in courses if course.location.org not in org_filter_out_set]
@@ -42,7 +42,7 @@ def get_university_for_request():
Return the university name specified for the domain, or None
if no university was specified
"""
- return MicrositeConfiguration.get_microsite_configuration_value('university')
+ return microsite.get_value('university')
def get_logo_url():
@@ -52,7 +52,7 @@ def get_logo_url():
# if the MicrositeConfiguration has a value for the logo_image_url
# let's use that
- image_url = MicrositeConfiguration.get_microsite_configuration_value('logo_image_url')
+ image_url = microsite.get_value('logo_image_url')
if image_url:
return '{static_url}{image_url}'.format(
static_url=settings.STATIC_URL,
@@ -60,7 +60,7 @@ def get_logo_url():
)
# otherwise, use the legacy means to configure this
- university = MicrositeConfiguration.get_microsite_configuration_value('university')
+ university = microsite.get_value('university')
if university is None:
return '{static_url}images/header-logo.png'.format(
diff --git a/lms/djangoapps/branding/views.py b/lms/djangoapps/branding/views.py
index be2c975087..06939e04cc 100644
--- a/lms/djangoapps/branding/views.py
+++ b/lms/djangoapps/branding/views.py
@@ -8,7 +8,7 @@ from edxmako.shortcuts import render_to_response
import student.views
import courseware.views
-from microsite_configuration.middleware import MicrositeConfiguration
+from microsite_configuration import microsite
from edxmako.shortcuts import marketing_link
from util.cache import cache_if_anonymous
@@ -27,7 +27,7 @@ def index(request):
from external_auth.views import ssl_login
return ssl_login(request)
- enable_mktg_site = MicrositeConfiguration.get_microsite_configuration_value(
+ enable_mktg_site = microsite.get_value(
'ENABLE_MKTG_SITE',
settings.FEATURES.get('ENABLE_MKTG_SITE', False)
)
@@ -35,11 +35,11 @@ def index(request):
if enable_mktg_site:
return redirect(settings.MKTG_URLS.get('ROOT'))
- university = MicrositeConfiguration.match_university(request.META.get('HTTP_HOST'))
+ domain = request.META.get('HTTP_HOST')
# keep specialized logic for Edge until we can migrate over Edge to fully use
# microsite definitions
- if university == 'edge':
+ if domain and 'edge.edx.org' in domain:
context = {
'suppress_toplevel_navigation': True
}
@@ -59,7 +59,7 @@ def courses(request):
to that. Otherwise, if subdomain branding is on, this is the university
profile page. Otherwise, it's the edX courseware.views.courses page
"""
- enable_mktg_site = MicrositeConfiguration.get_microsite_configuration_value(
+ enable_mktg_site = microsite.get_value(
'ENABLE_MKTG_SITE',
settings.FEATURES.get('ENABLE_MKTG_SITE', False)
)
diff --git a/lms/djangoapps/courseware/tests/test_microsites.py b/lms/djangoapps/courseware/tests/test_microsites.py
index 4293e2bc8e..52105f33d8 100644
--- a/lms/djangoapps/courseware/tests/test_microsites.py
+++ b/lms/djangoapps/courseware/tests/test_microsites.py
@@ -70,7 +70,7 @@ class TestMicrosites(ModuleStoreTestCase, LoginEnrollmentTestCase):
self.assertContains(resp, 'This is a Test Microsite Overlay') # Overlay test message
self.assertContains(resp, 'test_microsite/images/header-logo.png') # logo swap
- self.assertContains(resp, 'test_microsite/css/test_microsite.css') # css override
+ self.assertContains(resp, 'test_microsite/css/test_microsite') # css override
self.assertContains(resp, 'Test Microsite') # page title
# assert that test course display name is visible
@@ -101,7 +101,7 @@ class TestMicrosites(ModuleStoreTestCase, LoginEnrollmentTestCase):
self.assertNotContains(resp, 'This is a Test Microsite Overlay') # Overlay test message
self.assertNotContains(resp, 'test_microsite/images/header-logo.png') # logo swap
- self.assertNotContains(resp, 'test_microsite/css/test_microsite.css') # css override
+ self.assertNotContains(resp, 'test_microsite/css/test_microsite') # css override
self.assertNotContains(resp, 'Test Microsite') # page title
# assert that test course display name IS NOT VISIBLE, since that is a Microsite only course
diff --git a/lms/djangoapps/courseware/views.py b/lms/djangoapps/courseware/views.py
index dd64db6516..41ef619ebd 100644
--- a/lms/djangoapps/courseware/views.py
+++ b/lms/djangoapps/courseware/views.py
@@ -38,7 +38,7 @@ from xmodule.modulestore.search import path_to_location
from xmodule.course_module import CourseDescriptor
import shoppingcart
-from microsite_configuration.middleware import MicrositeConfiguration
+from microsite_configuration import microsite
log = logging.getLogger("edx.courseware")
@@ -528,7 +528,7 @@ def registered_for_course(course, user):
@cache_if_anonymous
def course_about(request, course_id):
- if MicrositeConfiguration.get_microsite_configuration_value(
+ if microsite.get_value(
'ENABLE_MKTG_SITE',
settings.FEATURES.get('ENABLE_MKTG_SITE', False)
):
diff --git a/lms/djangoapps/instructor/enrollment.py b/lms/djangoapps/instructor/enrollment.py
index 5042f6996d..e301a41630 100644
--- a/lms/djangoapps/instructor/enrollment.py
+++ b/lms/djangoapps/instructor/enrollment.py
@@ -14,7 +14,7 @@ from student.models import CourseEnrollment, CourseEnrollmentAllowed
from courseware.models import StudentModule
from edxmako.shortcuts import render_to_string
-from microsite_configuration.middleware import MicrositeConfiguration
+from microsite_configuration import microsite
# For determining if a shibboleth course
SHIBBOLETH_DOMAIN_PREFIX = 'shib:'
@@ -229,7 +229,7 @@ def send_mail_to_student(student, param_dict):
if 'course' in param_dict:
param_dict['course_name'] = param_dict['course'].display_name_with_default
- param_dict['site_name'] = MicrositeConfiguration.get_microsite_configuration_value(
+ param_dict['site_name'] = microsite.get_value(
'SITE_NAME',
param_dict['site_name']
)
@@ -271,7 +271,7 @@ def send_mail_to_student(student, param_dict):
# Email subject *must not* contain newlines
subject = ''.join(subject.splitlines())
- from_address = MicrositeConfiguration.get_microsite_configuration_value(
+ from_address = microsite.get_value(
'email_from_address',
settings.DEFAULT_FROM_EMAIL
)
diff --git a/lms/djangoapps/instructor/views/legacy.py b/lms/djangoapps/instructor/views/legacy.py
index 2b6daf349b..ba013b1067 100644
--- a/lms/djangoapps/instructor/views/legacy.py
+++ b/lms/djangoapps/instructor/views/legacy.py
@@ -62,7 +62,7 @@ from xblock.field_data import DictFieldData
from xblock.fields import ScopeIds
from django.utils.translation import ugettext as _u
-from microsite_configuration.middleware import MicrositeConfiguration
+from microsite_configuration import microsite
log = logging.getLogger(__name__)
@@ -1295,7 +1295,7 @@ def _do_enroll_students(course, course_id, students, overload=False, auto_enroll
ceaset.delete()
if email_students:
- stripped_site_name = MicrositeConfiguration.get_microsite_configuration_value(
+ stripped_site_name = microsite.get_value(
'SITE_NAME',
settings.SITE_NAME
)
@@ -1389,7 +1389,7 @@ def _do_unenroll_students(course_id, students, email_students=False):
old_students, _ = get_and_clean_student_list(students)
status = dict([x, 'unprocessed'] for x in old_students)
- stripped_site_name = MicrositeConfiguration.get_microsite_configuration_value(
+ stripped_site_name = microsite.get_value(
'SITE_NAME',
settings.SITE_NAME
)
@@ -1469,7 +1469,7 @@ def send_mail_to_student(student, param_dict):
# add some helpers and microconfig subsitutions
if 'course' in param_dict:
param_dict['course_name'] = param_dict['course'].display_name_with_default
- param_dict['site_name'] = MicrositeConfiguration.get_microsite_configuration_value(
+ param_dict['site_name'] = microsite.get_value(
'SITE_NAME',
param_dict.get('site_name', '')
)
@@ -1497,7 +1497,7 @@ def send_mail_to_student(student, param_dict):
# Email subject *must not* contain newlines
subject = ''.join(subject.splitlines())
- from_address = MicrositeConfiguration.get_microsite_configuration_value(
+ from_address = microsite.get_value(
'email_from_address',
settings.DEFAULT_FROM_EMAIL
)
diff --git a/lms/djangoapps/shoppingcart/models.py b/lms/djangoapps/shoppingcart/models.py
index 5c98a36feb..42c25e0750 100644
--- a/lms/djangoapps/shoppingcart/models.py
+++ b/lms/djangoapps/shoppingcart/models.py
@@ -35,7 +35,7 @@ from verify_student.models import SoftwareSecurePhotoVerification
from .exceptions import (InvalidCartItem, PurchasedCallbackException, ItemAlreadyInCartException,
AlreadyEnrolledInCourseException, CourseDoesNotExistException)
-from microsite_configuration.middleware import MicrositeConfiguration
+from microsite_configuration import microsite
log = logging.getLogger("shoppingcart")
@@ -175,7 +175,7 @@ class Order(models.Model):
}
)
try:
- from_address = MicrositeConfiguration.get_microsite_configuration_value(
+ from_address = microsite.get_value(
'email_from_address',
settings.DEFAULT_FROM_EMAIL
)
@@ -477,7 +477,7 @@ class CertificateItem(OrderItem):
user_email=course_enrollment.user.email,
order_number=order_number)
to_email = [settings.PAYMENT_SUPPORT_EMAIL]
- from_email = [MicrositeConfiguration.get_microsite_configuration_value(
+ from_email = [microsite.get_value(
'payment_support_email',
settings.PAYMENT_SUPPORT_EMAIL
)]
diff --git a/lms/envs/aws.py b/lms/envs/aws.py
index 720d418c7e..ee424f84cc 100644
--- a/lms/envs/aws.py
+++ b/lms/envs/aws.py
@@ -356,14 +356,7 @@ MAX_FAILED_LOGIN_ATTEMPTS_ALLOWED = ENV_TOKENS.get("MAX_FAILED_LOGIN_ATTEMPTS_AL
MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS = ENV_TOKENS.get("MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS", 15 * 60)
MICROSITE_CONFIGURATION = ENV_TOKENS.get('MICROSITE_CONFIGURATION', {})
-MICROSITE_ROOT_DIR = ENV_TOKENS.get('MICROSITE_ROOT_DIR')
-if MICROSITE_CONFIGURATION:
- enable_microsites(
- MICROSITE_CONFIGURATION,
- SUBDOMAIN_BRANDING,
- VIRTUAL_UNIVERSITIES,
- microsites_root=path(MICROSITE_ROOT_DIR)
- )
+MICROSITE_ROOT_DIR = path(ENV_TOKENS.get('MICROSITE_ROOT_DIR', ''))
#### PASSWORD POLICY SETTINGS #####
PASSWORD_MIN_LENGTH = ENV_TOKENS.get("PASSWORD_MIN_LENGTH")
diff --git a/lms/envs/cms/microsite_test.py b/lms/envs/cms/microsite_test.py
index 700e7c6c16..09ea6aa3dd 100644
--- a/lms/envs/cms/microsite_test.py
+++ b/lms/envs/cms/microsite_test.py
@@ -6,7 +6,7 @@ This is a localdev test for the Microsite processing pipeline
# pylint: disable=W0401, W0614
from .dev import *
-from .dev import SUBDOMAIN_BRANDING, VIRTUAL_UNIVERSITIES
+from ..dev import ENV_ROOT, FEATURES
MICROSITE_CONFIGURATION = {
@@ -30,13 +30,9 @@ MICROSITE_CONFIGURATION = {
}
}
-if len(MICROSITE_CONFIGURATION.keys()) > 0:
- enable_microsites(
- MICROSITE_CONFIGURATION,
- SUBDOMAIN_BRANDING,
- VIRTUAL_UNIVERSITIES
- )
+MICROSITE_ROOT_DIR = ENV_ROOT / 'edx-microsite'
# pretend we are behind some marketing site, we want to be able to assert that the Microsite config values override
# this global setting
FEATURES['ENABLE_MKTG_SITE'] = True
+FEATURES['USE_MICROSITES'] = True
diff --git a/lms/envs/common.py b/lms/envs/common.py
index fd8172d4fe..cf6107f17c 100644
--- a/lms/envs/common.py
+++ b/lms/envs/common.py
@@ -229,6 +229,9 @@ FEATURES = {
# 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
'ALLOW_WIKI_ROOT_ACCESS': True,
+
+ # Turn on/off Microsites feature
+ 'USE_MICROSITES': False,
}
# Used for A/B testing
@@ -693,7 +696,7 @@ TEMPLATE_LOADERS = (
MIDDLEWARE_CLASSES = (
'request_cache.middleware.RequestCache',
- 'microsite_configuration.middleware.MicrositeConfiguration',
+ 'microsite_configuration.middleware.MicrositeMiddleware',
'django_comment_client.middleware.AjaxExceptionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
@@ -1183,64 +1186,6 @@ MKTG_URL_LINK_MAP = {
}
-############################### MICROSITES ################################
-def enable_microsites(microsite_config_dict, subdomain_branding, virtual_universities, microsites_root=ENV_ROOT / "microsites"):
- """
- Enable the use of microsites, which are websites that allow
- for subdomains for the edX platform, e.g. foo.edx.org
- """
-
- if not microsite_config_dict:
- return
-
- FEATURES['USE_MICROSITES'] = True
-
- for microsite_name in microsite_config_dict.keys():
- # Calculate the location of the microsite's files
- microsite_root = microsites_root / microsite_name
- microsite_config = microsite_config_dict[microsite_name]
-
- # pull in configuration information from each
- # microsite root
-
- if os.path.isdir(microsite_root):
- # store the path on disk for later use
- microsite_config['microsite_root'] = microsite_root
-
- # get the domain that this should reside
- domain = microsite_config['domain_prefix']
-
- # get the virtual university that this should use
- university = microsite_config['university']
-
- # add to the existing maps in our settings
- subdomain_branding[domain] = university
- virtual_universities.append(university)
-
- template_dir = microsite_root / 'templates'
- microsite_config['template_dir'] = template_dir
-
- microsite_config['microsite_name'] = microsite_name
-
- else:
- # not sure if we have application logging at this stage of
- # startup
- print '**** Error loading microsite {0}. Directory does not exist'.format(microsite_root)
- # remove from our configuration as it is not valid
- del microsite_config_dict[microsite_name]
-
- # if we have microsites, then let's turn on SUBDOMAIN_BRANDING
- # Note check size of the dict because some microsites might not be found on disk and
- # we could be left with none
- if microsite_config_dict:
- FEATURES['SUBDOMAIN_BRANDING'] = True
-
- TEMPLATE_DIRS.append(microsites_root)
- MAKO_TEMPLATES['main'].append(microsites_root)
-
- STATICFILES_DIRS.append(microsites_root)
-
-
################# Student Verification #################
VERIFY_STUDENT = {
"DAYS_GOOD_FOR": 365, # How many days is a verficiation good for?
diff --git a/lms/envs/test.py b/lms/envs/test.py
index f72609050b..8c9b8a7ce6 100644
--- a/lms/envs/test.py
+++ b/lms/envs/test.py
@@ -299,16 +299,14 @@ MICROSITE_CONFIGURATION = {
"course_index_overlay_text": "This is a Test Microsite Overlay Text.",
"course_index_overlay_logo_file": "test_microsite/images/header-logo.png",
"homepage_overlay_html": "This is a Test Microsite Overlay HTML
"
+ },
+ "default": {
+ "university": "default_university",
+ "domain_prefix": "www",
}
}
-
-if len(MICROSITE_CONFIGURATION.keys()) > 0:
- enable_microsites(
- MICROSITE_CONFIGURATION,
- SUBDOMAIN_BRANDING,
- VIRTUAL_UNIVERSITIES,
- microsites_root=COMMON_ROOT / "test" / 'test_microsites'
- )
+MICROSITE_ROOT_DIR = COMMON_ROOT / 'test' / 'test_microsites'
+FEATURES['USE_MICROSITES'] = True
######### LinkedIn ########
LINKEDIN_API['COMPANY_ID'] = '0000000'
diff --git a/lms/startup.py b/lms/startup.py
index 7bf9cf7481..1c8cdc8ef7 100644
--- a/lms/startup.py
+++ b/lms/startup.py
@@ -9,6 +9,9 @@ settings.INSTALLED_APPS # pylint: disable=W0104
from django_startup import autostartup
import edxmako
+import logging
+
+log = logging.getLogger(__name__)
def run():
@@ -20,6 +23,9 @@ def run():
if settings.FEATURES.get('USE_CUSTOM_THEME', False):
enable_theme()
+ if settings.FEATURES.get('USE_MICROSITES', False):
+ enable_microsites()
+
def enable_theme():
"""
@@ -51,3 +57,45 @@ def enable_theme():
settings.STATICFILES_DIRS.append(
(u'themes/{}'.format(settings.THEME_NAME), theme_root / 'static')
)
+
+
+def enable_microsites():
+ """
+ Enable the use of microsites, which are websites that allow
+ for subdomains for the edX platform, e.g. foo.edx.org
+ """
+
+ microsites_root = settings.MICROSITE_ROOT_DIR
+ microsite_config_dict = settings.MICROSITE_CONFIGURATION
+
+ for ms_name, ms_config in microsite_config_dict.items():
+ # Calculate the location of the microsite's files
+ ms_root = microsites_root / ms_name
+ ms_config = microsite_config_dict[ms_name]
+
+ # pull in configuration information from each
+ # microsite root
+
+ if ms_root.isdir():
+ # store the path on disk for later use
+ ms_config['microsite_root'] = ms_root
+
+ template_dir = ms_root / 'templates'
+ ms_config['template_dir'] = template_dir
+
+ ms_config['microsite_name'] = ms_name
+ log.info('Loading microsite {0}'.format(ms_root))
+ else:
+ # not sure if we have application logging at this stage of
+ # startup
+ log.error('Error loading microsite {0}. Directory does not exist'.format(ms_root))
+ # remove from our configuration as it is not valid
+ del microsite_config_dict[ms_name]
+
+ # if we have any valid microsites defined, let's wire in the Mako and STATIC_FILES search paths
+ if microsite_config_dict:
+ settings.TEMPLATE_DIRS.append(microsites_root)
+ settings.MAKO_TEMPLATES['main'].append(microsites_root)
+ edxmako.startup.run()
+
+ settings.STATICFILES_DIRS.insert(0, microsites_root)
diff --git a/lms/templates/courseware/course_about.html b/lms/templates/courseware/course_about.html
index fe1af720e7..8023c6734b 100644
--- a/lms/templates/courseware/course_about.html
+++ b/lms/templates/courseware/course_about.html
@@ -12,7 +12,7 @@
cart_link = ""
%>
<%namespace name='static' file='../static_content.html'/>
-<%! from microsite_configuration.middleware import MicrositeConfiguration %>
+<%! from microsite_configuration import microsite %>
<%inherit file="../main.html" />
@@ -20,13 +20,15 @@
<%
if self.theme_enabled():
- google_analytics_file = u'../' + MicrositeConfiguration.get_microsite_configuration_value('google_analytics_file', 'theme-google-analytics.html')
+ google_analytics_file = u'../{ga}'.format(
+ ga=microsite.get_value('google_analytics_file', 'theme-google-analytics.html')
+ )
else:
google_analytics_file = '../google_analytics.html'
%>
<%include file="${google_analytics_file}" />
-
+
## OG (Open Graph) title and description added below to give social media info to display
## (https://developers.facebook.com/docs/opengraph/howtos/maximizing-distribution-media-content#tags)
@@ -141,7 +143,7 @@
%endif
${_("You are registered for this course")}
-
+
%if show_courseware_link:
${_("View Courseware")}
@@ -169,7 +171,7 @@
% elif is_course_full:
${_("Course is full")}
-
+
%else:
${_("Register for {course.display_number_with_default}").format(course=course) | h}
@@ -216,7 +218,7 @@