Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions common/djangoapps/edxmako/paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from mako.lookup import TemplateLookup

from microsite_configuration import microsite
from openedx.core.djangoapps.theming.core import get_template_path
from . import LOOKUP


Expand Down Expand Up @@ -51,13 +52,14 @@ def get_template(self, uri):
"""
Overridden method which will hand-off the template lookup to the microsite subsystem
"""
microsite_template = microsite.get_template(uri)
if microsite.is_request_in_microsite():

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These microsite references should be routed through the theming app -- the goal of this work is two-fold: to support multiple sites with comprehensive theming and eliminate the existing microsites implementation.

microsite_template = microsite.get_template(uri)
if microsite_template:
return microsite_template
else:
uri = get_template_path(uri)

return (
microsite_template
if microsite_template
else super(DynamicTemplateLookup, self).get_template(uri)
)
return super(DynamicTemplateLookup, self).get_template(uri)


def clear_lookups(namespace):
Expand Down
12 changes: 10 additions & 2 deletions common/djangoapps/pipeline_mako/templates/static_content.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,21 @@
from django.utils.translation import get_language_bidi
from mako.exceptions import TemplateLookupException

from openedx.core.djangoapps.theming.helpers import get_page_title_breadcrumbs, get_value, get_template_path, get_themed_template_path, is_request_in_themed_site
from openedx.core.djangoapps.theming.helpers import (
get_page_title_breadcrumbs,
get_value,
get_template_path,
get_themed_template_path,
is_request_in_themed_site,
get_request_domain,
)
from certificates.api import get_asset_url_by_slug
%>

<%def name='url(file, raw=False)'><%
try:
url = staticfiles_storage.url(file)
domain = get_request_domain(request)
url = staticfiles_storage.url(file, domain=domain)
except:
url = file
%>${url}${"?raw" if raw else ""}</%def>
Expand Down
4 changes: 2 additions & 2 deletions lms/envs/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@
DATA_DIR = COURSES_ROOT

# comprehensive theming system
COMPREHENSIVE_THEME_DIR = ""
COMPREHENSIVE_THEME_DIR = "/".join([REPO_ROOT, "themes"])

# TODO: Remove the rest of the sys.path modification here and in cms/envs/common.py
sys.path.append(REPO_ROOT)
Expand Down Expand Up @@ -776,7 +776,7 @@
CMS_BASE = 'localhost:8001'

# Site info
SITE_ID = 1
# SITE_ID = 1
SITE_NAME = "example.com"
HTTPS = 'on'
ROOT_URLCONF = 'lms.urls'
Expand Down
1 change: 1 addition & 0 deletions lms/envs/devstack.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ def should_show_debug_toolbar(_):

# Revert to the default set of finders as we don't want the production pipeline
STATICFILES_FINDERS = [
'openedx.core.djangoapps.theming.finders.ComprehensiveThemeFinder',
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
]
Expand Down
77 changes: 58 additions & 19 deletions openedx/core/djangoapps/theming/core.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
"""
Core logic for Comprehensive Theming.
"""
import os.path
from path import Path

from django.conf import settings
from django.contrib.sites.shortcuts import get_current_site

from edxmako.middleware import REQUEST_CONTEXT
from util.url import strip_port_from_host

def comprehensive_theme_changes(theme_dir):

