changeset 428:58f3120f7e78

web: Fix how missing pages are handled. * Show a "this page doesn't exist yet" page. * Show that page for missing endpoint pages where the endpoint is not a query endpoint.
author Ludovic Chabant <ludovic@chabant.com>
date Thu, 30 Mar 2017 08:45:57 -0700
parents bbe048e682ec
children b2a6b3d8e190
files wikked/api/read.py wikked/templates/read-page-missing.html wikked/utils.py wikked/views/read.py wikked/webimpl/__init__.py wikked/webimpl/read.py wikked/webimpl/special.py
diffstat 7 files changed, 84 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/wikked/api/read.py	Thu Mar 30 08:21:23 2017 -0700
+++ b/wikked/api/read.py	Thu Mar 30 08:45:57 2017 -0700
@@ -6,9 +6,9 @@
 from wikked.webimpl import (
         CHECK_FOR_READ,
         url_from_viewarg,
-        get_page_or_raise, get_page_or_none,
-        get_page_meta, is_page_readable,
-        RedirectNotFound, CircularRedirectError)
+        get_page_or_raise,
+        get_page_meta,
+        PageNotFoundError, RedirectNotFoundError, CircularRedirectError)
 from wikked.webimpl.read import (
         read_page, get_incoming_links, get_outgoing_links)
 from wikked.webimpl.special import list_pages
@@ -40,7 +40,7 @@
     try:
         result = read_page(wiki, user, url)
         return jsonify(result)
-    except RedirectNotFound as e:
+    except (PageNotFoundError, RedirectNotFoundError) as e:
         app.logger.exception(e)
         abort(404)
     except CircularRedirectError as e:
@@ -131,5 +131,3 @@
     user = current_user.get_id()
     result = get_incoming_links(wiki, user, url)
     return jsonify(result)
-
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wikked/templates/read-page-missing.html	Thu Mar 30 08:45:57 2017 -0700
@@ -0,0 +1,26 @@
+{% extends 'index.html' %}
+{% block content %}
+<article class="wiki-page">
+    <header>
+        <h1>{{meta.title}}</h1>
+        {% if endpoint %}
+        <div class="decorator">{{endpoint}}</div>
+        {% endif %}
+        {% if redirected_from %}
+        <div class="decorator"><small>Redirected from 
+            {% for r in redirected_from %}
+            {% if not loop.first %} | {% endif %}
+            <a class="wiki-link" data-wiki-url="{{r}}"
+               href="{{get_read_url(r)}}?no_redirect">{{r}}</a>
+            {% endfor %}
+        </small></div>
+        {% endif %}
+    </header>
+    <section class="content">
+        <p>This page doesn't exist yet. You can 
+            <a class="wiki-link missing" data-wiki-url="{{meta.url}}"
+               href="{{get_edit_url(meta.url)}}">create it now</a>.
+        </p>
+    </section>
+</article>
+{% endblock %}
--- a/wikked/utils.py	Thu Mar 30 08:21:23 2017 -0700
+++ b/wikked/utils.py	Thu Mar 30 08:45:57 2017 -0700
@@ -20,6 +20,10 @@
     def __init__(self, url, message=None, *args):
         Exception.__init__(self, url, message, *args)
 
+    @property
+    def url(self):
+        return self.args[0]
+
     def __str__(self):
         url = self.args[0]
         message = self.args[1]
--- a/wikked/views/read.py	Thu Mar 30 08:21:23 2017 -0700
+++ b/wikked/views/read.py	Thu Mar 30 08:45:57 2017 -0700
@@ -1,12 +1,14 @@
 import urllib.parse
 from flask import (
-        render_template, request, abort)
+    render_template, request, abort)
 from flask.ext.login import current_user
+from wikked.utils import split_page_url, PageNotFoundError
 from wikked.views import add_auth_data, add_navigation_data, errorhandling_ui
 from wikked.web import app, get_wiki
-from wikked.webimpl import url_from_viewarg
+from wikked.webimpl import (
+    url_from_viewarg, make_page_title, RedirectNotFoundError)
 from wikked.webimpl.read import (
-        read_page, get_incoming_links)
+    read_page, get_incoming_links)
 from wikked.webimpl.special import get_search_results
 
 
@@ -17,6 +19,19 @@
     return read(url)
 
 
+def _make_missing_page_data(url):
+    endpoint, path = split_page_url(url)
+    data = {
+        'endpoint': endpoint,
+        'meta': {
+            'url': url,
+            'title': make_page_title(path)
+        },
+        'format': None
+    }
+    return data
+
+
 @app.route('/read/<path:url>')
 @errorhandling_ui
 def read(url):
