diff options
Diffstat (limited to 'pysite')
| -rw-r--r-- | pysite/database.py | 15 | ||||
| -rw-r--r-- | pysite/views/wiki/edit.py | 10 | ||||
| -rw-r--r-- | pysite/views/wiki/search.py | 66 | 
3 files changed, 86 insertions, 5 deletions
| diff --git a/pysite/database.py b/pysite/database.py index 86c8685d..41fbd253 100644 --- a/pysite/database.py +++ b/pysite/database.py @@ -1,8 +1,10 @@  # coding=utf-8 +import html  import json  import logging  import os  from typing import Any, Callable, Dict, Iterator, List, Optional, Union +import re  import rethinkdb  from flask import abort @@ -22,6 +24,9 @@ ALL_TABLES = {      "wiki_revisions": "id"  } +STRIP_REGEX = re.compile(r"<[^<]+?>") +WIKI_TABLE = "wiki" +  class RethinkDB: @@ -55,6 +60,13 @@ class RethinkDB:                      tables = ", ".join([f"{table} ({count} items)" for table, count in initialized.items()])                      self.log.debug(f"Initialized the following tables: {tables}") +                # Upgrade wiki articles +                for article in self.pluck(WIKI_TABLE, "html", "text", "slug"): +                    if "text" not in article: +                        article["text"] = html.unescape(STRIP_REGEX.sub("", article["html"]).strip()) + +                    self.insert(WIKI_TABLE, article, conflict="update") +      def create_tables(self) -> List[str]:          """          Creates whichever tables exist in the ALL_TABLES @@ -496,9 +508,6 @@ class RethinkDB:          """          Map a function over every document in a table, with the possibility of modifying it -        r.table('users').map( -        lambda doc: doc.merge({'user_id': doc['id']}).without('id')).run(conn) -          As an example, you could do the following to rename the "id" field to "user_id" for all documents          in the "users" table. diff --git a/pysite/views/wiki/edit.py b/pysite/views/wiki/edit.py index 2cd4181c..bb39ed2b 100644 --- a/pysite/views/wiki/edit.py +++ b/pysite/views/wiki/edit.py @@ -1,5 +1,7 @@  import datetime  import difflib +import html +import re  import requests  from flask import redirect, request, url_for @@ -11,6 +13,8 @@ from pysite.decorators import csrf, require_roles  from pysite.mixins import DBMixin  from pysite.rst import render +STRIP_REGEX = re.compile(r"<[^<]+?>") +  class EditView(RouteView, DBMixin):      path = "/edit/<path:page>"  # "path" means that it accepts slashes @@ -55,11 +59,12 @@ class EditView(RouteView, DBMixin):      @csrf      def post(self, page):          rst = request.form.get("rst") +        title = request.form["title"] -        if not rst: +        if not rst or not not rst.strip():              raise BadRequest() -        if not rst.strip(): +        if not title or not title.strip():              raise BadRequest()          rendered = render(rst) @@ -69,6 +74,7 @@ class EditView(RouteView, DBMixin):              "title": request.form["title"],              "rst": rst,              "html": rendered["html"], +            "text": html.unescape(STRIP_REGEX.sub("", rendered["html"]).strip()),              "headers": rendered["headers"]          } diff --git a/pysite/views/wiki/search.py b/pysite/views/wiki/search.py new file mode 100644 index 00000000..1c920e15 --- /dev/null +++ b/pysite/views/wiki/search.py @@ -0,0 +1,66 @@ +import html +import re + +from flask import redirect, request, url_for +from werkzeug.exceptions import BadRequest + +from pysite.base_route import RouteView +from pysite.decorators import csrf +from pysite.mixins import DBMixin + +STRIP_REGEX = re.compile(r"<[^<]+?>") + + +class SearchView(RouteView, DBMixin): +    path = "/search"  # "path" means that it accepts slashes +    name = "search" +    table_name = "wiki" +    revision_table_name = "wiki_revisions" + +    def get(self): +        return self.render("wiki/search.html") + +    @csrf +    def post(self): +        given_query = request.form.get("query") + +        if not given_query or not given_query.strip(): +            raise BadRequest() + +        query = f"({re.escape(given_query)})" + +        pages = self.db.filter( +            self.table_name, +            lambda doc: doc["text"].match(query) +        ) + +        if len(pages) == 1: +            slug = pages[0]["slug"] +            return redirect(url_for("wiki.page", page=slug), code=303) + +        for obj in pages: +            text = obj["text"] + +            matches = re.finditer(query, text) +            snippets = [] + +            for match in matches: +                start = match.start() - 50 + +                if start < 0: +                    start = 0 + +                end = match.end() + 50 + +                if end > len(text): +                    end = len(text) + +                match_text = text[start:end] +                match_text = re.sub(query, r"<strong>\1</strong>", html.escape(match_text)) + +                snippets.append(match_text.replace("\n", "<br />")) + +            obj["matches"] = snippets + +        pages = sorted(pages, key=lambda d: d["title"]) +        return self.render("wiki/search_results.html", pages=pages, query=given_query) | 
