Files
edx-platform/common/djangoapps/microsite_configuration/middleware.py
Chris Dodge a3211a7405 Introduction of the Microsite feature which allows for limited multi-tenant branding on a subdomain basis, e.g. foo.edx.org and bar.edx.org
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
2014-01-14 14:36:01 -05:00

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