def comprehensive_theme_changes(themes_dir):
"""
Calculate the set of changes needed to enable a comprehensive theme.

Arguments:
theme_dir (path.path): the full path to the theming directory to use.
themes_dir (path.path): the full path to the directory where all themse are listed.

Returns:
A dict indicating the changes to make:
Expand All @@ -27,27 +32,20 @@ def comprehensive_theme_changes(theme_dir):
'settings': {},
'template_paths': [],
}
root = Path(settings.PROJECT_ROOT)
if root.name == "":
root = root.parent

component_dir = theme_dir / root.name

templates_dir = component_dir / "templates"
if templates_dir.isdir():
changes['template_paths'].append(templates_dir)
root_name = get_project_root_name()

staticfiles_dir = component_dir / "static"
if staticfiles_dir.isdir():
changes['settings']['STATICFILES_DIRS'] = [staticfiles_dir] + settings.STATICFILES_DIRS
if themes_dir.isdir():
changes['template_paths'].append(themes_dir)

locale_dir = component_dir / "conf" / "locale"
if locale_dir.isdir():
changes['settings']['LOCALE_PATHS'] = [locale_dir] + settings.LOCALE_PATHS
for theme_dir in os.listdir(themes_dir):
staticfiles_dir = os.path.join(themes_dir, theme_dir, root_name, "static")
if staticfiles_dir.isdir():
changes['settings']['STATICFILES_DIRS'] = settings.STATICFILES_DIRS + [staticfiles_dir]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Static file lookups will be handled custom ComprehensiveThemeFinder, do we still need to add theme staticfile dirs to STATICFILES_DIRS?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each theme is added to STATICFILES_DIRS since collectstatic would not run in request/response cycle and we would not know current site.


favicon = component_dir / "static" / "images" / "favicon.ico"
if favicon.isfile():
changes['settings']['FAVICON_PATH'] = str(favicon)
locale_dir = os.path.join(themes_dir, theme_dir, root_name, "conf", "locale")
if locale_dir.isdir():
changes['settings']['LOCALE_PATHS'] = [locale_dir] + settings.LOCALE_PATHS

return changes

Expand All @@ -64,3 +62,44 @@ def enable_comprehensive_theme(theme_dir):
for template_dir in changes['template_paths']:
settings.DEFAULT_TEMPLATE_ENGINE['DIRS'].insert(0, template_dir)
settings.MAKO_TEMPLATES['main'].insert(0, template_dir)


def get_template_path(relative_path):
"""
Returns a path (string) to a Mako template, if one is found in theme directory
otherwise return what is passed.
"""
request = getattr(REQUEST_CONTEXT, 'request', None)
if not request:
return relative_path

domain = get_current_site(request).domain
domain = strip_port_from_host(domain)
root_name = get_project_root_name()
template_path = "/".join([
settings.COMPREHENSIVE_THEME_DIR,
domain,
root_name,
"templates"
])

search_path = os.path.join(template_path, relative_path)
if os.path.isfile(search_path):
path = '/{domain}/{root_name}/templates/{relative_path}'.format(
domain=domain,
root_name=root_name,
relative_path=relative_path,
)
return path
else:
return relative_path


def get_project_root_name():
"""
:return:
"""
root = Path(settings.PROJECT_ROOT)
if root.name == "":
root = root.parent
return root.name
22 changes: 11 additions & 11 deletions openedx/core/djangoapps/theming/finders.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@
.. _Django-Pipeline: http://django-pipeline.readthedocs.org/
.. _Django-Require: https://github.com/etianen/django-require
"""
from path import Path
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.contrib.staticfiles import utils
from django.contrib.staticfiles.finders import BaseFinder

from openedx.core.djangoapps.theming.storage import CachedComprehensiveThemingStorage
from openedx.core.djangoapps.theming.helpers import is_themed_dir


class ComprehensiveThemeFinder(BaseFinder):
Expand All @@ -34,7 +35,7 @@ class ComprehensiveThemeFinder(BaseFinder):
"""
def __init__(self, *args, **kwargs):
super(ComprehensiveThemeFinder, self).__init__(*args, **kwargs)

self.storage = None
theme_dir = getattr(settings, "COMPREHENSIVE_THEME_DIR", "")
if not theme_dir:
self.storage = None
Expand All @@ -43,13 +44,7 @@ def __init__(self, *args, **kwargs):
if not isinstance(theme_dir, basestring):
raise ImproperlyConfigured("Your COMPREHENSIVE_THEME_DIR setting must be a string")

root = Path(settings.PROJECT_ROOT)
if root.name == "":
root = root.parent

component_dir = Path(theme_dir) / root.name
static_dir = component_dir / "static"
self.storage = CachedComprehensiveThemingStorage(location=static_dir)
self.storage = CachedComprehensiveThemingStorage(location=theme_dir)

def find(self, path, all=False): # pylint: disable=redefined-builtin
"""
Expand All @@ -62,8 +57,13 @@ def find(self, path, all=False): # pylint: disable=redefined-builtin
# strip the prefix
path = path[len(self.storage.prefix):]

