comparison src/server/server.py @ 923:edb322c87ea4

server (pages): pages now handle redirection, check self.pageRedirect docstring for details
author Goffi <goffi@goffi.org>
date Mon, 03 Apr 2017 01:00:29 +0200
parents 16d1084d1371
children 94f88277c2e7
comparison
equal deleted inserted replaced
922:16d1084d1371 923:edb322c87ea4
1421 1421
1422 class LiberviaPage(web_resource.Resource): 1422 class LiberviaPage(web_resource.Resource):
1423 isLeaf = True # we handle subpages ourself 1423 isLeaf = True # we handle subpages ourself
1424 named_pages = {} 1424 named_pages = {}
1425 1425
1426 def __init__(self, host, root_dir, name=None, access=None, parse_url=None, 1426 def __init__(self, host, root_dir, name=None, redirect=None, access=None, parse_url=None,
1427 prepare_render=None, render=None, template=None): 1427 prepare_render=None, render=None, template=None):
1428 """initiate LiberviaPages 1428 """initiate LiberviaPages
1429 1429
1430 LiberviaPages are the main resources of Libervia, using easy to set python files 1430 LiberviaPages are the main resources of Libervia, using easy to set python files
1431 The arguments are the variables found in page_meta.py 1431 The arguments are the variables found in page_meta.py
1432 @param host(Libervia): the running instance of Libervia 1432 @param host(Libervia): the running instance of Libervia
1433 @param root_dir(unicode): aboslute path of the page 1433 @param root_dir(unicode): aboslute path of the page
1434 @param name(unicode, None): if not None, a unique name to identify the page 1434 @param name(unicode, None): if not None, a unique name to identify the page
1435 can then be used for e.g. redirection 1435 can then be used for e.g. redirection
1436 "/" is not allowed in names (as it can be used to construct URL paths)
1437 @param redirect(unicode, None): if not None, this page will be a redirected
1438 parameter is used as in self.pageRedirect. parse_url will not be skipped
1439 using this redirect parameter is called "full redirection"
1440 using self.pageRedirect is called "partial redirection" (because some rendering method
1441 can still be used, e.g. parse_url)
1436 @param access(unicode, None): permission needed to access the page 1442 @param access(unicode, None): permission needed to access the page
1437 None means public access. 1443 None means public access.
1438 Pages inherit from parent pages: e.g. if a "settings" page is restricted to admins, 1444 Pages inherit from parent pages: e.g. if a "settings" page is restricted to admins,
1439 and if "settings/blog" is public, it still can only be accessed by admins. 1445 and if "settings/blog" is public, it still can only be accessed by admins.
1440 see C.PAGES_ACCESS_* for details 1446 see C.PAGES_ACCESS_* for details
1454 self.host = host 1460 self.host = host
1455 self.root_dir = root_dir 1461 self.root_dir = root_dir
1456 if name is not None: 1462 if name is not None:
1457 if name in self.named_pages: 1463 if name in self.named_pages:
1458 raise exceptions.ConflictError(_(u'a Libervia page named "{}" already exists'.format(name))) 1464 raise exceptions.ConflictError(_(u'a Libervia page named "{}" already exists'.format(name)))
1465 if u'/' in name:
1466 raise ValueError(_(u'"/" is not allowed in page names'))
1467 if not name:
1468 raise ValueError(_(u"a page name can't be empty"))
1459 self.named_pages[name] = self 1469 self.named_pages[name] = self
1460 if access is None: 1470 if access is None:
1461 access = C.PAGES_ACCESS_PUBLIC 1471 access = C.PAGES_ACCESS_PUBLIC
1462 if access not in (C.PAGES_ACCESS_PUBLIC, C.PAGES_ACCESS_PROFILE, C.PAGES_ACCESS_NONE): 1472 if access not in (C.PAGES_ACCESS_PUBLIC, C.PAGES_ACCESS_PROFILE, C.PAGES_ACCESS_NONE):
1463 raise NotImplementedError(_(u"{} access is not implemented yet").format(access)) 1473 raise NotImplementedError(_(u"{} access is not implemented yet").format(access))
1464 self.access = access 1474 self.access = access
1475 if redirect is not None:
1476 # only page access and name make sense in case of full redirection
1477 if not all(lambda x: x is not None
1478 for x in (parse_url, prepare_render, render, template)):
1479 raise ValueError(_(u"you can't use full page redirection with other rendering method,"
1480 u"check self.pageRedirect if you need to use them"))
1481 self.redirect = redirect
1482 else:
1483 self.redirect = None
1465 self.parse_url = parse_url 1484 self.parse_url = parse_url
1466 self.prepare_render = prepare_render 1485 self.prepare_render = prepare_render
1467 self.template = template 1486 self.template = template
1468 self.render_method = render 1487 self.render_method = render
1469 if access == C.PAGES_ACCESS_NONE: 1488 if access == C.PAGES_ACCESS_NONE:
1501 execfile(meta_path, page_data) 1520 execfile(meta_path, page_data)
1502 resource = LiberviaPage( 1521 resource = LiberviaPage(
1503 host, 1522 host,
1504 dir_path, 1523 dir_path,
1505 name=page_data.get('name'), 1524 name=page_data.get('name'),
1525 redirect=page_data.get('redirect'),
1506 access=page_data.get('access'), 1526 access=page_data.get('access'),
1507 parse_url=page_data.get('parse_url'), 1527 parse_url=page_data.get('parse_url'),
1508 prepare_render=page_data.get('prepare_render'), 1528 prepare_render=page_data.get('prepare_render'),
1509 render=page_data.get('render'), 1529 render=page_data.get('render'),
1510 template=page_data.get('template')) 1530 template=page_data.get('template'))
1527 """ 1547 """
1528 pathElement = request.postpath.pop(0) 1548 pathElement = request.postpath.pop(0)
1529 request.prepath.append(pathElement) 1549 request.prepath.append(pathElement)
1530 return urllib.unquote(pathElement).decode('utf-8') 1550 return urllib.unquote(pathElement).decode('utf-8')
1531 1551
1552 def pageRedirect(self, page_path, request, skip_parse_url=True):
1553 """redirect a page to a named page
1554
1555 the workflow will continue with the workflow of the named page,
1556 skipping named page's parse_url method if it exist.
1557 @param page_path(unicode): path to page (elements are separated by "/"):
1558 if path starts with a "/":
1559 path is a full path starting from root
1560 else:
1561 - first element is name as registered in name variable
1562 - following element are subpages path
1563 e.g.: "blog" redirect to page named "blog"
1564 "blog/atom.xml" redirect to atom.xml subpage of "blog"
1565 "/common/blog/atom.xml" redirect to the page at the fiven full path
1566 @param request(server.Request): current HTTP request
1567 @param skip_parse_url(bool): if True, parse_url method on redirect page will be skipped
1568 @raise KeyError: there is no known page with this name
1569 """
1570 # FIXME: render non LiberviaPage resources
1571 path = page_path.rstrip(u'/').split(u'/')
1572 if not path[0]:
1573 redirect_page = self.host.root
1574 else:
1575 redirect_page = self.named_pages[path[0]]
1576
1577 for subpage in path[1:]:
1578 redirect_page = redirect_page.childen[subpage]
1579
1580 redirect_page.renderPage(request, skip_parse_url=True)
1581 raise failure.Failure(exceptions.CancelError(u'page redirection is used'))
1582
1532 def pageError(self, request, code=C.HTTP_NOT_FOUND): 1583 def pageError(self, request, code=C.HTTP_NOT_FOUND):
1533 """generate an error page and terminate the request 1584 """generate an error page and terminate the request
1534 1585
1535 @param request(server.Request): HTTP request 1586 @param request(server.Request): HTTP request
1536 @param core(int): error code to use 1587 @param core(int): error code to use
1624 # no session started, access is not granted 1675 # no session started, access is not granted
1625 self.pageError(request, C.HTTP_UNAUTHORIZED) 1676 self.pageError(request, C.HTTP_UNAUTHORIZED)
1626 1677
1627 return data 1678 return data
1628 1679
1629 def render_GET(self, request): 1680 def renderPage(self, request, skip_parse_url=False):
1681 # template_data are the variables passed to template
1630 if not hasattr(request, 'template_data'): 1682 if not hasattr(request, 'template_data'):
1631 request.template_data = {} 1683 request.template_data = {}
1632 1684
1633 # XXX: here is the code which need to be executed once 1685 # XXX: here is the code which need to be executed once
1634 # at the beginning of the request hanling 1686 # at the beginning of the request hanling
1637 del request.postpath[-1] 1689 del request.postpath[-1]
1638 1690
1639 d = defer.Deferred() 1691 d = defer.Deferred()
1640 d.addCallback(self._checkAccess, request) 1692 d.addCallback(self._checkAccess, request)
1641 1693
1642 if self.parse_url is not None: 1694 if self.redirect is not None:
1695 self.pageRedirect(self.redirect, request, skip_parse_url=False)
1696
1697 if self.parse_url is not None and not skip_parse_url:
1643 d.addCallback(self.parse_url, request) 1698 d.addCallback(self.parse_url, request)
1644 1699
1645 d.addCallback(self._subpagesHandler, request) 1700 d.addCallback(self._subpagesHandler, request)
1646 1701
1647 if self.prepare_render: 1702 if self.prepare_render:
1654 1709
1655 d.addCallback(self.writeData, request) 1710 d.addCallback(self.writeData, request)
1656 d.addErrback(self._renderEb, request) 1711 d.addErrback(self._renderEb, request)
1657 d.callback(self) 1712 d.callback(self)
1658 return server.NOT_DONE_YET 1713 return server.NOT_DONE_YET
1714
1715 def render_GET(self, request):
1716 return self.renderPage(request)
1659 1717
1660 1718
1661 class Libervia(service.Service): 1719 class Libervia(service.Service):
1662 1720
1663 def __init__(self, options): 1721 def __init__(self, options):