general: always use a django template to render pages (#25057)

This commit is contained in:
Frédéric Péters 2018-07-04 15:27:05 +02:00
parent f463708630
commit 6aebe1a458
20 changed files with 124 additions and 28 deletions

View File

@ -46,11 +46,14 @@ from utilities import get_app, login, create_temporary_pub, clean_temporary_pub,
def pytest_generate_tests(metafunc):
if 'pub' in metafunc.fixturenames:
metafunc.parametrize('pub', ['pickle', 'sql'], indirect=True)
metafunc.parametrize('pub', ['pickle', 'sql', 'pickle-templates'], indirect=True)
@pytest.fixture
def pub(request):
pub = create_temporary_pub(sql_mode=(request.param == 'sql'))
pub = create_temporary_pub(
sql_mode=bool('sql' in request.param),
templates_mode=bool('templates' in request.param)
)
req = HTTPRequest(None, {'SCRIPT_NAME': '/', 'SERVER_NAME': 'example.net'})
pub.set_app_dir(req)
@ -4521,7 +4524,7 @@ def test_settings_theme_preview(pub):
app = login(get_app(pub))
assert not 'alto/wcs.css' in app.get('/').body
resp = app.get('/backoffice/settings/themes')
assert resp.form['theme'].value == 'default'
assert resp.form['theme'].value in ('default', 'django')
# visit theme preview
resp = resp.click(href='theme_preview/alto/')

View File

@ -51,11 +51,14 @@ from utilities import (get_app, login, create_temporary_pub,
def pytest_generate_tests(metafunc):
if 'pub' in metafunc.fixturenames:
metafunc.parametrize('pub', ['pickle', 'sql'], indirect=True)
metafunc.parametrize('pub', ['pickle', 'sql', 'pickle-templates'], indirect=True)
@pytest.fixture
def pub(request):
pub = create_temporary_pub(sql_mode=(request.param == 'sql'))
pub = create_temporary_pub(
sql_mode=bool('sql' in request.param),
templates_mode=bool('templates' in request.param)
)
req = HTTPRequest(None, {'SCRIPT_NAME': '/', 'SERVER_NAME': 'example.net'})
pub.set_app_dir(req)

View File

@ -55,11 +55,14 @@ def assert_equal_zip(stream1, stream2):
def pytest_generate_tests(metafunc):
if 'pub' in metafunc.fixturenames:
metafunc.parametrize('pub', ['pickle', 'sql'], indirect=True)
metafunc.parametrize('pub', ['pickle', 'sql', 'pickle-templates'], indirect=True)
@pytest.fixture
def pub(request, emails):
pub = create_temporary_pub(sql_mode=(request.param == 'sql'))
pub = create_temporary_pub(
sql_mode=bool('sql' in request.param),
templates_mode=bool('templates' in request.param)
)
pub.cfg['identification'] = {'methods': ['password']}
pub.cfg['language'] = {'language': 'en'}
pub.write_cfg()

View File

@ -36,10 +36,11 @@ class KnownElements(object):
pickle_app_dir = None
sql_app_dir = None
sql_db_name = None
templates_app_dir = None
known_elements = KnownElements()
def create_temporary_pub(sql_mode=False):
def create_temporary_pub(sql_mode=False, templates_mode=False):
if sql_mode is True:
if pytest.config.getoption('without_postgresql_tests'):
pytest.skip("unsupported configuration")
@ -47,13 +48,17 @@ def create_temporary_pub(sql_mode=False):
if get_publisher():
get_publisher().cleanup()
cleanup()
if sql_mode is False and known_elements.pickle_app_dir:
if templates_mode and known_elements.templates_app_dir:
APP_DIR = known_elements.templates_app_dir
elif (not sql_mode and not templates_mode) and known_elements.pickle_app_dir:
APP_DIR = known_elements.pickle_app_dir
elif sql_mode is True and known_elements.sql_app_dir:
APP_DIR = known_elements.sql_app_dir
else:
APP_DIR = tempfile.mkdtemp()
if sql_mode is True:
if templates_mode:
known_elements.templates_app_dir = APP_DIR
elif sql_mode is True:
known_elements.sql_app_dir = APP_DIR
elif sql_mode is False:
known_elements.pickle_app_dir = APP_DIR
@ -115,11 +120,26 @@ def create_temporary_pub(sql_mode=False):
pub.cfg['postgresql'] = {'database': known_elements.sql_db_name, 'user': os.environ['USER']}
pub.cfg['misc'] = {'charset': 'utf-8'}
pub.cfg['language'] = {'language': 'en'}
if templates_mode:
pub.cfg['branding'] = {'theme': 'django'}
pub.write_cfg()
else:
pub.cfg['branding'] = {'theme': 'default'}
pub.write_cfg()
pub.write_cfg()
return pub
os.symlink(os.path.join(os.path.dirname(__file__), 'templates'),
os.path.join(pub.app_dir, 'templates'))
os.path.join(pub.app_dir, 'templates'))
if templates_mode:
pub.cfg['branding'] = {'theme': 'django'}
pub.write_cfg()
else:
pub.cfg['branding'] = {'theme': 'default'}
pub.write_cfg()
if sql_mode:
conn = psycopg2.connect(user=os.environ['USER'])
conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
@ -147,6 +167,9 @@ def create_temporary_pub(sql_mode=False):
def clean_temporary_pub():
if get_publisher():
get_publisher().cleanup()
if known_elements.templates_app_dir and os.path.exists(known_elements.templates_app_dir):
shutil.rmtree(known_elements.templates_app_dir)
known_elements.templates_app_dir = None
if known_elements.pickle_app_dir and os.path.exists(known_elements.pickle_app_dir):
shutil.rmtree(known_elements.pickle_app_dir)
known_elements.pickle_app_dir = None

View File

@ -36,6 +36,7 @@ from qommon import _
from qommon import get_cfg
from qommon import errors
from qommon import misc
from qommon import template
from qommon.form import *
from qommon.sms import SMS
@ -367,6 +368,8 @@ class ThemePreviewDirectory(Directory):
output = root_directory._q_traverse(path[1:])
from qommon.template import decorate
if isinstance(output, template.QommonTemplateResponse):
output = template.render(output.templates, output.context)
theme_preview = decorate(output, response)
# restore original branding in case it has been changed

View File

@ -48,6 +48,7 @@ class TemplateWithFallbackView(TemplateView):
try:
context = self.get_context_data(**kwargs)
self.quixote_response = request.quixote_request.response
except PublishError as exc:
context = {'body': get_publisher().finish_interrupted_request(exc)}
self.quixote_response = get_request().response
@ -160,11 +161,33 @@ class CompatWcsPublisher(WcsPublisher):
if not os.path.exists(os.path.join(theme_directory, 'templates/wcs/base.html')):
return self.render_response(output)
template_name = 'wcs/base.html'
context = template.get_decorate_vars(output, response)
if isinstance(output, template.QommonTemplateResponse):
template_response = output
else:
template_response = template.QommonTemplateResponse(
templates=['wcs/base.html'],
context={'body': output})
return self.render_template(
request,
response,
template_response)
def render_template(self, request, response, template_response):
if 'form' in template_response.context:
# run add_media on all widgets so we get them in the page <head>
for widget in template_response.context['form'].get_all_widgets():
if hasattr(widget, 'add_media'):
widget.add_media()
context = template.get_decorate_vars(
template_response.context.get('body'),
response,
generate_breadcrumb=False,
template_context=template_response.context)
context['request'] = request.django_request
context.update(template_response.context)
django_response = TemplateResponse(request.django_request,
template_name,
template_response.templates,
context,
content_type=response.content_type,
status=response.status_code)
@ -199,6 +222,12 @@ class CompatWcsPublisher(WcsPublisher):
status=response.status_code,
reason=response.reason_phrase)
if not request.ignore_session:
# it is necessary to save the session one last time as the actual
# rendering may have altered it (for example a form would add its
# token).
self.session_manager.finish_successful_request()
for name, value in response.generate_headers():
if name in ('Connection', 'Content-Length'):
continue

