Roundup Tracker

Markup Using Markdown or Creole

The following example shows how to integrate Markdown or Creole into Roundup. (Note consider security issues before using on a public tracker. E.G. Markdown can include escapes allowing access to features you may not want. Creole may do the same. Also users may be able to include script tags that are unescaped when displayed. The user should test.)

You can also see: https://issues.roundup-tracker.org/issue2550856 for native markdown and reStructured text support. It also discusses security issues when processing the markup languages.

One thing missing from below is the ability to preview the entered text as html. Extending the REST interface to format markup like markdown or creole can allow the user to preview their text. Setting up the REST interface (roundup 2.0 and newer) is discussed in:

On b1b3b84f07a5 commits were made to the jinja2 template that uses SimpleMDE for markdown editing. This permits preview without using the server.

For Markdown:

Web Editing

Consider using an editor interface like https://github.com/fatihege/downarea.

Preview

The REST interface could be extended to format markdown to html. See:

for ideas on a POC. The messages above describe restructured text rather than markdown but the modification should be straight forwrad.

Backend Change

For this you have to save local_markdown.py in the extensions folder.

    import commonmark


    def local_markdown(message):
        return commonmark.commonmark(message)

    def init(instance):
        pass

    def quicktest(msgstr):
        print("'%s' -> '%s'" % (msgstr, local_markdown(msgstr)))


    if "__main__" == __name__:

        quicktest("Hello *World*")
        quicktest("Hello **World**")
        quicktest("Hello ***World***")
        quicktest("Hello _World_")
        quicktest("Hello __World__")
        quicktest("Hello ___World___")
        quicktest("Hello *World* Hello")
        quicktest("* World \n * World")

local_replace.py must be modified to call local_markdown.

    --- a/local_replace.py
    +++ b/local_replace.py
    @@ -1,6 +1,8 @@
     from __future__ import print_function
     import re

    +import local_markdown
    +
     hg_url_base = r'http://sourceforge.net/p/roundup/code/ci/'

     substitutions = [ (re.compile(r'debian:\#(?P<id>\d+)'),
    @@ -23,6 +25,8 @@
         for cre, replacement in substitutions:
             message = cre.sub(replacement, message)

    +    message = local_markdown.local_markdown(message)
    +
         return message

For Creole:

Install https://pypi.org/project/python-creole/.

For this you have to save local_creole.py in the extensions folder.

    from creole import creole2html
    import re

    r = re.compile(r'(<a href=.*?<\/a>)')

    def local_creole(message):
        # The links are already in HTML format. creole2html would translate it a
        # second time to hatml. That's why they're filtered out.
        links = r.findall(message)
        i = 0
        for l in links:
            message = message.replace(l, "<Dummy_" + str(i)+ ">")
            i = i + 1

        message = creole2html(message)

        i = 0
        for l in links:
            message = message.replace("<Dummy_" + str(i) + ">", l)
            i = i + 1

        return message

    def init(instance):
        pass

    def quicktest(msgstr):
        print("'%s' -> '%s'" % (msgstr, local_creole(msgstr)))


    if "__main__" == __name__:

        quicktest("Hello *World*")
        quicktest("Hello **World**")
        quicktest("Hello ***World***")
        quicktest("Hello //World//")
        quicktest("= Extra-large heading")
        quicktest("== Large heading")
        quicktest("=== Medium heading")
        quicktest("----")

local_replace.py must be modified to call local_creole.

    --- a/local_replace.py
    +++ b/local_replace.py
    @@ -1,6 +1,8 @@
     from __future__ import print_function
     import re

    +import local_creole
    +
     hg_url_base = r'http://sourceforge.net/p/roundup/code/ci/'

     substitutions = [ (re.compile(r'debian:\#(?P<id>\d+)'),
    @@ -23,6 +25,8 @@
         for cre, replacement in substitutions:
             message = cre.sub(replacement, message)

    +    message = local_creole.local_creole(message)
    +
         return message