Make comprehensive theme work with django templates.

Comprehensive theming did not work with django templates (used by course wiki).

The reason it didn't work was that in order for the theme to work, theme template folder
has to be added to django template dirs setting *before* django startup.
After django startup, modifying `settings.DEFAULT_TEMPLATE_ENGINE['DIRS']` has no effect,
because at that point the template engine is already initialized with a copy of the
template dirs list.

Instead of running the theme startup code as an autostartup hook, we manually run it
*before* `django.setup()`. This is fine because theme startup code doesn't have to do
anything else besides modifying some settings and doesn't actually need django to be
initialized.
This commit is contained in:
Matjaz Gregoric
2016-01-24 19:28:30 +01:00
parent 8c26178df3
commit 9b89bd3245
6 changed files with 72 additions and 26 deletions

View File

@@ -14,6 +14,8 @@ from monkey_patch import third_party_auth
import xmodule.x_module
import cms.lib.xblock.runtime
from openedx.core.djangoapps.theming.core import enable_comprehensive_theme
def run():
"""
@@ -21,6 +23,11 @@ def run():
"""
third_party_auth.patch()
# Comprehensive theming needs to be set up before django startup,
# because modifying django template paths after startup has no effect.
if settings.COMPREHENSIVE_THEME_DIR:
enable_comprehensive_theme(settings.COMPREHENSIVE_THEME_DIR)
django.setup()
autostartup()

View File

@@ -0,0 +1,45 @@
"""
Tests for wiki middleware.
"""
from django.conf import settings
from django.test.client import Client
from nose.plugins.attrib import attr
from wiki.models import URLPath
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
from openedx.core.djangoapps.theming.test_util import with_comprehensive_theme
from courseware.tests.factories import InstructorFactory
from course_wiki.views import get_or_create_root
@attr('shard_1')
class TestComprehensiveTheming(ModuleStoreTestCase):
"""Tests for comprehensive theming of wiki pages."""
def setUp(self):
"""Test setup."""
super(TestComprehensiveTheming, self).setUp()
self.wiki = get_or_create_root()
self.course_math101 = CourseFactory.create(org='edx', number='math101', display_name='2014',
metadata={'use_unique_wiki_id': 'false'})
self.course_math101_instructor = InstructorFactory(course_key=self.course_math101.id, username='instructor',
password='secret')
self.wiki_math101 = URLPath.create_article(self.wiki, 'math101', title='math101')
self.client = Client()
self.client.login(username='instructor', password='secret')
@with_comprehensive_theme(settings.REPO_ROOT / 'themes/red-theme')
def test_themed_footer(self):
"""
Tests that theme footer is used rather than standard
footer when comprehensive theme is enabled.
"""
response = self.client.get('/courses/edx/math101/2014/wiki/math101/')
self.assertEqual(response.status_code, 200)
# This string comes from themes/red-theme/lms/templates/footer.html
self.assertContains(response, "super-ugly")

View File

@@ -18,6 +18,7 @@ from monkey_patch import third_party_auth
import xmodule.x_module
import lms_xblock.runtime
from openedx.core.djangoapps.theming.core import enable_comprehensive_theme
from microsite_configuration import microsite
log = logging.getLogger(__name__)
@@ -33,6 +34,11 @@ def run():
if settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH', False):
enable_third_party_auth()
# Comprehensive theming needs to be set up before django startup,
# because modifying django template paths after startup has no effect.
if settings.COMPREHENSIVE_THEME_DIR:
enable_comprehensive_theme(settings.COMPREHENSIVE_THEME_DIR)
# We currently use 2 template rendering engines, mako and django_templates,
# and one of them (django templates), requires the directories be added
# before the django.setup().

View File

@@ -5,8 +5,6 @@ from path import Path
from django.conf import settings
import edxmako
def comprehensive_theme_changes(theme_dir):
"""
@@ -20,14 +18,14 @@ def comprehensive_theme_changes(theme_dir):
* 'settings': a dictionary of settings names and their new values.
* 'mako_paths': a list of directories to prepend to the edxmako
template lookup path.
* 'template_paths': a list of directories to prepend to template
lookup path.
"""
changes = {
'settings': {},
'mako_paths': [],
'template_paths': [],
}
root = Path(settings.PROJECT_ROOT)
if root.name == "":
@@ -37,8 +35,7 @@ def comprehensive_theme_changes(theme_dir):
templates_dir = component_dir / "templates"
if templates_dir.isdir():
changes['settings']['TEMPLATE_DIRS'] = [templates_dir] + settings.DEFAULT_TEMPLATE_ENGINE['DIRS']
changes['mako_paths'].append(templates_dir)
changes['template_paths'].append(templates_dir)
staticfiles_dir = component_dir / "static"
if staticfiles_dir.isdir():
@@ -64,5 +61,6 @@ def enable_comprehensive_theme(theme_dir):
# Use the changes
for name, value in changes['settings'].iteritems():
setattr(settings, name, value)
for template_dir in changes['mako_paths']:
edxmako.paths.add_lookup('main', template_dir, prepend=True)
for template_dir in changes['template_paths']:
settings.DEFAULT_TEMPLATE_ENGINE['DIRS'].insert(0, template_dir)
settings.MAKO_TEMPLATES['main'].insert(0, template_dir)

View File

@@ -1,14 +0,0 @@
"""
Startup code for Comprehensive Theming
"""
from path import Path as path
from django.conf import settings
from .core import enable_comprehensive_theme
def run():
"""Enable comprehensive theming, if we should."""
if settings.COMPREHENSIVE_THEME_DIR:
enable_comprehensive_theme(theme_dir=path(settings.COMPREHENSIVE_THEME_DIR))

View File

@@ -9,6 +9,7 @@ import os.path
from mock import patch
from django.conf import settings
from django.template import Engine
from django.test.utils import override_settings
import edxmako
@@ -35,11 +36,14 @@ def with_comprehensive_theme(theme_dir):
@wraps(func)
def _decorated(*args, **kwargs): # pylint: disable=missing-docstring
with override_settings(COMPREHENSIVE_THEME_DIR=theme_dir, **changes['settings']):
default_engine = Engine.get_default()
dirs = default_engine.dirs[:]
with edxmako.save_lookups():
for template_dir in changes['mako_paths']:
for template_dir in changes['template_paths']:
edxmako.paths.add_lookup('main', template_dir, prepend=True)
return func(*args, **kwargs)
dirs.insert(0, template_dir)
with patch.object(default_engine, 'dirs', dirs):
return func(*args, **kwargs)
return _decorated
return _decorator