# w.c.s. - web application for online forms
# Copyright (C) 2005-2010 Entr'ouvert
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see .
import io
import os
import re
import django.template
from django.template import TemplateSyntaxError as DjangoTemplateSyntaxError
from django.template import VariableDoesNotExist as DjangoVariableDoesNotExist
from django.template import engines
from django.template.loader import render_to_string
from django.utils.encoding import force_text, smart_text
from quixote import get_publisher, get_request, get_response, get_session
from quixote.html import TemplateIO, htmlescape, htmltext
from . import ezt, force_str
def get_theme_directory(theme_id):
system_location = os.path.join(get_publisher().data_dir, 'themes', theme_id)
local_location = os.path.join(get_publisher().app_dir, 'themes', theme_id)
if os.path.exists(local_location):
location = local_location
elif os.path.exists(system_location):
location = system_location
else:
return None
while os.path.islink(location):
location = os.path.join(os.path.dirname(location), os.readlink(location))
if not os.path.exists(location):
return None
return location
def html_top(title=None, default_org=None):
if not hasattr(get_response(), 'filter'):
get_response().filter = {}
get_response().filter['title'] = title
get_response().filter['default_org'] = default_org
def error_page(error_message, error_title=None, location_hint=None):
from . import _
if not error_title:
error_title = _('Error')
kwargs = {'title': error_title}
if get_request().is_in_backoffice() and get_request().user and get_request().user.can_go_in_backoffice():
from wcs.qommon.backoffice.menu import html_top as backoffice_html_top
get_response().add_javascript(['jquery.js', 'qommon.js', 'gadjo.js'])
backoffice_html_top(section='', **kwargs)
context = get_decorate_vars('', get_response())
context['error_message'] = error_message
return QommonTemplateResponse(
templates=['wcs/backoffice/error.html'], context=context, is_django_native=True
)
r = TemplateIO(html=True)
html_top(**kwargs)
r += htmltext('
')
r += htmltext('
%s
') % error_message
continue_link = htmltext('
%s') % (get_publisher().get_root_url(), _('the homepage'))
r += htmltext('
%s
') % htmltext(_('Continue to %s')) % continue_link
r += htmltext('
')
return htmltext(r.getvalue())
def get_decorate_vars(body, response, generate_breadcrumb=True, **kwargs):
from .publisher import get_cfg
if response.content_type != 'text/html':
return {'body': body}
body = str(body)
if get_request().get_header('x-popup') == 'true':
return {'body': body}
kwargs = {}
for k, v in response.filter.items():
if v:
kwargs[k] = str(v)
if 'lang' not in kwargs and hasattr(get_request(), 'language'):
response.filter['lang'] = get_request().language
if ('rel="popup"' in body or 'rel="popup"' in kwargs.get('sidebar', '')) or (
'data-popup' in body or 'data-popup' in kwargs.get('sidebar', '')
):
response.add_javascript(['popup.js', 'widget_list.js'])
onload = kwargs.get('onload')
org_name = get_cfg('sp', {}).get('organization_name', kwargs.get('default_org', get_publisher().APP_NAME))
site_name = get_cfg('misc', {}).get('sitename', org_name)
current_theme = get_cfg('branding', {}).get('theme', get_publisher().default_theme)
if kwargs.get('title'):
title = kwargs.get('title')
page_title = '%s - %s' % (site_name, title)
title_or_orgname = title
else:
page_title = site_name
title = None
title_or_orgname = site_name
script = kwargs.get('script') or ''
script += response.get_css_includes_for_header()
script += response.get_javascript_for_header()
try:
user = get_request().user
except Exception:
user = None
if type(user) in (int, str) and get_session():
try:
user = get_session().get_user_object()
except KeyError:
pass
root_url = get_publisher().get_application_static_files_root_url()
theme_url = '%sthemes/%s' % (root_url, current_theme)
is_in_backoffice = response.filter.get('admin_ezt')
if is_in_backoffice:
header_menu = kwargs.get('header_menu')
user_info = kwargs.get('user_info')
page_title = kwargs.get('sitetitle', '') + kwargs.get('title', '')
subtitle = kwargs.get('subtitle')
sidebar = kwargs.get('sidebar')
css = root_url + get_publisher().qommon_static_dir + get_publisher().qommon_admin_css
extra_head = get_publisher().get_site_option('backoffice_extra_head')
app_label = get_publisher().get_site_option('app_label') or 'w.c.s.'
else:
css = root_url + 'themes/%s/%s.css' % (current_theme, get_publisher().APP_NAME)
# this variable is kept in locals() as it was once part of the default
# template and existing installations may have template changes that
# still have it.
prelude = ''
if generate_breadcrumb:
breadcrumb = ''
if hasattr(response, 'breadcrumb') and response.breadcrumb:
s = []
path = root_url
if is_in_backoffice:
path += response.breadcrumb[0][0]
response.breadcrumb = response.breadcrumb[1:]
total_len = sum(len(str(x[1])) for x in response.breadcrumb if x[1] is not None)
for component, label in response.breadcrumb:
if component.startswith('http:') or component.startswith('https:'):
s.append('%s' % (component, label))
continue
if label is not None:
if isinstance(label, str):
label = htmlescape(label)
if not is_in_backoffice and (
total_len > 80 and len(label) > 10 and response.breadcrumb[-1] != (component, label)
):
s.append('%s' % (path, component, label, '...'))
else:
s.append('%s' % (path, component, label))
path += component.split('#')[0] # remove anchor for next parts
breadcrumb = ' > '.join(s)
vars = response.filter.copy()
vars.update(get_publisher().substitutions.get_context_variables())
vars.update(locals())
return vars
def render(template_name, context):
request = getattr(get_request(), 'django_request', None)
result = render_to_string(template_name, context, request=request)
return htmltext(force_str(result))
class QommonTemplateResponse:
is_django_native = False
def __init__(self, templates, context, is_django_native=False):
self.templates = templates
self.context = context
self.is_django_native = is_django_native
def add_media(self):
# run add_media so we get them in the page
if 'html_form' in self.context:
self.context['html_form'].add_media()
if 'form' in self.context and hasattr(self.context['form'], 'add_media'):
# legacy name, conflicting with formdata "form*" variables
self.context['form'].add_media()
class TemplateError(Exception):
def __init__(self, msg, params=()):
self.msg = msg
self.params = params
def __str__(self):
from . import misc
return misc.site_encode(smart_text(self.msg) % self.params)
def ezt_raises(exception, on_parse=False):
from . import _
parts = []
parts.append(
{
ezt.ArgCountSyntaxError: _('wrong number of arguments'),
ezt.UnknownReference: _('unknown reference'),
ezt.NeedSequenceError: _('sequence required'),
ezt.UnclosedBlocksError: _('unclosed block'),
ezt.UnmatchedEndError: _('unmatched [end]'),
ezt.UnmatchedElseError: _('unmatched [else]'),
ezt.BaseUnavailableError: _('unavailable base location'),
ezt.BadFormatConstantError: _('bad format constant'),
ezt.UnknownFormatConstantError: _('unknown format constant'),
}.get(exception.__class__, _('unknown error'))
)
if exception.line is not None:
parts.append(
_('at line %(line)d and column %(column)d')
% {'line': exception.line + 1, 'column': exception.column + 1}
)
if on_parse:
message = _('syntax error in ezt template: %s')
else:
message = _('failure to render ezt template: %s')
raise TemplateError(message % ' '.join([str(x) for x in parts]))
class Template:
def __init__(self, value, raises=False, ezt_format=ezt.FORMAT_RAW, ezt_only=False, autoescape=True):
'''Guess kind of template (Django or ezt), and parse it'''
self.value = value
self.raises = raises
if ('{{' in value or '{%' in value) and not ezt_only: # Django template
self.format = 'django'
self.render = self.django_render
if autoescape is False:
value = '{%% autoescape off %%}%s{%% endautoescape %%}' % value
try:
self.template = engines['django'].from_string(value)
except DjangoTemplateSyntaxError as e:
if raises:
from . import _
raise TemplateError(_('syntax error in Django template: %s'), e)
self.render = self.null_render
elif '[' in value and '