Mercurial > libervia-web
comparison src/server/server.py @ 980:bcacf970f970
core (pages redirection): inverted redirection + getSubPageURL:
- page redirection now also work in other redirection meaning that if "/redirecting_url" => "/page_name/arg_1/arg_2" is used,
a getURL(page_name, arg_1, arg_2) will return the redirecting_url.
query_args are not handled yet by getURL.
- page redirection dict now use path_args and query_args insteand of args and kwargs, which show the relation with URL.
- new getSubPageURL return absolute URL to a subpage, which is more solid than relative URL and allows to use it in sub-hierarchy.
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 14 Nov 2017 08:35:17 +0100 |
parents | 1d558dfb32ca |
children | f0fc28b3bd1e |
comparison
equal
deleted
inserted
replaced
979:1d558dfb32ca | 980:bcacf970f970 |
---|---|
132 if 'url' in new_data: | 132 if 'url' in new_data: |
133 new = new_data['url'] | 133 new = new_data['url'] |
134 elif 'page' in new_data: | 134 elif 'page' in new_data: |
135 new = new_data | 135 new = new_data |
136 new['type'] = 'page' | 136 new['type'] = 'page' |
137 if 'args' in new: | 137 new.setdefault('path_args', []) |
138 # we need lists in args because it will be used | 138 if not isinstance(new['path_args'], list): |
139 # as it in request.args | 139 log.error(_(u'"path_args" in redirection of {old} must be a list. Ignoring the redirection'.format( |
140 for k,v in new['args'].iteritems(): | 140 old = old))) |
141 if isinstance(v, basestring): | 141 continue |
142 new['args'][k] = [v] | 142 new.setdefault('query_args', {}) |
143 if not isinstance(new['query_args'], dict): | |
144 log.error(_(u'"query_args" in redirection of {old} must be a dictionary. Ignoring the redirection'.format( | |
145 old = old))) | |
146 continue | |
147 new['path_args'] = [quote(a) for a in new['path_args']] | |
148 # we keep an inversed dict of page redirection (page/path_args => redirecting URL) | |
149 # so getURL can return the redirecting URL if the same arguments are used | |
150 # making the URL consistent | |
151 args_hash = tuple(new['path_args']) | |
152 LiberviaPage.pages_redirects.setdefault(new_data['page'], {})[args_hash] = old | |
153 | |
154 # we need lists in query_args because it will be used | |
155 # as it in request.path_args | |
156 for k,v in new['query_args'].iteritems(): | |
157 if isinstance(v, basestring): | |
158 new['query_args'][k] = [v] | |
143 elif 'path' in new_data: | 159 elif 'path' in new_data: |
144 new = 'file:{}'.format(urllib.quote(new_data['path'])) | 160 new = 'file:{}'.format(urllib.quote(new_data['path'])) |
145 else: | 161 else: |
146 new = new_data | 162 new = new_data |
147 new_data = {} | 163 new_data = {} |
296 page = LiberviaPage.getPageByName(request_data['page']) | 312 page = LiberviaPage.getPageByName(request_data['page']) |
297 except KeyError: | 313 except KeyError: |
298 log.error(_(u"Can't find page named \"{name}\" requested in redirection").format( | 314 log.error(_(u"Can't find page named \"{name}\" requested in redirection").format( |
299 name = request_data['page'])) | 315 name = request_data['page'])) |
300 return web_resource.NoResource() | 316 return web_resource.NoResource() |
317 request.postpath = request_data['path_args'][:] + request.postpath | |
318 | |
301 try: | 319 try: |
302 request.args.update(request_data['args']) | 320 request.args.update(request_data['query_args']) |
303 except KeyError: | 321 except (TypeError, ValueError): |
304 pass | 322 log.error(_(u"Invalid args in redirection: {query_args}").format( |
305 except Exception: | 323 query_args=request_data['query_args'])) |
306 log.error(_(u"Invalid args in redirection: {args}").format(request_data['args'])) | |
307 return web_resource.NoResource() | 324 return web_resource.NoResource() |
308 return page | 325 return page |
309 else: | 326 else: |
310 raise exceptions.InternalError(u'unknown request_data type') | 327 raise exceptions.InternalError(u'unknown request_data type') |
311 else: | 328 else: |
1351 | 1368 |
1352 class LiberviaPage(web_resource.Resource): | 1369 class LiberviaPage(web_resource.Resource): |
1353 isLeaf = True # we handle subpages ourself | 1370 isLeaf = True # we handle subpages ourself |
1354 named_pages = {} | 1371 named_pages = {} |
1355 uri_callbacks = {} | 1372 uri_callbacks = {} |
1373 pages_redirects = {} | |
1356 | 1374 |
1357 def __init__(self, host, root_dir, url, name=None, redirect=None, access=None, parse_url=None, | 1375 def __init__(self, host, root_dir, url, name=None, redirect=None, access=None, parse_url=None, |
1358 prepare_render=None, render=None, template=None, on_data_post=None): | 1376 prepare_render=None, render=None, template=None, on_data_post=None): |
1359 """initiate LiberviaPages | 1377 """initiate LiberviaPages |
1360 | 1378 |
1395 | 1413 |
1396 web_resource.Resource.__init__(self) | 1414 web_resource.Resource.__init__(self) |
1397 self.host = host | 1415 self.host = host |
1398 self.root_dir = root_dir | 1416 self.root_dir = root_dir |
1399 self.url = url | 1417 self.url = url |
1418 self.name = name | |
1400 if name is not None: | 1419 if name is not None: |
1401 if name in self.named_pages: | 1420 if name in self.named_pages: |
1402 raise exceptions.ConflictError(_(u'a Libervia page named "{}" already exists'.format(name))) | 1421 raise exceptions.ConflictError(_(u'a Libervia page named "{}" already exists'.format(name))) |
1403 if u'/' in name: | 1422 if u'/' in name: |
1404 raise ValueError(_(u'"/" is not allowed in page names')) | 1423 raise ValueError(_(u'"/" is not allowed in page names')) |
1410 if access not in (C.PAGES_ACCESS_PUBLIC, C.PAGES_ACCESS_PROFILE, C.PAGES_ACCESS_NONE): | 1429 if access not in (C.PAGES_ACCESS_PUBLIC, C.PAGES_ACCESS_PROFILE, C.PAGES_ACCESS_NONE): |
1411 raise NotImplementedError(_(u"{} access is not implemented yet").format(access)) | 1430 raise NotImplementedError(_(u"{} access is not implemented yet").format(access)) |
1412 self.access = access | 1431 self.access = access |
1413 if redirect is not None: | 1432 if redirect is not None: |
1414 # only page access and name make sense in case of full redirection | 1433 # only page access and name make sense in case of full redirection |
1434 # so we check that rendering methods/values are not set | |
1415 if not all(lambda x: x is not None | 1435 if not all(lambda x: x is not None |
1416 for x in (parse_url, prepare_render, render, template)): | 1436 for x in (parse_url, prepare_render, render, template)): |
1417 raise ValueError(_(u"you can't use full page redirection with other rendering method," | 1437 raise ValueError(_(u"you can't use full page redirection with other rendering method," |
1418 u"check self.pageRedirect if you need to use them")) | 1438 u"check self.pageRedirect if you need to use them")) |
1419 self.redirect = redirect | 1439 self.redirect = redirect |
1420 else: | 1440 else: |
1421 self.redirect = None | 1441 self.redirect = None |
1422 self.parse_url = parse_url | 1442 self.parse_url = parse_url |
1423 self.prepare_render = prepare_render | 1443 self.prepare_render = prepare_render |
1552 """retrieve URL of the page set arguments | 1572 """retrieve URL of the page set arguments |
1553 | 1573 |
1554 *args(list[unicode]): argument to add to the URL as path elements | 1574 *args(list[unicode]): argument to add to the URL as path elements |
1555 """ | 1575 """ |
1556 url_args = [quote(a) for a in args] | 1576 url_args = [quote(a) for a in args] |
1577 | |
1578 if self.name is not None and self.name in self.pages_redirects: | |
1579 # we check for redirection | |
1580 redirect_data = self.pages_redirects[self.name] | |
1581 args_hash = tuple(args) | |
1582 for limit in xrange(len(args)+1): | |
1583 current_hash = args_hash[:limit] | |
1584 if current_hash in redirect_data: | |
1585 url_base = redirect_data[current_hash] | |
1586 remaining = args[limit:] | |
1587 remaining_url = '/'.join(remaining) | |
1588 return os.path.join('/', url_base, remaining_url) | |
1589 | |
1557 return os.path.join(self.url, *url_args) | 1590 return os.path.join(self.url, *url_args) |
1591 | |
1592 def getSubPageURL(self, request, page_name, *args): | |
1593 """retrieve a page in direct children and build its URL according to request | |
1594 | |
1595 request's current path is used as base (at current parsing point, | |
1596 i.e. it's more prepath than path). | |
1597 Requested page is checked in children and an absolute URL is then built | |
1598 by the resulting combination. | |
1599 This method is useful to construct absolute URLs for children instead of | |
1600 using relative path, which may not work in subpages, and are linked to the | |
1601 names of directories (i.e. relative URL will break if subdirectory is renamed | |
1602 while getSubPageURL won't as long as page_name is consistent). | |
1603 Also, request.path is used, keeping real path used by user, | |
1604 and potential redirections. | |
1605 @param request(server.Request): current HTTP request | |
1606 @param page_name(unicode): name of the page to retrieve | |
1607 it must be a direct children of current page | |
1608 @param *args(list[unicode]): arguments to add as path elements | |
1609 @return unicode: absolute URL to the sub page | |
1610 """ | |
1611 # we get url in the following way (splitting request.path instead of using | |
1612 # request.prepath) because request.prepath may have been modified by | |
1613 # redirection (if redirection args have been specified), while path reflect | |
1614 # the real request | |
1615 | |
1616 # we ignore empty path elements (i.e. double '/' or '/' at the end) | |
1617 path_elts = [p for p in request.path.split('/') if p] | |
1618 | |
1619 if request.postpath: | |
1620 if not request.postpath[-1]: | |
1621 # we remove trailing slash | |
1622 request.postpath = request.postpath[:-1] | |
1623 if request.postpath: | |
1624 # getSubPageURL must return subpage from the point where | |
1625 # the it is called, so we have to remove remanining | |
1626 # path elements | |
1627 path_elts = path_elts[:-len(request.postpath)] | |
1628 | |
1629 current_url = '/' + '/'.join(path_elts).decode('utf-8') | |
1630 | |
1631 for path, child in self.children.iteritems(): | |
1632 try: | |
1633 child_name = child.name | |
1634 except AttributeError: | |
1635 # LiberviaPage have a name, but maybe this is an other Resource | |
1636 continue | |
1637 if child_name == page_name: | |
1638 return os.path.join(u'/', current_url, path, *args) | |
1639 raise exceptions.NotFound(_(u'requested sub page has not been found')) | |
1558 | 1640 |
1559 def getChildWithDefault(self, path, request): | 1641 def getChildWithDefault(self, path, request): |
1560 # we handle children ourselves | 1642 # we handle children ourselves |
1561 raise exceptions.InternalError(u"this method should not be used with LiberviaPage") | 1643 raise exceptions.InternalError(u"this method should not be used with LiberviaPage") |
1562 | 1644 |