Mercurial > libervia-web
annotate src/server/pages.py @ 995:f88325b56a6a
server: dynamic pages first draft:
/!\ new dependency: autobahn
This patch introduce server part of dynamic pages.
Dynamic pages use websockets to establish constant connection with a Libervia page, allowing to receive real time data or update it.
The feature is activated by specifying "dynamic = true" in the page.
Once activated, page can implement "on_data" method which will be called when data are sent by the page.
To send data the other way, the page can use request.sendData.
The new "registerSignal" method allows to use an "on_signal" method to be called each time given signal is received, with automatic (and optional) filtering on profile.
New renderPartial and renderAndUpdate method allow to append new HTML elements to the dynamic page.
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 03 Jan 2018 01:10:12 +0100 |
parents | b92b06f023cb |
children | 0848b8b0188d |
rev | line source |
---|---|
331
06a48d805547
server side: make Libervia a Twisted plugin, and add it the --port argument + add a config file for the port.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
330
diff
changeset
|
1 #!/usr/bin/python |
06a48d805547
server side: make Libervia a Twisted plugin, and add it the --port argument + add a config file for the port.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
330
diff
changeset
|
2 # -*- coding: utf-8 -*- |
06a48d805547
server side: make Libervia a Twisted plugin, and add it the --port argument + add a config file for the port.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
330
diff
changeset
|
3 |
339
2067d6241927
fixed docstrings wrong usage for licence informations
Goffi <goffi@goffi.org>
parents:
336
diff
changeset
|
4 # Libervia: a Salut à Toi frontend |
964
fd4eae654182
misc: date update (yes it's a bit late :p )
Goffi <goffi@goffi.org>
parents:
962
diff
changeset
|
5 # Copyright (C) 2011-2017 Jérôme Poisson <goffi@goffi.org> |
331
06a48d805547
server side: make Libervia a Twisted plugin, and add it the --port argument + add a config file for the port.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
330
diff
changeset
|
6 |
339
2067d6241927
fixed docstrings wrong usage for licence informations
Goffi <goffi@goffi.org>
parents:
336
diff
changeset
|
7 # This program is free software: you can redistribute it and/or modify |
2067d6241927
fixed docstrings wrong usage for licence informations
Goffi <goffi@goffi.org>
parents:
336
diff
changeset
|
8 # it under the terms of the GNU Affero General Public License as published by |
2067d6241927
fixed docstrings wrong usage for licence informations
Goffi <goffi@goffi.org>
parents:
336
diff
changeset
|
9 # the Free Software Foundation, either version 3 of the License, or |
2067d6241927
fixed docstrings wrong usage for licence informations
Goffi <goffi@goffi.org>
parents:
336
diff
changeset
|
10 # (at your option) any later version. |
331
06a48d805547
server side: make Libervia a Twisted plugin, and add it the --port argument + add a config file for the port.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
330
diff
changeset
|
11 |
339
2067d6241927
fixed docstrings wrong usage for licence informations
Goffi <goffi@goffi.org>
parents:
336
diff
changeset
|
12 # This program is distributed in the hope that it will be useful, |
2067d6241927
fixed docstrings wrong usage for licence informations
Goffi <goffi@goffi.org>
parents:
336
diff
changeset
|
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
2067d6241927
fixed docstrings wrong usage for licence informations
Goffi <goffi@goffi.org>
parents:
336
diff
changeset
|
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2067d6241927
fixed docstrings wrong usage for licence informations
Goffi <goffi@goffi.org>
parents:
336
diff
changeset
|
15 # GNU Affero General Public License for more details. |
331
06a48d805547
server side: make Libervia a Twisted plugin, and add it the --port argument + add a config file for the port.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
330
diff
changeset
|
16 |
339
2067d6241927
fixed docstrings wrong usage for licence informations
Goffi <goffi@goffi.org>
parents:
336
diff
changeset
|
17 # You should have received a copy of the GNU Affero General Public License |
2067d6241927
fixed docstrings wrong usage for licence informations
Goffi <goffi@goffi.org>
parents:
336
diff
changeset
|
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
331
06a48d805547
server side: make Libervia a Twisted plugin, and add it the --port argument + add a config file for the port.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
330
diff
changeset
|
19 from twisted.web import server |
858 | 20 from twisted.web import resource as web_resource |
21 from twisted.web import util as web_util | |
984
f0fc28b3bd1e
server: moved LiberviaPage code in its own module
Goffi <goffi@goffi.org>
parents:
980
diff
changeset
|
22 from twisted.internet import defer |
985
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
23 from twisted.words.protocols.jabber import jid |
917 | 24 from twisted.python import failure |
449
981ed669d3b3
/!\ reorganize all the file hierarchy, move the code and launching script to src:
souliane <souliane@mailoo.org>
parents:
448
diff
changeset
|
25 |
984
f0fc28b3bd1e
server: moved LiberviaPage code in its own module
Goffi <goffi@goffi.org>
parents:
980
diff
changeset
|
26 from sat.core.i18n import _ |
f0fc28b3bd1e
server: moved LiberviaPage code in its own module
Goffi <goffi@goffi.org>
parents:
980
diff
changeset
|
27 from sat.core import exceptions |
f0fc28b3bd1e
server: moved LiberviaPage code in its own module
Goffi <goffi@goffi.org>
parents:
980
diff
changeset
|
28 from sat.tools.common import uri as common_uri |
438
582c435dab6b
server side: new log system is used
Goffi <goffi@goffi.org>
parents:
435
diff
changeset
|
29 from sat.core.log import getLogger |
582c435dab6b
server side: new log system is used
Goffi <goffi@goffi.org>
parents:
435
diff
changeset
|
30 log = getLogger(__name__) |
984
f0fc28b3bd1e
server: moved LiberviaPage code in its own module
Goffi <goffi@goffi.org>
parents:
980
diff
changeset
|
31 from libervia.server.constants import Const as C |
f0fc28b3bd1e
server: moved LiberviaPage code in its own module
Goffi <goffi@goffi.org>
parents:
980
diff
changeset
|
32 from libervia.server import session_iface |
f0fc28b3bd1e
server: moved LiberviaPage code in its own module
Goffi <goffi@goffi.org>
parents:
980
diff
changeset
|
33 from libervia.server.utils import quote |
682
e6bb64bd6b4d
server side: implemented methods to get SàT and Libervia versions
Goffi <goffi@goffi.org>
parents:
679
diff
changeset
|
34 import libervia |
331
06a48d805547
server side: make Libervia a Twisted plugin, and add it the --port argument + add a config file for the port.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
330
diff
changeset
|
35 |
995 | 36 from collections import namedtuple |
37 import uuid | |
984
f0fc28b3bd1e
server: moved LiberviaPage code in its own module
Goffi <goffi@goffi.org>
parents:
980
diff
changeset
|
38 import os.path |
f0fc28b3bd1e
server: moved LiberviaPage code in its own module
Goffi <goffi@goffi.org>
parents:
980
diff
changeset
|
39 import urllib |
985
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
40 import time |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
41 |
995 | 42 WebsocketMeta = namedtuple("WebsocketMeta", ('url', 'token', 'debug')) |
43 | |
985
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
44 |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
45 class Cache(object): |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
46 |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
47 def __init__(self, rendered): |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
48 self._created = time.time() |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
49 self._last_access = self._created |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
50 self._rendered = rendered |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
51 |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
52 @property |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
53 def created(self): |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
54 return self._created |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
55 |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
56 @property |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
57 def last_access(self): |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
58 return self._last_access |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
59 |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
60 @last_access.setter |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
61 def last_access(self, timestamp): |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
62 self._last_access = timestamp |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
63 |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
64 @property |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
65 def rendered(self): |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
66 return self._rendered |
331
06a48d805547
server side: make Libervia a Twisted plugin, and add it the --port argument + add a config file for the port.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
330
diff
changeset
|
67 |
06a48d805547
server side: make Libervia a Twisted plugin, and add it the --port argument + add a config file for the port.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
330
diff
changeset
|
68 |
917 | 69 class LiberviaPage(web_resource.Resource): |
70 isLeaf = True # we handle subpages ourself | |
71 named_pages = {} | |
925 | 72 uri_callbacks = {} |
995 | 73 signals_handlers = {} |
980
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
74 pages_redirects = {} |
985
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
75 cache = {} |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
76 # Set of tuples (service/node/sub_id) of nodes subscribed for caching |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
77 # sub_id can be empty string if not handled by service |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
78 cache_pubsub_sub = set() |
990
6daa59d44ee2
pages: menu implementation, first draft:
Goffi <goffi@goffi.org>
parents:
985
diff
changeset
|
79 main_menu = None |
917 | 80 |
995 | 81 def __init__(self, host, root_dir, url, name=None, redirect=None, access=None, dynamic=False, parse_url=None, |
82 prepare_render=None, render=None, template=None, | |
83 on_data_post=None, on_data=None, on_signal=None): | |
917 | 84 """initiate LiberviaPages |
85 | |
86 LiberviaPages are the main resources of Libervia, using easy to set python files | |
87 The arguments are the variables found in page_meta.py | |
88 @param host(Libervia): the running instance of Libervia | |
962 | 89 @param root_dir(unicode): aboslute file path of the page |
90 @param url(unicode): relative URL to the page | |
91 this URL may not be valid, as pages may require path arguments | |
917 | 92 @param name(unicode, None): if not None, a unique name to identify the page |
93 can then be used for e.g. redirection | |
923
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
94 "/" is not allowed in names (as it can be used to construct URL paths) |
962 | 95 @param redirect(unicode, None): if not None, this page will be redirected. A redirected |
923
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
96 parameter is used as in self.pageRedirect. parse_url will not be skipped |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
97 using this redirect parameter is called "full redirection" |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
98 using self.pageRedirect is called "partial redirection" (because some rendering method |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
99 can still be used, e.g. parse_url) |
917 | 100 @param access(unicode, None): permission needed to access the page |
101 None means public access. | |
102 Pages inherit from parent pages: e.g. if a "settings" page is restricted to admins, | |
103 and if "settings/blog" is public, it still can only be accessed by admins. | |
104 see C.PAGES_ACCESS_* for details | |
995 | 105 @param dynamic(bool): if True, activate websocket for bidirectional communication |
917 | 106 @param parse_url(callable, None): if set it will be called to handle the URL path |
107 after this method, the page will be rendered if noting is left in path (request.postpath) | |
108 else a the request will be transmitted to a subpage | |
109 @param prepare_render(callable, None): if set, will be used to prepare the rendering | |
110 that often means gathering data using the bridge | |
111 @param render(callable, None): if not template is set, this method will be called and | |
112 what it returns will be rendered. | |
113 This method is mutually exclusive with template and must return a unicode string. | |
114 @param template(unicode, None): path to the template to render. | |
115 This method is mutually exclusive with render | |
931
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
116 @param on_data_post(callable, None): method to call when data is posted |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
117 None if not post is handled |
962 | 118 on_data_post can return a string with following value: |
119 - C.POST_NO_CONFIRM: confirm flag will not be set | |
995 | 120 @param on_data(callable, None): method to call when dynamic data is sent |
121 this method is used with Libervia's websocket mechanism | |
122 @param on_signal(callable, None): method to call when a registered signal is received | |
123 this method is used with Libervia's websocket mechanism | |
917 | 124 """ |
125 | |
126 web_resource.Resource.__init__(self) | |
127 self.host = host | |
128 self.root_dir = root_dir | |
962 | 129 self.url = url |
980
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
130 self.name = name |
917 | 131 if name is not None: |
132 if name in self.named_pages: | |
133 raise exceptions.ConflictError(_(u'a Libervia page named "{}" already exists'.format(name))) | |
923
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
134 if u'/' in name: |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
135 raise ValueError(_(u'"/" is not allowed in page names')) |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
136 if not name: |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
137 raise ValueError(_(u"a page name can't be empty")) |
917 | 138 self.named_pages[name] = self |
139 if access is None: | |
140 access = C.PAGES_ACCESS_PUBLIC | |
922
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
141 if access not in (C.PAGES_ACCESS_PUBLIC, C.PAGES_ACCESS_PROFILE, C.PAGES_ACCESS_NONE): |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
142 raise NotImplementedError(_(u"{} access is not implemented yet").format(access)) |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
143 self.access = access |
995 | 144 self.dynamic = dynamic |
923
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
145 if redirect is not None: |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
146 # only page access and name make sense in case of full redirection |
980
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
147 # so we check that rendering methods/values are not set |
923
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
148 if not all(lambda x: x is not None |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
149 for x in (parse_url, prepare_render, render, template)): |
980
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
150 raise ValueError(_(u"you can't use full page redirection with other rendering method," |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
151 u"check self.pageRedirect if you need to use them")) |
923
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
152 self.redirect = redirect |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
153 else: |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
154 self.redirect = None |
917 | 155 self.parse_url = parse_url |
156 self.prepare_render = prepare_render | |
157 self.template = template | |
158 self.render_method = render | |
931
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
159 self.on_data_post = on_data_post |
995 | 160 self.on_data = on_data |
161 self.on_signal = on_signal | |
922
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
162 if access == C.PAGES_ACCESS_NONE: |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
163 # none pages just return a 404, no further check is needed |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
164 return |
917 | 165 if template is None: |
166 if not callable(render): | |
167 log.error(_(u"render must be implemented and callable if template is not set")) | |
168 else: | |
169 if render is not None: | |
170 log.error(_(u"render can't be used at the same time as template")) | |
171 if parse_url is not None and not callable(parse_url): | |
172 log.error(_(u"parse_url must be a callable")) | |
173 | |
985
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
174 # if not None, next rendering will be cached |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
175 # it must then contain a list of the the keys to use (without the page instance) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
176 # e.g. [C.SERVICE_PROFILE, "pubsub", server@example.tld, pubsub_node] |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
177 self._do_cache = None |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
178 |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
179 def __unicode__(self): |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
180 return u'LiberviaPage {name} at {url}'.format( |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
181 name = self.name or u'<anonymous>', |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
182 url = self.url) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
183 |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
184 def __str__(self): |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
185 return self.__unicode__.encode('utf-8') |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
186 |
925 | 187 @classmethod |
188 def importPages(cls, host, parent=None, path=None): | |
937
00236973e138
server (pages): an HTTP internal error is raised if an error is uncatched during page workflow
Goffi <goffi@goffi.org>
parents:
936
diff
changeset
|
189 """Recursively import Libervia pages""" |
917 | 190 if path is None: |
191 path = [] | |
192 if parent is None: | |
193 root_dir = os.path.join(os.path.dirname(libervia.__file__), C.PAGES_DIR) | |
194 parent = host | |
195 else: | |
196 root_dir = parent.root_dir | |
197 for d in os.listdir(root_dir): | |
198 dir_path = os.path.join(root_dir, d) | |
199 if not os.path.isdir(dir_path): | |
200 continue | |
201 meta_path = os.path.join(dir_path, C.PAGES_META_FILE) | |
202 if os.path.isfile(meta_path): | |
203 page_data = {} | |
962 | 204 new_path = path + [d] |
917 | 205 # we don't want to force the presence of __init__.py |
206 # so we use execfile instead of import. | |
207 # TODO: when moved to Python 3, __init__.py is not mandatory anymore | |
208 # so we can switch to import | |
209 execfile(meta_path, page_data) | |
210 resource = LiberviaPage( | |
211 host, | |
212 dir_path, | |
962 | 213 u'/' + u'/'.join(new_path), |
917 | 214 name=page_data.get('name'), |
923
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
215 redirect=page_data.get('redirect'), |
917 | 216 access=page_data.get('access'), |
995 | 217 dynamic=page_data.get('dynamic', False), |
917 | 218 parse_url=page_data.get('parse_url'), |
219 prepare_render=page_data.get('prepare_render'), | |
220 render=page_data.get('render'), | |
931
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
221 template=page_data.get('template'), |
995 | 222 on_data_post=page_data.get('on_data_post'), |
223 on_data=page_data.get('on_data'), | |
224 on_signal=page_data.get('on_signal'), | |
225 ) | |
917 | 226 parent.putChild(d, resource) |
227 log.info(u"Added /{path} page".format(path=u'[...]/'.join(new_path))) | |
925 | 228 if 'uri_handlers' in page_data: |
229 if not isinstance(page_data, dict): | |
230 log.error(_(u'uri_handlers must be a dict')) | |
231 else: | |
232 for uri_tuple, cb_name in page_data['uri_handlers'].iteritems(): | |
233 if len(uri_tuple) != 2 or not isinstance(cb_name, basestring): | |
234 log.error(_(u"invalid uri_tuple")) | |
235 continue | |
236 log.info(_(u'setting {}/{} URIs handler').format(*uri_tuple)) | |
237 try: | |
238 cb = page_data[cb_name] | |
239 except KeyError: | |
240 log.error(_(u'missing {name} method to handle {1}/{2}').format( | |
241 name = cb_name, *uri_tuple)) | |
242 continue | |
243 else: | |
244 cls.registerURI(uri_tuple, cb, new_path) | |
245 | |
917 | 246 LiberviaPage.importPages(host, resource, new_path) |
247 | |
925 | 248 @classmethod |
990
6daa59d44ee2
pages: menu implementation, first draft:
Goffi <goffi@goffi.org>
parents:
985
diff
changeset
|
249 def setMenu(cls, menus): |
6daa59d44ee2
pages: menu implementation, first draft:
Goffi <goffi@goffi.org>
parents:
985
diff
changeset
|
250 main_menu = [] |
6daa59d44ee2
pages: menu implementation, first draft:
Goffi <goffi@goffi.org>
parents:
985
diff
changeset
|
251 for menu in menus: |
6daa59d44ee2
pages: menu implementation, first draft:
Goffi <goffi@goffi.org>
parents:
985
diff
changeset
|
252 if not menu: |
6daa59d44ee2
pages: menu implementation, first draft:
Goffi <goffi@goffi.org>
parents:
985
diff
changeset
|
253 raise ValueError(_(u"menu item can't be empty")) |
6daa59d44ee2
pages: menu implementation, first draft:
Goffi <goffi@goffi.org>
parents:
985
diff
changeset
|
254 elif isinstance(menu, list): |
6daa59d44ee2
pages: menu implementation, first draft:
Goffi <goffi@goffi.org>
parents:
985
diff
changeset
|
255 if len(menu) != 2: |
6daa59d44ee2
pages: menu implementation, first draft:
Goffi <goffi@goffi.org>
parents:
985
diff
changeset
|
256 raise ValueError(_(u"menu item as list must be in the form [page_name, absolue URL]")) |
6daa59d44ee2
pages: menu implementation, first draft:
Goffi <goffi@goffi.org>
parents:
985
diff
changeset
|
257 page_name, url = menu |
6daa59d44ee2
pages: menu implementation, first draft:
Goffi <goffi@goffi.org>
parents:
985
diff
changeset
|
258 else: |
6daa59d44ee2
pages: menu implementation, first draft:
Goffi <goffi@goffi.org>
parents:
985
diff
changeset
|
259 page_name = menu |
6daa59d44ee2
pages: menu implementation, first draft:
Goffi <goffi@goffi.org>
parents:
985
diff
changeset
|
260 url = cls.getPageByName(page_name).url |
6daa59d44ee2
pages: menu implementation, first draft:
Goffi <goffi@goffi.org>
parents:
985
diff
changeset
|
261 main_menu.append((page_name, url)) |
6daa59d44ee2
pages: menu implementation, first draft:
Goffi <goffi@goffi.org>
parents:
985
diff
changeset
|
262 cls.main_menu = main_menu |
6daa59d44ee2
pages: menu implementation, first draft:
Goffi <goffi@goffi.org>
parents:
985
diff
changeset
|
263 |
6daa59d44ee2
pages: menu implementation, first draft:
Goffi <goffi@goffi.org>
parents:
985
diff
changeset
|
264 @classmethod |
925 | 265 def registerURI(cls, uri_tuple, get_uri_cb, pre_path): |
266 """register a URI handler | |
267 | |
268 @param uri_tuple(tuple[unicode, unicode]): type or URIs handler | |
269 type/subtype as returned by tools/common/parseXMPPUri | |
270 @param get_uri_cb(callable): method which take uri_data dict as only argument | |
271 and return path with correct arguments relative to page itself | |
272 @param pre_path(list[unicode]): prefix path to reference the handler page | |
273 """ | |
274 if uri_tuple in cls.uri_callbacks: | |
275 log.info(_(u"{}/{} URIs are already handled, replacing by the new handler").format(*uri_tuple)) | |
276 cls.uri_callbacks[uri_tuple] = {u'callback': get_uri_cb, | |
277 u'pre_path': pre_path} | |
278 | |
995 | 279 def registerSignal(self, request, signal, check_profile=True): |
280 r"""register a signal handler | |
281 | |
282 the page must be dynamic | |
283 when signal is received, self.on_signal will be called with: | |
284 - request | |
285 - signal name | |
286 - signal arguments | |
287 signal handler will be removed when connection with dynamic page will be lost | |
288 @param signal(unicode): name of the signal | |
289 last arg of signal must be profile, as it will be checked to filter signals | |
290 @param check_profile(bool): if True, signal profile (which MUST be last arg) will be | |
291 checked against session profile. | |
292 /!\ if False, profile will not be checked/filtered, be sure to know what you are doing | |
293 if you unset this option /!\ | |
294 """ | |
295 # FIXME: add a timeout, if socket is not opened before it, signal handler must be removed | |
296 if not self.dynamic: | |
297 log.error(_(u"You can't register signal if page is not dynamic")) | |
298 return | |
299 LiberviaPage.signals_handlers.setdefault(signal, {})[id(request)] = (self, request, check_profile) | |
300 request._signals_registered.append(signal) | |
301 | |
927
bb4dfc2802c0
server (pages): added getPagePathFromURI method to retrieve page handling an URI
Goffi <goffi@goffi.org>
parents:
926
diff
changeset
|
302 def getPagePathFromURI(self, uri): |
bb4dfc2802c0
server (pages): added getPagePathFromURI method to retrieve page handling an URI
Goffi <goffi@goffi.org>
parents:
926
diff
changeset
|
303 """Retrieve page URL from xmpp: URI |
bb4dfc2802c0
server (pages): added getPagePathFromURI method to retrieve page handling an URI
Goffi <goffi@goffi.org>
parents:
926
diff
changeset
|
304 |
bb4dfc2802c0
server (pages): added getPagePathFromURI method to retrieve page handling an URI
Goffi <goffi@goffi.org>
parents:
926
diff
changeset
|
305 @param uri(unicode): URI with a xmpp: scheme |
bb4dfc2802c0
server (pages): added getPagePathFromURI method to retrieve page handling an URI
Goffi <goffi@goffi.org>
parents:
926
diff
changeset
|
306 @return (unicode,None): absolute path (starting from root "/") to page handling the URI |
bb4dfc2802c0
server (pages): added getPagePathFromURI method to retrieve page handling an URI
Goffi <goffi@goffi.org>
parents:
926
diff
changeset
|
307 None is returned if not page has been registered for this URI |
bb4dfc2802c0
server (pages): added getPagePathFromURI method to retrieve page handling an URI
Goffi <goffi@goffi.org>
parents:
926
diff
changeset
|
308 """ |
bb4dfc2802c0
server (pages): added getPagePathFromURI method to retrieve page handling an URI
Goffi <goffi@goffi.org>
parents:
926
diff
changeset
|
309 uri_data = common_uri.parseXMPPUri(uri) |
bb4dfc2802c0
server (pages): added getPagePathFromURI method to retrieve page handling an URI
Goffi <goffi@goffi.org>
parents:
926
diff
changeset
|
310 try: |
bb4dfc2802c0
server (pages): added getPagePathFromURI method to retrieve page handling an URI
Goffi <goffi@goffi.org>
parents:
926
diff
changeset
|
311 callback_data = self.uri_callbacks[uri_data['type'], uri_data.get('sub_type')] |
bb4dfc2802c0
server (pages): added getPagePathFromURI method to retrieve page handling an URI
Goffi <goffi@goffi.org>
parents:
926
diff
changeset
|
312 except KeyError: |
bb4dfc2802c0
server (pages): added getPagePathFromURI method to retrieve page handling an URI
Goffi <goffi@goffi.org>
parents:
926
diff
changeset
|
313 return |
bb4dfc2802c0
server (pages): added getPagePathFromURI method to retrieve page handling an URI
Goffi <goffi@goffi.org>
parents:
926
diff
changeset
|
314 else: |
bb4dfc2802c0
server (pages): added getPagePathFromURI method to retrieve page handling an URI
Goffi <goffi@goffi.org>
parents:
926
diff
changeset
|
315 url = os.path.join(u'/', u'/'.join(callback_data['pre_path']), callback_data['callback'](self, uri_data)) |
bb4dfc2802c0
server (pages): added getPagePathFromURI method to retrieve page handling an URI
Goffi <goffi@goffi.org>
parents:
926
diff
changeset
|
316 return url |
bb4dfc2802c0
server (pages): added getPagePathFromURI method to retrieve page handling an URI
Goffi <goffi@goffi.org>
parents:
926
diff
changeset
|
317 |
979 | 318 @classmethod |
319 def getPageByName(cls, name): | |
936
78692d47340d
server (pages): added getPageByName
Goffi <goffi@goffi.org>
parents:
935
diff
changeset
|
320 """retrieve page instance from its name |
78692d47340d
server (pages): added getPageByName
Goffi <goffi@goffi.org>
parents:
935
diff
changeset
|
321 |
78692d47340d
server (pages): added getPageByName
Goffi <goffi@goffi.org>
parents:
935
diff
changeset
|
322 @param name(unicode): name of the page |
78692d47340d
server (pages): added getPageByName
Goffi <goffi@goffi.org>
parents:
935
diff
changeset
|
323 @return (LiberviaPage): page instance |
78692d47340d
server (pages): added getPageByName
Goffi <goffi@goffi.org>
parents:
935
diff
changeset
|
324 @raise KeyError: the page doesn't exist |
78692d47340d
server (pages): added getPageByName
Goffi <goffi@goffi.org>
parents:
935
diff
changeset
|
325 """ |
979 | 326 return cls.named_pages[name] |
936
78692d47340d
server (pages): added getPageByName
Goffi <goffi@goffi.org>
parents:
935
diff
changeset
|
327 |
962 | 328 def getPageRedirectURL(self, request, page_name=u'login', url=None): |
329 """generate URL for a page with redirect_url parameter set | |
330 | |
331 mainly used for login page with redirection to current page | |
332 @param request(server.Request): current HTTP request | |
333 @param page_name(unicode): name of the page to go | |
334 @param url(None, unicode): url to redirect to | |
335 None to use request path (i.e. current page) | |
336 @return (unicode): URL to use | |
337 """ | |
338 return u'{root_url}?redirect_url={redirect_url}'.format( | |
339 root_url = self.getPageByName(page_name).url, | |
340 redirect_url=urllib.quote_plus(request.uri) if url is None else url.encode('utf-8')) | |
341 | |
972
c4e58c4dba75
server: getURL + minor improvments:
Goffi <goffi@goffi.org>
parents:
968
diff
changeset
|
342 def getURL(self, *args): |
c4e58c4dba75
server: getURL + minor improvments:
Goffi <goffi@goffi.org>
parents:
968
diff
changeset
|
343 """retrieve URL of the page set arguments |
c4e58c4dba75
server: getURL + minor improvments:
Goffi <goffi@goffi.org>
parents:
968
diff
changeset
|
344 |
c4e58c4dba75
server: getURL + minor improvments:
Goffi <goffi@goffi.org>
parents:
968
diff
changeset
|
345 *args(list[unicode]): argument to add to the URL as path elements |
c4e58c4dba75
server: getURL + minor improvments:
Goffi <goffi@goffi.org>
parents:
968
diff
changeset
|
346 """ |
c4e58c4dba75
server: getURL + minor improvments:
Goffi <goffi@goffi.org>
parents:
968
diff
changeset
|
347 url_args = [quote(a) for a in args] |
980
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
348 |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
349 if self.name is not None and self.name in self.pages_redirects: |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
350 # we check for redirection |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
351 redirect_data = self.pages_redirects[self.name] |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
352 args_hash = tuple(args) |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
353 for limit in xrange(len(args)+1): |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
354 current_hash = args_hash[:limit] |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
355 if current_hash in redirect_data: |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
356 url_base = redirect_data[current_hash] |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
357 remaining = args[limit:] |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
358 remaining_url = '/'.join(remaining) |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
359 return os.path.join('/', url_base, remaining_url) |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
360 |
972
c4e58c4dba75
server: getURL + minor improvments:
Goffi <goffi@goffi.org>
parents:
968
diff
changeset
|
361 return os.path.join(self.url, *url_args) |
c4e58c4dba75
server: getURL + minor improvments:
Goffi <goffi@goffi.org>
parents:
968
diff
changeset
|
362 |
980
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
363 def getSubPageURL(self, request, page_name, *args): |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
364 """retrieve a page in direct children and build its URL according to request |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
365 |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
366 request's current path is used as base (at current parsing point, |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
367 i.e. it's more prepath than path). |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
368 Requested page is checked in children and an absolute URL is then built |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
369 by the resulting combination. |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
370 This method is useful to construct absolute URLs for children instead of |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
371 using relative path, which may not work in subpages, and are linked to the |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
372 names of directories (i.e. relative URL will break if subdirectory is renamed |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
373 while getSubPageURL won't as long as page_name is consistent). |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
374 Also, request.path is used, keeping real path used by user, |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
375 and potential redirections. |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
376 @param request(server.Request): current HTTP request |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
377 @param page_name(unicode): name of the page to retrieve |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
378 it must be a direct children of current page |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
379 @param *args(list[unicode]): arguments to add as path elements |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
380 @return unicode: absolute URL to the sub page |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
381 """ |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
382 # we get url in the following way (splitting request.path instead of using |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
383 # request.prepath) because request.prepath may have been modified by |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
384 # redirection (if redirection args have been specified), while path reflect |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
385 # the real request |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
386 |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
387 # we ignore empty path elements (i.e. double '/' or '/' at the end) |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
388 path_elts = [p for p in request.path.split('/') if p] |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
389 |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
390 if request.postpath: |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
391 if not request.postpath[-1]: |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
392 # we remove trailing slash |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
393 request.postpath = request.postpath[:-1] |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
394 if request.postpath: |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
395 # getSubPageURL must return subpage from the point where |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
396 # the it is called, so we have to remove remanining |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
397 # path elements |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
398 path_elts = path_elts[:-len(request.postpath)] |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
399 |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
400 current_url = '/' + '/'.join(path_elts).decode('utf-8') |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
401 |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
402 for path, child in self.children.iteritems(): |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
403 try: |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
404 child_name = child.name |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
405 except AttributeError: |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
406 # LiberviaPage have a name, but maybe this is an other Resource |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
407 continue |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
408 if child_name == page_name: |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
409 return os.path.join(u'/', current_url, path, *args) |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
410 raise exceptions.NotFound(_(u'requested sub page has not been found')) |
bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
Goffi <goffi@goffi.org>
parents:
979
diff
changeset
|
411 |
917 | 412 def getChildWithDefault(self, path, request): |
413 # we handle children ourselves | |
414 raise exceptions.InternalError(u"this method should not be used with LiberviaPage") | |
415 | |
416 def nextPath(self, request): | |
417 """get next URL path segment, and update request accordingly | |
418 | |
419 will move first segment of postpath in prepath | |
420 @param request(server.Request): current HTTP request | |
421 @return (unicode): unquoted segment | |
422 @raise IndexError: there is no segment left | |
423 """ | |
424 pathElement = request.postpath.pop(0) | |
425 request.prepath.append(pathElement) | |
426 return urllib.unquote(pathElement).decode('utf-8') | |
427 | |
985
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
428 def checkCacheSubscribeCb(self, sub_id, service, node): |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
429 self.cache_pubsub_sub.add((service, node, sub_id)) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
430 |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
431 def checkCacheSubscribeEb(self, failure_, service, node): |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
432 log.warning(_(u"Can't subscribe to node: {msg}").format(msg=failure_)) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
433 # FIXME: cache must be marked as unusable here |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
434 |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
435 def psNodeWatchAddEb(self, failure_, service, node): |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
436 log.warning(_(u"Can't add node watched: {msg}").format(msg=failure_)) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
437 |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
438 def checkCache(self, request, cache_type, **kwargs): |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
439 """check if a page is in cache and return cached version if suitable |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
440 |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
441 this method may perform extra operation to handle cache (e.g. subscribing to a |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
442 pubsub node) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
443 @param request(server.Request): current HTTP request |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
444 @param cache_type(int): on of C.CACHE_* const. |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
445 @param **kwargs: args according to cache_type: |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
446 C.CACHE_PROFILE: |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
447 service: pubsub service |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
448 node: pubsub node |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
449 short: short name of feature (needed if node is empty) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
450 |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
451 """ |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
452 if request.postpath: |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
453 # we are not on the final page, no need to go further |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
454 return |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
455 profile = self.getProfile(request) or C.SERVICE_PROFILE |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
456 |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
457 if cache_type == C.CACHE_PUBSUB: |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
458 service, node = kwargs['service'], kwargs['node'] |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
459 if not node: |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
460 try: |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
461 short = kwargs['short'] |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
462 node = self.host.ns_map[short] |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
463 except KeyError: |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
464 log.warning(_(u"Can't use cache for empty node without namespace set, please ensure to set \"short\" and that it is registered")) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
465 return |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
466 if profile != C.SERVICE_PROFILE: |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
467 # only service profile is cache for now |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
468 return |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
469 try: |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
470 cache = self.cache[profile][cache_type][service][node][self] |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
471 except KeyError: |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
472 # no cache yet, let's subscribe to the pubsub node |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
473 d1 = self.host.bridgeCall('psSubscribe', service.full(), node, {}, profile) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
474 d1.addCallback(self.checkCacheSubscribeCb, service, node) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
475 d1.addErrback(self.checkCacheSubscribeEb, service, node) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
476 d2 = self.host.bridgeCall('psNodeWatchAdd', service.full(), node, profile) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
477 d2.addErrback(self.psNodeWatchAddEb, service, node) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
478 self._do_cache = [profile, cache_type, service, node] |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
479 # we don't return the Deferreds as it is not needed to wait for |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
480 # the subscription to continue with page rendering |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
481 return |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
482 |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
483 else: |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
484 raise exceptions.InternalError(u'Unknown cache_type') |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
485 log.debug(u'using cache for {page}'.format(page=self)) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
486 cache.last_access = time.time() |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
487 request.write(cache.rendered) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
488 request.finish() |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
489 raise failure.Failure(exceptions.CancelError(u'cache is used')) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
490 |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
491 @classmethod |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
492 def onNodeEvent(cls, host, service, node, event_type, items, profile): |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
493 """Invalidate cache for all pages linked to this node""" |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
494 try: |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
495 cache = cls.cache[profile][C.CACHE_PUBSUB][jid.JID(service)][node] |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
496 except KeyError: |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
497 log.info(_(u'Removing subscription for {service}/{node}: ' |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
498 u'the page is not cached').format(service=service, node=node)) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
499 d1 = host.bridgeCall('psUnsubscribe', service, node, profile) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
500 d1.addErrback(lambda failure_: |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
501 log.warning(_(u"Can't unsubscribe from {service}/{node}: {msg}").format( |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
502 service=service, node=node, msg=failure_))) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
503 d2 = host.bridgeCall('psNodeWatchAdd', service, node, profile) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
504 # TODO: check why the page is not in cache, remove subscription? |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
505 d2.addErrback(lambda failure_: |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
506 log.warning(_(u"Can't remove watch for {service}/{node}: {msg}").format( |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
507 service=service, node=node, msg=failure_))) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
508 else: |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
509 cache.clear() |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
510 |
995 | 511 @classmethod |
512 def onSignal(cls, host, signal, *args): | |
513 """Generic method which receive registered signals | |
514 | |
515 if a callback is registered for this signal, call it | |
516 @param host: Libervia instance | |
517 @param signal(unicode): name of the signal | |
518 @param *args: args of the signals | |
519 """ | |
520 for page, request, check_profile in cls.signals_handlers.get(signal, {}).itervalues(): | |
521 if check_profile: | |
522 signal_profile = args[-1] | |
523 request_profile = page.getProfile(request) | |
524 if not request_profile: | |
525 # if you want to use signal without session, unset check_profile | |
526 # (be sure to know what you are doing) | |
527 log.error(_(u"no session started, signal can't be checked")) | |
528 continue | |
529 if signal_profile != request_profile: | |
530 # we ignore the signal, it's not for our profile | |
531 continue | |
532 if request._signals_cache is not None: | |
533 # socket is not yet opened, we cache the signal | |
534 request._signals_cache.append((request, signal, args)) | |
535 log.debug(u"signal [{signal}] cached: {args}".format( | |
536 signal = signal, | |
537 args = args)) | |
538 else: | |
539 page.on_signal(page, request, signal, *args) | |
540 | |
541 def onSocketOpen(self, request): | |
542 """Called for dynamic pages when socket has just been opened | |
543 | |
544 we send all cached signals | |
545 """ | |
546 assert request._signals_cache is not None | |
547 cache = request._signals_cache | |
548 request._signals_cache = None | |
549 for request, signal, args in cache: | |
550 self.on_signal(self, request, signal, *args) | |
551 | |
552 def onSocketClose(self, request): | |
553 """Called for dynamic pages when socket has just been closed | |
554 | |
555 we remove signal handler | |
556 """ | |
557 for signal in request._signals_registered: | |
558 try: | |
559 del LiberviaPage.signals_handlers[signal][id(request)] | |
560 except KeyError: | |
561 log.error(_(u"Can't find signal handler for [{signal}], this should not happen").format( | |
562 signal = signal)) | |
563 else: | |
564 log.debug(_(u"Removed signal handler")) | |
565 | |
962 | 566 def HTTPRedirect(self, request, url): |
567 """redirect to an URL using HTTP redirection | |
568 | |
569 @param request(server.Request): current HTTP request | |
570 @param url(unicode): url to redirect to | |
571 """ | |
572 | |
573 web_util.redirectTo(url.encode('utf-8'), request) | |
574 request.finish() | |
575 raise failure.Failure(exceptions.CancelError(u'HTTP redirection is used')) | |
576 | |
577 def redirectOrContinue(self, request, redirect_arg=u'redirect_url'): | |
578 """helper method to redirect a page to an url given as arg | |
579 | |
580 if the arg is not present, the page will continue normal workflow | |
581 @param request(server.Request): current HTTP request | |
582 @param redirect_arg(unicode): argument to use to get redirection URL | |
583 @interrupt: redirect the page to requested URL | |
584 @interrupt pageError(C.HTTP_BAD_REQUEST): empty or non local URL is used | |
585 """ | |
586 try: | |
587 url = self.getPostedData(request, 'redirect_url') | |
588 except KeyError: | |
589 pass | |
590 else: | |
591 # a redirection is requested | |
592 if not url or url[0] != u'/': | |
593 # we only want local urls | |
594 self.pageError(request, C.HTTP_BAD_REQUEST) | |
595 else: | |
596 self.HTTPRedirect(request, url) | |
597 | |
923
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
598 def pageRedirect(self, page_path, request, skip_parse_url=True): |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
599 """redirect a page to a named page |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
600 |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
601 the workflow will continue with the workflow of the named page, |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
602 skipping named page's parse_url method if it exist. |
962 | 603 If you want to do a HTTP redirection, use HTTPRedirect |
923
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
604 @param page_path(unicode): path to page (elements are separated by "/"): |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
605 if path starts with a "/": |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
606 path is a full path starting from root |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
607 else: |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
608 - first element is name as registered in name variable |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
609 - following element are subpages path |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
610 e.g.: "blog" redirect to page named "blog" |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
611 "blog/atom.xml" redirect to atom.xml subpage of "blog" |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
612 "/common/blog/atom.xml" redirect to the page at the fiven full path |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
613 @param request(server.Request): current HTTP request |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
614 @param skip_parse_url(bool): if True, parse_url method on redirect page will be skipped |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
615 @raise KeyError: there is no known page with this name |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
616 """ |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
617 # FIXME: render non LiberviaPage resources |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
618 path = page_path.rstrip(u'/').split(u'/') |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
619 if not path[0]: |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
620 redirect_page = self.host.root |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
621 else: |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
622 redirect_page = self.named_pages[path[0]] |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
623 |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
624 for subpage in path[1:]: |
962 | 625 if redirect_page is self.host.root: |
626 redirect_page = redirect_page.children[subpage] | |
627 else: | |
628 redirect_page = redirect_page.original.children[subpage] | |
923
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
629 |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
630 redirect_page.renderPage(request, skip_parse_url=True) |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
631 raise failure.Failure(exceptions.CancelError(u'page redirection is used')) |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
632 |
922
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
633 def pageError(self, request, code=C.HTTP_NOT_FOUND): |
917 | 634 """generate an error page and terminate the request |
635 | |
636 @param request(server.Request): HTTP request | |
637 @param core(int): error code to use | |
638 """ | |
639 template = u'error/' + unicode(code) + '.html' | |
640 | |
641 request.setResponseCode(code) | |
642 | |
643 rendered = self.host.renderer.render( | |
644 template, | |
645 root_path = '/templates/', | |
646 error_code = code, | |
647 **request.template_data) | |
648 | |
649 self.writeData(rendered, request) | |
650 raise failure.Failure(exceptions.CancelError(u'error page is used')) | |
651 | |
652 def writeData(self, data, request): | |
937
00236973e138
server (pages): an HTTP internal error is raised if an error is uncatched during page workflow
Goffi <goffi@goffi.org>
parents:
936
diff
changeset
|
653 """write data to transport and finish the request""" |
917 | 654 if data is None: |
655 self.pageError(request) | |
985
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
656 data_encoded = data.encode('utf-8') |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
657 request.write(data_encoded) |
917 | 658 request.finish() |
985
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
659 if self._do_cache is not None: |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
660 cache = reduce(lambda d, k: d.setdefault(k, {}), self._do_cache, self.cache) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
661 cache[self] = Cache(data_encoded) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
662 log.debug(_(u'{page} put in cache for [{profile}]').format( |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
663 page=self, |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
664 profile=self._do_cache[0])) |
64826e69f365
pages: cache mechanism, first draft:
Goffi <goffi@goffi.org>
parents:
984
diff
changeset
|
665 self._do_cache = None |
917 | 666 |
667 def _subpagesHandler(self, dummy, request): | |
668 """render subpage if suitable | |
669 | |
670 this method checks if there is still an unmanaged part of the path | |
671 and check if it corresponds to a subpage. If so, it render the subpage | |
672 else it render a NoResource. | |
673 If there is no unmanaged part of the segment, current page workflow is pursued | |
674 """ | |
675 if request.postpath: | |
676 subpage = self.nextPath(request) | |
677 try: | |
678 child = self.children[subpage] | |
679 except KeyError: | |
680 self.pageError(request) | |
681 else: | |
682 child.render(request) | |
683 raise failure.Failure(exceptions.CancelError(u'subpage page is used')) | |
684 | |
685 def _prepare_render(self, dummy, request): | |
926
612e33fd32a8
server (pages): fixed _prepare_render handling
Goffi <goffi@goffi.org>
parents:
925
diff
changeset
|
686 return defer.maybeDeferred(self.prepare_render, self, request) |
917 | 687 |
688 def _render_method(self, dummy, request): | |
689 return defer.maybeDeferred(self.render_method, self, request) | |
690 | |
962 | 691 def _render_template(self, dummy, request): |
692 template_data = request.template_data | |
693 | |
694 # if confirm variable is set in case of successfuly data post | |
695 session_data = self.host.getSessionData(request, session_iface.ISATSession) | |
696 if session_data.popPageFlag(self, C.FLAG_CONFIRM): | |
697 template_data[u'confirm'] = True | |
698 | |
917 | 699 return self.host.renderer.render( |
700 self.template, | |
701 root_path = '/templates/', | |
962 | 702 media_path = '/' + C.MEDIA_DIR, |
995 | 703 cache_path = session_data.cache_dir, |
990
6daa59d44ee2
pages: menu implementation, first draft:
Goffi <goffi@goffi.org>
parents:
985
diff
changeset
|
704 main_menu = LiberviaPage.main_menu, |
917 | 705 **template_data) |
706 | |
707 def _renderEb(self, failure_, request): | |
708 """don't raise error on CancelError""" | |
709 failure_.trap(exceptions.CancelError) | |
710 | |
937
00236973e138
server (pages): an HTTP internal error is raised if an error is uncatched during page workflow
Goffi <goffi@goffi.org>
parents:
936
diff
changeset
|
711 def _internalError(self, failure_, request): |
00236973e138
server (pages): an HTTP internal error is raised if an error is uncatched during page workflow
Goffi <goffi@goffi.org>
parents:
936
diff
changeset
|
712 """called if an error is not catched""" |
00236973e138
server (pages): an HTTP internal error is raised if an error is uncatched during page workflow
Goffi <goffi@goffi.org>
parents:
936
diff
changeset
|
713 log.error(_(u"Uncatched error for HTTP request on {url}: {msg}").format( |
00236973e138
server (pages): an HTTP internal error is raised if an error is uncatched during page workflow
Goffi <goffi@goffi.org>
parents:
936
diff
changeset
|
714 url = request.URLPath(), |
00236973e138
server (pages): an HTTP internal error is raised if an error is uncatched during page workflow
Goffi <goffi@goffi.org>
parents:
936
diff
changeset
|
715 msg = failure_)) |
00236973e138
server (pages): an HTTP internal error is raised if an error is uncatched during page workflow
Goffi <goffi@goffi.org>
parents:
936
diff
changeset
|
716 self.pageError(request, C.HTTP_INTERNAL_ERROR) |
00236973e138
server (pages): an HTTP internal error is raised if an error is uncatched during page workflow
Goffi <goffi@goffi.org>
parents:
936
diff
changeset
|
717 |
956
dabecab10faa
server (pages): impleted CSRF protection:
Goffi <goffi@goffi.org>
parents:
955
diff
changeset
|
718 def _on_data_post_redirect(self, ret, request): |
968
4d37b23777c3
pages (core, tickets/new): replaced post_redirect_uri mechanism by post_redirect_page:
Goffi <goffi@goffi.org>
parents:
966
diff
changeset
|
719 """called when page's on_data_post has been done successfuly |
956
dabecab10faa
server (pages): impleted CSRF protection:
Goffi <goffi@goffi.org>
parents:
955
diff
changeset
|
720 |
968
4d37b23777c3
pages (core, tickets/new): replaced post_redirect_uri mechanism by post_redirect_page:
Goffi <goffi@goffi.org>
parents:
966
diff
changeset
|
721 This will do a Post/Redirect/Get pattern. |
4d37b23777c3
pages (core, tickets/new): replaced post_redirect_uri mechanism by post_redirect_page:
Goffi <goffi@goffi.org>
parents:
966
diff
changeset
|
722 this method redirect to the same page or to request.data['post_redirect_page'] |
4d37b23777c3
pages (core, tickets/new): replaced post_redirect_uri mechanism by post_redirect_page:
Goffi <goffi@goffi.org>
parents:
966
diff
changeset
|
723 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. |
4d37b23777c3
pages (core, tickets/new): replaced post_redirect_uri mechanism by post_redirect_page:
Goffi <goffi@goffi.org>
parents:
966
diff
changeset
|
724 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. |
4d37b23777c3
pages (core, tickets/new): replaced post_redirect_uri mechanism by post_redirect_page:
Goffi <goffi@goffi.org>
parents:
966
diff
changeset
|
725 HTTP status code "See Other" (303) is used as it is the recommanded code in this case. |
962 | 726 @param ret(None, unicode, iterable): on_data_post return value |
727 see LiberviaPage.__init__ on_data_post docstring | |
956
dabecab10faa
server (pages): impleted CSRF protection:
Goffi <goffi@goffi.org>
parents:
955
diff
changeset
|
728 """ |
962 | 729 if ret is None: |
730 ret = () | |
731 elif isinstance(ret, basestring): | |
732 ret = (ret,) | |
733 else: | |
734 ret = tuple(ret) | |
735 raise NotImplementedError(_(u'iterable in on_data_post return value is not used yet')) | |
957
67bf14c91d5c
server (pages): added a confirm flag on successful post:
Goffi <goffi@goffi.org>
parents:
956
diff
changeset
|
736 session_data = self.host.getSessionData(request, session_iface.ISATSession) |
974
4aa38c49bff7
pages: fixed use of request data in _on_data_post_redirect
Goffi <goffi@goffi.org>
parents:
972
diff
changeset
|
737 request_data = self.getRData(request) |
4aa38c49bff7
pages: fixed use of request data in _on_data_post_redirect
Goffi <goffi@goffi.org>
parents:
972
diff
changeset
|
738 if 'post_redirect_page' in request_data: |
4aa38c49bff7
pages: fixed use of request data in _on_data_post_redirect
Goffi <goffi@goffi.org>
parents:
972
diff
changeset
|
739 redirect_page_data = request_data['post_redirect_page'] |
968
4d37b23777c3
pages (core, tickets/new): replaced post_redirect_uri mechanism by post_redirect_page:
Goffi <goffi@goffi.org>
parents:
966
diff
changeset
|
740 if isinstance(redirect_page_data, tuple): |
4d37b23777c3
pages (core, tickets/new): replaced post_redirect_uri mechanism by post_redirect_page:
Goffi <goffi@goffi.org>
parents:
966
diff
changeset
|
741 redirect_page = redirect_page_data[0] |
972
c4e58c4dba75
server: getURL + minor improvments:
Goffi <goffi@goffi.org>
parents:
968
diff
changeset
|
742 redirect_page_args = redirect_page_data[1:] |
c4e58c4dba75
server: getURL + minor improvments:
Goffi <goffi@goffi.org>
parents:
968
diff
changeset
|
743 redirect_uri = redirect_page.getURL(*redirect_page_args) |
968
4d37b23777c3
pages (core, tickets/new): replaced post_redirect_uri mechanism by post_redirect_page:
Goffi <goffi@goffi.org>
parents:
966
diff
changeset
|
744 else: |
4d37b23777c3
pages (core, tickets/new): replaced post_redirect_uri mechanism by post_redirect_page:
Goffi <goffi@goffi.org>
parents:
966
diff
changeset
|
745 redirect_page = redirect_page_data |
972
c4e58c4dba75
server: getURL + minor improvments:
Goffi <goffi@goffi.org>
parents:
968
diff
changeset
|
746 redirect_uri = redirect_page.url |
968
4d37b23777c3
pages (core, tickets/new): replaced post_redirect_uri mechanism by post_redirect_page:
Goffi <goffi@goffi.org>
parents:
966
diff
changeset
|
747 else: |
4d37b23777c3
pages (core, tickets/new): replaced post_redirect_uri mechanism by post_redirect_page:
Goffi <goffi@goffi.org>
parents:
966
diff
changeset
|
748 redirect_page = self |
4d37b23777c3
pages (core, tickets/new): replaced post_redirect_uri mechanism by post_redirect_page:
Goffi <goffi@goffi.org>
parents:
966
diff
changeset
|
749 redirect_uri = request.uri |
4d37b23777c3
pages (core, tickets/new): replaced post_redirect_uri mechanism by post_redirect_page:
Goffi <goffi@goffi.org>
parents:
966
diff
changeset
|
750 |
962 | 751 if not C.POST_NO_CONFIRM in ret: |
968
4d37b23777c3
pages (core, tickets/new): replaced post_redirect_uri mechanism by post_redirect_page:
Goffi <goffi@goffi.org>
parents:
966
diff
changeset
|
752 session_data.setPageFlag(redirect_page, C.FLAG_CONFIRM) |
956
dabecab10faa
server (pages): impleted CSRF protection:
Goffi <goffi@goffi.org>
parents:
955
diff
changeset
|
753 request.setResponseCode(C.HTTP_SEE_OTHER) |
968
4d37b23777c3
pages (core, tickets/new): replaced post_redirect_uri mechanism by post_redirect_page:
Goffi <goffi@goffi.org>
parents:
966
diff
changeset
|
754 request.setHeader("location", redirect_uri) |
955
4f7cb6335a33
server(pages): do Post/Redirect/Get pattern when on_data_post is used (avoid double posting on refresh)
Goffi <goffi@goffi.org>
parents:
950
diff
changeset
|
755 request.finish() |
4f7cb6335a33
server(pages): do Post/Redirect/Get pattern when on_data_post is used (avoid double posting on refresh)
Goffi <goffi@goffi.org>
parents:
950
diff
changeset
|
756 raise failure.Failure(exceptions.CancelError(u'Post/Redirect/Get is used')) |
4f7cb6335a33
server(pages): do Post/Redirect/Get pattern when on_data_post is used (avoid double posting on refresh)
Goffi <goffi@goffi.org>
parents:
950
diff
changeset
|
757 |
956
dabecab10faa
server (pages): impleted CSRF protection:
Goffi <goffi@goffi.org>
parents:
955
diff
changeset
|
758 def _on_data_post(self, dummy, request): |
dabecab10faa
server (pages): impleted CSRF protection:
Goffi <goffi@goffi.org>
parents:
955
diff
changeset
|
759 csrf_token = self.host.getSessionData(request, session_iface.ISATSession).csrf_token |
dabecab10faa
server (pages): impleted CSRF protection:
Goffi <goffi@goffi.org>
parents:
955
diff
changeset
|
760 try: |
dabecab10faa
server (pages): impleted CSRF protection:
Goffi <goffi@goffi.org>
parents:
955
diff
changeset
|
761 given_csrf = self.getPostedData(request, u'csrf_token') |
dabecab10faa
server (pages): impleted CSRF protection:
Goffi <goffi@goffi.org>
parents:
955
diff
changeset
|
762 except KeyError: |
dabecab10faa
server (pages): impleted CSRF protection:
Goffi <goffi@goffi.org>
parents:
955
diff
changeset
|
763 given_csrf = None |
dabecab10faa
server (pages): impleted CSRF protection:
Goffi <goffi@goffi.org>
parents:
955
diff
changeset
|
764 if given_csrf is None or given_csrf != csrf_token: |
dabecab10faa
server (pages): impleted CSRF protection:
Goffi <goffi@goffi.org>
parents:
955
diff
changeset
|
765 log.warning(_(u"invalid CSRF token, hack attempt? URL: {url}, IP: {ip}").format( |
dabecab10faa
server (pages): impleted CSRF protection:
Goffi <goffi@goffi.org>
parents:
955
diff
changeset
|
766 url=request.uri, |
dabecab10faa
server (pages): impleted CSRF protection:
Goffi <goffi@goffi.org>
parents:
955
diff
changeset
|
767 ip=request.getClientIP())) |
dabecab10faa
server (pages): impleted CSRF protection:
Goffi <goffi@goffi.org>
parents:
955
diff
changeset
|
768 self.pageError(request, C.HTTP_UNAUTHORIZED) |
dabecab10faa
server (pages): impleted CSRF protection:
Goffi <goffi@goffi.org>
parents:
955
diff
changeset
|
769 d = defer.maybeDeferred(self.on_data_post, self, request) |
dabecab10faa
server (pages): impleted CSRF protection:
Goffi <goffi@goffi.org>
parents:
955
diff
changeset
|
770 d.addCallback(self._on_data_post_redirect, request) |
dabecab10faa
server (pages): impleted CSRF protection:
Goffi <goffi@goffi.org>
parents:
955
diff
changeset
|
771 return d |
dabecab10faa
server (pages): impleted CSRF protection:
Goffi <goffi@goffi.org>
parents:
955
diff
changeset
|
772 |
931
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
773 def getPostedData(self, request, keys, multiple=False): |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
774 """get data from a POST request and decode it |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
775 |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
776 @param request(server.Request): request linked to the session |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
777 @param keys(unicode, iterable[unicode]): name of the value(s) to get |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
778 unicode to get one value |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
779 iterable to get more than one |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
780 @param multiple(bool): True if multiple values are possible/expected |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
781 if False, the first value is returned |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
782 @return (iterator[unicode], list[iterator[unicode], unicode, list[unicode]): values received for this(these) key(s) |
956
dabecab10faa
server (pages): impleted CSRF protection:
Goffi <goffi@goffi.org>
parents:
955
diff
changeset
|
783 @raise KeyError: one specific key has been requested, and it is missing |
931
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
784 """ |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
785 if isinstance(keys, basestring): |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
786 keys = [keys] |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
787 get_first = True |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
788 else: |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
789 get_first = False |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
790 |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
791 ret = [] |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
792 for key in keys: |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
793 gen = (urllib.unquote(v).decode('utf-8') for v in request.args.get(key,[])) |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
794 if multiple: |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
795 ret.append(gen) |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
796 else: |
956
dabecab10faa
server (pages): impleted CSRF protection:
Goffi <goffi@goffi.org>
parents:
955
diff
changeset
|
797 try: |
dabecab10faa
server (pages): impleted CSRF protection:
Goffi <goffi@goffi.org>
parents:
955
diff
changeset
|
798 ret.append(next(gen)) |
dabecab10faa
server (pages): impleted CSRF protection:
Goffi <goffi@goffi.org>
parents:
955
diff
changeset
|
799 except StopIteration: |
962 | 800 raise KeyError(key) |
931
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
801 |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
802 return ret[0] if get_first else ret |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
803 |
959 | 804 def getAllPostedData(self, request, except_=()): |
805 """get all posted data | |
806 | |
807 @param request(server.Request): request linked to the session | |
808 @param except_(iterable[unicode]): key of values to ignore | |
809 csrf_token will always be ignored | |
810 @return (dict[unicode, list[unicode]]): post values | |
811 """ | |
812 except_ = tuple(except_) + (u'csrf_token',) | |
813 ret = {} | |
814 for key, values in request.args.iteritems(): | |
815 key = urllib.unquote(key).decode('utf-8') | |
816 if key in except_: | |
817 continue | |
818 ret[key] = [urllib.unquote(v).decode('utf-8') for v in values] | |
819 return ret | |
820 | |
922
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
821 def getProfile(self, request): |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
822 """helper method to easily get current profile |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
823 |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
824 @return (unicode, None): current profile |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
825 None if no profile session is started |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
826 """ |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
827 sat_session = self.host.getSessionData(request, session_iface.ISATSession) |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
828 return sat_session.profile |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
829 |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
830 def getRData(self, request): |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
831 """helper method to get request data dict |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
832 |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
833 this dictionnary if for the request only, it is not saved in session |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
834 It is mainly used to pass data between pages/methods called during request workflow |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
835 @return (dict): request data |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
836 """ |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
837 try: |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
838 return request.data |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
839 except AttributeError: |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
840 request.data = {} |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
841 return request.data |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
842 |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
843 def _checkAccess(self, data, request): |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
844 """Check access according to self.access |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
845 |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
846 if access is not granted, show a HTTP_UNAUTHORIZED pageError and stop request, |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
847 else return data (so it can be inserted in deferred chain |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
848 """ |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
849 if self.access == C.PAGES_ACCESS_PUBLIC: |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
850 pass |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
851 elif self.access == C.PAGES_ACCESS_PROFILE: |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
852 profile = self.getProfile(request) |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
853 if not profile: |
962 | 854 # no session started |
855 if not self.host.options["allow_registration"]: | |
856 # registration not allowed, access is not granted | |
857 self.pageError(request, C.HTTP_UNAUTHORIZED) | |
858 else: | |
859 # registration allowed, we redirect to login page | |
860 login_url = self.getPageRedirectURL(request) | |
861 self.HTTPRedirect(request, login_url) | |
922
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
862 |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
863 return data |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
864 |
995 | 865 def renderPartial(self, request, template, template_data): |
866 """Render a template to be inserted in dynamic page | |
867 | |
868 this is NOT the normal page rendering method, it is used only to update | |
869 dynamic pages | |
870 @param template(unicode): path of the template to render | |
871 @param template_data(dict): template_data to use | |
872 """ | |
873 if not self.dynamic: | |
874 raise exceptions.InternalError(_(u"renderPartial must only be used with dynamic pages")) | |
875 session_data = self.host.getSessionData(request, session_iface.ISATSession) | |
876 | |
877 return self.host.renderer.render( | |
878 template, | |
879 root_path = '/templates/', | |
880 media_path = '/' + C.MEDIA_DIR, | |
881 cache_path = session_data.cache_dir, | |
882 main_menu = LiberviaPage.main_menu, | |
883 **template_data) | |
884 | |
885 def renderAndUpdate(self, request, template, selectors, template_data_update, update_type="append"): | |
886 """Helper method to render a partial page element and update the page | |
887 | |
888 this is NOT the normal page rendering method, it is used only to update | |
889 dynamic pages | |
890 @param request(server.Request): current HTTP request | |
891 @param template: same as for [renderPartial] | |
892 @param selectors: CSS selectors to use | |
893 @param template_data_update: template data to use | |
894 template data cached in request will be copied then updated | |
895 with this data | |
896 @parap update_type(unicode): one of: | |
897 append: append rendered element to selected element | |
898 """ | |
899 template_data = request.template_data.copy() | |
900 template_data.update(template_data_update) | |
901 html = self.renderPartial(request, template, template_data) | |
902 request.sendData(u'dom', | |
903 selectors=selectors, | |
904 update_type=update_type, | |
905 html=html) | |
906 | |
923
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
907 def renderPage(self, request, skip_parse_url=False): |
937
00236973e138
server (pages): an HTTP internal error is raised if an error is uncatched during page workflow
Goffi <goffi@goffi.org>
parents:
936
diff
changeset
|
908 """Main method to handle the workflow of a LiberviaPage""" |
994
b92b06f023cb
pages: profile is now always set in template_data, and None if there is no user logged
Goffi <goffi@goffi.org>
parents:
990
diff
changeset
|
909 |
923
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
910 # template_data are the variables passed to template |
917 | 911 if not hasattr(request, 'template_data'): |
957
67bf14c91d5c
server (pages): added a confirm flag on successful post:
Goffi <goffi@goffi.org>
parents:
956
diff
changeset
|
912 session_data = self.host.getSessionData(request, session_iface.ISATSession) |
67bf14c91d5c
server (pages): added a confirm flag on successful post:
Goffi <goffi@goffi.org>
parents:
956
diff
changeset
|
913 csrf_token = session_data.csrf_token |
994
b92b06f023cb
pages: profile is now always set in template_data, and None if there is no user logged
Goffi <goffi@goffi.org>
parents:
990
diff
changeset
|
914 request.template_data = {u'profile': session_data.profile, |
b92b06f023cb
pages: profile is now always set in template_data, and None if there is no user logged
Goffi <goffi@goffi.org>
parents:
990
diff
changeset
|
915 u'csrf_token': csrf_token} |
995 | 916 if self.dynamic: |
917 # we need to activate dynamic page | |
918 # we set data for template, and create/register token | |
919 socket_token = unicode(uuid.uuid4()) | |
920 socket_url = self.host.getWebsocketURL(request) | |
921 socket_debug = C.boolConst(self.host.debug) | |
922 request.template_data['websocket'] = WebsocketMeta(socket_url, socket_token, socket_debug) | |
923 self.host.registerWSToken(socket_token, self, request) | |
924 # we will keep track of handlers to remove | |
925 request._signals_registered = [] | |
926 # we will cache registered signals until socket is opened | |
927 request._signals_cache = [] | |
922
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
928 |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
929 # XXX: here is the code which need to be executed once |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
930 # at the beginning of the request hanling |
917 | 931 if request.postpath and not request.postpath[-1]: |
932 # we don't differenciate URLs finishing with '/' or not | |
933 del request.postpath[-1] | |
922
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
934 |
917 | 935 d = defer.Deferred() |
922
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
936 d.addCallback(self._checkAccess, request) |
16d1084d1371
server (pages): added "None" access (page is not rendered at all) and some HTTP code constants + helper methods to get session data
Goffi <goffi@goffi.org>
parents:
921
diff
changeset
|
937 |
923
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
938 if self.redirect is not None: |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
939 self.pageRedirect(self.redirect, request, skip_parse_url=False) |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
940 |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
941 if self.parse_url is not None and not skip_parse_url: |
917 | 942 d.addCallback(self.parse_url, request) |
943 | |
944 d.addCallback(self._subpagesHandler, request) | |
945 | |
931
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
946 if request.method not in (C.HTTP_METHOD_GET, C.HTTP_METHOD_POST): |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
947 # only HTTP GET and POST are handled so far |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
948 d.addCallback(lambda dummy: self.pageError(request, C.HTTP_BAD_REQUEST)) |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
949 |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
950 if request.method == C.HTTP_METHOD_POST: |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
951 if self.on_data_post is None: |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
952 # if we don't have on_data_post, the page was not expecting POST |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
953 # so we return an error |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
954 d.addCallback(lambda dummy: self.pageError(request, C.HTTP_BAD_REQUEST)) |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
955 else: |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
956 d.addCallback(self._on_data_post, request) |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
957 # by default, POST follow normal behaviour after on_data_post is called |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
958 # this can be changed by a redirection or other method call in on_data_post |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
959 |
917 | 960 if self.prepare_render: |
961 d.addCallback(self._prepare_render, request) | |
962 | |
963 if self.template: | |
962 | 964 d.addCallback(self._render_template, request) |
917 | 965 elif self.render_method: |
966 d.addCallback(self._render_method, request) | |
967 | |
968 d.addCallback(self.writeData, request) | |
969 d.addErrback(self._renderEb, request) | |
937
00236973e138
server (pages): an HTTP internal error is raised if an error is uncatched during page workflow
Goffi <goffi@goffi.org>
parents:
936
diff
changeset
|
970 d.addErrback(self._internalError, request) |
917 | 971 d.callback(self) |
972 return server.NOT_DONE_YET | |
973 | |
923
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
974 def render_GET(self, request): |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
975 return self.renderPage(request) |
edb322c87ea4
server (pages): pages now handle redirection, check self.pageRedirect docstring for details
Goffi <goffi@goffi.org>
parents:
922
diff
changeset
|
976 |
931
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
977 def render_POST(self, request): |
8a393ae90f8c
server (pages): post requests are now handled:
Goffi <goffi@goffi.org>
parents:
927
diff
changeset
|
978 return self.renderPage(request) |