From f6ea608a0401841a508d98623dc5a1da417e0d8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Tue, 20 May 2014 12:23:59 +0200 Subject: [PATCH] Moving wiki mentions to an extension --- taiga/mdrender/gfm/__init__.py | 2 + taiga/mdrender/gfm/emojify.py | 4 +- taiga/mdrender/gfm/mentions.py | 68 +++++++++++++++++++++++++++ taiga/mdrender/processors/mentions.py | 52 -------------------- taiga/mdrender/service.py | 5 +- tests/unit/test_mdrender.py | 20 ++++---- 6 files changed, 86 insertions(+), 65 deletions(-) create mode 100644 taiga/mdrender/gfm/mentions.py delete mode 100644 taiga/mdrender/processors/mentions.py 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 == 'smile' + result = emojify.EmojifyPreprocessor().run(["**:smile:**"]) + assert result == ["**![smile](http://localhost:8000/static/img/emojis/smile.png)**"] 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():