Moving wiki mentions to an extension
parent
db91acb065
commit
f6ea608a04
|
@ -10,6 +10,7 @@ from . import spaced_link
|
||||||
from . import strikethrough
|
from . import strikethrough
|
||||||
from . import wikilinks
|
from . import wikilinks
|
||||||
from . import emojify
|
from . import emojify
|
||||||
|
from . import mentions
|
||||||
|
|
||||||
AutolinkExtension = autolink.AutolinkExtension
|
AutolinkExtension = autolink.AutolinkExtension
|
||||||
AutomailExtension = automail.AutomailExtension
|
AutomailExtension = automail.AutomailExtension
|
||||||
|
@ -19,3 +20,4 @@ SpacedLinkExtension = spaced_link.SpacedLinkExtension
|
||||||
StrikethroughExtension = strikethrough.StrikethroughExtension
|
StrikethroughExtension = strikethrough.StrikethroughExtension
|
||||||
WikiLinkExtension = wikilinks.WikiLinkExtension
|
WikiLinkExtension = wikilinks.WikiLinkExtension
|
||||||
EmojifyExtension = emojify.EmojifyExtension
|
EmojifyExtension = emojify.EmojifyExtension
|
||||||
|
MentionsExtension = mentions.MentionsExtension
|
||||||
|
|
|
@ -159,6 +159,8 @@ class EmojifyExtension(Extension):
|
||||||
class EmojifyPreprocessor(Preprocessor):
|
class EmojifyPreprocessor(Preprocessor):
|
||||||
|
|
||||||
def run(self, lines):
|
def run(self, lines):
|
||||||
|
pattern = re.compile(':([a-z0-9\+\-_]+):')
|
||||||
|
|
||||||
new_lines = []
|
new_lines = []
|
||||||
|
|
||||||
def emojify(match):
|
def emojify(match):
|
||||||
|
@ -173,7 +175,7 @@ class EmojifyPreprocessor(Preprocessor):
|
||||||
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if line.strip():
|
if line.strip():
|
||||||
line = re.sub(r':([a-z0-9\+\-_]+):', emojify, line, flags=re.UNICODE)
|
line = pattern.sub(emojify, line)
|
||||||
|
|
||||||
new_lines.append(line)
|
new_lines.append(line)
|
||||||
|
|
||||||
|
|
|
@ -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)
|
|
@ -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']
|
|
|
@ -15,8 +15,8 @@ from .gfm import SpacedLinkExtension
|
||||||
from .gfm import StrikethroughExtension
|
from .gfm import StrikethroughExtension
|
||||||
from .gfm import WikiLinkExtension
|
from .gfm import WikiLinkExtension
|
||||||
from .gfm import EmojifyExtension
|
from .gfm import EmojifyExtension
|
||||||
|
from .gfm import MentionsExtension
|
||||||
|
|
||||||
from .processors.mentions import mentions
|
|
||||||
from .processors.references import references
|
from .processors.references import references
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ def _make_extensions_list(wikilinks_config=None):
|
||||||
StrikethroughExtension(),
|
StrikethroughExtension(),
|
||||||
WikiLinkExtension(wikilinks_config),
|
WikiLinkExtension(wikilinks_config),
|
||||||
EmojifyExtension(),
|
EmojifyExtension(),
|
||||||
|
MentionsExtension(),
|
||||||
"extra",
|
"extra",
|
||||||
"codehilite"]
|
"codehilite"]
|
||||||
|
|
||||||
|
@ -61,7 +62,7 @@ def _render_markdown(project, text):
|
||||||
|
|
||||||
|
|
||||||
def _preprocessors(project, text):
|
def _preprocessors(project, text):
|
||||||
pre = F() >> mentions >> F(references, project)
|
pre = F() >> F(references, project)
|
||||||
return pre(text)
|
return pre(text)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@ from unittest import mock
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import taiga.base
|
import taiga.base
|
||||||
from taiga.mdrender.processors import emoji
|
from taiga.mdrender.gfm import mentions
|
||||||
from taiga.mdrender.processors import mentions
|
from taiga.mdrender.gfm import emojify
|
||||||
from taiga.mdrender.processors import references
|
from taiga.mdrender.processors import references
|
||||||
from taiga.mdrender.service import render
|
from taiga.mdrender.service import render
|
||||||
|
|
||||||
|
@ -16,12 +16,12 @@ dummy_project.id = 1
|
||||||
dummy_project.slug = "test"
|
dummy_project.slug = "test"
|
||||||
|
|
||||||
def test_proccessor_valid_emoji():
|
def test_proccessor_valid_emoji():
|
||||||
result = emoji.emoji("<b>:smile:</b>")
|
result = emojify.EmojifyPreprocessor().run(["**:smile:**"])
|
||||||
assert result == '<b><img class="emoji" title="smile" alt="smile" height="20" width="20" src="http://localhost:8000/static/img/emojis/smile.png" align="top"></b>'
|
assert result == ["****"]
|
||||||
|
|
||||||
def test_proccessor_invalid_emoji():
|
def test_proccessor_invalid_emoji():
|
||||||
result = emoji.emoji("<b>:notvalidemoji:</b>")
|
result = emojify.EmojifyPreprocessor().run(["**:notvalidemoji:**"])
|
||||||
assert result == "<b>:notvalidemoji:</b>"
|
assert result == ["**:notvalidemoji:**"]
|
||||||
|
|
||||||
def test_proccessor_valid_user_mention():
|
def test_proccessor_valid_user_mention():
|
||||||
DummyModel = DummyClass()
|
DummyModel = DummyClass()
|
||||||
|
@ -30,8 +30,8 @@ def test_proccessor_valid_user_mention():
|
||||||
|
|
||||||
mentions.User = DummyModel
|
mentions.User = DummyModel
|
||||||
|
|
||||||
result = mentions.mentions("**@user1**")
|
result = mentions.MentionsPreprocessor().run(["**@user1**"])
|
||||||
assert result == '**[@user1](/#/profile/user1 "@user1")**'
|
assert result == ["**[@user1](/#/profile/user1 \"@user1\")**"]
|
||||||
|
|
||||||
def test_proccessor_invalid_user_mention():
|
def test_proccessor_invalid_user_mention():
|
||||||
DummyModel = DummyClass()
|
DummyModel = DummyClass()
|
||||||
|
@ -40,8 +40,8 @@ def test_proccessor_invalid_user_mention():
|
||||||
|
|
||||||
mentions.User = DummyModel
|
mentions.User = DummyModel
|
||||||
|
|
||||||
result = mentions.mentions("**@notvaliduser**")
|
result = mentions.MentionsPreprocessor().run(["**@notvaliduser**"])
|
||||||
assert result == '**@notvaliduser**'
|
assert result == ['**@notvaliduser**']
|
||||||
|
|
||||||
|
|
||||||
def test_proccessor_valid_us_reference():
|
def test_proccessor_valid_us_reference():
|
||||||
|
|
Loading…
Reference in New Issue