Mercurial > libervia-web
comparison libervia/server/pages.py @ 1128:6414fd795df4
server, pages: multi-sites refactoring:
Libervia is now handling external sites (i.e. other sites than Libervia official site).
The external site are declared in sites_path_public_dict (in [DEFAULT] section) which is read by template engine, then they are linked to virtual host with vhosts_dict (linking host name to site name) in [libervia] section.
Sites are only instanced once, so adding an alias is just a matter of mapping the alias host name in vhosts_dict with the same site name.
menu_json and url_redirections_dict can now accept keys named after site name, which will be linked to the data for the site. Data for default site can still be keyed at first level.
Libervia official pages are added to external site (if pages are not overriden), allowing to call pages of the framework and to have facilities like login handling.
Deprecated url_redirections_profile option has been removed.
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 14 Sep 2018 21:41:28 +0200 |
parents | 9234f29053b0 |
children | 02fc28aac2b6 |
comparison
equal
deleted
inserted
replaced
1127:9234f29053b0 | 1128:6414fd795df4 |
---|---|
23 from twisted.words.protocols.jabber import jid | 23 from twisted.words.protocols.jabber import jid |
24 from twisted.python import failure | 24 from twisted.python import failure |
25 | 25 |
26 from sat.core.i18n import _ | 26 from sat.core.i18n import _ |
27 from sat.core import exceptions | 27 from sat.core import exceptions |
28 from sat.tools.common import uri as common_uri | |
29 from sat.tools.common import date_utils | 28 from sat.tools.common import date_utils |
30 from sat.core.log import getLogger | 29 from sat.core.log import getLogger |
31 | 30 |
32 log = getLogger(__name__) | 31 log = getLogger(__name__) |
33 from libervia.server.constants import Const as C | 32 from libervia.server.constants import Const as C |
34 from libervia.server import session_iface | 33 from libervia.server import session_iface |
35 from libervia.server.utils import quote, SubPage | 34 from libervia.server.utils import quote, SubPage |
36 import libervia | |
37 | 35 |
38 from collections import namedtuple | 36 from collections import namedtuple |
39 import uuid | 37 import uuid |
40 import os.path | 38 import os.path |
41 import urllib | 39 import urllib |
100 request.postpath = self._postpath[:] | 98 request.postpath = self._postpath[:] |
101 | 99 |
102 | 100 |
103 class LiberviaPage(web_resource.Resource): | 101 class LiberviaPage(web_resource.Resource): |
104 isLeaf = True # we handle subpages ourself | 102 isLeaf = True # we handle subpages ourself |
105 named_pages = {} | |
106 uri_callbacks = {} | |
107 signals_handlers = {} | 103 signals_handlers = {} |
108 pages_redirects = {} | |
109 cache = {} | 104 cache = {} |
110 cached_urls = {} | |
111 # Set of tuples (service/node/sub_id) of nodes subscribed for caching | 105 # Set of tuples (service/node/sub_id) of nodes subscribed for caching |
112 # sub_id can be empty string if not handled by service | 106 # sub_id can be empty string if not handled by service |
113 cache_pubsub_sub = set() | 107 cache_pubsub_sub = set() |
114 main_menu = None | |
115 | 108 |
116 def __init__( | 109 def __init__( |
117 self, | 110 self, host, vhost_root, root_dir, url, name=None, redirect=None, access=None, |
118 host, | 111 dynamic=False, parse_url=None, prepare_render=None, render=None, template=None, |
119 root_dir, | 112 on_data_post=None, on_data=None, on_signal=None, url_cache=False, |
120 url, | 113 ): |
121 name=None, | 114 """Initiate LiberviaPage instance |
122 redirect=None, | |
123 access=None, | |
124 dynamic=False, | |
125 parse_url=None, | |
126 prepare_render=None, | |
127 render=None, | |
128 template=None, | |
129 on_data_post=None, | |
130 on_data=None, | |
131 on_signal=None, | |
132 url_cache=False, | |
133 ): | |
134 """initiate LiberviaPages | |
135 | 115 |
136 LiberviaPages are the main resources of Libervia, using easy to set python files | 116 LiberviaPages are the main resources of Libervia, using easy to set python files |
137 The arguments are the variables found in page_meta.py | 117 The non mandatory arguments are the variables found in page_meta.py |
138 @param host(Libervia): the running instance of Libervia | 118 @param host(Libervia): the running instance of Libervia |
119 @param vhost_root(web_resource.Resource): root resource of the virtual host which | |
120 handle this page. | |
139 @param root_dir(unicode): aboslute file path of the page | 121 @param root_dir(unicode): aboslute file path of the page |
140 @param url(unicode): relative URL to the page | 122 @param url(unicode): relative URL to the page |
141 this URL may not be valid, as pages may require path arguments | 123 this URL may not be valid, as pages may require path arguments |
142 @param name(unicode, None): if not None, a unique name to identify the page | 124 @param name(unicode, None): if not None, a unique name to identify the page |
143 can then be used for e.g. redirection | 125 can then be used for e.g. redirection |
144 "/" is not allowed in names (as it can be used to construct URL paths) | 126 "/" is not allowed in names (as it can be used to construct URL paths) |
145 @param redirect(unicode, None): if not None, this page will be redirected. A redirected | 127 @param redirect(unicode, None): if not None, this page will be redirected. |
146 parameter is used as in self.pageRedirect. parse_url will not be skipped | 128 A redirected parameter is used as in self.pageRedirect. |
129 parse_url will not be skipped | |
147 using this redirect parameter is called "full redirection" | 130 using this redirect parameter is called "full redirection" |
148 using self.pageRedirect is called "partial redirection" (because some rendering method | 131 using self.pageRedirect is called "partial redirection" (because some |
149 can still be used, e.g. parse_url) | 132 rendering method can still be used, e.g. parse_url) |
150 @param access(unicode, None): permission needed to access the page | 133 @param access(unicode, None): permission needed to access the page |
151 None means public access. | 134 None means public access. |
152 Pages inherit from parent pages: e.g. if a "settings" page is restricted to admins, | 135 Pages inherit from parent pages: e.g. if a "settings" page is restricted |
153 and if "settings/blog" is public, it still can only be accessed by admins. | 136 to admins, and if "settings/blog" is public, it still can only be accessed by |
154 see C.PAGES_ACCESS_* for details | 137 admins. See C.PAGES_ACCESS_* for details |
155 @param dynamic(bool): if True, activate websocket for bidirectional communication | 138 @param dynamic(bool): if True, activate websocket for bidirectional communication |
156 @param parse_url(callable, None): if set it will be called to handle the URL path | 139 @param parse_url(callable, None): if set it will be called to handle the URL path |
157 after this method, the page will be rendered if noting is left in path (request.postpath) | 140 after this method, the page will be rendered if noting is left in path |
158 else a the request will be transmitted to a subpage | 141 (request.postpath) else a the request will be transmitted to a subpage |
159 @param prepare_render(callable, None): if set, will be used to prepare the rendering | 142 @param prepare_render(callable, None): if set, will be used to prepare the |
160 that often means gathering data using the bridge | 143 rendering. That often means gathering data using the bridge |
161 @param render(callable, None): if not template is set, this method will be called and | 144 @param render(callable, None): if not template is set, this method will be |
162 what it returns will be rendered. | 145 called and what it returns will be rendered. |
163 This method is mutually exclusive with template and must return a unicode string. | 146 This method is mutually exclusive with template and must return a unicode |
147 string. | |
164 @param template(unicode, None): path to the template to render. | 148 @param template(unicode, None): path to the template to render. |
165 This method is mutually exclusive with render | 149 This method is mutually exclusive with render |
166 @param on_data_post(callable, None): method to call when data is posted | 150 @param on_data_post(callable, None): method to call when data is posted |
167 None if not post is handled | 151 None if not post is handled |
168 on_data_post can return a string with following value: | 152 on_data_post can return a string with following value: |
169 - C.POST_NO_CONFIRM: confirm flag will not be set | 153 - C.POST_NO_CONFIRM: confirm flag will not be set |
170 @param on_data(callable, None): method to call when dynamic data is sent | 154 @param on_data(callable, None): method to call when dynamic data is sent |
171 this method is used with Libervia's websocket mechanism | 155 this method is used with Libervia's websocket mechanism |
172 @param on_signal(callable, None): method to call when a registered signal is received | 156 @param on_signal(callable, None): method to call when a registered signal is |
173 this method is used with Libervia's websocket mechanism | 157 received. This method is used with Libervia's websocket mechanism |
158 @param url_cache(boolean): if set, result of parse_url is cached (per profile). | |
159 Useful when costly calls (e.g. network) are done while parsing URL. | |
174 """ | 160 """ |
175 | 161 |
176 web_resource.Resource.__init__(self) | 162 web_resource.Resource.__init__(self) |
177 self.host = host | 163 self.host = host |
164 self.vhost_root = vhost_root | |
178 self.root_dir = root_dir | 165 self.root_dir = root_dir |
179 self.url = url | 166 self.url = url |
180 self.name = name | 167 self.name = name |
181 if name is not None: | 168 if name is not None: |
182 if name in self.named_pages: | 169 if name in self.named_pages: |
183 raise exceptions.ConflictError( | 170 raise exceptions.ConflictError( |
184 _(u'a Libervia page named "{}" already exists'.format(name)) | 171 _(u'a Libervia page named "{}" already exists'.format(name))) |
185 ) | |
186 if u"/" in name: | 172 if u"/" in name: |
187 raise ValueError(_(u'"/" is not allowed in page names')) | 173 raise ValueError(_(u'"/" is not allowed in page names')) |
188 if not name: | 174 if not name: |
189 raise ValueError(_(u"a page name can't be empty")) | 175 raise ValueError(_(u"a page name can't be empty")) |
190 self.named_pages[name] = self | 176 self.named_pages[name] = self |
206 if not all( | 192 if not all( |
207 lambda x: x is not None | 193 lambda x: x is not None |
208 for x in (parse_url, prepare_render, render, template) | 194 for x in (parse_url, prepare_render, render, template) |
209 ): | 195 ): |
210 raise ValueError( | 196 raise ValueError( |
211 _( | 197 _(u"you can't use full page redirection with other rendering" |
212 u"you can't use full page redirection with other rendering method," | 198 u"method, check self.pageRedirect if you need to use them")) |
213 u"check self.pageRedirect if you need to use them" | |
214 ) | |
215 ) | |
216 self.redirect = redirect | 199 self.redirect = redirect |
217 else: | 200 else: |
218 self.redirect = None | 201 self.redirect = None |
219 self.parse_url = parse_url | 202 self.parse_url = parse_url |
220 self.prepare_render = prepare_render | 203 self.prepare_render = prepare_render |
236 # it must then contain a list of the the keys to use (without the page instance) | 219 # it must then contain a list of the the keys to use (without the page instance) |
237 # e.g. [C.SERVICE_PROFILE, "pubsub", server@example.tld, pubsub_node] | 220 # e.g. [C.SERVICE_PROFILE, "pubsub", server@example.tld, pubsub_node] |
238 self._do_cache = None | 221 self._do_cache = None |
239 | 222 |
240 def __unicode__(self): | 223 def __unicode__(self): |
241 return u"LiberviaPage {name} at {url}".format( | 224 return u"LiberviaPage {name} at {url} (vhost: {vhost_root})".format( |
242 name=self.name or u"<anonymous>", url=self.url | 225 name=self.name or u"<anonymous>", url=self.url, vhost_root=self.vhost_root) |
243 ) | |
244 | 226 |
245 def __str__(self): | 227 def __str__(self): |
246 return self.__unicode__().encode("utf-8") | 228 return self.__unicode__().encode("utf-8") |
247 | 229 |
230 | |
231 @property | |
232 def named_pages(self): | |
233 return self.vhost_root.named_pages | |
234 | |
235 @property | |
236 def uri_callbacks(self): | |
237 return self.vhost_root.uri_callbacks | |
238 | |
239 @property | |
240 def pages_redirects(self): | |
241 return self.vhost_root.pages_redirects | |
242 | |
243 @property | |
244 def cached_urls(self): | |
245 return self.vhost_root.cached_urls | |
246 | |
247 @property | |
248 def main_menu(self): | |
249 return self.vhost_root.main_menu | |
250 | |
248 @classmethod | 251 @classmethod |
249 def importPages(cls, host, parent=None, path=None): | 252 def importPages(cls, host, vhost_root, root_path=None, _parent=None, _path=None, |
250 """Recursively import Libervia pages""" | 253 _extra_pages=False): |
251 if path is None: | 254 """Recursively import Libervia pages |
252 path = [] | 255 |
253 if parent is None: | 256 @param host(Libervia): Libervia instance |
254 root_dir = os.path.join(os.path.dirname(libervia.__file__), C.PAGES_DIR) | 257 @param vhost_root(LiberviaRootResource): root of this VirtualHost |
255 parent = host | 258 @param root_path(unicode, None): use this root path instead of vhost_root's one |
259 Used to add default site pages to external sites | |
260 @param _parent(Resource, None): _parent page. Do not set yourself, this is for | |
261 internal use only | |
262 @param _path(list(unicode), None): current path. Do not set yourself, this is for | |
263 internal use only | |
264 @param _extra_pages(boolean): set to True when extra pages are used (i.e. | |
265 root_path is set). Do not set yourself, this is for internal use only | |
266 """ | |
267 if _path is None: | |
268 _path = [] | |
269 if _parent is None: | |
270 if root_path is None: | |
271 root_dir = os.path.join(vhost_root.site_path, C.PAGES_DIR) | |
272 else: | |
273 root_dir = os.path.join(root_path, C.PAGES_DIR) | |
274 _extra_pages = True | |
275 _parent = vhost_root | |
256 else: | 276 else: |
257 root_dir = parent.root_dir | 277 root_dir = _parent.root_dir |
258 for d in os.listdir(root_dir): | 278 for d in os.listdir(root_dir): |
259 dir_path = os.path.join(root_dir, d) | 279 dir_path = os.path.join(root_dir, d) |
260 if not os.path.isdir(dir_path): | 280 if not os.path.isdir(dir_path): |
261 continue | 281 continue |
282 if _extra_pages and d in _parent.children: | |
283 log.debug(_(u"[{host_name}] {path} is already present, ignoring it").format( | |
284 host_name=vhost_root.host_name, path=u'/'.join(_path+[d]))) | |
285 continue | |
262 meta_path = os.path.join(dir_path, C.PAGES_META_FILE) | 286 meta_path = os.path.join(dir_path, C.PAGES_META_FILE) |
263 if os.path.isfile(meta_path): | 287 if os.path.isfile(meta_path): |
264 page_data = {} | 288 page_data = {} |
265 new_path = path + [d] | 289 new_path = _path + [d] |
266 # we don't want to force the presence of __init__.py | 290 # we don't want to force the presence of __init__.py |
267 # so we use execfile instead of import. | 291 # so we use execfile instead of import. |
268 # TODO: when moved to Python 3, __init__.py is not mandatory anymore | 292 # TODO: when moved to Python 3, __init__.py is not mandatory anymore |
269 # so we can switch to import | 293 # so we can switch to import |
270 execfile(meta_path, page_data) | 294 execfile(meta_path, page_data) |
271 resource = LiberviaPage( | 295 try: |
272 host, | 296 resource = LiberviaPage( |
273 dir_path, | 297 host=host, |
274 u"/" + u"/".join(new_path), | 298 vhost_root=vhost_root, |
275 name=page_data.get("name"), | 299 root_dir=dir_path, |
276 redirect=page_data.get("redirect"), | 300 url=u"/" + u"/".join(new_path), |
277 access=page_data.get("access"), | 301 name=page_data.get(u"name"), |
278 dynamic=page_data.get("dynamic", False), | 302 redirect=page_data.get(u"redirect"), |
279 parse_url=page_data.get("parse_url"), | 303 access=page_data.get(u"access"), |
280 prepare_render=page_data.get("prepare_render"), | 304 dynamic=page_data.get(u"dynamic", False), |
281 render=page_data.get("render"), | 305 parse_url=page_data.get(u"parse_url"), |
282 template=page_data.get("template"), | 306 prepare_render=page_data.get(u"prepare_render"), |
283 on_data_post=page_data.get("on_data_post"), | 307 render=page_data.get(u"render"), |
284 on_data=page_data.get("on_data"), | 308 template=page_data.get(u"template"), |
285 on_signal=page_data.get("on_signal"), | 309 on_data_post=page_data.get(u"on_data_post"), |
286 url_cache=page_data.get("url_cache", False), | 310 on_data=page_data.get(u"on_data"), |
287 ) | 311 on_signal=page_data.get(u"on_signal"), |
288 parent.putChild(d, resource) | 312 url_cache=page_data.get(u"url_cache", False), |
289 log.info(u"Added /{path} page".format(path=u"[...]/".join(new_path))) | 313 ) |
314 except exceptions.ConflictError as e: | |
315 if _extra_pages: | |
316 # extra pages are discarded if there is already an existing page | |
317 continue | |
318 else: | |
319 raise e | |
320 _parent.putChild(d, resource) | |
321 log_msg = (u"[{host_name}] Added /{path} page".format( | |
322 host_name=vhost_root.host_name, | |
323 path=u"[…]/".join(new_path))) | |
324 if _extra_pages: | |
325 log.debug(log_msg) | |
326 else: | |
327 log.info(log_msg) | |
290 if "uri_handlers" in page_data: | 328 if "uri_handlers" in page_data: |
291 if not isinstance(page_data, dict): | 329 if not isinstance(page_data, dict): |
292 log.error(_(u"uri_handlers must be a dict")) | 330 log.error(_(u"uri_handlers must be a dict")) |
293 else: | 331 else: |
294 for uri_tuple, cb_name in page_data["uri_handlers"].iteritems(): | 332 for uri_tuple, cb_name in page_data["uri_handlers"].iteritems(): |
295 if len(uri_tuple) != 2 or not isinstance(cb_name, basestring): | 333 if len(uri_tuple) != 2 or not isinstance(cb_name, basestring): |
296 log.error(_(u"invalid uri_tuple")) | 334 log.error(_(u"invalid uri_tuple")) |
297 continue | 335 continue |
298 log.info(_(u"setting {}/{} URIs handler").format(*uri_tuple)) | 336 if not _extra_pages: |
337 log.info(_(u"setting {}/{} URIs handler") | |
338 .format(*uri_tuple)) | |
299 try: | 339 try: |
300 cb = page_data[cb_name] | 340 cb = page_data[cb_name] |
301 except KeyError: | 341 except KeyError: |
302 log.error( | 342 log.error(_(u"missing {name} method to handle {1}/{2}") |
303 _(u"missing {name} method to handle {1}/{2}").format( | 343 .format(name=cb_name, *uri_tuple)) |
304 name=cb_name, *uri_tuple | |
305 ) | |
306 ) | |
307 continue | 344 continue |
308 else: | 345 else: |
309 resource.registerURI(uri_tuple, cb) | 346 resource.registerURI(uri_tuple, cb) |
310 | 347 |
311 LiberviaPage.importPages(host, resource, new_path) | 348 LiberviaPage.importPages( |
312 | 349 host, vhost_root, _parent=resource, _path=new_path, _extra_pages=_extra_pages) |
313 @classmethod | |
314 def setMenu(cls, menus): | |
315 main_menu = [] | |
316 for menu in menus: | |
317 if not menu: | |
318 msg = _(u"menu item can't be empty") | |
319 log.error(msg) | |
320 raise ValueError(msg) | |
321 elif isinstance(menu, list): | |
322 if len(menu) != 2: | |
323 msg = _( | |
324 u"menu item as list must be in the form [page_name, absolue URL]" | |
325 ) | |
326 log.error(msg) | |
327 raise ValueError(msg) | |
328 page_name, url = menu | |
329 else: | |
330 page_name = menu | |
331 try: | |
332 url = cls.getPageByName(page_name).url | |
333 except KeyError as e: | |
334 log.error( | |
335 _( | |
336 u"Can'find a named page ({msg}), please check menu_json in configuration." | |
337 ).format(msg=e) | |
338 ) | |
339 raise e | |
340 main_menu.append((page_name, url)) | |
341 cls.main_menu = main_menu | |
342 | 350 |
343 def registerURI(self, uri_tuple, get_uri_cb): | 351 def registerURI(self, uri_tuple, get_uri_cb): |
344 """register a URI handler | 352 """register a URI handler |
345 | 353 |
346 @param uri_tuple(tuple[unicode, unicode]): type or URIs handler | 354 @param uri_tuple(tuple[unicode, unicode]): type or URIs handler |
349 @param get_uri_cb(callable): method which take uri_data dict as only argument | 357 @param get_uri_cb(callable): method which take uri_data dict as only argument |
350 and return absolute path with correct arguments or None if the page | 358 and return absolute path with correct arguments or None if the page |
351 can't handle this URL | 359 can't handle this URL |
352 """ | 360 """ |
353 if uri_tuple in self.uri_callbacks: | 361 if uri_tuple in self.uri_callbacks: |
354 log.info( | 362 log.info(_(u"{}/{} URIs are already handled, replacing by the new handler") |
355 _(u"{}/{} URIs are already handled, replacing by the new handler").format( | 363 .format( *uri_tuple)) |
356 *uri_tuple | |
357 ) | |
358 ) | |
359 self.uri_callbacks[uri_tuple] = (self, get_uri_cb) | 364 self.uri_callbacks[uri_tuple] = (self, get_uri_cb) |
360 | 365 |
361 def registerSignal(self, request, signal, check_profile=True): | 366 def registerSignal(self, request, signal, check_profile=True): |
362 r"""register a signal handler | 367 r"""register a signal handler |
363 | 368 |
367 - signal name | 372 - signal name |
368 - signal arguments | 373 - signal arguments |
369 signal handler will be removed when connection with dynamic page will be lost | 374 signal handler will be removed when connection with dynamic page will be lost |
370 @param signal(unicode): name of the signal | 375 @param signal(unicode): name of the signal |
371 last arg of signal must be profile, as it will be checked to filter signals | 376 last arg of signal must be profile, as it will be checked to filter signals |
372 @param check_profile(bool): if True, signal profile (which MUST be last arg) will be | 377 @param check_profile(bool): if True, signal profile (which MUST be last arg) |
373 checked against session profile. | 378 will be checked against session profile. |
374 /!\ if False, profile will not be checked/filtered, be sure to know what you are doing | 379 /!\ if False, profile will not be checked/filtered, be sure to know what you |
375 if you unset this option /!\ | 380 are doing if you unset this option /!\ |
376 """ | 381 """ |
377 # FIXME: add a timeout, if socket is not opened before it, signal handler must be removed | 382 # FIXME: add a timeout; if socket is not opened before it, signal handler |
383 # must be removed | |
378 if not self.dynamic: | 384 if not self.dynamic: |
379 log.error(_(u"You can't register signal if page is not dynamic")) | 385 log.error(_(u"You can't register signal if page is not dynamic")) |
380 return | 386 return |
381 LiberviaPage.signals_handlers.setdefault(signal, {})[id(request)] = ( | 387 LiberviaPage.signals_handlers.setdefault(signal, {})[id(request)] = ( |
382 self, | 388 self, |
383 request, | 389 request, |
384 check_profile, | 390 check_profile, |
385 ) | 391 ) |
386 request._signals_registered.append(signal) | 392 request._signals_registered.append(signal) |
387 | 393 |
388 @classmethod | 394 def getPageByName(self, name): |
389 def getPagePathFromURI(cls, uri): | 395 return self.vhost_root.getPageByName(name) |
390 """Retrieve page URL from xmpp: URI | 396 |
391 | 397 def getPagePathFromURI(self, uri): |
392 @param uri(unicode): URI with a xmpp: scheme | 398 return self.vhost.getPagePathFromURI(uri) |
393 @return (unicode,None): absolute path (starting from root "/") to page handling the URI | |
394 None is returned if no page has been registered for this URI | |
395 """ | |
396 uri_data = common_uri.parseXMPPUri(uri) | |
397 try: | |
398 page, cb = cls.uri_callbacks[uri_data["type"], uri_data["sub_type"]] | |
399 except KeyError: | |
400 url = None | |
401 else: | |
402 url = cb(page, uri_data) | |
403 if url is None: | |
404 # no handler found | |
405 # we try to find a more generic one | |
406 try: | |
407 page, cb = cls.uri_callbacks[uri_data["type"], None] | |
408 except KeyError: | |
409 pass | |
410 else: | |
411 url = cb(page, uri_data) | |
412 return url | |
413 | |
414 @classmethod | |
415 def getPageByName(cls, name): | |
416 """retrieve page instance from its name | |
417 | |
418 @param name(unicode): name of the page | |
419 @return (LiberviaPage): page instance | |
420 @raise KeyError: the page doesn't exist | |
421 """ | |
422 return cls.named_pages[name] | |
423 | 399 |
424 def getPageRedirectURL(self, request, page_name=u"login", url=None): | 400 def getPageRedirectURL(self, request, page_name=u"login", url=None): |
425 """generate URL for a page with redirect_url parameter set | 401 """generate URL for a page with redirect_url parameter set |
426 | 402 |
427 mainly used for login page with redirection to current page | 403 mainly used for login page with redirection to current page |
548 ) | 524 ) |
549 | 525 |
550 def getURLByNames(self, named_path): | 526 def getURLByNames(self, named_path): |
551 """retrieve URL from pages names and arguments | 527 """retrieve URL from pages names and arguments |
552 | 528 |
529 @param request(server.Request): request linked to the session | |
553 @param named_path(list[tuple[unicode, list[unicode]]]): path to the page as a list | 530 @param named_path(list[tuple[unicode, list[unicode]]]): path to the page as a list |
554 of tuples of 2 items: | 531 of tuples of 2 items: |
555 - first item is page name | 532 - first item is page name |
556 - second item is list of path arguments of this page | 533 - second item is list of path arguments of this page |
557 @return (unicode): URL to the requested page with given path arguments | 534 @return (unicode): URL to the requested page with given path arguments |
568 page_name, parent=current_page | 545 page_name, parent=current_page |
569 ) | 546 ) |
570 path.append(sub_path) | 547 path.append(sub_path) |
571 if page_args: | 548 if page_args: |
572 path.extend([quote(a) for a in page_args]) | 549 path.extend([quote(a) for a in page_args]) |
573 return self.host.checkRedirection(u"/".join(path)) | 550 return self.host.checkRedirection(self.vhost_root, u"/".join(path)) |
574 | 551 |
575 def getURLByPath(self, *args): | 552 def getURLByPath(self, *args): |
576 """generate URL by path | 553 """generate URL by path |
577 | 554 |
578 this method as a similar effect as getURLByNames, but it is more readable | 555 this method as a similar effect as getURLByNames, but it is more readable |
579 by using SubPage to get pages instead of using tuples | 556 by using SubPage to get pages instead of using tuples |
557 @param request(server.Request): request linked to the session | |
580 @param *args: path element: | 558 @param *args: path element: |
581 - if unicode, will be used as argument | 559 - if unicode, will be used as argument |
582 - if util.SubPage instance, must be the name of a subpage | 560 - if util.SubPage instance, must be the name of a subpage |
583 @return (unicode): generated path | 561 @return (unicode): generated path |
584 """ | 562 """ |
605 if not args: | 583 if not args: |
606 break | 584 break |
607 else: | 585 else: |
608 path, current_page = current_page.getSubPageByName(args.pop(0)) | 586 path, current_page = current_page.getSubPageByName(args.pop(0)) |
609 arguments = [path] | 587 arguments = [path] |
610 return self.host.checkRedirection(u"/".join(url_elts)) | 588 return self.host.checkRedirection(self.vhost_root, u"/".join(url_elts)) |
611 | 589 |
612 def getChildWithDefault(self, path, request): | 590 def getChildWithDefault(self, path, request): |
613 # we handle children ourselves | 591 # we handle children ourselves |
614 raise exceptions.InternalError( | 592 raise exceptions.InternalError( |
615 u"this method should not be used with LiberviaPage" | 593 u"this method should not be used with LiberviaPage" |
653 """get several path arguments at once | 631 """get several path arguments at once |
654 | 632 |
655 Arguments will be put in request data. | 633 Arguments will be put in request data. |
656 Missing arguments will have None value | 634 Missing arguments will have None value |
657 @param names(list[unicode]): list of arguments to get | 635 @param names(list[unicode]): list of arguments to get |
658 @param min_args(int): if less than min_args are found, PageError is used with C.HTTP_BAD_REQUEST | 636 @param min_args(int): if less than min_args are found, PageError is used with |
659 use 0 to ignore | 637 C.HTTP_BAD_REQUEST |
638 Use 0 to ignore | |
660 @param **kwargs: special value or optional callback to use for arguments | 639 @param **kwargs: special value or optional callback to use for arguments |
661 names of the arguments must correspond to those in names | 640 names of the arguments must correspond to those in names |
662 special values may be: | 641 special values may be: |
663 - '': use empty string instead of None when no value is specified | 642 - '': use empty string instead of None when no value is specified |
664 - '@': if value of argument is empty or '@', empty string will be used | 643 - '@': if value of argument is empty or '@', empty string will be used |
665 - 'jid': value must be converted to jid.JID if it exists, else empty string is used | 644 - 'jid': value must be converted to jid.JID if it exists, else empty |
666 - '@jid': if value of arguments is empty or '@', empty string will be used, else it will be converted to jid | 645 string is used |
646 - '@jid': if value of arguments is empty or '@', empty string will be | |
647 used, else it will be converted to jid | |
667 """ | 648 """ |
668 data = self.getRData(request) | 649 data = self.getRData(request) |
669 | 650 |
670 for idx, name in enumerate(names): | 651 for idx, name in enumerate(names): |
671 if name[0] == u"*": | 652 if name[0] == u"*": |
686 idx -= 1 | 667 idx -= 1 |
687 break | 668 break |
688 | 669 |
689 values_count = idx + 1 | 670 values_count = idx + 1 |
690 if values_count < min_args: | 671 if values_count < min_args: |
691 log.warning( | 672 log.warning(_(u"Missing arguments in URL (got {count}, expected at least " |
692 _( | 673 u"{min_args})").format(count=values_count, min_args=min_args)) |
693 u"Missing arguments in URL (got {count}, expected at least {min_args})" | |
694 ).format(count=values_count, min_args=min_args) | |
695 ) | |
696 self.pageError(request, C.HTTP_BAD_REQUEST) | 674 self.pageError(request, C.HTTP_BAD_REQUEST) |
697 | 675 |
698 for name in names[values_count:]: | 676 for name in names[values_count:]: |
699 data[name] = None | 677 data[name] = None |
700 | 678 |
765 if not node: | 743 if not node: |
766 try: | 744 try: |
767 short = kwargs["short"] | 745 short = kwargs["short"] |
768 node = self.host.ns_map[short] | 746 node = self.host.ns_map[short] |
769 except KeyError: | 747 except KeyError: |
770 log.warning( | 748 log.warning(_(u'Can\'t use cache for empty node without namespace ' |
771 _( | 749 u'set, please ensure to set "short" and that it is ' |
772 u'Can\'t use cache for empty node without namespace set, please ensure to set "short" and that it is registered' | 750 u'registered')) |
773 ) | |
774 ) | |
775 return | 751 return |
776 if profile != C.SERVICE_PROFILE: | 752 if profile != C.SERVICE_PROFILE: |
777 # only service profile is cache for now | 753 # only service profile is cache for now |
778 return | 754 return |
779 try: | 755 try: |
780 cache = self.cache[profile][cache_type][service][node][request.uri][self] | 756 cache = (self.cache[profile][cache_type][service][node] |
757 [self.vhost_root][request.uri][self]) | |
781 except KeyError: | 758 except KeyError: |
782 # no cache yet, let's subscribe to the pubsub node | 759 # no cache yet, let's subscribe to the pubsub node |
783 d1 = self.host.bridgeCall( | 760 d1 = self.host.bridgeCall( |
784 "psSubscribe", service.full(), node, {}, profile | 761 "psSubscribe", service.full(), node, {}, profile |
785 ) | 762 ) |
786 d1.addCallback(self.checkCacheSubscribeCb, service, node) | 763 d1.addCallback(self.checkCacheSubscribeCb, service, node) |
787 d1.addErrback(self.checkCacheSubscribeEb, service, node) | 764 d1.addErrback(self.checkCacheSubscribeEb, service, node) |
788 d2 = self.host.bridgeCall("psNodeWatchAdd", service.full(), node, profile) | 765 d2 = self.host.bridgeCall("psNodeWatchAdd", service.full(), node, profile) |
789 d2.addErrback(self.psNodeWatchAddEb, service, node) | 766 d2.addErrback(self.psNodeWatchAddEb, service, node) |
790 self._do_cache = [self, profile, cache_type, service, node, request.uri] | 767 self._do_cache = [self, profile, cache_type, service, node, |
768 self.vhost_root, request.uri] | |
791 # we don't return the Deferreds as it is not needed to wait for | 769 # we don't return the Deferreds as it is not needed to wait for |
792 # the subscription to continue with page rendering | 770 # the subscription to continue with page rendering |
793 return | 771 return |
794 | 772 |
795 else: | 773 else: |
800 self._checkCacheHeaders(request, cache) | 778 self._checkCacheHeaders(request, cache) |
801 request.write(cache.rendered) | 779 request.write(cache.rendered) |
802 request.finish() | 780 request.finish() |
803 raise failure.Failure(exceptions.CancelError(u"cache is used")) | 781 raise failure.Failure(exceptions.CancelError(u"cache is used")) |
804 | 782 |
805 def _cacheURL(self, dummy, request, profile): | 783 def _cacheURL(self, __, request, profile): |
806 self.cached_urls.setdefault(profile, {})[request.uri] = CacheURL(request) | 784 self.cached_urls.setdefault(profile, {})[request.uri] = CacheURL(request) |
807 | 785 |
808 @classmethod | 786 @classmethod |
809 def onNodeEvent(cls, host, service, node, event_type, items, profile): | 787 def onNodeEvent(cls, host, service, node, event_type, items, profile): |
810 """Invalidate cache for all pages linked to this node""" | 788 """Invalidate cache for all pages linked to this node""" |
811 try: | 789 try: |
812 cache = cls.cache[profile][C.CACHE_PUBSUB][jid.JID(service)][node] | 790 cache = cls.cache[profile][C.CACHE_PUBSUB][jid.JID(service)][node] |
813 except KeyError: | 791 except KeyError: |
814 log.info( | 792 log.info(_( |
815 _( | 793 u"Removing subscription for {service}/{node}: " |
816 u"Removing subscription for {service}/{node}: " | 794 u"the page is not cached").format(service=service, node=node)) |
817 u"the page is not cached" | |
818 ).format(service=service, node=node) | |
819 ) | |
820 d1 = host.bridgeCall("psUnsubscribe", service, node, profile) | 795 d1 = host.bridgeCall("psUnsubscribe", service, node, profile) |
821 d1.addErrback( | 796 d1.addErrback( |
822 lambda failure_: log.warning( | 797 lambda failure_: log.warning( |
823 _(u"Can't unsubscribe from {service}/{node}: {msg}").format( | 798 _(u"Can't unsubscribe from {service}/{node}: {msg}").format( |
824 service=service, node=node, msg=failure_ | 799 service=service, node=node, msg=failure_))) |
825 ) | |
826 ) | |
827 ) | |
828 d2 = host.bridgeCall("psNodeWatchAdd", service, node, profile) | 800 d2 = host.bridgeCall("psNodeWatchAdd", service, node, profile) |
829 # TODO: check why the page is not in cache, remove subscription? | 801 # TODO: check why the page is not in cache, remove subscription? |
830 d2.addErrback( | 802 d2.addErrback( |
831 lambda failure_: log.warning( | 803 lambda failure_: log.warning( |
832 _(u"Can't remove watch for {service}/{node}: {msg}").format( | 804 _(u"Can't remove watch for {service}/{node}: {msg}").format( |
833 service=service, node=node, msg=failure_ | 805 service=service, node=node, msg=failure_))) |
834 ) | |
835 ) | |
836 ) | |
837 else: | 806 else: |
838 cache.clear() | 807 cache.clear() |
839 | 808 |
840 @classmethod | 809 @classmethod |
841 def onSignal(cls, host, signal, *args): | 810 def onSignal(cls, host, signal, *args): |
887 """ | 856 """ |
888 for signal in request._signals_registered: | 857 for signal in request._signals_registered: |
889 try: | 858 try: |
890 del LiberviaPage.signals_handlers[signal][id(request)] | 859 del LiberviaPage.signals_handlers[signal][id(request)] |
891 except KeyError: | 860 except KeyError: |
892 log.error( | 861 log.error(_(u"Can't find signal handler for [{signal}], this should not " |
893 _( | 862 u"happen").format(signal=signal)) |
894 u"Can't find signal handler for [{signal}], this should not happen" | |
895 ).format(signal=signal) | |
896 ) | |
897 else: | 863 else: |
898 log.debug(_(u"Removed signal handler")) | 864 log.debug(_(u"Removed signal handler")) |
899 | 865 |
900 def delegateToResource(self, request, resource): | 866 def delegateToResource(self, request, resource): |
901 """continue workflow with Twisted Resource""" | 867 """continue workflow with Twisted Resource""" |
950 else: | 916 else: |
951 - first element is name as registered in name variable | 917 - first element is name as registered in name variable |
952 - following element are subpages path | 918 - following element are subpages path |
953 e.g.: "blog" redirect to page named "blog" | 919 e.g.: "blog" redirect to page named "blog" |
954 "blog/atom.xml" redirect to atom.xml subpage of "blog" | 920 "blog/atom.xml" redirect to atom.xml subpage of "blog" |
955 "/common/blog/atom.xml" redirect to the page at the fiven full path | 921 "/common/blog/atom.xml" redirect to the page at the given full path |
956 @param request(server.Request): current HTTP request | 922 @param request(server.Request): current HTTP request |
957 @param skip_parse_url(bool): if True, parse_url method on redirect page will be skipped | 923 @param skip_parse_url(bool): if True, parse_url method on redirect page will be |
924 skipped | |
958 @param path_args(list[unicode], None): path arguments to use in redirected page | 925 @param path_args(list[unicode], None): path arguments to use in redirected page |
959 @raise KeyError: there is no known page with this name | 926 @raise KeyError: there is no known page with this name |
960 """ | 927 """ |
961 # FIXME: render non LiberviaPage resources | 928 # FIXME: render non LiberviaPage resources |
962 path = page_path.rstrip(u"/").split(u"/") | 929 path = page_path.rstrip(u"/").split(u"/") |
963 if not path[0]: | 930 if not path[0]: |
964 redirect_page = self.host.root | 931 redirect_page = self.vhost_root |
965 else: | 932 else: |
966 redirect_page = self.named_pages[path[0]] | 933 redirect_page = self.named_pages[path[0]] |
967 | 934 |
968 for subpage in path[1:]: | 935 for subpage in path[1:]: |
969 if redirect_page is self.host.root: | 936 if redirect_page is self.vhost_root: |
970 redirect_page = redirect_page.children[subpage] | 937 redirect_page = redirect_page.children[subpage] |
971 else: | 938 else: |
972 redirect_page = redirect_page.original.children[subpage] | 939 redirect_page = redirect_page.original.children[subpage] |
973 | 940 |
974 if path_args is not None: | 941 if path_args is not None: |
993 request.setResponseCode(code) | 960 request.setResponseCode(code) |
994 if no_body: | 961 if no_body: |
995 request.finish() | 962 request.finish() |
996 else: | 963 else: |
997 template = u"error/" + unicode(code) + ".html" | 964 template = u"error/" + unicode(code) + ".html" |
965 if self.vhost_root.site_name: | |
966 request.template_data[u'site'] = self.vhost_root.site_name | |
998 | 967 |
999 rendered = self.host.renderer.render( | 968 rendered = self.host.renderer.render( |
1000 template, | 969 template, |
1001 error_code=code, | 970 error_code=code, |
1002 **request.template_data | 971 **request.template_data |
1014 if self._do_cache is not None: | 983 if self._do_cache is not None: |
1015 redirected_page = self._do_cache.pop(0) | 984 redirected_page = self._do_cache.pop(0) |
1016 cache = reduce(lambda d, k: d.setdefault(k, {}), self._do_cache, self.cache) | 985 cache = reduce(lambda d, k: d.setdefault(k, {}), self._do_cache, self.cache) |
1017 page_cache = cache[redirected_page] = CachePage(data_encoded) | 986 page_cache = cache[redirected_page] = CachePage(data_encoded) |
1018 self._setCacheHeaders(request, page_cache) | 987 self._setCacheHeaders(request, page_cache) |
1019 log.debug( | 988 log.debug(_(u"{page} put in cache for [{profile}]") |
1020 _(u"{page} put in cache for [{profile}]").format( | 989 .format( page=self, profile=self._do_cache[0])) |
1021 page=self, profile=self._do_cache[0] | |
1022 ) | |
1023 ) | |
1024 self._do_cache = None | 990 self._do_cache = None |
1025 self._checkCacheHeaders(request, page_cache) | 991 self._checkCacheHeaders(request, page_cache) |
1026 | 992 |
1027 request.write(data_encoded) | 993 request.write(data_encoded) |
1028 request.finish() | 994 request.finish() |
1029 | 995 |
1030 def _subpagesHandler(self, dummy, request): | 996 def _subpagesHandler(self, __, request): |
1031 """render subpage if suitable | 997 """render subpage if suitable |
1032 | 998 |
1033 this method checks if there is still an unmanaged part of the path | 999 this method checks if there is still an unmanaged part of the path |
1034 and check if it corresponds to a subpage. If so, it render the subpage | 1000 and check if it corresponds to a subpage. If so, it render the subpage |
1035 else it render a NoResource. | 1001 else it render a NoResource. |
1043 self.pageError(request) | 1009 self.pageError(request) |
1044 else: | 1010 else: |
1045 child.render(request) | 1011 child.render(request) |
1046 raise failure.Failure(exceptions.CancelError(u"subpage page is used")) | 1012 raise failure.Failure(exceptions.CancelError(u"subpage page is used")) |
1047 | 1013 |
1048 def _prepare_dynamic(self, dummy, request): | 1014 def _prepare_dynamic(self, __, request): |
1049 # we need to activate dynamic page | 1015 # we need to activate dynamic page |
1050 # we set data for template, and create/register token | 1016 # we set data for template, and create/register token |
1051 socket_token = unicode(uuid.uuid4()) | 1017 socket_token = unicode(uuid.uuid4()) |
1052 socket_url = self.host.getWebsocketURL(request) | 1018 socket_url = self.host.getWebsocketURL(request) |
1053 socket_debug = C.boolConst(self.host.debug) | 1019 socket_debug = C.boolConst(self.host.debug) |
1058 # we will keep track of handlers to remove | 1024 # we will keep track of handlers to remove |
1059 request._signals_registered = [] | 1025 request._signals_registered = [] |
1060 # we will cache registered signals until socket is opened | 1026 # we will cache registered signals until socket is opened |
1061 request._signals_cache = [] | 1027 request._signals_cache = [] |
1062 | 1028 |
1063 def _prepare_render(self, dummy, request): | 1029 def _prepare_render(self, __, request): |
1064 return defer.maybeDeferred(self.prepare_render, self, request) | 1030 return defer.maybeDeferred(self.prepare_render, self, request) |
1065 | 1031 |
1066 def _render_method(self, dummy, request): | 1032 def _render_method(self, __, request): |
1067 return defer.maybeDeferred(self.render_method, self, request) | 1033 return defer.maybeDeferred(self.render_method, self, request) |
1068 | 1034 |
1069 def _render_template(self, dummy, request): | 1035 def _render_template(self, __, request): |
1070 template_data = request.template_data | 1036 template_data = request.template_data |
1071 | 1037 |
1072 # if confirm variable is set in case of successfuly data post | 1038 # if confirm variable is set in case of successfuly data post |
1073 session_data = self.host.getSessionData(request, session_iface.ISATSession) | 1039 session_data = self.host.getSessionData(request, session_iface.ISATSession) |
1074 if session_data.popPageFlag(self, C.FLAG_CONFIRM): | 1040 if session_data.popPageFlag(self, C.FLAG_CONFIRM): |
1075 template_data[u"confirm"] = True | 1041 template_data[u"confirm"] = True |
1042 if self.vhost_root.site_name: | |
1043 template_data[u'site'] = self.vhost_root.site_name | |
1076 | 1044 |
1077 return self.host.renderer.render( | 1045 return self.host.renderer.render( |
1078 self.template, | 1046 self.template, |
1079 media_path="/" + C.MEDIA_DIR, | 1047 media_path="/" + C.MEDIA_DIR, |
1080 cache_path=session_data.cache_dir, | 1048 cache_path=session_data.cache_dir, |
1081 main_menu=LiberviaPage.main_menu, | 1049 main_menu=self.main_menu, |
1082 **template_data | 1050 **template_data) |
1083 ) | |
1084 | 1051 |
1085 def _renderEb(self, failure_, request): | 1052 def _renderEb(self, failure_, request): |
1086 """don't raise error on CancelError""" | 1053 """don't raise error on CancelError""" |
1087 failure_.trap(exceptions.CancelError) | 1054 failure_.trap(exceptions.CancelError) |
1088 | 1055 |
1089 def _internalError(self, failure_, request): | 1056 def _internalError(self, failure_, request): |
1090 """called if an error is not catched""" | 1057 """called if an error is not catched""" |
1091 log.error( | 1058 log.error(_(u"Uncatched error for HTTP request on {url}: {msg}") |
1092 _(u"Uncatched error for HTTP request on {url}: {msg}").format( | 1059 .format( url=request.URLPath(), msg=failure_)) |
1093 url=request.URLPath(), msg=failure_ | |
1094 ) | |
1095 ) | |
1096 self.pageError(request, C.HTTP_INTERNAL_ERROR) | 1060 self.pageError(request, C.HTTP_INTERNAL_ERROR) |
1097 | 1061 |
1098 def _on_data_post_redirect(self, ret, request): | 1062 def _on_data_post_redirect(self, ret, request): |
1099 """called when page's on_data_post has been done successfuly | 1063 """called when page's on_data_post has been done successfuly |
1100 | 1064 |
1101 This will do a Post/Redirect/Get pattern. | 1065 This will do a Post/Redirect/Get pattern. |
1102 this method redirect to the same page or to request.data['post_redirect_page'] | 1066 this method redirect to the same page or to request.data['post_redirect_page'] |
1103 post_redirect_page can be either a page or a tuple with page as first item, then a list of unicode arguments to append to the url. | 1067 post_redirect_page can be either a page or a tuple with page as first item, then |
1104 if post_redirect_page is not used, initial request.uri (i.e. the same page as where the data have been posted) will be used for redirection. | 1068 a list of unicode arguments to append to the url. |
1105 HTTP status code "See Other" (303) is used as it is the recommanded code in this case. | 1069 if post_redirect_page is not used, initial request.uri (i.e. the same page as |
1070 where the data have been posted) will be used for redirection. | |
1071 HTTP status code "See Other" (303) is used as it is the recommanded code in | |
1072 this case. | |
1106 @param ret(None, unicode, iterable): on_data_post return value | 1073 @param ret(None, unicode, iterable): on_data_post return value |
1107 see LiberviaPage.__init__ on_data_post docstring | 1074 see LiberviaPage.__init__ on_data_post docstring |
1108 """ | 1075 """ |
1109 if ret is None: | 1076 if ret is None: |
1110 ret = () | 1077 ret = () |
1135 request.setResponseCode(C.HTTP_SEE_OTHER) | 1102 request.setResponseCode(C.HTTP_SEE_OTHER) |
1136 request.setHeader("location", redirect_uri) | 1103 request.setHeader("location", redirect_uri) |
1137 request.finish() | 1104 request.finish() |
1138 raise failure.Failure(exceptions.CancelError(u"Post/Redirect/Get is used")) | 1105 raise failure.Failure(exceptions.CancelError(u"Post/Redirect/Get is used")) |
1139 | 1106 |
1140 def _on_data_post(self, dummy, request): | 1107 def _on_data_post(self, __, request): |
1141 csrf_token = self.host.getSessionData( | 1108 csrf_token = self.host.getSessionData( |
1142 request, session_iface.ISATSession | 1109 request, session_iface.ISATSession |
1143 ).csrf_token | 1110 ).csrf_token |
1144 try: | 1111 try: |
1145 given_csrf = self.getPostedData(request, u"csrf_token") | 1112 given_csrf = self.getPostedData(request, u"csrf_token") |
1163 @param keys(unicode, iterable[unicode]): name of the value(s) to get | 1130 @param keys(unicode, iterable[unicode]): name of the value(s) to get |
1164 unicode to get one value | 1131 unicode to get one value |
1165 iterable to get more than one | 1132 iterable to get more than one |
1166 @param multiple(bool): True if multiple values are possible/expected | 1133 @param multiple(bool): True if multiple values are possible/expected |
1167 if False, the first value is returned | 1134 if False, the first value is returned |
1168 @return (iterator[unicode], list[iterator[unicode], unicode, list[unicode]): values received for this(these) key(s) | 1135 @return (iterator[unicode], list[iterator[unicode], unicode, list[unicode]): |
1136 values received for this(these) key(s) | |
1169 @raise KeyError: one specific key has been requested, and it is missing | 1137 @raise KeyError: one specific key has been requested, and it is missing |
1170 """ | 1138 """ |
1171 # FIXME: request.args is already unquoting the value, it seems we are doing double unquote | 1139 # FIXME: request.args is already unquoting the value, it seems we are doing |
1140 # double unquote | |
1172 if isinstance(keys, basestring): | 1141 if isinstance(keys, basestring): |
1173 keys = [keys] | 1142 keys = [keys] |
1174 get_first = True | 1143 get_first = True |
1175 else: | 1144 else: |
1176 get_first = False | 1145 get_first = False |
1220 | 1189 |
1221 def getRData(self, request): | 1190 def getRData(self, request): |
1222 """helper method to get request data dict | 1191 """helper method to get request data dict |
1223 | 1192 |
1224 this dictionnary if for the request only, it is not saved in session | 1193 this dictionnary if for the request only, it is not saved in session |
1225 It is mainly used to pass data between pages/methods called during request workflow | 1194 It is mainly used to pass data between pages/methods called during request |
1195 workflow | |
1226 @return (dict): request data | 1196 @return (dict): request data |
1227 """ | 1197 """ |
1228 try: | 1198 try: |
1229 return request.data | 1199 return request.data |
1230 except AttributeError: | 1200 except AttributeError: |
1264 if not self.dynamic: | 1234 if not self.dynamic: |
1265 raise exceptions.InternalError( | 1235 raise exceptions.InternalError( |
1266 _(u"renderPartial must only be used with dynamic pages") | 1236 _(u"renderPartial must only be used with dynamic pages") |
1267 ) | 1237 ) |
1268 session_data = self.host.getSessionData(request, session_iface.ISATSession) | 1238 session_data = self.host.getSessionData(request, session_iface.ISATSession) |
1239 if self.vhost_root.site_name: | |
1240 template_data[u'site'] = self.vhost_root.site_name | |
1269 | 1241 |
1270 return self.host.renderer.render( | 1242 return self.host.renderer.render( |
1271 template, | 1243 template, |
1272 media_path="/" + C.MEDIA_DIR, | 1244 media_path="/" + C.MEDIA_DIR, |
1273 cache_path=session_data.cache_dir, | 1245 cache_path=session_data.cache_dir, |
1274 main_menu=LiberviaPage.main_menu, | 1246 main_menu=self.main_menu, |
1275 **template_data | 1247 **template_data |
1276 ) | 1248 ) |
1277 | 1249 |
1278 def renderAndUpdate( | 1250 def renderAndUpdate( |
1279 self, request, template, selectors, template_data_update, update_type="append" | 1251 self, request, template, selectors, template_data_update, update_type="append" |
1317 d = defer.Deferred() | 1289 d = defer.Deferred() |
1318 d.addCallback(self._checkAccess, request) | 1290 d.addCallback(self._checkAccess, request) |
1319 | 1291 |
1320 if self.redirect is not None: | 1292 if self.redirect is not None: |
1321 d.addCallback( | 1293 d.addCallback( |
1322 lambda dummy: self.pageRedirect( | 1294 lambda __: self.pageRedirect( |
1323 self.redirect, request, skip_parse_url=False | 1295 self.redirect, request, skip_parse_url=False |
1324 ) | 1296 ) |
1325 ) | 1297 ) |
1326 | 1298 |
1327 if self.parse_url is not None and not skip_parse_url: | 1299 if self.parse_url is not None and not skip_parse_url: |
1342 | 1314 |
1343 d.addCallback(self._subpagesHandler, request) | 1315 d.addCallback(self._subpagesHandler, request) |
1344 | 1316 |
1345 if request.method not in (C.HTTP_METHOD_GET, C.HTTP_METHOD_POST): | 1317 if request.method not in (C.HTTP_METHOD_GET, C.HTTP_METHOD_POST): |
1346 # only HTTP GET and POST are handled so far | 1318 # only HTTP GET and POST are handled so far |
1347 d.addCallback(lambda dummy: self.pageError(request, C.HTTP_BAD_REQUEST)) | 1319 d.addCallback(lambda __: self.pageError(request, C.HTTP_BAD_REQUEST)) |
1348 | 1320 |
1349 if request.method == C.HTTP_METHOD_POST: | 1321 if request.method == C.HTTP_METHOD_POST: |
1350 if self.on_data_post is None: | 1322 if self.on_data_post is None: |
1351 # if we don't have on_data_post, the page was not expecting POST | 1323 # if we don't have on_data_post, the page was not expecting POST |
1352 # so we return an error | 1324 # so we return an error |
1353 d.addCallback(lambda dummy: self.pageError(request, C.HTTP_BAD_REQUEST)) | 1325 d.addCallback(lambda __: self.pageError(request, C.HTTP_BAD_REQUEST)) |
1354 else: | 1326 else: |
1355 d.addCallback(self._on_data_post, request) | 1327 d.addCallback(self._on_data_post, request) |
1356 # by default, POST follow normal behaviour after on_data_post is called | 1328 # by default, POST follow normal behaviour after on_data_post is called |
1357 # this can be changed by a redirection or other method call in on_data_post | 1329 # this can be changed by a redirection or other method call in on_data_post |
1358 | 1330 |