diff --git a/taiga/mdrender/gfm/__init__.py b/taiga/mdrender/gfm/__init__.py
index 094a08df..a5aa0ac1 100644
--- a/taiga/mdrender/gfm/__init__.py
+++ b/taiga/mdrender/gfm/__init__.py
@@ -10,6 +10,7 @@ from . import spaced_link
from . import strikethrough
from . import wikilinks
from . import emojify
+from . import mentions
AutolinkExtension = autolink.AutolinkExtension
AutomailExtension = automail.AutomailExtension
@@ -19,3 +20,4 @@ SpacedLinkExtension = spaced_link.SpacedLinkExtension
StrikethroughExtension = strikethrough.StrikethroughExtension
WikiLinkExtension = wikilinks.WikiLinkExtension
EmojifyExtension = emojify.EmojifyExtension
+MentionsExtension = mentions.MentionsExtension
diff --git a/taiga/mdrender/gfm/emojify.py b/taiga/mdrender/gfm/emojify.py
index bbf9bebd..93321fb5 100644
--- a/taiga/mdrender/gfm/emojify.py
+++ b/taiga/mdrender/gfm/emojify.py
@@ -159,6 +159,8 @@ class EmojifyExtension(Extension):
class EmojifyPreprocessor(Preprocessor):
def run(self, lines):
+ pattern = re.compile(':([a-z0-9\+\-_]+):')
+
new_lines = []
def emojify(match):
@@ -173,7 +175,7 @@ class EmojifyPreprocessor(Preprocessor):
for line in lines:
if line.strip():
- line = re.sub(r':([a-z0-9\+\-_]+):', emojify, line, flags=re.UNICODE)
+ line = pattern.sub(emojify, line)
new_lines.append(line)
diff --git a/taiga/mdrender/gfm/mentions.py b/taiga/mdrender/gfm/mentions.py
new file mode 100644
index 00000000..1b8e445d
--- /dev/null
+++ b/taiga/mdrender/gfm/mentions.py
@@ -0,0 +1,68 @@
+#-*- coding: utf-8 -*-
+
+# Tested on Markdown 2.3.1
+#
+# Copyright (c) 2014, Esteban Castro Borsani
+# The MIT License (MIT)
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+
+import re
+import os
+
+from markdown.extensions import Extension
+from markdown.preprocessors import Preprocessor
+
+
+class MentionsExtension(Extension):
+
+ def extendMarkdown(self, md, md_globals):
+ md.registerExtension(self)
+ md.preprocessors.add('emojify',
+ MentionsPreprocessor(md),
+ '_end')
+
+
+class MentionsPreprocessor(Preprocessor):
+
+ def run(self, lines):
+ new_lines = []
+ pattern = re.compile('(?<=^|(?<=[^a-zA-Z0-9-_\.]))@([A-Za-z]+[A-Za-z0-9]+)')
+
+ def make_mention_link(m):
+ name = m.group(1)
+
+ if not User.objects.filter(username=name):
+ return "@{name}".format(name=name)
+
+ tpl = ('[@{name}](/#/profile/{name} "@{name}")')
+ return tpl.format(name=name)
+
+ for line in lines:
+ if line.strip():
+ line = pattern.sub(make_mention_link, line)
+
+ new_lines.append(line)
+
+ return new_lines
+
+
+def makeExtension(configs=None):
+ return MentionsExtension(configs=configs)
diff --git a/taiga/mdrender/processors/mentions.py b/taiga/mdrender/processors/mentions.py
deleted file mode 100644
index 4d65a527..00000000
--- a/taiga/mdrender/processors/mentions.py
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2012, lepture.com
-# Copyright (c) 2014, taiga.io
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials provided
-# with the distribution.
-# * Neither the name of the author nor the names of its contributors
-# may be used to endorse or promote products derived from this
-# software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import re
-
-from taiga.users.models import User
-
-def mentions(text):
- pattern = re.compile('(?<=^|(?<=[^a-zA-Z0-9-_\.]))@([A-Za-z]+[A-Za-z0-9]+)')
-
- def make_mention_link(m):
- name = m.group(1)
-
- if not User.objects.filter(username=name):
- return "@{name}".format(name=name)
-
- tpl = ('[@{name}](/#/profile/{name} "@{name}")')
- return tpl.format(name=name)
-
- text = pattern.sub(make_mention_link, text)
- return text
-
-__all__ = ['mentions']
diff --git a/taiga/mdrender/service.py b/taiga/mdrender/service.py
index 3802be00..9f13bc18 100644
--- a/taiga/mdrender/service.py
+++ b/taiga/mdrender/service.py
@@ -15,8 +15,8 @@ from .gfm import SpacedLinkExtension
from .gfm import StrikethroughExtension
from .gfm import WikiLinkExtension
from .gfm import EmojifyExtension
+from .gfm import MentionsExtension
-from .processors.mentions import mentions
from .processors.references import references
@@ -28,6 +28,7 @@ def _make_extensions_list(wikilinks_config=None):
StrikethroughExtension(),
WikiLinkExtension(wikilinks_config),
EmojifyExtension(),
+ MentionsExtension(),
"extra",
"codehilite"]
@@ -61,7 +62,7 @@ def _render_markdown(project, text):
def _preprocessors(project, text):
- pre = F() >> mentions >> F(references, project)
+ pre = F() >> F(references, project)
return pre(text)
diff --git a/tests/unit/test_mdrender.py b/tests/unit/test_mdrender.py
index 1d71a310..0ec6a55e 100644
--- a/tests/unit/test_mdrender.py
+++ b/tests/unit/test_mdrender.py
@@ -3,8 +3,8 @@ from unittest import mock
import pytest
import taiga.base
-from taiga.mdrender.processors import emoji
-from taiga.mdrender.processors import mentions
+from taiga.mdrender.gfm import mentions
+from taiga.mdrender.gfm import emojify
from taiga.mdrender.processors import references
from taiga.mdrender.service import render
@@ -16,12 +16,12 @@ dummy_project.id = 1
dummy_project.slug = "test"
def test_proccessor_valid_emoji():
- result = emoji.emoji(":smile:")
- assert result == '
'
+ result = emojify.EmojifyPreprocessor().run(["**:smile:**"])
+ assert result == ["****"]
def test_proccessor_invalid_emoji():
- result = emoji.emoji(":notvalidemoji:")
- assert result == ":notvalidemoji:"
+ result = emojify.EmojifyPreprocessor().run(["**:notvalidemoji:**"])
+ assert result == ["**:notvalidemoji:**"]
def test_proccessor_valid_user_mention():
DummyModel = DummyClass()
@@ -30,8 +30,8 @@ def test_proccessor_valid_user_mention():
mentions.User = DummyModel
- result = mentions.mentions("**@user1**")
- assert result == '**[@user1](/#/profile/user1 "@user1")**'
+ result = mentions.MentionsPreprocessor().run(["**@user1**"])
+ assert result == ["**[@user1](/#/profile/user1 \"@user1\")**"]
def test_proccessor_invalid_user_mention():
DummyModel = DummyClass()
@@ -40,8 +40,8 @@ def test_proccessor_invalid_user_mention():
mentions.User = DummyModel
- result = mentions.mentions("**@notvaliduser**")
- assert result == '**@notvaliduser**'
+ result = mentions.MentionsPreprocessor().run(["**@notvaliduser**"])
+ assert result == ['**@notvaliduser**']
def test_proccessor_valid_us_reference():