Mercurial > libervia-backend
comparison sat_frontends/jp/output_template.py @ 2671:0fa217fafabf
tools (common/template), jp: refactoring to handle multiple sites:
- site can now be specified in template header before theme, for instance: (some_site/some_theme)path/to/template.ext
- absolute template paths are now implemented, but Renderer must be instanciated with trusted to True for security reason (it's the case for jp)
- a new "front_url_filter" callable can be given to Renderer, which will convert template path to URL seen by end-user (default to real path).
- the "front_url_filter" can be used in templates with… "front_url" filter
- template_data is a new named tuple available in templates, which give site, theme and template relative URL
- search order is site/theme, site/default_theme, and default/default_theme where default link to sat_pubsub templates
- when loading CSS files, files with _noscript suffixes are now loaded, and used when javascript is not available
- "styles_extra.css" is also loaded before "styles.css", useful when a theme want to reuse default style, and just override some rules
- new site can be specified in sat.conf [DEFAULT] section, using sites_path_public_dict or sites_path_private_dict (where sites_path_private_dict won't be used in public frontends, like Libervia)
- "private" argument of Renderer tells the renderer to load private sites or not
- templates are now loaded from "templates" subdirectory, to differenciate them from other data like i18n
- jp template output has been updated to handle those changes, and to manage absolute templates
author | Goffi <goffi@goffi.org> |
---|---|
date | Mon, 10 Sep 2018 08:58:18 +0200 |
parents | 56f94936df1e |
children | 003b8b4b56a7 |
comparison
equal
deleted
inserted
replaced
2670:ef93fcbaa749 | 2671:0fa217fafabf |
---|---|
19 """Standard outputs""" | 19 """Standard outputs""" |
20 | 20 |
21 | 21 |
22 from sat_frontends.jp.constants import Const as C | 22 from sat_frontends.jp.constants import Const as C |
23 from sat.core.i18n import _ | 23 from sat.core.i18n import _ |
24 from sat.core import log | |
24 from sat.tools.common import template | 25 from sat.tools.common import template |
26 from functools import partial | |
27 import logging | |
25 import webbrowser | 28 import webbrowser |
26 import tempfile | 29 import tempfile |
27 import os.path | 30 import os.path |
28 | 31 |
29 __outputs__ = ["Template"] | 32 __outputs__ = ["Template"] |
35 """outputs data using SàT templates""" | 38 """outputs data using SàT templates""" |
36 | 39 |
37 def __init__(self, jp): | 40 def __init__(self, jp): |
38 self.host = jp | 41 self.host = jp |
39 jp.register_output(C.OUTPUT_COMPLEX, TEMPLATE, self.render) | 42 jp.register_output(C.OUTPUT_COMPLEX, TEMPLATE, self.render) |
43 | |
44 def _front_url_tmp_dir(self, ctx, relative_url, tmp_dir): | |
45 """Get front URL for temporary directory""" | |
46 template_data = ctx[u'template_data'] | |
47 return u"file://" + os.path.join(tmp_dir, template_data.theme, relative_url) | |
48 | |
49 def _do_render(self, template_path, css_inline, **kwargs): | |
50 try: | |
51 return self.renderer.render(template_path, css_inline=css_inline, **kwargs) | |
52 except template.TemplateNotFound: | |
53 self.host.disp(_(u"Can't find requested template: {template_path}") | |
54 .format(template_path=template_path), error=True) | |
55 self.host.quit(C.EXIT_NOT_FOUND) | |
40 | 56 |
41 def render(self, data): | 57 def render(self, data): |
42 """render output data using requested template | 58 """render output data using requested template |
43 | 59 |
44 template to render the data can be either command's TEMPLATE or | 60 template to render the data can be either command's TEMPLATE or |
53 cmd = self.host.command | 69 cmd = self.host.command |
54 try: | 70 try: |
55 template_path = cmd.TEMPLATE | 71 template_path = cmd.TEMPLATE |
56 except AttributeError: | 72 except AttributeError: |
57 if not "template" in cmd.args.output_opts: | 73 if not "template" in cmd.args.output_opts: |
58 self.host.disp( | 74 self.host.disp(_( |
59 u"no default template set for this command, " | 75 u"no default template set for this command, you need to specify a " |
60 u"you need to specify a template using --oo template=[path/to/template.html]", | 76 u"template using --oo template=[path/to/template.html]"), |
61 error=True, | 77 error=True, |
62 ) | 78 ) |
63 self.host.quit(C.EXIT_BAD_ARG) | 79 self.host.quit(C.EXIT_BAD_ARG) |
64 | 80 |
65 options = self.host.parse_output_options() | 81 options = self.host.parse_output_options() |
66 self.host.check_output_options(OPTIONS, options) | 82 self.host.check_output_options(OPTIONS, options) |
67 self.renderer = template.Renderer(self.host) | |
68 try: | 83 try: |
69 template_path = options["template"] | 84 template_path = options["template"] |
70 except KeyError: | 85 except KeyError: |
71 # template is not specified, we use default one | 86 # template is not specified, we use default one |
72 pass | 87 pass |
73 if template_path is None: | 88 if template_path is None: |
74 self.host.disp(u"Can't parse template, please check its syntax", error=True) | 89 self.host.disp(_(u"Can't parse template, please check its syntax"), |
90 error=True) | |
75 self.host.quit(C.EXIT_BAD_ARG) | 91 self.host.quit(C.EXIT_BAD_ARG) |
76 | 92 |
77 try: | 93 try: |
78 mapping_cb = cmd.template_data_mapping | 94 mapping_cb = cmd.template_data_mapping |
79 except AttributeError: | 95 except AttributeError: |
80 kwargs = data | 96 kwargs = data |
81 else: | 97 else: |
82 kwargs = mapping_cb(data) | 98 kwargs = mapping_cb(data) |
83 | 99 |
84 css_inline = u"inline-css" in options | 100 css_inline = u"inline-css" in options |
85 rendered = self.renderer.render(template_path, css_inline=css_inline, **kwargs) | |
86 | 101 |
87 if "browser" in options: | 102 if "browser" in options: |
88 template_name = os.path.basename(template_path) | 103 template_name = os.path.basename(template_path) |
89 tmp_dir = tempfile.mkdtemp() | 104 tmp_dir = tempfile.mkdtemp() |
90 self.host.disp( | 105 front_url_filter = partial(self._front_url_tmp_dir, tmp_dir=tmp_dir) |
91 _( | 106 self.renderer = template.Renderer( |
92 u"Browser opening requested.\nTemporary files are put in the following directory, " | 107 self.host, front_url_filter=front_url_filter, trusted=True) |
93 u"you'll have to delete it yourself once finished viewing: {}" | 108 rendered = self._do_render(template_path, css_inline=css_inline, **kwargs) |
94 ).format(tmp_dir) | 109 self.host.disp(_( |
95 ) | 110 u"Browser opening requested.\n" |
111 u"Temporary files are put in the following directory, you'll have to " | |
112 u"delete it yourself once finished viewing: {}").format(tmp_dir)) | |
96 tmp_file = os.path.join(tmp_dir, template_name) | 113 tmp_file = os.path.join(tmp_dir, template_name) |
97 with open(tmp_file, "w") as f: | 114 with open(tmp_file, "w") as f: |
98 f.write(rendered.encode("utf-8")) | 115 f.write(rendered.encode("utf-8")) |
99 theme, theme_root_path = self.renderer.getThemeAndRoot(template_path) | 116 theme, theme_root_path = self.renderer.getThemeAndRoot(template_path) |
117 if theme is None: | |
118 # we have an absolute path | |
119 webbrowser | |
100 static_dir = os.path.join(theme_root_path, C.TEMPLATE_STATIC_DIR) | 120 static_dir = os.path.join(theme_root_path, C.TEMPLATE_STATIC_DIR) |
101 if os.path.exists(static_dir): | 121 if os.path.exists(static_dir): |
122 # we have to copy static files in a subdirectory, to avoid file download | |
123 # to be blocked by same origin policy | |
102 import shutil | 124 import shutil |
103 | |
104 shutil.copytree( | 125 shutil.copytree( |
105 static_dir, os.path.join(tmp_dir, theme, C.TEMPLATE_STATIC_DIR) | 126 static_dir, os.path.join(tmp_dir, theme, C.TEMPLATE_STATIC_DIR) |
106 ) | 127 ) |
107 webbrowser.open(tmp_file) | 128 webbrowser.open(tmp_file) |
108 else: | 129 else: |
130 # FIXME: Q&D way to disable template logging | |
131 # logs are overcomplicated, and need to be reworked | |
132 template_logger = log.getLogger(u"sat.tools.common.template") | |
133 template_logger.log = lambda *args: None | |
134 | |
135 logging.disable(logging.WARNING) | |
136 self.renderer = template.Renderer(self.host, trusted=True) | |
137 rendered = self._do_render(template_path, css_inline=css_inline, **kwargs) | |
109 self.host.disp(rendered) | 138 self.host.disp(rendered) |