View File

@ -17,7 +17,11 @@
from quixote import get_publisher, get_response, get_request
def publisher(request):
template_base = 'wcs/base.html'
if request.path.startswith('/backoffice/'):
template_base = 'wcs/blank.html'
return {'publisher': get_publisher,
'response': get_response,
'user': lambda: get_request() and get_request().user,
'template_base': template_base,
}

View File

@ -252,9 +252,9 @@ class FormStatusPage(Directory, FormTemplateMixin):
'workflow_form': form,
}
return template.render(
list(self.get_formdef_template_variants(self.status_templates)),
context)
return template.QommonTemplateResponse(
templates=list(self.get_formdef_template_variants(self.status_templates)),
context=context)
def export_to_json(self, anonymise=False):
get_response().set_content_type('application/json')

View File

@ -406,9 +406,9 @@ class FormPage(Directory, FormTemplateMixin):
if self.formdef.enable_tracking_codes and data:
context['tracking_code_box'] = lambda: self.tracking_code_box(data, magictoken)
return template.render(
list(self.get_formdef_template_variants(self.filling_templates)),
context)
return template.QommonTemplateResponse(
templates=list(self.get_formdef_template_variants(self.filling_templates)),
context=context)
def form_side(self, step_no, page, data=None, magictoken=None):
'''Create the elements that typically appear aside the main form
@ -1115,9 +1115,9 @@ class FormPage(Directory, FormTemplateMixin):
magictoken=magictoken),
}
return template.render(
list(self.get_formdef_template_variants(self.validation_templates)),
context)
return template.QommonTemplateResponse(
templates=list(self.get_formdef_template_variants(self.validation_templates)),
context=context)
def tryauth(self):
return tryauth(self.formdef.get_url())

View File

@ -854,6 +854,11 @@ class EmailWidget(StringWidget):
class WcsExtraStringWidget(StringWidget):
field = None
prefill = False
prefill_attributes = None
def add_media(self):
if self.prefill_attributes and 'geolocation' in self.prefill_attributes:
get_response().add_javascript(['qommon.geolocation.js'])
def render_content(self):
if self.field and self.field.validation and not 'pattern' in self.attrs:

View File

@ -390,6 +390,8 @@ class QommonPublisher(Publisher, object):
return self.finish_failed_request()
def render_response(self, content):
if isinstance(content, template.QommonTemplateResponse):
content = template.render(content.templates, content.context)
return template.decorate(content, self.get_request().response)
def install_lang(self, request):

View File

@ -244,7 +244,7 @@ def get_default_ezt_template():
return DEFAULT_TEMPLATE_EZT
def get_decorate_vars(body, response, generate_breadcrumb=True):
def get_decorate_vars(body, response, generate_breadcrumb=True, **kwargs):
from publisher import get_cfg
body = str(body)
@ -261,8 +261,6 @@ def get_decorate_vars(body, response, generate_breadcrumb=True):
if 'rel="popup"' in body or 'rel="popup"' in kwargs.get('sidebar', ''):
response.add_javascript(['jquery.js', 'jquery-ui.js', 'popup.js', 'widget_list.js'])
if 'data-geolocation' in body:
response.add_javascript(['qommon.geolocation.js'])
onload = kwargs.get('onload')
org_name = get_cfg('sp', {}).get('organization_name',
@ -420,6 +418,12 @@ def render(template_name, context):
return htmltext(render_to_string(template_name, context, request=request).encode('utf-8'))
class QommonTemplateResponse(object):
def __init__(self, templates, context):
self.templates = templates
self.context = context
class TemplateError(Exception):
def __init__(self, msg, params=()):
self.msg = msg

View File

@ -0,0 +1,2 @@
{% block body %}
{% endblock %}

View File

@ -0,0 +1,2 @@
{% block body %}
{% endblock %}

View File

@ -1,3 +1,7 @@
{% extends template_base %}
{% block body %}
{{ form_side|default:"" }}
{{ publisher.get_request.session.display_message|safe }}
{{ form.render|safe }}
{% endblock %}

View File

@ -1,5 +1,7 @@
{% extends template_base %}
{% load i18n %}
{% block body %}
{% with workflow_messages=view.workflow_messages %}
{% if workflow_messages %}
{{ workflow_messages|safe }}
@ -32,3 +34,4 @@
<a href="{{ publisher.get_root_url }}">{% trans "Back Home" %}</a>
</div>
{% endif %}
{% endblock %}

View File

@ -1,7 +1,10 @@
{% extends template_base %}
{% load qommon %}
{% block body %}
<div class="form-validation">
{{ form_side|default:"" }}
{% standard_text "check-before-submit" %}
{{ form.render|safe }}
</div>
{% endblock %}

View File

@ -18,7 +18,7 @@ from quixote import get_publisher, get_request, get_response
from .forms.root import RootDirectory as FormsRootDirectory
from .qommon.admin.texts import TextsDirectory
from .qommon.template import get_decorate_vars
from .qommon import template
from . import compat
@ -55,8 +55,11 @@ class Backoffice(compat.TemplateWithFallbackView):
with compat.request(self.request):
get_request().response.filter = {'admin_ezt': True}
body = get_publisher().try_publish(get_request())
if isinstance(body, template.QommonTemplateResponse):
body = template.render(body.templates, body.context)
get_publisher().session_manager.finish_successful_request()
self.quixote_response = get_request().response
context.update(get_decorate_vars(body, get_response(), generate_breadcrumb=True))
context.update(template.get_decorate_vars(body, get_response(), generate_breadcrumb=True))
return context