hobo/hobo/multitenant/template_loader.py

108 lines
4.4 KiB
Python

"""
Wrapper class that takes a list of template loaders as an argument and attempts
to load templates from them in order, caching the result.
"""
import hashlib
import itertools
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.db import connection
from django.template import Origin, TemplateDoesNotExist, engines
from django.template.loaders.cached import Loader as DjangoCachedLoader
from django.template.loaders.filesystem import Loader as DjangoFilesystemLoader
from django.utils._os import safe_join
from django.utils.encoding import force_bytes
from tenant_schemas.utils import get_public_schema_name
class CachedLoader(DjangoCachedLoader):
def cache_key(self, template_name, template_dirs, skip=None):
key = super(CachedLoader, self).cache_key(template_name, template_dirs, skip=skip)
if connection.tenant:
return connection.tenant.domain_url + '-' + key
return key
class FilesystemLoader(DjangoFilesystemLoader):
def get_template_sources(self, template_name, template_dirs=None):
"""
Returns the absolute paths to "template_name", when appended to each
directory in "template_dirs". Any paths that don't lie inside one of the
template dirs are excluded from the result set, for security reasons.
"""
if not connection.tenant or connection.tenant.schema_name == get_public_schema_name():
return
if not template_dirs:
try:
template_dirs = settings.TENANT_TEMPLATE_DIRS
except AttributeError:
raise ImproperlyConfigured(
'To use %s.%s you must define the TENANT_TEMPLATE_DIRS'
% (__name__, FilesystemLoader.__name__)
)
known_dirnames = ['templates', 'theme/templates']
if hasattr(settings, 'TEMPLATE_VARS'):
if settings.TEMPLATE_VARS.get('theme'):
theme_value = settings.TEMPLATE_VARS['theme']
if settings.TEMPLATE_VARS.get('is_portal_agent'):
known_dirnames = (
list(
itertools.chain(
*[
(
'%s/variants/%s/portal-agent' % (x, theme_value),
'%s/variants/%s' % (x, theme_value),
)
for x in known_dirnames
]
)
)
+ known_dirnames
)
elif settings.TEMPLATE_VARS.get('is_portal_user'):
known_dirnames = (
list(
itertools.chain(
*[
(
'%s/variants/%s/portal-user' % (x, theme_value),
'%s/variants/%s' % (x, theme_value),
)
for x in known_dirnames
]
)
)
+ known_dirnames
)
else:
known_dirnames = [
'%s/variants/%s' % (x, theme_value) for x in known_dirnames
] + known_dirnames
if settings.TEMPLATE_VARS.get('is_portal_agent'):
known_dirnames = ['%s/portal-agent' % x for x in known_dirnames] + known_dirnames
for template_dir in template_dirs:
for dirname in known_dirnames:
try:
template_path = safe_join(
template_dir, connection.tenant.domain_url, dirname, template_name
)
except UnicodeDecodeError:
# The template dir name was a bytestring that wasn't valid UTF-8.
raise
except ValueError:
# The joined path was located outside of this particular
# template_dir (it might be inside another one, so this isn't
# fatal).
pass
yield Origin(
template_path,
template_name=template_name,
loader=self,
)