mirror of
https://github.com/zulip/zulip.git
synced 2025-11-04 22:13:26 +00:00
This commit switches to use sprite sheets for rendering emojis in all the remaining places, i.e., message bodies and composebox typeahead. This commit also includes some changes to notifications.py file so that the spans used for rendering emojis can be converted to corresponding image tags so that we don't break the emoji rendering in missed message emails since we can't use sprite sheets there. As part of switching the bugdown system to use sprite sheets, we need to switch the name_to_codepoint mappings to match the new sprite sheets. This has the side effect of fixing a bunch of emoji like numbers and flag emoji in the emoji pickers. Fixes: #3895. Fixes: #3972.
1093 lines
55 KiB
Python
1093 lines
55 KiB
Python
# -*- coding: utf-8 -*-
|
|
from django.conf import settings
|
|
from django.test import TestCase, override_settings
|
|
|
|
from zerver.lib import bugdown
|
|
from zerver.lib.actions import (
|
|
do_remove_realm_emoji,
|
|
do_set_alert_words,
|
|
get_realm,
|
|
)
|
|
from zerver.lib.alert_words import alert_words_in_realm
|
|
from zerver.lib.camo import get_camo_url
|
|
from zerver.lib.emoji import get_emoji_url
|
|
from zerver.lib.mention import possible_mentions
|
|
from zerver.lib.message import render_markdown
|
|
from zerver.lib.request import (
|
|
JsonableError,
|
|
)
|
|
from zerver.lib.test_classes import (
|
|
ZulipTestCase,
|
|
)
|
|
from zerver.lib.str_utils import force_str
|
|
from zerver.models import (
|
|
realm_in_local_realm_filters_cache,
|
|
flush_per_request_caches,
|
|
flush_realm_filter,
|
|
get_client,
|
|
get_realm,
|
|
get_stream,
|
|
realm_filters_for_realm,
|
|
Message,
|
|
Stream,
|
|
Realm,
|
|
RealmFilter,
|
|
Recipient,
|
|
)
|
|
|
|
import copy
|
|
import mock
|
|
import os
|
|
import ujson
|
|
|
|
from six.moves import urllib
|
|
from zerver.lib.str_utils import NonBinaryStr
|
|
from typing import Any, AnyStr, Dict, List, Optional, Set, Tuple, Text
|
|
|
|
class FencedBlockPreprocessorTest(TestCase):
|
|
def test_simple_quoting(self):
|
|
# type: () -> None
|
|
processor = bugdown.fenced_code.FencedBlockPreprocessor(None)
|
|
markdown = [
|
|
'~~~ quote',
|
|
'hi',
|
|
'bye',
|
|
'',
|
|
''
|
|
]
|
|
expected = [
|
|
'',
|
|
'> hi',
|
|
'> bye',
|
|
'',
|
|
'',
|
|
''
|
|
]
|
|
lines = processor.run(markdown)
|
|
self.assertEqual(lines, expected)
|
|
|
|
def test_serial_quoting(self):
|
|
# type: () -> None
|
|
processor = bugdown.fenced_code.FencedBlockPreprocessor(None)
|
|
markdown = [
|
|
'~~~ quote',
|
|
'hi',
|
|
'~~~',
|
|
'',
|
|
'~~~ quote',
|
|
'bye',
|
|
'',
|
|
''
|
|
]
|
|
expected = [
|
|
'',
|
|
'> hi',
|
|
'',
|
|
'',
|
|
'',
|
|
'> bye',
|
|
'',
|
|
'',
|
|
''
|
|
]
|
|
lines = processor.run(markdown)
|
|
self.assertEqual(lines, expected)
|
|
|
|
def test_serial_code(self):
|
|
# type: () -> None
|
|
processor = bugdown.fenced_code.FencedBlockPreprocessor(None)
|
|
|
|
# Simulate code formatting.
|
|
processor.format_code = lambda lang, code: lang + ':' + code # type: ignore # mypy doesn't allow monkey-patching functions
|
|
processor.placeholder = lambda s: '**' + s.strip('\n') + '**' # type: ignore # https://github.com/python/mypy/issues/708
|
|
|
|
markdown = [
|
|
'``` .py',
|
|
'hello()',
|
|
'```',
|
|
'',
|
|
'```vb.net',
|
|
'goodbye()',
|
|
'```',
|
|
'',
|
|
'```c#',
|
|
'weirdchar()',
|
|
'```',
|
|
''
|
|
]
|
|
expected = [
|
|
'',
|
|
'**py:hello()**',
|
|
'',
|
|
'',
|
|
'',
|
|
'**vb.net:goodbye()**',
|
|
'',
|
|
'',
|
|
'',
|
|
'**c#:weirdchar()**',
|
|
'',
|
|
''
|
|
]
|
|
lines = processor.run(markdown)
|
|
self.assertEqual(lines, expected)
|
|
|
|
def test_nested_code(self):
|
|
# type: () -> None
|
|
processor = bugdown.fenced_code.FencedBlockPreprocessor(None)
|
|
|
|
# Simulate code formatting.
|
|
processor.format_code = lambda lang, code: lang + ':' + code # type: ignore # mypy doesn't allow monkey-patching functions
|
|
processor.placeholder = lambda s: '**' + s.strip('\n') + '**' # type: ignore # https://github.com/python/mypy/issues/708
|
|
|
|
markdown = [
|
|
'~~~ quote',
|
|
'hi',
|
|
'``` .py',
|
|
'hello()',
|
|
'```',
|
|
'',
|
|
''
|
|
]
|
|
expected = [
|
|
'',
|
|
'> hi',
|
|
'',
|
|
'> **py:hello()**',
|
|
'',
|
|
'',
|
|
''
|
|
]
|
|
lines = processor.run(markdown)
|
|
self.assertEqual(lines, expected)
|
|
|
|
def bugdown_convert(text):
|
|
# type: (Text) -> Text
|
|
return bugdown.convert(text, message_realm=get_realm('zulip'))
|
|
|
|
class BugdownTest(ZulipTestCase):
|
|
def load_bugdown_tests(self):
|
|
# type: () -> Tuple[Dict[Text, Any], List[List[Text]]]
|
|
test_fixtures = {}
|
|
data_file = open(os.path.join(os.path.dirname(__file__), '../fixtures/markdown_test_cases.json'), 'r')
|
|
data = ujson.loads('\n'.join(data_file.readlines()))
|
|
for test in data['regular_tests']:
|
|
test_fixtures[test['name']] = test
|
|
|
|
return test_fixtures, data['linkify_tests']
|
|
|
|
def test_bugdown_fixtures(self):
|
|
# type: () -> None
|
|
format_tests, linkify_tests = self.load_bugdown_tests()
|
|
|
|
for name, test in format_tests.items():
|
|
converted = bugdown_convert(test['input'])
|
|
|
|
print("Running Bugdown test %s" % (name,))
|
|
self.assertEqual(converted, test['expected_output'])
|
|
|
|
def replaced(payload, url, phrase=''):
|
|
# type: (Text, Text, Text) -> Text
|
|
target = " target=\"_blank\""
|
|
if url[:4] == 'http':
|
|
href = url
|
|
elif '@' in url:
|
|
href = 'mailto:' + url
|
|
target = ""
|
|
else:
|
|
href = 'http://' + url
|
|
return payload % ("<a href=\"%s\"%s title=\"%s\">%s</a>" % (href, target, href, url),)
|
|
|
|
print("Running Bugdown Linkify tests")
|
|
with mock.patch('zerver.lib.url_preview.preview.link_embed_data_from_cache', return_value=None):
|
|
for inline_url, reference, url in linkify_tests:
|
|
try:
|
|
match = replaced(reference, url, phrase=inline_url)
|
|
except TypeError:
|
|
match = reference
|
|
converted = bugdown_convert(inline_url)
|
|
self.assertEqual(match, converted)
|
|
|
|
def test_inline_file(self):
|
|
# type: () -> None
|
|
msg = 'Check out this file file:///Volumes/myserver/Users/Shared/pi.py'
|
|
converted = bugdown_convert(msg)
|
|
self.assertEqual(converted, '<p>Check out this file <a href="file:///Volumes/myserver/Users/Shared/pi.py" target="_blank" title="file:///Volumes/myserver/Users/Shared/pi.py">file:///Volumes/myserver/Users/Shared/pi.py</a></p>')
|
|
|
|
with self.settings(ENABLE_FILE_LINKS=False):
|
|
realm = Realm.objects.create(string_id='file_links_test')
|
|
bugdown.make_md_engine(
|
|
realm.id,
|
|
{'realm_filters': [[], u'file_links_test.example.com'], 'realm': [u'file_links_test.example.com', 'Realm name']})
|
|
converted = bugdown.convert(msg, message_realm=realm)
|
|
self.assertEqual(converted, '<p>Check out this file file:///Volumes/myserver/Users/Shared/pi.py</p>')
|
|
|
|
def test_inline_youtube(self):
|
|
# type: () -> None
|
|
msg = 'Check out the debate: http://www.youtube.com/watch?v=hx1mjT73xYE'
|
|
converted = bugdown_convert(msg)
|
|
|
|
self.assertEqual(converted, '<p>Check out the debate: <a href="http://www.youtube.com/watch?v=hx1mjT73xYE" target="_blank" title="http://www.youtube.com/watch?v=hx1mjT73xYE">http://www.youtube.com/watch?v=hx1mjT73xYE</a></p>\n<div class="youtube-video message_inline_image"><a data-id="hx1mjT73xYE" href="http://www.youtube.com/watch?v=hx1mjT73xYE" target="_blank" title="http://www.youtube.com/watch?v=hx1mjT73xYE"><img src="https://i.ytimg.com/vi/hx1mjT73xYE/default.jpg"></a></div>')
|
|
|
|
@override_settings(INLINE_IMAGE_PREVIEW=True)
|
|
def test_inline_image_preview(self):
|
|
# type: () -> None
|
|
with_preview = '<p><a href="http://cdn.wallpapersafari.com/13/6/16eVjx.jpeg" target="_blank" title="http://cdn.wallpapersafari.com/13/6/16eVjx.jpeg">http://cdn.wallpapersafari.com/13/6/16eVjx.jpeg</a></p>\n<div class="message_inline_image"><a href="http://cdn.wallpapersafari.com/13/6/16eVjx.jpeg" target="_blank" title="http://cdn.wallpapersafari.com/13/6/16eVjx.jpeg"><img src="https://external-content.zulipcdn.net/389b5d7148a0cbc7475ed564e1b03ceb476bdacb/687474703a2f2f63646e2e77616c6c70617065727361666172692e636f6d2f31332f362f313665566a782e6a706567"></a></div>'
|
|
without_preview = '<p><a href="http://cdn.wallpapersafari.com/13/6/16eVjx.jpeg" target="_blank" title="http://cdn.wallpapersafari.com/13/6/16eVjx.jpeg">http://cdn.wallpapersafari.com/13/6/16eVjx.jpeg</a></p>'
|
|
content = 'http://cdn.wallpapersafari.com/13/6/16eVjx.jpeg'
|
|
|
|
sender_user_profile = self.example_user('othello')
|
|
msg = Message(sender=sender_user_profile, sending_client=get_client("test"))
|
|
converted = render_markdown(msg, content)
|
|
self.assertEqual(converted, with_preview)
|
|
|
|
realm = msg.get_realm()
|
|
setattr(realm, 'inline_image_preview', False)
|
|
realm.save()
|
|
|
|
sender_user_profile = self.example_user('othello')
|
|
msg = Message(sender=sender_user_profile, sending_client=get_client("test"))
|
|
converted = render_markdown(msg, content)
|
|
self.assertEqual(converted, without_preview)
|
|
|
|
@override_settings(INLINE_IMAGE_PREVIEW=True)
|
|
def test_inline_image_preview_order(self):
|
|
# type: () -> None
|
|
content = 'http://imaging.nikon.com/lineup/dslr/df/img/sample/img_01.jpg\nhttp://imaging.nikon.com/lineup/dslr/df/img/sample/img_02.jpg\nhttp://imaging.nikon.com/lineup/dslr/df/img/sample/img_03.jpg'
|
|
expected = '<p><a href="http://imaging.nikon.com/lineup/dslr/df/img/sample/img_01.jpg" target="_blank" title="http://imaging.nikon.com/lineup/dslr/df/img/sample/img_01.jpg">http://imaging.nikon.com/lineup/dslr/df/img/sample/img_01.jpg</a><br>\n<a href="http://imaging.nikon.com/lineup/dslr/df/img/sample/img_02.jpg" target="_blank" title="http://imaging.nikon.com/lineup/dslr/df/img/sample/img_02.jpg">http://imaging.nikon.com/lineup/dslr/df/img/sample/img_02.jpg</a><br>\n<a href="http://imaging.nikon.com/lineup/dslr/df/img/sample/img_03.jpg" target="_blank" title="http://imaging.nikon.com/lineup/dslr/df/img/sample/img_03.jpg">http://imaging.nikon.com/lineup/dslr/df/img/sample/img_03.jpg</a></p>\n<div class="message_inline_image"><a href="http://imaging.nikon.com/lineup/dslr/df/img/sample/img_01.jpg" target="_blank" title="http://imaging.nikon.com/lineup/dslr/df/img/sample/img_01.jpg"><img src="https://external-content.zulipcdn.net/1081f3eb3d307ff5b578c1f5ce9d4cef8f8953c4/687474703a2f2f696d6167696e672e6e696b6f6e2e636f6d2f6c696e6575702f64736c722f64662f696d672f73616d706c652f696d675f30312e6a7067"></a></div><div class="message_inline_image"><a href="http://imaging.nikon.com/lineup/dslr/df/img/sample/img_02.jpg" target="_blank" title="http://imaging.nikon.com/lineup/dslr/df/img/sample/img_02.jpg"><img src="https://external-content.zulipcdn.net/8a2da7577389c522fab18ba2e6d6947b85458074/687474703a2f2f696d6167696e672e6e696b6f6e2e636f6d2f6c696e6575702f64736c722f64662f696d672f73616d706c652f696d675f30322e6a7067"></a></div><div class="message_inline_image"><a href="http://imaging.nikon.com/lineup/dslr/df/img/sample/img_03.jpg" target="_blank" title="http://imaging.nikon.com/lineup/dslr/df/img/sample/img_03.jpg"><img src="https://external-content.zulipcdn.net/9c389273b239846aa6e07e109216773934e52828/687474703a2f2f696d6167696e672e6e696b6f6e2e636f6d2f6c696e6575702f64736c722f64662f696d672f73616d706c652f696d675f30332e6a7067"></a></div>'
|
|
|
|
sender_user_profile = self.example_user('othello')
|
|
msg = Message(sender=sender_user_profile, sending_client=get_client("test"))
|
|
converted = render_markdown(msg, content)
|
|
self.assertEqual(converted, expected)
|
|
|
|
content = 'Test 1\n[21136101110_1dde1c1a7e_o.jpg](/user_uploads/1/6d/F1PX6u16JA2P-nK45PyxHIYZ/21136101110_1dde1c1a7e_o.jpg) \n\nNext Image\n[IMG_20161116_023910.jpg](/user_uploads/1/69/sh7L06e7uH7NaX6d5WFfVYQp/IMG_20161116_023910.jpg) \n\nAnother Screenshot\n[Screenshot-from-2016-06-01-16-22-42.png](/user_uploads/1/70/_aZmIEWaN1iUaxwkDjkO7bpj/Screenshot-from-2016-06-01-16-22-42.png)'
|
|
expected = '<p>Test 1<br>\n<a href="/user_uploads/1/6d/F1PX6u16JA2P-nK45PyxHIYZ/21136101110_1dde1c1a7e_o.jpg" target="_blank" title="21136101110_1dde1c1a7e_o.jpg">21136101110_1dde1c1a7e_o.jpg</a> </p>\n<p>Next Image<br>\n<a href="/user_uploads/1/69/sh7L06e7uH7NaX6d5WFfVYQp/IMG_20161116_023910.jpg" target="_blank" title="IMG_20161116_023910.jpg">IMG_20161116_023910.jpg</a> </p>\n<p>Another Screenshot<br>\n<a href="/user_uploads/1/70/_aZmIEWaN1iUaxwkDjkO7bpj/Screenshot-from-2016-06-01-16-22-42.png" target="_blank" title="Screenshot-from-2016-06-01-16-22-42.png">Screenshot-from-2016-06-01-16-22-42.png</a></p>\n<div class="message_inline_image"><a href="/user_uploads/1/6d/F1PX6u16JA2P-nK45PyxHIYZ/21136101110_1dde1c1a7e_o.jpg" target="_blank" title="21136101110_1dde1c1a7e_o.jpg"><img src="/user_uploads/1/6d/F1PX6u16JA2P-nK45PyxHIYZ/21136101110_1dde1c1a7e_o.jpg"></a></div><div class="message_inline_image"><a href="/user_uploads/1/69/sh7L06e7uH7NaX6d5WFfVYQp/IMG_20161116_023910.jpg" target="_blank" title="IMG_20161116_023910.jpg"><img src="/user_uploads/1/69/sh7L06e7uH7NaX6d5WFfVYQp/IMG_20161116_023910.jpg"></a></div><div class="message_inline_image"><a href="/user_uploads/1/70/_aZmIEWaN1iUaxwkDjkO7bpj/Screenshot-from-2016-06-01-16-22-42.png" target="_blank" title="Screenshot-from-2016-06-01-16-22-42.png"><img src="/user_uploads/1/70/_aZmIEWaN1iUaxwkDjkO7bpj/Screenshot-from-2016-06-01-16-22-42.png"></a></div>'
|
|
|
|
msg = Message(sender=sender_user_profile, sending_client=get_client("test"))
|
|
converted = render_markdown(msg, content)
|
|
self.assertEqual(converted, expected)
|
|
|
|
@override_settings(INLINE_IMAGE_PREVIEW=False)
|
|
def test_image_preview_enabled_for_realm(self):
|
|
# type: () -> None
|
|
ret = bugdown.image_preview_enabled_for_realm()
|
|
self.assertEqual(ret, False)
|
|
|
|
settings.INLINE_IMAGE_PREVIEW = True
|
|
|
|
sender_user_profile = self.example_user('othello')
|
|
bugdown.current_message = copy.deepcopy(Message(sender=sender_user_profile, sending_client=get_client("test")))
|
|
realm = bugdown.current_message.get_realm()
|
|
|
|
ret = bugdown.image_preview_enabled_for_realm()
|
|
self.assertEqual(ret, realm.inline_image_preview)
|
|
|
|
bugdown.current_message = None
|
|
ret = bugdown.image_preview_enabled_for_realm()
|
|
self.assertEqual(ret, True)
|
|
|
|
@override_settings(INLINE_URL_EMBED_PREVIEW=False)
|
|
def test_url_embed_preview_enabled_for_realm(self):
|
|
# type: () -> None
|
|
sender_user_profile = self.example_user('othello')
|
|
message = copy.deepcopy(Message(sender=sender_user_profile, sending_client=get_client("test")))
|
|
realm = message.get_realm()
|
|
|
|
ret = bugdown.url_embed_preview_enabled_for_realm(message)
|
|
self.assertEqual(ret, False)
|
|
|
|
settings.INLINE_URL_EMBED_PREVIEW = True
|
|
|
|
ret = bugdown.url_embed_preview_enabled_for_realm(message)
|
|
self.assertEqual(ret, realm.inline_image_preview)
|
|
|
|
ret = bugdown.url_embed_preview_enabled_for_realm(None)
|
|
self.assertEqual(ret, True)
|
|
|
|
def test_inline_dropbox(self):
|
|
# type: () -> None
|
|
msg = 'Look at how hilarious our old office was: https://www.dropbox.com/s/ymdijjcg67hv2ta/IMG_0923.JPG'
|
|
image_info = {'image': 'https://photos-4.dropbox.com/t/2/AABIre1oReJgPYuc_53iv0IHq1vUzRaDg2rrCfTpiWMccQ/12/129/jpeg/1024x1024/2/_/0/4/IMG_0923.JPG/CIEBIAEgAiAHKAIoBw/ymdijjcg67hv2ta/AABz2uuED1ox3vpWWvMpBxu6a/IMG_0923.JPG', 'desc': 'Shared with Dropbox', 'title': 'IMG_0923.JPG'}
|
|
with mock.patch('zerver.lib.bugdown.fetch_open_graph_image', return_value=image_info):
|
|
converted = bugdown_convert(msg)
|
|
|
|
self.assertEqual(converted, '<p>Look at how hilarious our old office was: <a href="https://www.dropbox.com/s/ymdijjcg67hv2ta/IMG_0923.JPG" target="_blank" title="https://www.dropbox.com/s/ymdijjcg67hv2ta/IMG_0923.JPG">https://www.dropbox.com/s/ymdijjcg67hv2ta/IMG_0923.JPG</a></p>\n<div class="message_inline_image"><a href="https://www.dropbox.com/s/ymdijjcg67hv2ta/IMG_0923.JPG" target="_blank" title="IMG_0923.JPG"><img src="https://www.dropbox.com/s/ymdijjcg67hv2ta/IMG_0923.JPG?dl=1"></a></div>')
|
|
|
|
msg = 'Look at my hilarious drawing folder: https://www.dropbox.com/sh/cm39k9e04z7fhim/AAAII5NK-9daee3FcF41anEua?dl='
|
|
image_info = {'image': 'https://cf.dropboxstatic.com/static/images/icons128/folder_dropbox.png', 'desc': 'Shared with Dropbox', 'title': 'Saves'}
|
|
with mock.patch('zerver.lib.bugdown.fetch_open_graph_image', return_value=image_info):
|
|
converted = bugdown_convert(msg)
|
|
|
|
self.assertEqual(converted, '<p>Look at my hilarious drawing folder: <a href="https://www.dropbox.com/sh/cm39k9e04z7fhim/AAAII5NK-9daee3FcF41anEua?dl=" target="_blank" title="https://www.dropbox.com/sh/cm39k9e04z7fhim/AAAII5NK-9daee3FcF41anEua?dl=">https://www.dropbox.com/sh/cm39k9e04z7fhim/AAAII5NK-9daee3FcF41anEua?dl=</a></p>\n<div class="message_inline_ref"><a href="https://www.dropbox.com/sh/cm39k9e04z7fhim/AAAII5NK-9daee3FcF41anEua?dl=" target="_blank" title="Saves"><img src="https://cf.dropboxstatic.com/static/images/icons128/folder_dropbox.png"></a><div><div class="message_inline_image_title">Saves</div><desc class="message_inline_image_desc"></desc></div></div>')
|
|
|
|
def test_inline_dropbox_preview(self):
|
|
# type: () -> None
|
|
# Test photo album previews
|
|
msg = 'https://www.dropbox.com/sc/tditp9nitko60n5/03rEiZldy5'
|
|
image_info = {'image': 'https://photos-6.dropbox.com/t/2/AAAlawaeD61TyNewO5vVi-DGf2ZeuayfyHFdNTNzpGq-QA/12/271544745/jpeg/1024x1024/2/_/0/5/baby-piglet.jpg/CKnjvYEBIAIgBygCKAc/tditp9nitko60n5/AADX03VAIrQlTl28CtujDcMla/0', 'desc': 'Shared with Dropbox', 'title': '1 photo'}
|
|
with mock.patch('zerver.lib.bugdown.fetch_open_graph_image', return_value=image_info):
|
|
converted = bugdown_convert(msg)
|
|
|
|
self.assertEqual(converted, '<p><a href="https://www.dropbox.com/sc/tditp9nitko60n5/03rEiZldy5" target="_blank" title="https://www.dropbox.com/sc/tditp9nitko60n5/03rEiZldy5">https://www.dropbox.com/sc/tditp9nitko60n5/03rEiZldy5</a></p>\n<div class="message_inline_image"><a href="https://www.dropbox.com/sc/tditp9nitko60n5/03rEiZldy5" target="_blank" title="1 photo"><img src="https://photos-6.dropbox.com/t/2/AAAlawaeD61TyNewO5vVi-DGf2ZeuayfyHFdNTNzpGq-QA/12/271544745/jpeg/1024x1024/2/_/0/5/baby-piglet.jpg/CKnjvYEBIAIgBygCKAc/tditp9nitko60n5/AADX03VAIrQlTl28CtujDcMla/0"></a></div>')
|
|
|
|
def test_inline_dropbox_negative(self):
|
|
# type: () -> None
|
|
# Make sure we're not overzealous in our conversion:
|
|
msg = 'Look at the new dropbox logo: https://www.dropbox.com/static/images/home_logo.png'
|
|
with mock.patch('zerver.lib.bugdown.fetch_open_graph_image', return_value=None):
|
|
converted = bugdown_convert(msg)
|
|
|
|
self.assertEqual(converted, '<p>Look at the new dropbox logo: <a href="https://www.dropbox.com/static/images/home_logo.png" target="_blank" title="https://www.dropbox.com/static/images/home_logo.png">https://www.dropbox.com/static/images/home_logo.png</a></p>\n<div class="message_inline_image"><a href="https://www.dropbox.com/static/images/home_logo.png" target="_blank" title="https://www.dropbox.com/static/images/home_logo.png"><img src="https://www.dropbox.com/static/images/home_logo.png"></a></div>')
|
|
|
|
def test_inline_dropbox_bad(self):
|
|
# type: () -> None
|
|
# Don't fail on bad dropbox links
|
|
msg = "https://zulip-test.dropbox.com/photos/cl/ROmr9K1XYtmpneM"
|
|
with mock.patch('zerver.lib.bugdown.fetch_open_graph_image', return_value=None):
|
|
converted = bugdown_convert(msg)
|
|
self.assertEqual(converted, '<p><a href="https://zulip-test.dropbox.com/photos/cl/ROmr9K1XYtmpneM" target="_blank" title="https://zulip-test.dropbox.com/photos/cl/ROmr9K1XYtmpneM">https://zulip-test.dropbox.com/photos/cl/ROmr9K1XYtmpneM</a></p>')
|
|
|
|
def test_inline_github_preview(self):
|
|
# type: () -> None
|
|
# Test photo album previews
|
|
msg = 'https://github.com/zulip/zulip/blob/master/static/images/logo/zulip-icon-128x128.png'
|
|
converted = bugdown_convert(msg)
|
|
|
|
self.assertEqual(converted, '<p><a href="https://github.com/zulip/zulip/blob/master/static/images/logo/zulip-icon-128x128.png" target="_blank" title="https://github.com/zulip/zulip/blob/master/static/images/logo/zulip-icon-128x128.png">https://github.com/zulip/zulip/blob/master/static/images/logo/zulip-icon-128x128.png</a></p>\n<div class="message_inline_image"><a href="https://github.com/zulip/zulip/blob/master/static/images/logo/zulip-icon-128x128.png" target="_blank" title="https://github.com/zulip/zulip/blob/master/static/images/logo/zulip-icon-128x128.png"><img src="https://raw.githubusercontent.com/zulip/zulip/master/static/images/logo/zulip-icon-128x128.png"></a></div>')
|
|
|
|
msg = 'https://developer.github.com/assets/images/hero-circuit-bg.png'
|
|
converted = bugdown_convert(msg)
|
|
|
|
self.assertEqual(converted, '<p><a href="https://developer.github.com/assets/images/hero-circuit-bg.png" target="_blank" title="https://developer.github.com/assets/images/hero-circuit-bg.png">https://developer.github.com/assets/images/hero-circuit-bg.png</a></p>\n<div class="message_inline_image"><a href="https://developer.github.com/assets/images/hero-circuit-bg.png" target="_blank" title="https://developer.github.com/assets/images/hero-circuit-bg.png"><img src="https://developer.github.com/assets/images/hero-circuit-bg.png"></a></div>')
|
|
|
|
def test_twitter_id_extraction(self):
|
|
# type: () -> None
|
|
self.assertEqual(bugdown.get_tweet_id('http://twitter.com/#!/VizzQuotes/status/409030735191097344'), '409030735191097344')
|
|
self.assertEqual(bugdown.get_tweet_id('http://twitter.com/VizzQuotes/status/409030735191097344'), '409030735191097344')
|
|
self.assertEqual(bugdown.get_tweet_id('http://twitter.com/VizzQuotes/statuses/409030735191097344'), '409030735191097344')
|
|
self.assertEqual(bugdown.get_tweet_id('https://twitter.com/wdaher/status/1017581858'), '1017581858')
|
|
self.assertEqual(bugdown.get_tweet_id('https://twitter.com/wdaher/status/1017581858/'), '1017581858')
|
|
self.assertEqual(bugdown.get_tweet_id('https://twitter.com/windyoona/status/410766290349879296/photo/1'), '410766290349879296')
|
|
self.assertEqual(bugdown.get_tweet_id('https://twitter.com/windyoona/status/410766290349879296/'), '410766290349879296')
|
|
|
|
def test_inline_interesting_links(self):
|
|
# type: () -> None
|
|
def make_link(url):
|
|
# type: (Text) -> Text
|
|
return '<a href="%s" target="_blank" title="%s">%s</a>' % (url, url, url)
|
|
|
|
normal_tweet_html = ('<a href="https://twitter.com/twitter" target="_blank"'
|
|
' title="https://twitter.com/twitter">@twitter</a> '
|
|
'meets @seepicturely at #tcdisrupt cc.'
|
|
'<a href="https://twitter.com/boscomonkey" target="_blank"'
|
|
' title="https://twitter.com/boscomonkey">@boscomonkey</a> '
|
|
'<a href="https://twitter.com/episod" target="_blank"'
|
|
' title="https://twitter.com/episod">@episod</a> '
|
|
'<a href="http://t.co/6J2EgYM" target="_blank"'
|
|
' title="http://t.co/6J2EgYM">http://instagram.com/p/MuW67/</a>')
|
|
|
|
mention_in_link_tweet_html = """<a href="http://t.co/@foo" target="_blank" title="http://t.co/@foo">http://foo.com</a>"""
|
|
|
|
media_tweet_html = ('<a href="http://t.co/xo7pAhK6n3" target="_blank" title="http://t.co/xo7pAhK6n3">'
|
|
'http://twitter.com/NEVNBoston/status/421654515616849920/photo/1</a>')
|
|
|
|
emoji_in_tweet_html = """Zulip is <span class="emoji emoji-1f4af" title="hundred points">:hundred_points:</span>% open-source!"""
|
|
|
|
def make_inline_twitter_preview(url, tweet_html, image_html=''):
|
|
# type: (Text, Text, Text) -> Text
|
|
## As of right now, all previews are mocked to be the exact same tweet
|
|
return ('<div class="inline-preview-twitter">'
|
|
'<div class="twitter-tweet">'
|
|
'<a href="%s" target="_blank">'
|
|
'<img class="twitter-avatar"'
|
|
' src="https://si0.twimg.com/profile_images/1380912173/Screen_shot_2011-06-03_at_7.35.36_PM_normal.png">'
|
|
'</a>'
|
|
'<p>%s</p>'
|
|
'<span>- Eoin McMillan (@imeoin)</span>'
|
|
'%s'
|
|
'</div>'
|
|
'</div>') % (url, tweet_html, image_html)
|
|
|
|
msg = 'http://www.twitter.com'
|
|
converted = bugdown_convert(msg)
|
|
self.assertEqual(converted, '<p>%s</p>' % make_link('http://www.twitter.com'))
|
|
|
|
msg = 'http://www.twitter.com/wdaher/'
|
|
converted = bugdown_convert(msg)
|
|
self.assertEqual(converted, '<p>%s</p>' % make_link('http://www.twitter.com/wdaher/'))
|
|
|
|
msg = 'http://www.twitter.com/wdaher/status/3'
|
|
converted = bugdown_convert(msg)
|
|
self.assertEqual(converted, '<p>%s</p>' % make_link('http://www.twitter.com/wdaher/status/3'))
|
|
|
|
# id too long
|
|
msg = 'http://www.twitter.com/wdaher/status/2879779692873154569'
|
|
converted = bugdown_convert(msg)
|
|
self.assertEqual(converted, '<p>%s</p>' % make_link('http://www.twitter.com/wdaher/status/2879779692873154569'))
|
|
|
|
# id too large (i.e. tweet doesn't exist)
|
|
msg = 'http://www.twitter.com/wdaher/status/999999999999999999'
|
|
converted = bugdown_convert(msg)
|
|
self.assertEqual(converted, '<p>%s</p>' % make_link('http://www.twitter.com/wdaher/status/999999999999999999'))
|
|
|
|
msg = 'http://www.twitter.com/wdaher/status/287977969287315456'
|
|
converted = bugdown_convert(msg)
|
|
self.assertEqual(converted, '<p>%s</p>\n%s' % (
|
|
make_link('http://www.twitter.com/wdaher/status/287977969287315456'),
|
|
make_inline_twitter_preview('http://www.twitter.com/wdaher/status/287977969287315456', normal_tweet_html)))
|
|
|
|
msg = 'https://www.twitter.com/wdaher/status/287977969287315456'
|
|
converted = bugdown_convert(msg)
|
|
self.assertEqual(converted, '<p>%s</p>\n%s' % (
|
|
make_link('https://www.twitter.com/wdaher/status/287977969287315456'),
|
|
make_inline_twitter_preview('https://www.twitter.com/wdaher/status/287977969287315456', normal_tweet_html)))
|
|
|
|
msg = 'http://twitter.com/wdaher/status/287977969287315456'
|
|
converted = bugdown_convert(msg)
|
|
self.assertEqual(converted, '<p>%s</p>\n%s' % (
|
|
make_link('http://twitter.com/wdaher/status/287977969287315456'),
|
|
make_inline_twitter_preview('http://twitter.com/wdaher/status/287977969287315456', normal_tweet_html)))
|
|
|
|
# A max of 3 will be converted
|
|
msg = ('http://twitter.com/wdaher/status/287977969287315456 '
|
|
'http://twitter.com/wdaher/status/287977969287315457 '
|
|
'http://twitter.com/wdaher/status/287977969287315457 '
|
|
'http://twitter.com/wdaher/status/287977969287315457')
|
|
converted = bugdown_convert(msg)
|
|
self.assertEqual(converted, '<p>%s %s %s %s</p>\n%s%s%s' % (
|
|
make_link('http://twitter.com/wdaher/status/287977969287315456'),
|
|
make_link('http://twitter.com/wdaher/status/287977969287315457'),
|
|
make_link('http://twitter.com/wdaher/status/287977969287315457'),
|
|
make_link('http://twitter.com/wdaher/status/287977969287315457'),
|
|
make_inline_twitter_preview('http://twitter.com/wdaher/status/287977969287315456', normal_tweet_html),
|
|
make_inline_twitter_preview('http://twitter.com/wdaher/status/287977969287315457', normal_tweet_html),
|
|
make_inline_twitter_preview('http://twitter.com/wdaher/status/287977969287315457', normal_tweet_html)))
|
|
|
|
# Tweet has a mention in a URL, only the URL is linked
|
|
msg = 'http://twitter.com/wdaher/status/287977969287315458'
|
|
|
|
converted = bugdown_convert(msg)
|
|
self.assertEqual(converted, '<p>%s</p>\n%s' % (
|
|
make_link('http://twitter.com/wdaher/status/287977969287315458'),
|
|
make_inline_twitter_preview('http://twitter.com/wdaher/status/287977969287315458', mention_in_link_tweet_html)))
|
|
|
|
# Tweet with an image
|
|
msg = 'http://twitter.com/wdaher/status/287977969287315459'
|
|
|
|
converted = bugdown_convert(msg)
|
|
self.assertEqual(converted, '<p>%s</p>\n%s' % (
|
|
make_link('http://twitter.com/wdaher/status/287977969287315459'),
|
|
make_inline_twitter_preview('http://twitter.com/wdaher/status/287977969287315459',
|
|
media_tweet_html,
|
|
('<div class="twitter-image">'
|
|
'<a href="http://t.co/xo7pAhK6n3" target="_blank" title="http://t.co/xo7pAhK6n3">'
|
|
'<img src="https://pbs.twimg.com/media/BdoEjD4IEAIq86Z.jpg:small">'
|
|
'</a>'
|
|
'</div>'))))
|
|
|
|
msg = 'http://twitter.com/wdaher/status/287977969287315460'
|
|
converted = bugdown_convert(msg)
|
|
self.assertEqual(converted, '<p>%s</p>\n%s' % (
|
|
make_link('http://twitter.com/wdaher/status/287977969287315460'),
|
|
make_inline_twitter_preview('http://twitter.com/wdaher/status/287977969287315460', emoji_in_tweet_html)))
|
|
|
|
def test_fetch_tweet_data_settings_validation(self):
|
|
# type: () -> None
|
|
with self.settings(TEST_SUITE=False, TWITTER_CONSUMER_KEY=None):
|
|
self.assertIs(None, bugdown.fetch_tweet_data('287977969287315459'))
|
|
|
|
def test_content_has_emoji(self):
|
|
# type: () -> None
|
|
self.assertFalse(bugdown.content_has_emoji_syntax('boring'))
|
|
self.assertFalse(bugdown.content_has_emoji_syntax('hello: world'))
|
|
self.assertFalse(bugdown.content_has_emoji_syntax(':foobar'))
|
|
self.assertFalse(bugdown.content_has_emoji_syntax('::: hello :::'))
|
|
|
|
self.assertTrue(bugdown.content_has_emoji_syntax('foo :whatever:'))
|
|
self.assertTrue(bugdown.content_has_emoji_syntax('\n:whatever:'))
|
|
self.assertTrue(bugdown.content_has_emoji_syntax(':smile: ::::::'))
|
|
|
|
def test_realm_emoji(self):
|
|
# type: () -> None
|
|
def emoji_img(name, file_name, realm_id):
|
|
# type: (Text, Text, int) -> Text
|
|
return '<img alt="%s" class="emoji" src="%s" title="%s">' % (
|
|
name, get_emoji_url(file_name, realm_id), name[1:-1].replace("_", " "))
|
|
|
|
realm = get_realm('zulip')
|
|
|
|
# Needs to mock an actual message because that's how bugdown obtains the realm
|
|
msg = Message(sender=self.example_user('hamlet'))
|
|
converted = bugdown.convert(":green_tick:", message_realm=realm, message=msg)
|
|
self.assertEqual(converted, '<p>%s</p>' % (emoji_img(':green_tick:', 'green_tick.png', realm.id)))
|
|
|
|
# Deactivate realm emoji.
|
|
do_remove_realm_emoji(realm, 'green_tick')
|
|
converted = bugdown.convert(":green_tick:", message_realm=realm, message=msg)
|
|
self.assertEqual(converted, '<p>:green_tick:</p>')
|
|
|
|
def test_deactivated_realm_emoji(self):
|
|
# type: () -> None
|
|
# Deactivate realm emoji.
|
|
realm = get_realm('zulip')
|
|
do_remove_realm_emoji(realm, 'green_tick')
|
|
|
|
msg = Message(sender=self.example_user('hamlet'))
|
|
converted = bugdown.convert(":green_tick:", message_realm=realm, message=msg)
|
|
self.assertEqual(converted, '<p>:green_tick:</p>')
|
|
|
|
def test_unicode_emoji(self):
|
|
# type: () -> None
|
|
msg = u'\u2615' # ☕
|
|
converted = bugdown_convert(msg)
|
|
self.assertEqual(converted, u'<p><span class="emoji emoji-2615" title="coffee">:coffee:</span></p>')
|
|
|
|
msg = u'\u2615\u2615' # ☕☕
|
|
converted = bugdown_convert(msg)
|
|
self.assertEqual(converted, u'<p><span class="emoji emoji-2615" title="coffee">:coffee:</span><span class="emoji emoji-2615" title="coffee">:coffee:</span></p>')
|
|
|
|
def test_same_markup(self):
|
|
# type: () -> None
|
|
msg = u'\u2615' # ☕
|
|
unicode_converted = bugdown_convert(msg)
|
|
|
|
msg = u':coffee:' # ☕☕
|
|
converted = bugdown_convert(msg)
|
|
self.assertEqual(converted, unicode_converted)
|
|
|
|
def test_realm_patterns(self):
|
|
# type: () -> None
|
|
realm = get_realm('zulip')
|
|
url_format_string = r"https://trac.zulip.net/ticket/%(id)s"
|
|
realm_filter = RealmFilter(realm=realm,
|
|
pattern=r"#(?P<id>[0-9]{2,8})",
|
|
url_format_string=url_format_string)
|
|
realm_filter.save()
|
|
self.assertEqual(
|
|
realm_filter.__unicode__(),
|
|
'<RealmFilter(zulip): #(?P<id>[0-9]{2,8})'
|
|
' https://trac.zulip.net/ticket/%(id)s>')
|
|
|
|
msg = Message(sender=self.example_user('othello'),
|
|
subject="#444")
|
|
|
|
flush_per_request_caches()
|
|
|
|
content = "We should fix #224 and #115, but not issue#124 or #1124z or [trac #15](https://trac.zulip.net/ticket/16) today."
|
|
converted = bugdown.convert(content, message_realm=realm, message=msg)
|
|
converted_subject = bugdown.subject_links(realm.id, msg.subject)
|
|
|
|
self.assertEqual(converted, '<p>We should fix <a href="https://trac.zulip.net/ticket/224" target="_blank" title="https://trac.zulip.net/ticket/224">#224</a> and <a href="https://trac.zulip.net/ticket/115" target="_blank" title="https://trac.zulip.net/ticket/115">#115</a>, but not issue#124 or #1124z or <a href="https://trac.zulip.net/ticket/16" target="_blank" title="https://trac.zulip.net/ticket/16">trac #15</a> today.</p>')
|
|
self.assertEqual(converted_subject, [u'https://trac.zulip.net/ticket/444'])
|
|
|
|
RealmFilter(realm=realm, pattern=r'#(?P<id>[a-zA-Z]+-[0-9]+)',
|
|
url_format_string=r'https://trac.zulip.net/ticket/%(id)s').save()
|
|
msg = Message(sender=self.example_user('hamlet'))
|
|
|
|
content = '#ZUL-123 was fixed and code was deployed to production, also #zul-321 was deployed to staging'
|
|
converted = bugdown.convert(content, message_realm=realm, message=msg)
|
|
|
|
self.assertEqual(converted, '<p><a href="https://trac.zulip.net/ticket/ZUL-123" target="_blank" title="https://trac.zulip.net/ticket/ZUL-123">#ZUL-123</a> was fixed and code was deployed to production, also <a href="https://trac.zulip.net/ticket/zul-321" target="_blank" title="https://trac.zulip.net/ticket/zul-321">#zul-321</a> was deployed to staging</p>')
|
|
|
|
def test_maybe_update_realm_filters(self):
|
|
# type: () -> None
|
|
realm = get_realm('zulip')
|
|
url_format_string = r"https://trac.zulip.net/ticket/%(id)s"
|
|
realm_filter = RealmFilter(realm=realm,
|
|
pattern=r"#(?P<id>[0-9]{2,8})",
|
|
url_format_string=url_format_string)
|
|
realm_filter.save()
|
|
|
|
bugdown.realm_filter_data = {}
|
|
bugdown.maybe_update_realm_filters(None)
|
|
all_filters = bugdown.realm_filter_data
|
|
zulip_filters = all_filters[realm.id]
|
|
self.assertEqual(len(zulip_filters), 1)
|
|
self.assertEqual(zulip_filters[0],
|
|
(u'#(?P<id>[0-9]{2,8})', u'https://trac.zulip.net/ticket/%(id)s', realm_filter.id))
|
|
|
|
def test_flush_realm_filter(self):
|
|
# type: () -> None
|
|
realm = get_realm('zulip')
|
|
|
|
def flush():
|
|
# type: () -> None
|
|
'''
|
|
flush_realm_filter is a post-save hook, so calling it
|
|
directly for testing is kind of awkward
|
|
'''
|
|
class Instance(object):
|
|
realm_id = None # type: Optional[int]
|
|
instance = Instance()
|
|
instance.realm_id = realm.id
|
|
flush_realm_filter(sender=None, instance=instance)
|
|
|
|
def save_new_realm_filter():
|
|
# type: () -> None
|
|
realm_filter = RealmFilter(realm=realm,
|
|
pattern=r"whatever",
|
|
url_format_string='whatever')
|
|
realm_filter.save()
|
|
|
|
# start fresh for our realm
|
|
flush()
|
|
self.assertFalse(realm_in_local_realm_filters_cache(realm.id))
|
|
|
|
# call this just for side effects of populating the cache
|
|
realm_filters_for_realm(realm.id)
|
|
self.assertTrue(realm_in_local_realm_filters_cache(realm.id))
|
|
|
|
# Saving a new RealmFilter should have the side effect of
|
|
# flushing the cache.
|
|
save_new_realm_filter()
|
|
self.assertFalse(realm_in_local_realm_filters_cache(realm.id))
|
|
|
|
# and flush it one more time, to make sure we don't get a KeyError
|
|
flush()
|
|
self.assertFalse(realm_in_local_realm_filters_cache(realm.id))
|
|
|
|
def test_realm_patterns_negative(self):
|
|
# type: () -> None
|
|
realm = get_realm('zulip')
|
|
RealmFilter(realm=realm, pattern=r"#(?P<id>[0-9]{2,8})",
|
|
url_format_string=r"https://trac.zulip.net/ticket/%(id)s").save()
|
|
boring_msg = Message(sender=self.example_user('othello'),
|
|
subject=u"no match here")
|
|
converted_boring_subject = bugdown.subject_links(realm.id, boring_msg.subject)
|
|
self.assertEqual(converted_boring_subject, [])
|
|
|
|
def test_is_status_message(self):
|
|
# type: () -> None
|
|
user_profile = self.example_user('othello')
|
|
msg = Message(sender=user_profile, sending_client=get_client("test"))
|
|
|
|
content = '/me makes a list\n* one\n* two'
|
|
rendered_content = render_markdown(msg, content)
|
|
self.assertEqual(
|
|
rendered_content,
|
|
'<p>/me makes a list</p>\n<ul>\n<li>one</li>\n<li>two</li>\n</ul>'
|
|
)
|
|
self.assertFalse(Message.is_status_message(content, rendered_content))
|
|
|
|
content = '/me takes a walk'
|
|
rendered_content = render_markdown(msg, content)
|
|
self.assertEqual(
|
|
rendered_content,
|
|
'<p>/me takes a walk</p>'
|
|
)
|
|
self.assertTrue(Message.is_status_message(content, rendered_content))
|
|
|
|
def test_alert_words(self):
|
|
# type: () -> None
|
|
user_profile = self.example_user('othello')
|
|
do_set_alert_words(user_profile, ["ALERTWORD", "scaryword"])
|
|
msg = Message(sender=user_profile, sending_client=get_client("test"))
|
|
realm_alert_words = alert_words_in_realm(user_profile.realm)
|
|
|
|
def render(msg, content):
|
|
# type: (Message, Text) -> Text
|
|
return render_markdown(msg,
|
|
content,
|
|
realm_alert_words=realm_alert_words,
|
|
user_ids={user_profile.id})
|
|
|
|
content = "We have an ALERTWORD day today!"
|
|
self.assertEqual(render(msg, content), "<p>We have an ALERTWORD day today!</p>")
|
|
self.assertEqual(msg.user_ids_with_alert_words, set([user_profile.id]))
|
|
|
|
msg = Message(sender=user_profile, sending_client=get_client("test"))
|
|
content = "We have a NOTHINGWORD day today!"
|
|
self.assertEqual(render(msg, content), "<p>We have a NOTHINGWORD day today!</p>")
|
|
self.assertEqual(msg.user_ids_with_alert_words, set())
|
|
|
|
def test_mention_wildcard(self):
|
|
# type: () -> None
|
|
user_profile = self.example_user('othello')
|
|
msg = Message(sender=user_profile, sending_client=get_client("test"))
|
|
|
|
content = "@all test"
|
|
self.assertEqual(render_markdown(msg, content),
|
|
'<p><span class="user-mention" data-user-email="*" data-user-id="*">'
|
|
'@all'
|
|
'</span> test</p>')
|
|
self.assertTrue(msg.mentions_wildcard)
|
|
|
|
def test_mention_everyone(self):
|
|
# type: () -> None
|
|
user_profile = self.example_user('othello')
|
|
msg = Message(sender=user_profile, sending_client=get_client("test"))
|
|
|
|
content = "@everyone test"
|
|
self.assertEqual(render_markdown(msg, content),
|
|
'<p><span class="user-mention" data-user-email="*" data-user-id="*">@everyone</span> test</p>')
|
|
self.assertTrue(msg.mentions_wildcard)
|
|
|
|
def test_mention_everyone_style_normal_user(self):
|
|
# type: () -> None
|
|
user_profile = self.example_user('othello')
|
|
msg = Message(sender=user_profile, sending_client=get_client("test"))
|
|
|
|
content = "@aaron test"
|
|
self.assertEqual(render_markdown(msg, content),
|
|
'<p>@aaron test</p>')
|
|
self.assertFalse(msg.mentions_wildcard)
|
|
self.assertEqual(msg.mentions_user_ids, set([]))
|
|
|
|
def test_mention_single(self):
|
|
# type: () -> None
|
|
sender_user_profile = self.example_user('othello')
|
|
user_profile = self.example_user('hamlet')
|
|
msg = Message(sender=sender_user_profile, sending_client=get_client("test"))
|
|
user_id = user_profile.id
|
|
|
|
content = "@**King Hamlet**"
|
|
self.assertEqual(render_markdown(msg, content),
|
|
'<p><span class="user-mention" '
|
|
'data-user-email="%s" '
|
|
'data-user-id="%s">'
|
|
'@King Hamlet</span></p>' % (self.example_email("hamlet"), user_id))
|
|
self.assertEqual(msg.mentions_user_ids, set([user_profile.id]))
|
|
|
|
def test_possible_mentions(self):
|
|
# type: () -> None
|
|
def assert_mentions(content, names):
|
|
# type: (Text, Set[Text]) -> None
|
|
self.assertEqual(possible_mentions(content), names)
|
|
|
|
assert_mentions('', set())
|
|
assert_mentions('boring', set())
|
|
assert_mentions('@all', set())
|
|
assert_mentions('smush@**steve**smush', set())
|
|
|
|
assert_mentions(
|
|
'Hello @**King Hamlet** and @**Cordelia Lear**\n@**Foo van Barson** @**all**',
|
|
{'King Hamlet', 'Cordelia Lear', 'Foo van Barson'}
|
|
)
|
|
|
|
def test_mention_multiple(self):
|
|
# type: () -> None
|
|
sender_user_profile = self.example_user('othello')
|
|
hamlet = self.example_user('hamlet')
|
|
cordelia = self.example_user('cordelia')
|
|
msg = Message(sender=sender_user_profile, sending_client=get_client("test"))
|
|
|
|
content = "@**King Hamlet** and @**Cordelia Lear**, check this out"
|
|
|
|
self.assertEqual(render_markdown(msg, content),
|
|
'<p>'
|
|
'<span class="user-mention" '
|
|
'data-user-email="%s" '
|
|
'data-user-id="%s">@King Hamlet</span> and '
|
|
'<span class="user-mention" '
|
|
'data-user-email="%s" '
|
|
'data-user-id="%s">@Cordelia Lear</span>, '
|
|
'check this out</p>' % (hamlet.email, hamlet.id, cordelia.email, cordelia.id))
|
|
self.assertEqual(msg.mentions_user_ids, set([hamlet.id, cordelia.id]))
|
|
|
|
def test_mention_invalid(self):
|
|
# type: () -> None
|
|
sender_user_profile = self.example_user('othello')
|
|
msg = Message(sender=sender_user_profile, sending_client=get_client("test"))
|
|
|
|
content = "Hey @**Nonexistent User**"
|
|
self.assertEqual(render_markdown(msg, content),
|
|
'<p>Hey @<strong>Nonexistent User</strong></p>')
|
|
self.assertEqual(msg.mentions_user_ids, set())
|
|
|
|
def test_stream_single(self):
|
|
# type: () -> None
|
|
denmark = get_stream('Denmark', get_realm('zulip'))
|
|
sender_user_profile = self.example_user('othello')
|
|
msg = Message(sender=sender_user_profile, sending_client=get_client("test"))
|
|
content = "#**Denmark**"
|
|
self.assertEqual(
|
|
render_markdown(msg, content),
|
|
'<p><a class="stream" data-stream-id="{d.id}" href="/#narrow/stream/Denmark">#{d.name}</a></p>'.format(
|
|
d=denmark
|
|
))
|
|
|
|
def test_stream_multiple(self):
|
|
# type: () -> None
|
|
sender_user_profile = self.example_user('othello')
|
|
msg = Message(sender=sender_user_profile, sending_client=get_client("test"))
|
|
realm = get_realm('zulip')
|
|
denmark = get_stream('Denmark', realm)
|
|
scotland = get_stream('Scotland', realm)
|
|
content = "Look to #**Denmark** and #**Scotland**, there something"
|
|
self.assertEqual(render_markdown(msg, content),
|
|
'<p>Look to '
|
|
'<a class="stream" '
|
|
'data-stream-id="{denmark.id}" '
|
|
'href="/#narrow/stream/Denmark">#{denmark.name}</a> and '
|
|
'<a class="stream" '
|
|
'data-stream-id="{scotland.id}" '
|
|
'href="/#narrow/stream/Scotland">#{scotland.name}</a>, '
|
|
'there something</p>'.format(denmark=denmark, scotland=scotland))
|
|
|
|
def test_stream_case_sensitivity(self):
|
|
# type: () -> None
|
|
realm = get_realm('zulip')
|
|
case_sens = Stream.objects.create(name='CaseSens', realm=realm)
|
|
sender_user_profile = self.example_user('othello')
|
|
msg = Message(sender=sender_user_profile, sending_client=get_client("test"))
|
|
content = "#**CaseSens**"
|
|
self.assertEqual(
|
|
render_markdown(msg, content),
|
|
'<p><a class="stream" data-stream-id="{s.id}" href="/#narrow/stream/{s.name}">#{s.name}</a></p>'.format(
|
|
s=case_sens
|
|
))
|
|
|
|
def test_stream_case_sensitivity_nonmatching(self):
|
|
# type: () -> None
|
|
"""#StreamName requires the stream be spelled with the correct case
|
|
currently. If we change that in the future, we'll need to change this
|
|
test."""
|
|
realm = get_realm('zulip')
|
|
Stream.objects.create(name='CaseSens', realm=realm)
|
|
sender_user_profile = self.example_user('othello')
|
|
msg = Message(sender=sender_user_profile, sending_client=get_client("test"))
|
|
content = "#**casesens**"
|
|
self.assertEqual(
|
|
render_markdown(msg, content),
|
|
'<p>#<strong>casesens</strong></p>')
|
|
|
|
def test_possible_stream_names(self):
|
|
# type: () -> None
|
|
content = '''#**test here**
|
|
This mentions #**Denmark** too.
|
|
#**garçon** #**천국** @**Ignore Person**
|
|
'''
|
|
self.assertEqual(
|
|
bugdown.possible_linked_stream_names(content),
|
|
{'test here', 'Denmark', 'garçon', '천국'}
|
|
)
|
|
|
|
def test_stream_unicode(self):
|
|
# type: () -> None
|
|
realm = get_realm('zulip')
|
|
uni = Stream.objects.create(name=u'привет', realm=realm)
|
|
sender_user_profile = self.example_user('othello')
|
|
msg = Message(sender=sender_user_profile, sending_client=get_client("test"))
|
|
content = u"#**привет**"
|
|
self.assertEqual(
|
|
render_markdown(msg, content),
|
|
u'<p><a class="stream" data-stream-id="{s.id}" href="/#narrow/stream/{url}">#{s.name}</a></p>'.format(
|
|
s=uni,
|
|
url=urllib.parse.quote(force_str(uni.name))
|
|
))
|
|
|
|
def test_stream_invalid(self):
|
|
# type: () -> None
|
|
sender_user_profile = self.example_user('othello')
|
|
msg = Message(sender=sender_user_profile, sending_client=get_client("test"))
|
|
|
|
content = "There #**Nonexistentstream**"
|
|
self.assertEqual(render_markdown(msg, content),
|
|
'<p>There #<strong>Nonexistentstream</strong></p>')
|
|
self.assertEqual(msg.mentions_user_ids, set())
|
|
|
|
def test_stream_subscribe_button_simple(self):
|
|
# type: () -> None
|
|
msg = '!_stream_subscribe_button(simple)'
|
|
converted = bugdown_convert(msg)
|
|
self.assertEqual(
|
|
converted,
|
|
'<p>'
|
|
'<span class="inline-subscribe" data-stream-name="simple">'
|
|
'<button class="inline-subscribe-button btn">Subscribe to simple</button>'
|
|
'<span class="inline-subscribe-error"></span>'
|
|
'</span>'
|
|
'</p>'
|
|
)
|
|
|
|
def test_stream_subscribe_button_in_name(self):
|
|
# type: () -> None
|
|
msg = '!_stream_subscribe_button(simple (not\\))'
|
|
converted = bugdown_convert(msg)
|
|
self.assertEqual(
|
|
converted,
|
|
'<p>'
|
|
'<span class="inline-subscribe" data-stream-name="simple (not)">'
|
|
'<button class="inline-subscribe-button btn">Subscribe to simple (not)</button>'
|
|
'<span class="inline-subscribe-error"></span>'
|
|
'</span>'
|
|
'</p>'
|
|
)
|
|
|
|
def test_stream_subscribe_button_after_name(self):
|
|
# type: () -> None
|
|
msg = '!_stream_subscribe_button(simple) (not)'
|
|
converted = bugdown_convert(msg)
|
|
self.assertEqual(
|
|
converted,
|
|
'<p>'
|
|
'<span class="inline-subscribe" data-stream-name="simple">'
|
|
'<button class="inline-subscribe-button btn">Subscribe to simple</button>'
|
|
'<span class="inline-subscribe-error"></span>'
|
|
'</span>'
|
|
' (not)</p>'
|
|
)
|
|
|
|
def test_stream_subscribe_button_slash(self):
|
|
# type: () -> None
|
|
msg = '!_stream_subscribe_button(simple\\\\)'
|
|
converted = bugdown_convert(msg)
|
|
self.assertEqual(
|
|
converted,
|
|
'<p>'
|
|
'<span class="inline-subscribe" data-stream-name="simple\\">'
|
|
'<button class="inline-subscribe-button btn">Subscribe to simple\\</button>'
|
|
'<span class="inline-subscribe-error"></span>'
|
|
'</span>'
|
|
'</p>'
|
|
)
|
|
|
|
def test_in_app_modal_link(self):
|
|
# type: () -> None
|
|
msg = '!modal_link(#settings, Settings page)'
|
|
converted = bugdown_convert(msg)
|
|
self.assertEqual(
|
|
converted,
|
|
'<p>'
|
|
'<a href="#settings" title="#settings">Settings page</a>'
|
|
'</p>'
|
|
)
|
|
|
|
def test_image_preview_title(self):
|
|
# type: () -> None
|
|
msg = '[My favorite image](https://example.com/testimage.png)'
|
|
converted = bugdown_convert(msg)
|
|
self.assertEqual(
|
|
converted,
|
|
'<p>'
|
|
'<a href="https://example.com/testimage.png" target="_blank" title="https://example.com/testimage.png">My favorite image</a>'
|
|
'</p>\n'
|
|
'<div class="message_inline_image">'
|
|
'<a href="https://example.com/testimage.png" target="_blank" title="My favorite image">'
|
|
'<img src="https://example.com/testimage.png">'
|
|
'</a>'
|
|
'</div>'
|
|
)
|
|
|
|
def test_mit_rendering(self):
|
|
# type: () -> None
|
|
"""Test the markdown configs for the MIT Zephyr mirroring system;
|
|
verifies almost all inline patterns are disabled, but
|
|
inline_interesting_links is still enabled"""
|
|
msg = "**test**"
|
|
realm = get_realm("zephyr")
|
|
client = get_client("zephyr_mirror")
|
|
message = Message(sending_client=client,
|
|
sender=self.mit_user("sipbtest"))
|
|
converted = bugdown.convert(msg, message_realm=realm, message=message)
|
|
self.assertEqual(
|
|
converted,
|
|
"<p>**test**</p>",
|
|
)
|
|
msg = "* test"
|
|
converted = bugdown.convert(msg, message_realm=realm, message=message)
|
|
self.assertEqual(
|
|
converted,
|
|
"<p>* test</p>",
|
|
)
|
|
msg = "https://lists.debian.org/debian-ctte/2014/02/msg00173.html"
|
|
converted = bugdown.convert(msg, message_realm=realm, message=message)
|
|
self.assertEqual(
|
|
converted,
|
|
'<p><a href="https://lists.debian.org/debian-ctte/2014/02/msg00173.html" target="_blank" title="https://lists.debian.org/debian-ctte/2014/02/msg00173.html">https://lists.debian.org/debian-ctte/2014/02/msg00173.html</a></p>',
|
|
)
|
|
|
|
def test_url_to_a(self):
|
|
# type: () -> None
|
|
url = 'javascript://example.com/invalidURL'
|
|
converted = bugdown.url_to_a(url, url)
|
|
self.assertEqual(
|
|
converted,
|
|
'javascript://example.com/invalidURL',
|
|
)
|
|
|
|
class BugdownApiTests(ZulipTestCase):
|
|
def test_render_message_api(self):
|
|
# type: () -> None
|
|
content = 'That is a **bold** statement'
|
|
result = self.client_post(
|
|
'/api/v1/messages/render',
|
|
dict(content=content),
|
|
**self.api_auth(self.example_email("othello"))
|
|
)
|
|
self.assert_json_success(result)
|
|
self.assertEqual(result.json()['rendered'],
|
|
u'<p>That is a <strong>bold</strong> statement</p>')
|
|
|
|
def test_render_mention_stream_api(self):
|
|
# type: () -> None
|
|
"""Determines whether we're correctly passing the realm context"""
|
|
content = 'This mentions #**Denmark** and @**King Hamlet**.'
|
|
result = self.client_post(
|
|
'/api/v1/messages/render',
|
|
dict(content=content),
|
|
**self.api_auth(self.example_email("othello"))
|
|
)
|
|
self.assert_json_success(result)
|
|
user_id = self.example_user('hamlet').id
|
|
self.assertEqual(result.json()['rendered'],
|
|
u'<p>This mentions <a class="stream" data-stream-id="%s" href="/#narrow/stream/Denmark">#Denmark</a> and <span class="user-mention" data-user-email="%s" data-user-id="%s">@King Hamlet</span>.</p>' % (get_stream("Denmark", get_realm("zulip")).id, self.example_email("hamlet"), user_id))
|
|
|
|
class BugdownErrorTests(ZulipTestCase):
|
|
def test_bugdown_error_handling(self):
|
|
# type: () -> None
|
|
with self.simulated_markdown_failure():
|
|
with self.assertRaises(bugdown.BugdownRenderingException):
|
|
bugdown_convert('')
|
|
|
|
def test_send_message_errors(self):
|
|
# type: () -> None
|
|
|
|
message = 'whatever'
|
|
with self.simulated_markdown_failure():
|
|
# We don't use assertRaisesRegex because it seems to not
|
|
# handle i18n properly here on some systems.
|
|
with self.assertRaises(JsonableError):
|
|
self.send_message(self.example_email("othello"), "Denmark", Recipient.STREAM, message)
|
|
|
|
|
|
class BugdownAvatarTestCase(ZulipTestCase):
|
|
def test_possible_avatar_emails(self):
|
|
# type: () -> None
|
|
content = '''
|
|
hello !avatar(foo@example.com) my email is ignore@ignore.com
|
|
!gravatar(bar@yo.tv)
|
|
|
|
smushing!avatar(hamlet@example.org) is allowed
|
|
'''
|
|
self.assertEqual(
|
|
bugdown.possible_avatar_emails(content),
|
|
{'foo@example.com', 'bar@yo.tv', 'hamlet@example.org'},
|
|
)
|
|
|
|
def test_avatar_with_id(self):
|
|
# type: () -> None
|
|
sender_user_profile = self.example_user('othello')
|
|
message = Message(sender=sender_user_profile, sending_client=get_client("test"))
|
|
|
|
user_profile = self.example_user('hamlet')
|
|
msg = '!avatar({0})'.format(user_profile.email)
|
|
converted = bugdown.convert(msg, message=message)
|
|
values = {'email': user_profile.email, 'id': user_profile.id}
|
|
self.assertEqual(
|
|
converted,
|
|
'<p><img alt="{email}" class="message_body_gravatar" src="/avatar/{id}?s=30" title="{email}"></p>'.format(**values))
|
|
|
|
def test_avatar_of_unregistered_user(self):
|
|
# type: () -> None
|
|
sender_user_profile = self.example_user('othello')
|
|
message = Message(sender=sender_user_profile, sending_client=get_client("test"))
|
|
|
|
email = 'fakeuser@example.com'
|
|
msg = '!avatar({0})'.format(email)
|
|
converted = bugdown.convert(msg, message=message)
|
|
self.assertEqual(
|
|
converted,
|
|
'<p><img alt="{0}" class="message_body_gravatar" src="/avatar/{0}?s=30" title="{0}"></p>'.format(email))
|