if self.storage.exists(path):
match = self.storage.path(path)
path_parts = path.split("/", 1)
if not is_themed_dir(path_parts[0]):
return []

themed_path = path_parts[0] + "/" + self.storage.root_name + self.storage.prefix + "/" + path_parts[1]
if self.storage.exists(themed_path):
match = self.storage.path(themed_path)
if all:
match = [match]
return match
Expand Down
23 changes: 23 additions & 0 deletions openedx/core/djangoapps/theming/helpers.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,33 @@
"""
Helpers for accessing comprehensive theming related variables.
"""
import os

from django.contrib.sites.shortcuts import get_current_site

from microsite_configuration import microsite
from microsite_configuration import page_title_breadcrumbs
from django.conf import settings

from util.url import strip_port_from_host


def get_request_domain(request):
domain = get_current_site(request).domain
domain = strip_port_from_host(domain)
return domain


def is_themed_dir(str):
themes_dir = getattr(settings, "COMPREHENSIVE_THEME_DIR", "")
if not themes_dir.isdir():
return False

for theme_dir in os.listdir(themes_dir):
if theme_dir == str:
return True
return False


def get_page_title_breadcrumbs(*args):
"""
Expand Down
30 changes: 19 additions & 11 deletions openedx/core/djangoapps/theming/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,20 @@ def __init__(self, *args, **kwargs):
root = Path(settings.PROJECT_ROOT)
if root.name == "":
root = root.parent
self.root_name = root.name

component_dir = Path(theme_dir) / root.name
self.theme_location = component_dir / "static"
if theme_dir:
self.theme_location = theme_dir

@property
def prefix(self):
"""
This is used by the ComprehensiveThemeFinder in the collection step.
"""
theme_dir = getattr(settings, "COMPREHENSIVE_THEME_DIR", "")
if not theme_dir:
return None
theme_name = os.path.basename(os.path.normpath(theme_dir))
return "themes/{name}/".format(name=theme_name)
theme_prefix = ""
if self.theme_location:
theme_prefix = "/static"
return theme_prefix

def themed(self, name):
"""
Expand All @@ -67,13 +67,21 @@ def path(self, name):
path = safe_join(base, name)
return os.path.normpath(path)

def url(self, name, *args, **kwargs):
def url(self, name, domain=None):
"""
Add the theme prefix to the asset URL
"""
if self.themed(name):
name = self.prefix + name
return super(ComprehensiveThemingAwareMixin, self).url(name, *args, **kwargs)
if name.startswith(self.prefix):
# strip the prefix
name_without_prefix = name[len(self.prefix):]
else:
name_without_prefix = name

if domain:
themed_path = domain + "/" + self.root_name + self.prefix + name_without_prefix
if self.themed(themed_path):
name = self.prefix + "/" + domain + name_without_prefix
return super(ComprehensiveThemingAwareMixin, self).url(name)


class CachedComprehensiveThemingStorage(
Expand Down
3 changes: 3 additions & 0 deletions openedx/core/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
from django.contrib.staticfiles.storage import StaticFilesStorage, CachedFilesMixin
from pipeline.storage import PipelineMixin, NonPackagingMixin
from require.storage import OptimizedFilesMixin
from openedx.core.djangoapps.theming.storage import ComprehensiveThemingAwareMixin


class ProductionStorage(
ComprehensiveThemingAwareMixin,
OptimizedFilesMixin,
PipelineMixin,
CachedFilesMixin,
Expand All @@ -20,6 +22,7 @@ class ProductionStorage(


class DevelopmentStorage(
ComprehensiveThemingAwareMixin,
NonPackagingMixin,
PipelineMixin,
StaticFilesStorage
Expand Down
Binary file added themes/jane.org/lms/static/images/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions themes/jane.org/lms/templates/footer.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
## mako
<div> Jane's footer</div>