src/templates/wiki/edit.html \
src/templates/wiki/page.html \
src/templates/wiki/recent-changes.html \
- src/templates/wiki/revisions.html
+ src/templates/wiki/revisions.html \
+ src/templates/wiki/search-results.html
templates_wikidir = $(templatesdir)/wiki
import unicodedata
from . import misc
+from . import util
from .decorators import *
# Used to automatically link some things
ORDER BY COALESCE(updated_at, created_at) DESC LIMIT %s", limit)
def search(self, query, limit=None):
- query = self._parse_search_query(query)
+ query = util.parse_search_query(query)
return self._get_posts("SELECT blog.* FROM blog \
LEFT JOIN blog_search_index search_index ON blog.id = search_index.post_id \
ORDER BY ts_rank(search_index.document, to_tsquery('english', %s)) DESC \
LIMIT %s", query, query, limit)
- def _parse_search_query(self, query):
- q = []
- for word in query.split():
- # Is this lexeme negated?
- negated = word.startswith("!")
-
- # Remove any special characters
- word = re.sub(r"\W+", "", word, flags=re.UNICODE)
- if not word:
- continue
-
- # Restore negation
- if negated:
- word = "!%s" % word
-
- q.append(word)
-
- return " & ".join(q)
-
def create_post(self, title, text, author, tags=[], lang="markdown"):
"""
Creates a new post and returns the resulting Post object
-#!/usr/bin/python
+#!/usr/bin/python3
import random
+import re
import string
+def parse_search_query(query):
+ q = []
+ for word in query.split():
+ # Is this lexeme negated?
+ negated = word.startswith("!")
+
+ # Remove any special characters
+ word = re.sub(r"\W+", "", word, flags=re.UNICODE)
+ if not word:
+ continue
+
+ # Restore negation
+ if negated:
+ word = "!%s" % word
+
+ q.append(word)
+
+ return " & ".join(q)
+
def format_size(s, max_unit=None):
units = ("B", "kB", "MB", "GB", "TB")
import re
from . import misc
+from . import util
from .decorators import *
class Wiki(misc.Object):
return ret
+ def search(self, query, limit=None):
+ query = util.parse_search_query(query)
+
+ res = self._get_pages("SELECT wiki.* FROM wiki_search_index search_index \
+ LEFT JOIN wiki ON search_index.wiki_id = wiki.id \
+ WHERE search_index.document @@ to_tsquery('english', %s) \
+ ORDER BY ts_rank(search_index.document, to_tsquery('english', %s)) DESC \
+ LIMIT %s", query, query, limit)
+
+ return list(res)
+
+ def refresh(self):
+ """
+ Needs to be called after a page has been changed
+ """
+ self.db.execute("REFRESH MATERIALIZED VIEW wiki_search_index")
+
class Page(misc.Object):
def init(self, id, data=None):
--- /dev/null
+{% extends "../base.html" %}
+
+{% block title %}{{ _("Search results for '%s'") % q }}{% end block %}
+
+{% block content %}
+ <div class="card">
+ <div class="card-body">
+ <h5>{{ _("Search results for '%s'") % q }}</h5>
+
+ {% module WikiList(pages) %}
+ </div>
+ </div>
+{% end block %}
else:
self.redirect(page.url)
+ # Update the search index
+ with self.db.transaction():
+ self.backend.wiki.refresh()
+
class SearchHandler(auth.CacheMixin, base.BaseHandler):
@base.blacklisted
q = self.get_argument("q")
pages = self.backend.wiki.search(q, limit=50)
- if not pages:
- raise tornado.web.HTTPError(404, "Nothing found")
self.render("wiki/search-results.html", q=q, pages=pages)