]> git.ipfire.org Git - ipfire.org.git/blobdiff - src/backend/wiki.py
wiki: Only match usernames when a word starts with @
[ipfire.org.git] / src / backend / wiki.py
index 9c5f55aa72180a4e09676209a3a470e993c58f8a..8edfb4e6a1f3fb2f46062fb2a8e0a5bb8bfbc143 100644 (file)
@@ -67,12 +67,6 @@ class Wiki(misc.Object):
 
                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:
@@ -206,7 +200,7 @@ class Wiki(misc.Object):
                """
                        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("""
@@ -799,7 +793,8 @@ class WikiRenderer(misc.Object):
                self.revision = revision
 
                # Markdown Renderer
-               self.renderer = markdown.Markdown(
+               self.renderer = Markdown(
+                       self.backend,
                        extensions=[
                                LinkedFilesExtractorExtension(),
                                PrettyLinksExtension(),
@@ -819,6 +814,14 @@ class WikiRenderer(misc.Object):
        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):
@@ -954,6 +957,15 @@ class WikiRenderer(misc.Object):
                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
@@ -962,6 +974,9 @@ class PrettyLinksExtension(markdown.extensions.Extension):
                # 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)
@@ -979,6 +994,28 @@ class CVELinksPreprocessor(markdown.preprocessors.Preprocessor):
                        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