# HG changeset patch # User Goffi # Date 1491174029 -7200 # Node ID edb322c87ea4d72bed5e6321ad6f5f2625c7504f # Parent 16d1084d1371ab19250277e127ce8fd5af57c36c server (pages): pages now handle redirection, check self.pageRedirect docstring for details diff -r 16d1084d1371 -r edb322c87ea4 src/server/server.py --- a/src/server/server.py Mon Apr 03 01:00:26 2017 +0200 +++ b/src/server/server.py Mon Apr 03 01:00:29 2017 +0200 @@ -1423,7 +1423,7 @@ isLeaf = True # we handle subpages ourself named_pages = {} - def __init__(self, host, root_dir, name=None, access=None, parse_url=None, + def __init__(self, host, root_dir, name=None, redirect=None, access=None, parse_url=None, prepare_render=None, render=None, template=None): """initiate LiberviaPages @@ -1433,6 +1433,12 @@ @param root_dir(unicode): aboslute path of the page @param name(unicode, None): if not None, a unique name to identify the page can then be used for e.g. redirection + "/" is not allowed in names (as it can be used to construct URL paths) + @param redirect(unicode, None): if not None, this page will be a redirected + parameter is used as in self.pageRedirect. parse_url will not be skipped + using this redirect parameter is called "full redirection" + using self.pageRedirect is called "partial redirection" (because some rendering method + can still be used, e.g. parse_url) @param access(unicode, None): permission needed to access the page None means public access. Pages inherit from parent pages: e.g. if a "settings" page is restricted to admins, @@ -1456,12 +1462,25 @@ if name is not None: if name in self.named_pages: raise exceptions.ConflictError(_(u'a Libervia page named "{}" already exists'.format(name))) + if u'/' in name: + raise ValueError(_(u'"/" is not allowed in page names')) + if not name: + raise ValueError(_(u"a page name can't be empty")) self.named_pages[name] = self if access is None: access = C.PAGES_ACCESS_PUBLIC if access not in (C.PAGES_ACCESS_PUBLIC, C.PAGES_ACCESS_PROFILE, C.PAGES_ACCESS_NONE): raise NotImplementedError(_(u"{} access is not implemented yet").format(access)) self.access = access + if redirect is not None: + # only page access and name make sense in case of full redirection + if not all(lambda x: x is not None + for x in (parse_url, prepare_render, render, template)): + raise ValueError(_(u"you can't use full page redirection with other rendering method," + u"check self.pageRedirect if you need to use them")) + self.redirect = redirect + else: + self.redirect = None self.parse_url = parse_url self.prepare_render = prepare_render self.template = template @@ -1503,6 +1522,7 @@ host, dir_path, name=page_data.get('name'), + redirect=page_data.get('redirect'), access=page_data.get('access'), parse_url=page_data.get('parse_url'), prepare_render=page_data.get('prepare_render'), @@ -1529,6 +1549,37 @@ request.prepath.append(pathElement) return urllib.unquote(pathElement).decode('utf-8') + def pageRedirect(self, page_path, request, skip_parse_url=True): + """redirect a page to a named page + + the workflow will continue with the workflow of the named page, + skipping named page's parse_url method if it exist. + @param page_path(unicode): path to page (elements are separated by "/"): + if path starts with a "/": + path is a full path starting from root + else: + - first element is name as registered in name variable + - following element are subpages path + e.g.: "blog" redirect to page named "blog" + "blog/atom.xml" redirect to atom.xml subpage of "blog" + "/common/blog/atom.xml" redirect to the page at the fiven full path + @param request(server.Request): current HTTP request + @param skip_parse_url(bool): if True, parse_url method on redirect page will be skipped + @raise KeyError: there is no known page with this name + """ + # FIXME: render non LiberviaPage resources + path = page_path.rstrip(u'/').split(u'/') + if not path[0]: + redirect_page = self.host.root + else: + redirect_page = self.named_pages[path[0]] + + for subpage in path[1:]: + redirect_page = redirect_page.childen[subpage] + + redirect_page.renderPage(request, skip_parse_url=True) + raise failure.Failure(exceptions.CancelError(u'page redirection is used')) + def pageError(self, request, code=C.HTTP_NOT_FOUND): """generate an error page and terminate the request @@ -1626,7 +1677,8 @@ return data - def render_GET(self, request): + def renderPage(self, request, skip_parse_url=False): + # template_data are the variables passed to template if not hasattr(request, 'template_data'): request.template_data = {} @@ -1639,7 +1691,10 @@ d = defer.Deferred() d.addCallback(self._checkAccess, request) - if self.parse_url is not None: + if self.redirect is not None: + self.pageRedirect(self.redirect, request, skip_parse_url=False) + + if self.parse_url is not None and not skip_parse_url: d.addCallback(self.parse_url, request) d.addCallback(self._subpagesHandler, request) @@ -1657,6 +1712,9 @@ d.callback(self) return server.NOT_DONE_YET + def render_GET(self, request): + return self.renderPage(request) + class Libervia(service.Service):