fix errorenous logic when running a microsite that could reside in a hosting environment with a marketing site in front of it pep8/pylint fixes address PR feedback, remove underscore from test hostname more pep8/pylint cleanup. Skip test_microsites test, it works on localdev, not on Jenkins. Need to talk with QA team manually add Ned's single-to-double quote fix change aws.py runtimes so that the microsite_dir that is read from configuration is changed to a python path Conflicts: lms/templates/help_modal.html
184 lines
6.4 KiB
Python
184 lines
6.4 KiB
Python
"""
|
|
This file implements the initial 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
|
|
|
|
_microsite_configuration_threadlocal = threading.local()
|
|
_microsite_configuration_threadlocal.data = {}
|
|
|
|
|
|
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):
|
|
"""
|
|
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()
|
|
|
|
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
|
|
|
|
# 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()
|
|
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
|