return os.path.join("/docs", path)
- def page_exists(self, path):
- page = self.get_page(path)
-
- # Page must have been found and not deleted
- return page and not page.was_deleted()
-
def get_page_title(self, page, default=None):
doc = self.get_page(page)
if doc:
"""
Needs to be called after a page has been changed
"""
- self.db.execute("REFRESH MATERIALIZED VIEW wiki_search_index")
+ self.db.execute("REFRESH MATERIALIZED VIEW CONCURRENTLY wiki_search_index")
def get_watchlist(self, account):
pages = self._get_pages("""
self.revision = revision
# Markdown Renderer
- self.renderer = markdown.Markdown(
+ self.renderer = Markdown(
+ self.backend,
extensions=[
LinkedFilesExtractorExtension(),
PrettyLinksExtension(),
def _render_link(self, m):
url, text = m.groups()
+ # Treat linkes starting with a double slash as absolute
+ if url.startswith("//"):
+ # Remove the double-lash
+ url = url.removeprefix("/")
+
+ # Return a link
+ return """<a href="%s">%s</a>""" % (url, text or url)
+
# External Links
for schema in self.schemas:
if url.startswith(schema):
return files
+class Markdown(markdown.Markdown):
+ def __init__(self, backend, *args, **kwargs):
+ # Store the backend
+ self.backend = backend
+
+ # Call inherited setup routine
+ super().__init__(*args, **kwargs)
+
+
class PrettyLinksExtension(markdown.extensions.Extension):
def extendMarkdown(self, md):
# Create links to Bugzilla
# Create links to CVE
md.preprocessors.register(CVELinksPreprocessor(md), "cve", 10)
+ # Link mentioned users
+ md.preprocessors.register(UserMentionPreprocessor(md), "user-mention", 10)
+
class BugzillaLinksPreprocessor(markdown.preprocessors.Preprocessor):
regex = re.compile(r"(?:#(\d{5,}))", re.I)
yield self.regex.sub(r"[CVE-\1](https://cve.mitre.org/cgi-bin/cvename.cgi?name=\1)", line)
+class UserMentionPreprocessor(markdown.preprocessors.Preprocessor):
+ regex = re.compile(r"\b@(\w+)")
+
+ def run(self, lines):
+ for line in lines:
+ yield self.regex.sub(self._replace, line)
+
+ def _replace(self, m):
+ # Fetch the user's handle
+ uid, = m.groups()
+
+ # Fetch the user
+ user = self.md.backend.accounts.get_by_uid(uid)
+
+ # If the user was not found, we put back the matched text
+ if not user:
+ return m.group(0)
+
+ # Link the user
+ return "[%s](//users/%s)" % (user, user.uid)
+
+
class LinkedFilesExtractor(markdown.treeprocessors.Treeprocessor):
"""
Finds all Linked Files