aboutsummaryrefslogtreecommitdiffstats
path: root/pysite
diff options
context:
space:
mode:
authorGravatar Gareth Coles <[email protected]>2018-05-06 18:21:34 +0100
committerGravatar Gareth Coles <[email protected]>2018-05-06 18:21:34 +0100
commitefb902f3f293db4aac6e57b9f3a84143d84a90e9 (patch)
tree69fd91e690f1b8e150b839927c8bb312ebf81abc /pysite
parentI linted that, I swear (diff)
[Wiki] Misc improvements, plus a beta search feature
Diffstat (limited to 'pysite')
-rw-r--r--pysite/database.py15
-rw-r--r--pysite/views/wiki/edit.py10
-rw-r--r--pysite/views/wiki/search.py66
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)