@@ -24,7 +39,15 @@
     url = url_from_viewarg(url)
     user = current_user.get_id()
     no_redirect = 'no_redirect' in request.args
-    data = read_page(wiki, user, url, no_redirect=no_redirect)
+    tpl_name = 'read-page.html'
+    try:
+        data = read_page(wiki, user, url, no_redirect=no_redirect)
+    except PageNotFoundError as pnfe:
+        tpl_name = 'read-page-missing.html'
+        data = _make_missing_page_data(pnfe.url)
+    except RedirectNotFoundError as rnfe:
+        tpl_name = 'read-page-missing.html'
+        data = _make_missing_page_data(rnfe.url)
 
     if data['format']:
         custom_head = wiki.custom_heads.get(data['format'], '')
@@ -35,7 +58,7 @@
             url, data,
             edit=True, history=True, inlinks=True,
             raw_url='/api/raw/' + url.lstrip('/'))
-    return render_template('read-page.html', **data)
+    return render_template(tpl_name, **data)
 
 
 @app.route('/search')
--- a/wikked/webimpl/__init__.py	Thu Mar 30 08:21:23 2017 -0700
+++ b/wikked/webimpl/__init__.py	Thu Mar 30 08:45:57 2017 -0700
@@ -21,11 +21,13 @@
                 "after visiting: %s" % (url, visited))
 
 
-class RedirectNotFound(Exception):
+class RedirectNotFoundError(Exception):
     def __init__(self, url, not_found):
-        super(RedirectNotFound, self).__init__(
+        super(RedirectNotFoundError, self).__init__(
                 "Target redirect page '%s' not found from '%s'." %
                 (url, not_found))
+        self.origin_url = url
+        self.url = not_found
 
 
 class PermissionError(Exception):
@@ -133,12 +135,15 @@
     visited_paths = []
 
     while True:
-        page = get_page_or_none(
-                wiki, path,
-                fields=fields,
-                check_perms=check_perms)
-        if page is None:
-            raise RedirectNotFound(orig_path, path)
+        try:
+            page = get_page_or_raise(
+                    wiki, path,
+                    fields=fields,
+                    check_perms=check_perms)
+        except PageNotFoundError as pnfe:
+            if len(visited_paths) > 0:
+                raise RedirectNotFoundError(orig_path, path)
+            raise
 
         visited_paths.append(path)
         redirect_meta = page.getMeta('redirect')
--- a/wikked/webimpl/read.py	Thu Mar 30 08:21:23 2017 -0700
+++ b/wikked/webimpl/read.py	Thu Mar 30 08:45:57 2017 -0700
@@ -16,8 +16,6 @@
                 fields=['url', 'path', 'title', 'text', 'meta'],
                 check_perms=(user, CHECK_FOR_READ),
                 first_only=no_redirect)
-        if page is None:
-            raise PageNotFoundError(url)
 
         if no_redirect:
             additional_info['redirects_to'] = visited_paths[-1]
@@ -57,19 +55,19 @@
     if info_page is not None:
         ext = os.path.splitext(info_page.path)[1].lstrip('.')
 
-    if (endpoint_info is not None and
-            not endpoint_info.query
-            and info_page is not None):
+    if endpoint_info is not None and not endpoint_info.query:
         # Not a query-based endpoint (like categories). Let's just
-        # return the text.
-        result = {
+        # return the text if it exists, or a "not found" page.
+        if info_page is not None:
+            result = {
                 'endpoint': endpoint,
                 'meta': get_page_meta(info_page),
                 'text': info_page.text,
                 'page_title': info_page.title,
                 'format': ext}
-        result.update(additional_info)
-        return result
+            result.update(additional_info)
+            return result
+        raise PageNotFoundError(url)
 
     # Get the list of pages to show here.
     value = path.lstrip('/')
@@ -150,4 +148,3 @@
 
     result = {'meta': get_page_meta(page), 'out_links': links}
     return result
-
--- a/wikked/webimpl/special.py	Thu Mar 30 08:21:23 2017 -0700
+++ b/wikked/webimpl/special.py	Thu Mar 30 08:45:57 2017 -0700
@@ -7,7 +7,7 @@
         get_page_meta, get_page_or_raise, make_page_title,
         is_page_readable, get_redirect_target,
         get_or_build_pagelist, get_generic_pagelist_builder,
-        CircularRedirectError, RedirectNotFound)
+        CircularRedirectError, RedirectNotFoundError)
 
 
 def build_pagelist_view_data(pages, user):
@@ -68,7 +68,7 @@
                     fields=['url', 'meta'])
         except CircularRedirectError:
             return True
-        except RedirectNotFound:
+        except RedirectNotFoundError:
             return True
         return False