2014-01-31 23:13:58 +01:00
# -*- coding: utf-8 -*-
from django . conf import settings
2017-03-13 14:42:03 +01:00
from django . test import TestCase , override_settings
2014-01-31 23:13:58 +01:00
from zerver . lib import bugdown
from zerver . lib . actions import (
2018-01-15 19:36:32 +01:00
do_set_user_display_setting ,
2014-01-31 23:13:58 +01:00
do_remove_realm_emoji ,
2016-06-01 05:02:43 +02:00
do_set_alert_words ,
2017-01-04 05:30:48 +01:00
get_realm ,
2014-01-31 23:13:58 +01:00
)
2016-09-14 18:02:24 +02:00
from zerver . lib . alert_words import alert_words_in_realm
2016-04-28 06:43:40 +02:00
from zerver . lib . camo import get_camo_url
2017-10-13 00:06:24 +02:00
from zerver . lib . create_user import create_user
2017-03-13 05:45:50 +01:00
from zerver . lib . emoji import get_emoji_url
2017-09-25 09:47:15 +02:00
from zerver . lib . mention import possible_mentions , possible_user_group_mentions
2016-10-04 18:32:46 +02:00
from zerver . lib . message import render_markdown
2016-09-15 22:05:56 +02:00
from zerver . lib . request import (
JsonableError ,
)
2017-09-25 09:47:15 +02:00
from zerver . lib . user_groups import create_user_group
2016-11-10 19:30:09 +01:00
from zerver . lib . test_classes import (
2016-09-15 22:05:56 +02:00
ZulipTestCase ,
)
2017-10-07 00:29:18 +02:00
from zerver . lib . test_runner import slow
2017-12-04 10:10:15 +01:00
from zerver . lib import mdiff
2018-03-18 20:49:28 +01:00
from zerver . lib . tex import render_tex
2014-01-31 23:13:58 +01:00
from zerver . models import (
2016-12-31 03:08:43 +01:00
realm_in_local_realm_filters_cache ,
2016-09-23 20:06:37 +02:00
flush_per_request_caches ,
2016-09-23 21:55:21 +02:00
flush_realm_filter ,
2016-06-01 05:02:43 +02:00
get_client ,
2017-01-04 05:30:48 +01:00
get_realm ,
2016-10-26 20:56:17 +02:00
get_stream ,
2016-12-31 03:08:43 +01:00
realm_filters_for_realm ,
2018-02-09 19:49:13 +01:00
MAX_MESSAGE_LENGTH ,
2014-01-31 23:13:58 +01:00
Message ,
2016-10-26 20:56:17 +02:00
Stream ,
2016-09-23 21:55:21 +02:00
Realm ,
2018-03-11 18:55:20 +01:00
RealmEmoji ,
2014-01-31 23:13:58 +01:00
RealmFilter ,
2016-09-15 22:05:56 +02:00
Recipient ,
2017-10-13 00:06:24 +02:00
UserProfile ,
2017-09-25 09:47:15 +02:00
UserGroup ,
2014-01-31 23:13:58 +01:00
)
2017-03-13 14:42:03 +01:00
import copy
2016-04-30 00:25:58 +02:00
import mock
2014-01-31 23:13:58 +01:00
import os
import ujson
2017-11-05 05:30:31 +01:00
import urllib
2016-10-11 11:55:03 +02:00
from zerver . lib . str_utils import NonBinaryStr
2017-09-14 19:47:22 +02:00
from typing import Any , AnyStr , Dict , List , Optional , Set , Tuple , Text
2016-10-11 11:55:03 +02:00
2014-01-31 23:13:58 +01:00
class FencedBlockPreprocessorTest ( TestCase ) :
2017-11-05 10:51:25 +01:00
def test_simple_quoting ( self ) - > None :
2014-01-31 23:13:58 +01:00
processor = bugdown . fenced_code . FencedBlockPreprocessor ( None )
markdown = [
' ~~~ quote ' ,
' hi ' ,
' bye ' ,
' ' ,
' '
]
expected = [
' ' ,
' > hi ' ,
' > bye ' ,
' ' ,
' ' ,
' '
]
lines = processor . run ( markdown )
self . assertEqual ( lines , expected )
2017-11-05 10:51:25 +01:00
def test_serial_quoting ( self ) - > None :
2014-01-31 23:13:58 +01:00
processor = bugdown . fenced_code . FencedBlockPreprocessor ( None )
markdown = [
' ~~~ quote ' ,
' hi ' ,
' ~~~ ' ,
' ' ,
' ~~~ quote ' ,
' bye ' ,
' ' ,
' '
]
expected = [
' ' ,
' > hi ' ,
' ' ,
' ' ,
' ' ,
' > bye ' ,
' ' ,
' ' ,
' '
]
lines = processor . run ( markdown )
self . assertEqual ( lines , expected )
2017-11-05 10:51:25 +01:00
def test_serial_code ( self ) - > None :
2014-01-31 23:13:58 +01:00
processor = bugdown . fenced_code . FencedBlockPreprocessor ( None )
# Simulate code formatting.
2017-07-11 21:29:40 +02:00
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
2014-01-31 23:13:58 +01:00
markdown = [
' ``` .py ' ,
' hello() ' ,
' ``` ' ,
' ' ,
2017-06-16 00:01:19 +02:00
' ```vb.net ' ,
2014-01-31 23:13:58 +01:00
' goodbye() ' ,
' ``` ' ,
' ' ,
2017-06-16 00:01:19 +02:00
' ```c# ' ,
' weirdchar() ' ,
' ``` ' ,
2014-01-31 23:13:58 +01:00
' '
]
expected = [
' ' ,
' **py:hello()** ' ,
' ' ,
' ' ,
' ' ,
2017-06-16 00:01:19 +02:00
' **vb.net:goodbye()** ' ,
' ' ,
' ' ,
2014-01-31 23:13:58 +01:00
' ' ,
2017-06-16 00:01:19 +02:00
' **c#:weirdchar()** ' ,
2014-01-31 23:13:58 +01:00
' ' ,
' '
]
lines = processor . run ( markdown )
self . assertEqual ( lines , expected )
2017-11-05 10:51:25 +01:00
def test_nested_code ( self ) - > None :
2014-01-31 23:13:58 +01:00
processor = bugdown . fenced_code . FencedBlockPreprocessor ( None )
# Simulate code formatting.
2017-07-11 21:29:40 +02:00
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
2014-01-31 23:13:58 +01:00
markdown = [
' ~~~ quote ' ,
' hi ' ,
' ``` .py ' ,
' hello() ' ,
' ``` ' ,
' ' ,
' '
]
expected = [
' ' ,
' > hi ' ,
' ' ,
' > **py:hello()** ' ,
' ' ,
' ' ,
' '
]
lines = processor . run ( markdown )
self . assertEqual ( lines , expected )
2017-11-05 10:51:25 +01:00
def bugdown_convert ( text : Text ) - > Text :
2017-01-22 06:29:11 +01:00
return bugdown . convert ( text , message_realm = get_realm ( ' zulip ' ) )
2014-01-31 23:13:58 +01:00
2017-10-13 00:06:24 +02:00
class BugdownMiscTest ( ZulipTestCase ) :
2017-12-04 10:10:15 +01:00
def test_diffs_work_as_expected ( self ) - > None :
str1 = " <p>The quick brown fox jumps over the lazy dog. Animal stories are fun, yeah</p> "
str2 = " <p>The fast fox jumps over the lazy dogs and cats. Animal stories are fun</p> "
expected_diff = " \u001b [34m- \u001b [0m <p>The \u001b [33mquick brown \u001b [0m fox jumps over the lazy dog. Animal stories are fun \u001b [31m, yeah \u001b [0m</p> \n \u001b [34m+ \u001b [0m <p>The \u001b [33mfast \u001b [0m fox jumps over the lazy dog \u001b [32ms and cats \u001b [0m. Animal stories are fun</p> \n "
self . assertEqual ( mdiff . diff_strings ( str1 , str2 ) , expected_diff )
2017-11-05 10:51:25 +01:00
def test_get_full_name_info ( self ) - > None :
2017-10-13 00:06:24 +02:00
realm = get_realm ( ' zulip ' )
2017-11-05 10:51:25 +01:00
def make_user ( email : Text , full_name : Text ) - > UserProfile :
2017-10-13 00:06:24 +02:00
return create_user (
email = email ,
password = ' whatever ' ,
realm = realm ,
full_name = full_name ,
short_name = ' whatever ' ,
)
fred1 = make_user ( ' fred1@example.com ' , ' Fred Flintstone ' )
fred1 . is_active = False
fred1 . save ( )
fred2 = make_user ( ' fred2@example.com ' , ' Fred Flintstone ' )
fred3 = make_user ( ' fred3@example.com ' , ' Fred Flintstone ' )
fred3 . is_active = False
fred3 . save ( )
dct = bugdown . get_full_name_info ( realm . id , { ' Fred Flintstone ' , ' cordelia LEAR ' , ' Not A User ' } )
self . assertEqual ( set ( dct . keys ( ) ) , { ' fred flintstone ' , ' cordelia lear ' } )
self . assertEqual ( dct [ ' fred flintstone ' ] , dict (
email = ' fred2@example.com ' ,
full_name = ' Fred Flintstone ' ,
id = fred2 . id
) )
2017-11-05 10:51:25 +01:00
def test_mention_data ( self ) - > None :
2017-10-24 17:36:27 +02:00
realm = get_realm ( ' zulip ' )
hamlet = self . example_user ( ' hamlet ' )
cordelia = self . example_user ( ' cordelia ' )
content = ' @**King Hamlet** @**Cordelia lear** '
mention_data = bugdown . MentionData ( realm . id , content )
self . assertEqual ( mention_data . get_user_ids ( ) , { hamlet . id , cordelia . id } )
user = mention_data . get_user ( ' king hamLET ' )
2018-02-19 06:39:38 +01:00
assert ( user is not None )
2017-10-24 17:36:27 +02:00
self . assertEqual ( user [ ' email ' ] , hamlet . email )
2018-03-18 20:49:28 +01:00
def test_invalid_katex_path ( self ) - > None :
with self . settings ( STATIC_ROOT = " /invalid/path " ) :
with mock . patch ( ' logging.error ' ) as mock_logger :
render_tex ( " random text " )
mock_logger . assert_called_with ( " Cannot find KaTeX for latex rendering! " )
2017-05-07 17:21:26 +02:00
class BugdownTest ( ZulipTestCase ) :
2017-12-04 10:10:15 +01:00
def assertEqual ( self , first : Any , second : Any , msg : Text = " " ) - > None :
if isinstance ( first , Text ) and isinstance ( second , Text ) :
if first != second :
raise AssertionError ( " Actual and expected outputs do not match; showing diff. \n " +
mdiff . diff_strings ( first , second ) + msg )
else :
super ( ) . assertEqual ( first , second )
2017-11-05 10:51:25 +01:00
def load_bugdown_tests ( self ) - > Tuple [ Dict [ Text , Any ] , List [ List [ Text ] ] ] :
2014-01-31 23:13:58 +01:00
test_fixtures = { }
2018-04-19 20:17:24 +02:00
data_file = open ( os . path . join ( os . path . dirname ( __file__ ) , ' fixtures/markdown_test_cases.json ' ) , ' r ' )
2014-01-31 23:13:58 +01:00
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 ' ]
2018-03-28 10:40:44 +02:00
def test_bugdown_no_ignores ( self ) - > None :
# We do not want any ignored tests to be committed and merged.
format_tests , linkify_tests = self . load_bugdown_tests ( )
for name , test in format_tests . items ( ) :
message = ' Test " %s " shouldn \' t be ignored. ' % ( name , )
is_ignored = test . get ( ' ignore ' , False )
self . assertFalse ( is_ignored , message )
2017-10-07 00:29:18 +02:00
@slow ( " Aggregate of runs dozens of individual markdown tests " )
2017-11-05 10:51:25 +01:00
def test_bugdown_fixtures ( self ) - > None :
2014-01-31 23:13:58 +01:00
format_tests , linkify_tests = self . load_bugdown_tests ( )
2018-03-25 23:23:22 +02:00
valid_keys = set ( [ " name " , " input " , " expected_output " ,
2017-10-31 16:56:19 +01:00
" backend_only_rendering " ,
2018-03-25 23:23:22 +02:00
" marked_expected_output " , " text_content " ,
2018-03-28 10:40:44 +02:00
" translate_emoticons " , " ignore " ] )
2014-01-31 23:13:58 +01:00
2017-09-27 10:11:59 +02:00
for name , test in format_tests . items ( ) :
2017-10-31 16:56:19 +01:00
# Check that there aren't any unexpected keys as those are often typos
self . assertEqual ( len ( set ( test . keys ( ) ) - valid_keys ) , 0 )
2018-03-28 10:40:44 +02:00
# Ignore tests if specified
if test . get ( ' ignore ' , False ) :
return # nocoverage
2018-03-25 23:23:22 +02:00
if test . get ( ' translate_emoticons ' , False ) :
# Create a userprofile and send message with it.
user_profile = self . example_user ( ' othello ' )
do_set_user_display_setting ( user_profile , ' translate_emoticons ' , True )
msg = Message ( sender = user_profile , sending_client = get_client ( " test " ) )
converted = render_markdown ( msg , test [ ' input ' ] )
else :
converted = bugdown_convert ( test [ ' input ' ] )
2014-01-31 23:13:58 +01:00
2015-11-01 17:11:06 +01:00
print ( " Running Bugdown test %s " % ( name , ) )
2014-01-31 23:13:58 +01:00
self . assertEqual ( converted , test [ ' expected_output ' ] )
2017-11-05 10:51:25 +01:00
def replaced ( payload : Text , url : Text , phrase : Text = ' ' ) - > Text :
2014-01-31 23:13:58 +01:00
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 ) , )
2015-11-01 17:11:06 +01:00
print ( " Running Bugdown Linkify tests " )
2016-10-27 12:06:44 +02:00
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 )
2014-01-31 23:13:58 +01:00
2017-11-05 10:51:25 +01:00
def test_inline_file ( self ) - > None :
2016-03-10 17:17:40 +01:00
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 ) :
2017-03-14 00:51:51 +01:00
realm = Realm . objects . create ( string_id = ' file_links_test ' )
2017-11-11 16:00:46 +01:00
bugdown . maybe_update_markdown_engines ( realm . id , False )
2017-01-22 06:29:11 +01:00
converted = bugdown . convert ( msg , message_realm = realm )
2016-03-10 17:17:40 +01:00
self . assertEqual ( converted , ' <p>Check out this file file:///Volumes/myserver/Users/Shared/pi.py</p> ' )
2018-01-19 11:17:38 +01:00
def test_inline_bitcoin ( self ) - > None :
msg = ' To bitcoin:1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa or not to bitcoin '
converted = bugdown_convert ( msg )
self . assertEqual ( converted , ' <p>To <a href= " bitcoin:1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa " target= " _blank " title= " bitcoin:1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa " >bitcoin:1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa</a> or not to bitcoin</p> ' )
2017-11-05 10:51:25 +01:00
def test_inline_youtube ( self ) - > None :
2014-01-31 23:13:58 +01:00
msg = ' Check out the debate: http://www.youtube.com/watch?v=hx1mjT73xYE '
converted = bugdown_convert ( msg )
2016-10-17 22:02:01 +02:00
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> ' )
2014-01-31 23:13:58 +01:00
2017-11-27 10:03:18 +01:00
msg = ' http://www.youtube.com/watch?v=hx1mjT73xYE '
converted = bugdown_convert ( msg )
self . assertEqual ( converted , ' <p><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> ' )
2017-12-14 22:17:00 +01:00
def test_inline_vimeo ( self ) - > None :
msg = ' Check out the debate: https://vimeo.com/246979354 '
converted = bugdown_convert ( msg )
self . assertEqual ( converted , ' <p>Check out the debate: <a href= " https://vimeo.com/246979354 " target= " _blank " title= " https://vimeo.com/246979354 " >https://vimeo.com/246979354</a></p> ' )
msg = ' https://vimeo.com/246979354 '
converted = bugdown_convert ( msg )
self . assertEqual ( converted , ' <p><a href= " https://vimeo.com/246979354 " target= " _blank " title= " https://vimeo.com/246979354 " >https://vimeo.com/246979354</a></p> ' )
2017-03-13 14:42:03 +01:00
@override_settings ( INLINE_IMAGE_PREVIEW = True )
2017-11-05 10:51:25 +01:00
def test_inline_image_preview ( self ) - > None :
2017-11-27 10:08:32 +01:00
with_preview = ' <p>Test: <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>Test: <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 = ' Test: http://cdn.wallpapersafari.com/13/6/16eVjx.jpeg '
2017-03-13 14:42:03 +01:00
2017-05-07 17:21:26 +02:00
sender_user_profile = self . example_user ( ' othello ' )
2017-03-13 14:42:03 +01:00
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 ( )
2017-05-07 17:21:26 +02:00
sender_user_profile = self . example_user ( ' othello ' )
2017-03-13 14:42:03 +01:00
msg = Message ( sender = sender_user_profile , sending_client = get_client ( " test " ) )
converted = render_markdown ( msg , content )
self . assertEqual ( converted , without_preview )
2017-04-15 12:53:10 +02:00
@override_settings ( INLINE_IMAGE_PREVIEW = True )
2017-11-05 10:51:25 +01:00
def test_inline_image_preview_order ( self ) - > None :
2017-04-15 12:53:10 +02:00
content = ' http://imaging.nikon.com/lineup/dslr/df/img/sample/img_01.jpg \n http://imaging.nikon.com/lineup/dslr/df/img/sample/img_02.jpg \n http://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> '
2017-05-07 17:21:26 +02:00
sender_user_profile = self . example_user ( ' othello ' )
2017-04-15 12:53:10 +02:00
msg = Message ( sender = sender_user_profile , sending_client = get_client ( " test " ) )
converted = render_markdown ( msg , content )
self . assertEqual ( converted , expected )
2017-12-25 21:35:23 +01:00
content = ' http://imaging.nikon.com/lineup/dslr/df/img/sample/img_01.jpg \n \n >http://imaging.nikon.com/lineup/dslr/df/img/sample/img_02.jpg \n \n * http://imaging.nikon.com/lineup/dslr/df/img/sample/img_03.jpg \n * https://www.google.com/images/srpr/logo4w.png '
expected = ' <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><blockquote> \n <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></blockquote> \n <ul> \n <li><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></li> \n <li><div class= " message_inline_image " ><a href= " https://www.google.com/images/srpr/logo4w.png " target= " _blank " title= " https://www.google.com/images/srpr/logo4w.png " ><img src= " https://www.google.com/images/srpr/logo4w.png " ></a></div></li> \n </ul> '
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 )
2017-04-15 12:53:10 +02:00
content = ' Test 1 \n [21136101110_1dde1c1a7e_o.jpg](/user_uploads/1/6d/F1PX6u16JA2P-nK45PyxHIYZ/21136101110_1dde1c1a7e_o.jpg) \n \n Next Image \n [IMG_20161116_023910.jpg](/user_uploads/1/69/sh7L06e7uH7NaX6d5WFfVYQp/IMG_20161116_023910.jpg) \n \n Another 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) '
2017-12-25 21:35:23 +01:00
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 <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><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 <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><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/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> '
2017-04-15 12:53:10 +02:00
msg = Message ( sender = sender_user_profile , sending_client = get_client ( " test " ) )
converted = render_markdown ( msg , content )
self . assertEqual ( converted , expected )
2017-03-13 14:42:03 +01:00
@override_settings ( INLINE_IMAGE_PREVIEW = False )
2017-11-05 10:51:25 +01:00
def test_image_preview_enabled_for_realm ( self ) - > None :
2017-03-13 14:42:03 +01:00
ret = bugdown . image_preview_enabled_for_realm ( )
self . assertEqual ( ret , False )
settings . INLINE_IMAGE_PREVIEW = True
2017-05-07 17:21:26 +02:00
sender_user_profile = self . example_user ( ' othello ' )
2017-03-13 14:42:03 +01:00
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 )
2017-11-05 10:51:25 +01:00
def test_url_embed_preview_enabled_for_realm ( self ) - > None :
2017-05-07 17:21:26 +02:00
sender_user_profile = self . example_user ( ' othello ' )
2017-03-13 14:42:03 +01:00
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 )
2017-05-24 04:21:29 +02:00
ret = bugdown . url_embed_preview_enabled_for_realm ( None )
2017-03-13 14:42:03 +01:00
self . assertEqual ( ret , True )
2017-11-05 10:51:25 +01:00
def test_inline_dropbox ( self ) - > None :
2014-01-31 23:13:58 +01:00
msg = ' Look at how hilarious our old office was: https://www.dropbox.com/s/ymdijjcg67hv2ta/IMG_0923.JPG '
2016-04-30 00:25:58 +02:00
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 )
2014-01-31 23:13:58 +01:00
2014-07-17 02:41:49 +02:00
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> ' )
2014-01-31 23:13:58 +01:00
2014-07-17 02:41:49 +02:00
msg = ' Look at my hilarious drawing folder: https://www.dropbox.com/sh/cm39k9e04z7fhim/AAAII5NK-9daee3FcF41anEua?dl= '
2016-04-30 00:25:58 +02:00
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 )
2014-01-31 23:13:58 +01:00
2016-04-30 00:25:58 +02:00
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> ' )
2014-01-31 23:13:58 +01:00
2017-11-05 10:51:25 +01:00
def test_inline_dropbox_preview ( self ) - > None :
2014-02-26 21:25:27 +01:00
# Test photo album previews
msg = ' https://www.dropbox.com/sc/tditp9nitko60n5/03rEiZldy5 '
2016-04-30 00:25:58 +02:00
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 )
2014-02-26 21:25:27 +01:00
2016-04-30 00:25:58 +02:00
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> ' )
2014-01-31 23:13:58 +01:00
2017-11-05 10:51:25 +01:00
def test_inline_dropbox_negative ( self ) - > None :
2014-01-31 23:13:58 +01:00
# 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 '
2016-04-30 00:25:58 +02:00
with mock . patch ( ' zerver.lib.bugdown.fetch_open_graph_image ' , return_value = None ) :
converted = bugdown_convert ( msg )
2014-01-31 23:13:58 +01:00
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> ' )
2017-11-05 10:51:25 +01:00
def test_inline_dropbox_bad ( self ) - > None :
2014-07-17 02:41:49 +02:00
# Don't fail on bad dropbox links
2016-04-30 00:25:58 +02:00
msg = " https://zulip-test.dropbox.com/photos/cl/ROmr9K1XYtmpneM "
2017-01-30 07:06:34 +01:00
with mock . patch ( ' zerver.lib.bugdown.fetch_open_graph_image ' , return_value = None ) :
converted = bugdown_convert ( msg )
2016-04-30 00:40:52 +02:00
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> ' )
2014-07-17 02:41:49 +02:00
2017-11-05 10:51:25 +01:00
def test_inline_github_preview ( self ) - > None :
2017-05-03 18:42:55 +02:00
# Test photo album previews
2017-11-27 10:08:32 +01:00
msg = ' Test: https://github.com/zulip/zulip/blob/master/static/images/logo/zulip-icon-128x128.png '
2017-05-03 18:42:55 +02:00
converted = bugdown_convert ( msg )
2017-11-27 10:08:32 +01:00
self . assertEqual ( converted , ' <p>Test: <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> ' )
2017-05-03 18:42:55 +02:00
2017-11-27 10:08:32 +01:00
msg = ' Test: https://developer.github.com/assets/images/hero-circuit-bg.png '
2017-05-03 18:42:55 +02:00
converted = bugdown_convert ( msg )
2017-11-27 10:08:32 +01:00
self . assertEqual ( converted , ' <p>Test: <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> ' )
2017-05-03 18:42:55 +02:00
2017-11-05 10:51:25 +01:00
def test_twitter_id_extraction ( self ) - > None :
2014-01-31 23:13:58 +01:00
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 ' )
2017-11-05 10:51:25 +01:00
def test_inline_interesting_links ( self ) - > None :
def make_link ( url : Text ) - > Text :
2014-01-31 23:13:58 +01:00
return ' <a href= " %s " target= " _blank " title= " %s " > %s </a> ' % ( url , url , url )
2017-11-06 18:10:35 +01:00
normal_tweet_html = ( ' <a href= " https://twitter.com/Twitter " target= " _blank " '
' title= " https://twitter.com/Twitter " >@Twitter</a> '
2016-07-16 22:35:27 +02:00
' 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 " '
2017-11-06 18:10:35 +01:00
' title= " http://t.co/6J2EgYM " >http://instagr.am/p/MuW67/</a> ' )
2014-01-31 23:13:58 +01:00
mention_in_link_tweet_html = """ <a href= " http://t.co/@foo " target= " _blank " title= " http://t.co/@foo " >http://foo.com</a> """
2016-07-16 22:35:27 +02:00
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> ' )
2014-01-31 23:13:58 +01:00
2017-09-27 19:39:42 +02:00
emoji_in_tweet_html = """ Zulip is <span class= " emoji emoji-1f4af " title= " hundred points " >:hundred_points:</span> % o pen-source! """
2017-06-19 23:18:55 +02:00
2017-11-05 10:51:25 +01:00
def make_inline_twitter_preview ( url : Text , tweet_html : Text , image_html : Text = ' ' ) - > Text :
2014-01-31 23:13:58 +01:00
## As of right now, all previews are mocked to be the exact same tweet
2016-07-16 22:35:27 +02:00
return ( ' <div class= " inline-preview-twitter " > '
2016-11-30 14:17:35 +01:00
' <div class= " twitter-tweet " > '
' <a href= " %s " target= " _blank " > '
' <img class= " twitter-avatar " '
2017-11-06 18:10:35 +01:00
' src= " https://external-content.zulipcdn.net/1f7cd2436976d410eab8189ebceda87ae0b34ead/687474703a2f2f7062732e7477696d672e63 '
' 6f6d2f70726f66696c655f696d616765732f313338303931323137332f53637265656e5f73686f745f323031312d30362d30335f61745f372e33352e33 '
' 365f504d5f6e6f726d616c2e706e67 " > '
2016-11-30 14:17:35 +01:00
' </a> '
' <p> %s </p> '
2017-11-06 18:10:35 +01:00
' <span>- Eoin McMillan (@imeoin)</span> '
2016-11-30 14:17:35 +01:00
' %s '
' </div> '
2016-07-16 22:35:27 +02:00
' </div> ' ) % ( url , tweet_html , image_html )
2014-01-31 23:13:58 +01:00
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 )
2016-07-16 22:35:27 +02:00
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 ) ) )
2014-01-31 23:13:58 +01:00
msg = ' https://www.twitter.com/wdaher/status/287977969287315456 '
converted = bugdown_convert ( msg )
2016-07-16 22:35:27 +02:00
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 ) ) )
2014-01-31 23:13:58 +01:00
msg = ' http://twitter.com/wdaher/status/287977969287315456 '
converted = bugdown_convert ( msg )
2016-07-16 22:35:27 +02:00
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 ) ) )
2014-01-31 23:13:58 +01:00
# A max of 3 will be converted
2016-07-16 22:35:27 +02:00
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 ' )
2014-01-31 23:13:58 +01:00
converted = bugdown_convert ( msg )
2016-07-16 22:35:27 +02:00
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 ) ) )
2014-01-31 23:13:58 +01:00
# Tweet has a mention in a URL, only the URL is linked
msg = ' http://twitter.com/wdaher/status/287977969287315458 '
converted = bugdown_convert ( msg )
2016-07-16 22:35:27 +02:00
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 ) ) )
2014-01-31 23:13:58 +01:00
# Tweet with an image
msg = ' http://twitter.com/wdaher/status/287977969287315459 '
converted = bugdown_convert ( msg )
2016-07-16 22:35:27 +02:00
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 " > '
2016-11-30 14:17:35 +01:00
' <a href= " http://t.co/xo7pAhK6n3 " target= " _blank " title= " http://t.co/xo7pAhK6n3 " > '
' <img src= " https://pbs.twimg.com/media/BdoEjD4IEAIq86Z.jpg:small " > '
' </a> '
2016-07-16 22:35:27 +02:00
' </div> ' ) ) ) )
2014-01-31 23:13:58 +01:00
2017-06-19 23:18:55 +02:00
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 ) ) )
2017-11-05 10:51:25 +01:00
def test_fetch_tweet_data_settings_validation ( self ) - > None :
2015-10-02 13:01:25 +02:00
with self . settings ( TEST_SUITE = False , TWITTER_CONSUMER_KEY = None ) :
2015-09-30 09:55:56 +02:00
self . assertIs ( None , bugdown . fetch_tweet_data ( ' 287977969287315459 ' ) )
2017-11-05 10:51:25 +01:00
def test_content_has_emoji ( self ) - > None :
2017-09-15 03:08:15 +02:00
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: :::::: ' ) )
2017-11-05 10:51:25 +01:00
def test_realm_emoji ( self ) - > None :
def emoji_img ( name : Text , file_name : Text , realm_id : int ) - > Text :
2017-03-13 05:45:50 +01:00
return ' <img alt= " %s " class= " emoji " src= " %s " title= " %s " > ' % (
2017-06-09 10:30:24 +02:00
name , get_emoji_url ( file_name , realm_id ) , name [ 1 : - 1 ] . replace ( " _ " , " " ) )
2014-01-31 23:13:58 +01:00
2017-01-04 05:30:48 +01:00
realm = get_realm ( ' zulip ' )
2014-01-31 23:13:58 +01:00
# Needs to mock an actual message because that's how bugdown obtains the realm
2017-05-07 17:21:26 +02:00
msg = Message ( sender = self . example_user ( ' hamlet ' ) )
2017-07-18 00:22:27 +02:00
converted = bugdown . convert ( " :green_tick: " , message_realm = realm , message = msg )
2018-03-11 18:55:20 +01:00
realm_emoji = RealmEmoji . objects . filter ( realm = realm ,
name = ' green_tick ' ,
deactivated = False ) . get ( )
self . assertEqual ( converted , ' <p> %s </p> ' % ( emoji_img ( ' :green_tick: ' , realm_emoji . file_name , realm . id ) ) )
2014-01-31 23:13:58 +01:00
2017-07-18 00:22:27 +02:00
# 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> ' )
2014-01-31 23:13:58 +01:00
2017-11-05 10:51:25 +01:00
def test_deactivated_realm_emoji ( self ) - > None :
2017-07-18 00:22:27 +02:00
# Deactivate realm emoji.
2017-05-23 08:41:30 +02:00
realm = get_realm ( ' zulip ' )
2017-07-18 00:22:27 +02:00
do_remove_realm_emoji ( realm , ' green_tick ' )
2017-05-23 08:41:30 +02:00
msg = Message ( sender = self . example_user ( ' hamlet ' ) )
2017-07-18 00:22:27 +02:00
converted = bugdown . convert ( " :green_tick: " , message_realm = realm , message = msg )
self . assertEqual ( converted , ' <p>:green_tick:</p> ' )
2017-05-23 08:41:30 +02:00
2017-11-05 10:51:25 +01:00
def test_unicode_emoji ( self ) - > None :
2016-06-24 20:03:56 +02:00
msg = u ' \u2615 ' # ☕
converted = bugdown_convert ( msg )
2017-09-27 19:39:42 +02:00
self . assertEqual ( converted , u ' <p><span class= " emoji emoji-2615 " title= " coffee " >:coffee:</span></p> ' )
2016-06-24 20:03:56 +02:00
msg = u ' \u2615 \u2615 ' # ☕☕
converted = bugdown_convert ( msg )
2017-09-27 19:39:42 +02:00
self . assertEqual ( converted , u ' <p><span class= " emoji emoji-2615 " title= " coffee " >:coffee:</span><span class= " emoji emoji-2615 " title= " coffee " >:coffee:</span></p> ' )
2017-06-20 15:52:14 +02:00
2018-01-15 19:36:32 +01:00
def test_no_translate_emoticons_if_off ( self ) - > None :
user_profile = self . example_user ( ' othello ' )
do_set_user_display_setting ( user_profile , ' translate_emoticons ' , False )
msg = Message ( sender = user_profile , sending_client = get_client ( " test " ) )
content = u ' :) '
expected = u ' <p>:)</p> '
converted = render_markdown ( msg , content )
self . assertEqual ( converted , expected )
2017-11-05 10:51:25 +01:00
def test_same_markup ( self ) - > None :
2017-06-20 15:52:14 +02:00
msg = u ' \u2615 ' # ☕
unicode_converted = bugdown_convert ( msg )
msg = u ' :coffee: ' # ☕☕
converted = bugdown_convert ( msg )
self . assertEqual ( converted , unicode_converted )
2016-06-24 20:03:56 +02:00
2017-11-05 10:51:25 +01:00
def test_realm_patterns ( self ) - > None :
2017-01-04 05:30:48 +01:00
realm = get_realm ( ' zulip ' )
2016-09-19 23:30:41 +02:00
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 (
2017-10-27 09:06:40 +02:00
realm_filter . __str__ ( ) ,
2017-03-13 17:27:21 +01:00
' <RealmFilter(zulip): #(?P<id>[0-9] { 2,8}) '
2016-09-19 23:30:41 +02:00
' https://trac.zulip.net/ticket/ %(id)s > ' )
2017-05-07 17:21:26 +02:00
msg = Message ( sender = self . example_user ( ' othello ' ) ,
2016-06-01 04:45:00 +02:00
subject = " #444 " )
2014-01-31 23:13:58 +01:00
2016-09-23 20:06:37 +02:00
flush_per_request_caches ( )
2014-01-31 23:13:58 +01:00
content = " We should fix #224 and #115, but not issue#124 or #1124z or [trac #15](https://trac.zulip.net/ticket/16) today. "
2017-01-22 06:29:11 +01:00
converted = bugdown . convert ( content , message_realm = realm , message = msg )
2016-12-31 03:08:43 +01:00
converted_subject = bugdown . subject_links ( realm . id , msg . subject )
2014-01-31 23:13:58 +01:00
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> ' )
2017-01-24 06:21:14 +01:00
self . assertEqual ( converted_subject , [ u ' https://trac.zulip.net/ticket/444 ' ] )
2014-01-31 23:13:58 +01:00
2016-12-31 03:08:43 +01:00
RealmFilter ( realm = realm , pattern = r ' #(?P<id>[a-zA-Z]+-[0-9]+) ' ,
2016-02-13 19:17:15 +01:00
url_format_string = r ' https://trac.zulip.net/ticket/ %(id)s ' ) . save ( )
2017-05-07 17:21:26 +02:00
msg = Message ( sender = self . example_user ( ' hamlet ' ) )
2016-02-13 19:17:15 +01:00
content = ' #ZUL-123 was fixed and code was deployed to production, also #zul-321 was deployed to staging '
2017-01-22 06:29:11 +01:00
converted = bugdown . convert ( content , message_realm = realm , message = msg )
2016-02-13 19:17:15 +01:00
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> ' )
2017-11-05 10:51:25 +01:00
def test_maybe_update_markdown_engines ( self ) - > None :
2017-01-04 05:30:48 +01:00
realm = get_realm ( ' zulip ' )
2016-09-23 21:02:22 +02:00
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 = { }
2017-11-11 15:30:19 +01:00
bugdown . maybe_update_markdown_engines ( None , False )
2016-09-23 21:02:22 +02:00
all_filters = bugdown . realm_filter_data
2016-12-31 03:08:43 +01:00
zulip_filters = all_filters [ realm . id ]
2016-09-23 21:02:22 +02:00
self . assertEqual ( len ( zulip_filters ) , 1 )
self . assertEqual ( zulip_filters [ 0 ] ,
2016-12-03 00:04:17 +01:00
( u ' #(?P<id>[0-9] { 2,8}) ' , u ' https://trac.zulip.net/ticket/ %(id)s ' , realm_filter . id ) )
2016-09-23 21:02:22 +02:00
2017-11-05 10:51:25 +01:00
def test_flush_realm_filter ( self ) - > None :
2017-01-04 05:30:48 +01:00
realm = get_realm ( ' zulip ' )
2016-09-23 21:55:21 +02:00
2017-11-05 10:51:25 +01:00
def flush ( ) - > None :
2016-09-23 21:55:21 +02:00
'''
flush_realm_filter is a post - save hook , so calling it
directly for testing is kind of awkward
'''
2017-11-05 11:49:43 +01:00
class Instance :
2017-07-11 21:29:40 +02:00
realm_id = None # type: Optional[int]
2016-09-23 21:55:21 +02:00
instance = Instance ( )
2017-01-03 21:04:55 +01:00
instance . realm_id = realm . id
2016-09-23 21:55:21 +02:00
flush_realm_filter ( sender = None , instance = instance )
2017-11-05 10:51:25 +01:00
def save_new_realm_filter ( ) - > None :
2016-09-23 21:55:21 +02:00
realm_filter = RealmFilter ( realm = realm ,
pattern = r " whatever " ,
url_format_string = ' whatever ' )
realm_filter . save ( )
2017-01-08 20:24:05 +01:00
# start fresh for our realm
2016-09-23 21:55:21 +02:00
flush ( )
2016-12-31 03:08:43 +01:00
self . assertFalse ( realm_in_local_realm_filters_cache ( realm . id ) )
2016-09-23 21:55:21 +02:00
# call this just for side effects of populating the cache
2016-12-31 03:08:43 +01:00
realm_filters_for_realm ( realm . id )
self . assertTrue ( realm_in_local_realm_filters_cache ( realm . id ) )
2016-09-23 21:55:21 +02:00
# Saving a new RealmFilter should have the side effect of
# flushing the cache.
save_new_realm_filter ( )
2016-12-31 03:08:43 +01:00
self . assertFalse ( realm_in_local_realm_filters_cache ( realm . id ) )
2016-09-23 21:55:21 +02:00
# and flush it one more time, to make sure we don't get a KeyError
flush ( )
2016-12-31 03:08:43 +01:00
self . assertFalse ( realm_in_local_realm_filters_cache ( realm . id ) )
2016-09-23 21:55:21 +02:00
2017-11-05 10:51:25 +01:00
def test_realm_patterns_negative ( self ) - > None :
2017-01-04 05:30:48 +01:00
realm = get_realm ( ' zulip ' )
2016-06-01 04:50:26 +02:00
RealmFilter ( realm = realm , pattern = r " #(?P<id>[0-9] { 2,8}) " ,
url_format_string = r " https://trac.zulip.net/ticket/ %(id)s " ) . save ( )
2017-05-07 17:21:26 +02:00
boring_msg = Message ( sender = self . example_user ( ' othello ' ) ,
2016-06-01 04:50:26 +02:00
subject = u " no match here " )
2016-12-31 03:08:43 +01:00
converted_boring_subject = bugdown . subject_links ( realm . id , boring_msg . subject )
2017-01-24 06:21:14 +01:00
self . assertEqual ( converted_boring_subject , [ ] )
2016-06-01 04:50:26 +02:00
2017-11-05 10:51:25 +01:00
def test_is_status_message ( self ) - > None :
2017-05-07 17:21:26 +02:00
user_profile = self . example_user ( ' othello ' )
2016-10-03 17:53:53 +02:00
msg = Message ( sender = user_profile , sending_client = get_client ( " test " ) )
content = ' /me makes a list \n * one \n * two '
2016-10-04 18:32:46 +02:00
rendered_content = render_markdown ( msg , content )
2016-10-03 17:53:53 +02:00
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 '
2016-10-04 18:32:46 +02:00
rendered_content = render_markdown ( msg , content )
2016-10-03 17:53:53 +02:00
self . assertEqual (
rendered_content ,
' <p>/me takes a walk</p> '
)
self . assertTrue ( Message . is_status_message ( content , rendered_content ) )
2018-01-21 19:27:36 +01:00
content = ' /me writes a second line \n line '
rendered_content = render_markdown ( msg , content )
self . assertEqual (
rendered_content ,
' <p>/me writes a second line<br> \n line</p> '
)
self . assertFalse ( Message . is_status_message ( content , rendered_content ) )
2017-11-05 10:51:25 +01:00
def test_alert_words ( self ) - > None :
2017-05-07 17:21:26 +02:00
user_profile = self . example_user ( ' othello ' )
2016-06-01 05:02:43 +02:00
do_set_alert_words ( user_profile , [ " ALERTWORD " , " scaryword " ] )
msg = Message ( sender = user_profile , sending_client = get_client ( " test " ) )
2016-09-14 18:02:24 +02:00
realm_alert_words = alert_words_in_realm ( user_profile . realm )
2017-11-05 10:51:25 +01:00
def render ( msg : Message , content : Text ) - > Text :
2016-10-04 18:32:46 +02:00
return render_markdown ( msg ,
content ,
realm_alert_words = realm_alert_words ,
2017-09-09 02:50:57 +02:00
user_ids = { user_profile . id } )
2016-06-01 05:02:43 +02:00
content = " We have an ALERTWORD day today! "
2016-09-14 18:02:24 +02:00
self . assertEqual ( render ( msg , content ) , " <p>We have an ALERTWORD day today!</p> " )
2016-06-01 05:02:43 +02:00
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! "
2016-09-14 18:02:24 +02:00
self . assertEqual ( render ( msg , content ) , " <p>We have a NOTHINGWORD day today!</p> " )
2016-06-01 05:02:43 +02:00
self . assertEqual ( msg . user_ids_with_alert_words , set ( ) )
2017-11-05 10:51:25 +01:00
def test_mention_wildcard ( self ) - > None :
2017-05-07 17:21:26 +02:00
user_profile = self . example_user ( ' othello ' )
2016-06-01 05:24:01 +02:00
msg = Message ( sender = user_profile , sending_client = get_client ( " test " ) )
2018-01-24 17:18:07 +01:00
content = " @**all** test "
2016-10-04 18:32:46 +02:00
self . assertEqual ( render_markdown ( msg , content ) ,
2018-01-21 06:33:42 +01:00
' <p><span class= " user-mention " data-user-id= " * " > '
2017-02-02 21:19:25 +01:00
' @all '
' </span> test</p> ' )
2016-06-01 05:24:01 +02:00
self . assertTrue ( msg . mentions_wildcard )
2017-11-05 10:51:25 +01:00
def test_mention_everyone ( self ) - > None :
2017-05-07 17:21:26 +02:00
user_profile = self . example_user ( ' othello ' )
2016-06-01 05:24:01 +02:00
msg = Message ( sender = user_profile , sending_client = get_client ( " test " ) )
2018-01-24 17:18:07 +01:00
content = " @**everyone** test "
2016-10-04 18:32:46 +02:00
self . assertEqual ( render_markdown ( msg , content ) ,
2018-01-21 06:33:42 +01:00
' <p><span class= " user-mention " data-user-id= " * " > '
2018-01-24 17:18:07 +01:00
' @everyone '
' </span> test</p> ' )
2016-06-01 05:24:01 +02:00
self . assertTrue ( msg . mentions_wildcard )
2018-04-03 17:55:57 +02:00
def test_mention_stream ( self ) - > None :
user_profile = self . example_user ( ' othello ' )
msg = Message ( sender = user_profile , sending_client = get_client ( " test " ) )
content = " @**stream** test "
self . assertEqual ( render_markdown ( msg , content ) ,
' <p><span class= " user-mention " data-user-id= " * " > '
' @stream '
' </span> test</p> ' )
self . assertTrue ( msg . mentions_wildcard )
2018-01-24 17:18:07 +01:00
def test_mention_at_wildcard ( self ) - > 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>@all test</p> ' )
self . assertFalse ( msg . mentions_wildcard )
self . assertEqual ( msg . mentions_user_ids , set ( [ ] ) )
def test_mention_at_everyone ( self ) - > 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>@everyone test</p> ' )
self . assertFalse ( msg . mentions_wildcard )
self . assertEqual ( msg . mentions_user_ids , set ( [ ] ) )
def test_mention_word_starting_with_at_wildcard ( self ) - > None :
user_profile = self . example_user ( ' othello ' )
msg = Message ( sender = user_profile , sending_client = get_client ( " test " ) )
content = " test @alleycat.com test "
self . assertEqual ( render_markdown ( msg , content ) ,
' <p>test @alleycat.com test</p> ' )
self . assertFalse ( msg . mentions_wildcard )
self . assertEqual ( msg . mentions_user_ids , set ( [ ] ) )
def test_mention_at_normal_user ( self ) - > None :
2017-08-16 20:18:09 +02:00
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 ( [ ] ) )
2017-11-05 10:51:25 +01:00
def test_mention_single ( self ) - > None :
2017-05-07 17:21:26 +02:00
sender_user_profile = self . example_user ( ' othello ' )
user_profile = self . example_user ( ' hamlet ' )
2016-06-01 05:24:01 +02:00
msg = Message ( sender = sender_user_profile , sending_client = get_client ( " test " ) )
2017-01-20 18:27:30 +01:00
user_id = user_profile . id
2016-06-01 05:24:01 +02:00
content = " @**King Hamlet** "
2016-10-04 18:32:46 +02:00
self . assertEqual ( render_markdown ( msg , content ) ,
2017-02-02 21:19:25 +01:00
' <p><span class= " user-mention " '
' data-user-id= " %s " > '
2018-01-21 06:33:42 +01:00
' @King Hamlet</span></p> ' % ( user_id ) )
2016-06-01 05:24:01 +02:00
self . assertEqual ( msg . mentions_user_ids , set ( [ user_profile . id ] ) )
2017-11-05 10:51:25 +01:00
def test_possible_mentions ( self ) - > None :
def assert_mentions ( content : Text , names : Set [ Text ] ) - > None :
2017-09-14 19:47:22 +02:00
self . assertEqual ( possible_mentions ( content ) , names )
assert_mentions ( ' ' , set ( ) )
assert_mentions ( ' boring ' , set ( ) )
2018-01-24 17:18:07 +01:00
assert_mentions ( ' @**all** ' , set ( ) )
2017-09-14 19:47:22 +02:00
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 ' }
)
2017-11-05 10:51:25 +01:00
def test_mention_multiple ( self ) - > None :
2017-05-07 17:21:26 +02:00
sender_user_profile = self . example_user ( ' othello ' )
hamlet = self . example_user ( ' hamlet ' )
cordelia = self . example_user ( ' cordelia ' )
2016-06-01 05:24:01 +02:00
msg = Message ( sender = sender_user_profile , sending_client = get_client ( " test " ) )
2017-06-19 17:03:04 +02:00
content = " @**King Hamlet** and @**Cordelia Lear**, check this out "
2017-09-14 19:47:22 +02:00
2016-10-04 18:32:46 +02:00
self . assertEqual ( render_markdown ( msg , content ) ,
2016-06-01 05:24:01 +02:00
' <p> '
' <span class= " user-mention " '
2017-01-20 18:27:30 +01:00
' data-user-id= " %s " >@King Hamlet</span> and '
2016-06-01 05:24:01 +02:00
' <span class= " user-mention " '
2017-01-20 18:27:30 +01:00
' data-user-id= " %s " >@Cordelia Lear</span>, '
2018-01-21 06:33:42 +01:00
' check this out</p> ' % ( hamlet . id , cordelia . id ) )
2016-06-01 05:24:01 +02:00
self . assertEqual ( msg . mentions_user_ids , set ( [ hamlet . id , cordelia . id ] ) )
2017-11-05 10:51:25 +01:00
def test_mention_invalid ( self ) - > None :
2017-05-07 17:21:26 +02:00
sender_user_profile = self . example_user ( ' othello ' )
2016-06-01 05:24:01 +02:00
msg = Message ( sender = sender_user_profile , sending_client = get_client ( " test " ) )
content = " Hey @**Nonexistent User** "
2016-10-04 18:32:46 +02:00
self . assertEqual ( render_markdown ( msg , content ) ,
2016-06-01 05:24:01 +02:00
' <p>Hey @<strong>Nonexistent User</strong></p> ' )
self . assertEqual ( msg . mentions_user_ids , set ( ) )
2017-11-05 10:51:25 +01:00
def create_user_group_for_test ( self , user_group_name : Text ) - > UserGroup :
2017-09-25 09:47:15 +02:00
othello = self . example_user ( ' othello ' )
return create_user_group ( user_group_name , [ othello ] , get_realm ( ' zulip ' ) )
2017-11-05 10:51:25 +01:00
def test_user_group_mention_single ( self ) - > None :
2017-09-25 09:47:15 +02:00
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
user_group = self . create_user_group_for_test ( ' support ' )
content = " @**King Hamlet** @*support* "
self . assertEqual ( render_markdown ( msg , content ) ,
' <p><span class= " user-mention " '
' data-user-id= " %s " > '
' @King Hamlet</span> '
' <span class= " user-group-mention " '
' data-user-group-id= " %s " > '
2018-01-21 06:33:42 +01:00
' @support</span></p> ' % ( user_id ,
2017-09-25 09:47:15 +02:00
user_group . id ) )
self . assertEqual ( msg . mentions_user_ids , set ( [ user_profile . id ] ) )
self . assertEqual ( msg . mentions_user_group_ids , set ( [ user_group . id ] ) )
2017-11-05 10:51:25 +01:00
def test_possible_user_group_mentions ( self ) - > None :
def assert_mentions ( content : Text , names : Set [ Text ] ) - > None :
2017-09-25 09:47:15 +02:00
self . assertEqual ( possible_user_group_mentions ( content ) , names )
assert_mentions ( ' ' , set ( ) )
assert_mentions ( ' boring ' , set ( ) )
2018-01-24 17:18:07 +01:00
assert_mentions ( ' @**all** ' , set ( ) )
2017-09-25 09:47:15 +02:00
assert_mentions ( ' smush@*steve*smush ' , set ( ) )
assert_mentions (
' @*support* Hello @**King Hamlet** and @**Cordelia Lear** \n '
' @**Foo van Barson** @**all** ' , { ' support ' }
)
assert_mentions (
' Attention @*support*, @*frontend* and @*backend* \n groups. ' ,
{ ' support ' , ' frontend ' , ' backend ' }
)
2017-11-05 10:51:25 +01:00
def test_user_group_mention_multiple ( self ) - > None :
2017-09-25 09:47:15 +02:00
sender_user_profile = self . example_user ( ' othello ' )
msg = Message ( sender = sender_user_profile , sending_client = get_client ( " test " ) )
support = self . create_user_group_for_test ( ' support ' )
backend = self . create_user_group_for_test ( ' backend ' )
content = " @*support* and @*backend*, check this out "
self . assertEqual ( render_markdown ( msg , content ) ,
' <p> '
' <span class= " user-group-mention " '
' data-user-group-id= " %s " > '
' @support</span> '
' and '
' <span class= " user-group-mention " '
' data-user-group-id= " %s " > '
' @backend</span>, '
' check this out '
' </p> ' % ( support . id , backend . id ) )
self . assertEqual ( msg . mentions_user_group_ids , set ( [ support . id , backend . id ] ) )
2017-11-05 10:51:25 +01:00
def test_user_group_mention_invalid ( self ) - > None :
2017-09-25 09:47:15 +02:00
sender_user_profile = self . example_user ( ' othello ' )
msg = Message ( sender = sender_user_profile , sending_client = get_client ( " test " ) )
content = " Hey @*Nonexistent group* "
self . assertEqual ( render_markdown ( msg , content ) ,
' <p>Hey @<em>Nonexistent group</em></p> ' )
self . assertEqual ( msg . mentions_user_group_ids , set ( ) )
2017-11-05 10:51:25 +01:00
def test_stream_single ( self ) - > None :
2017-01-04 05:30:48 +01:00
denmark = get_stream ( ' Denmark ' , get_realm ( ' zulip ' ) )
2017-05-07 17:21:26 +02:00
sender_user_profile = self . example_user ( ' othello ' )
2016-10-26 20:56:17 +02:00
msg = Message ( sender = sender_user_profile , sending_client = get_client ( " test " ) )
content = " #**Denmark** "
self . assertEqual (
render_markdown ( msg , content ) ,
2018-02-15 21:02:47 +01:00
' <p><a class= " stream " data-stream-id= " {d.id} " href= " /#narrow/stream/ {d.id} -Denmark " ># {d.name} </a></p> ' . format (
2016-10-26 20:56:17 +02:00
d = denmark
) )
2017-11-05 10:51:25 +01:00
def test_stream_multiple ( self ) - > None :
2017-05-07 17:21:26 +02:00
sender_user_profile = self . example_user ( ' othello ' )
2016-10-26 20:56:17 +02:00
msg = Message ( sender = sender_user_profile , sending_client = get_client ( " test " ) )
2017-01-04 05:30:48 +01:00
realm = get_realm ( ' zulip ' )
2016-10-26 20:56:17 +02:00
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} " '
2018-02-15 21:02:47 +01:00
' href= " /#narrow/stream/ {denmark.id} -Denmark " ># {denmark.name} </a> and '
2016-10-26 20:56:17 +02:00
' <a class= " stream " '
' data-stream-id= " {scotland.id} " '
2018-02-15 21:02:47 +01:00
' href= " /#narrow/stream/ {scotland.id} -Scotland " ># {scotland.name} </a>, '
2016-10-26 20:56:17 +02:00
' there something</p> ' . format ( denmark = denmark , scotland = scotland ) )
2017-11-05 10:51:25 +01:00
def test_stream_case_sensitivity ( self ) - > None :
2017-01-04 05:30:48 +01:00
realm = get_realm ( ' zulip ' )
2016-10-26 20:56:17 +02:00
case_sens = Stream . objects . create ( name = ' CaseSens ' , realm = realm )
2017-05-07 17:21:26 +02:00
sender_user_profile = self . example_user ( ' othello ' )
2016-10-26 20:56:17 +02:00
msg = Message ( sender = sender_user_profile , sending_client = get_client ( " test " ) )
content = " #**CaseSens** "
self . assertEqual (
render_markdown ( msg , content ) ,
2018-02-15 21:02:47 +01:00
' <p><a class= " stream " data-stream-id= " {s.id} " href= " /#narrow/stream/ {s.id} - {s.name} " ># {s.name} </a></p> ' . format (
2016-10-26 20:56:17 +02:00
s = case_sens
) )
2017-11-05 10:51:25 +01:00
def test_stream_case_sensitivity_nonmatching ( self ) - > None :
2016-10-26 20:56:17 +02:00
""" #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 . """
2017-01-04 05:30:48 +01:00
realm = get_realm ( ' zulip ' )
2016-10-26 20:56:17 +02:00
Stream . objects . create ( name = ' CaseSens ' , realm = realm )
2017-05-07 17:21:26 +02:00
sender_user_profile = self . example_user ( ' othello ' )
2016-10-26 20:56:17 +02:00
msg = Message ( sender = sender_user_profile , sending_client = get_client ( " test " ) )
content = " #**casesens** "
self . assertEqual (
render_markdown ( msg , content ) ,
' <p>#<strong>casesens</strong></p> ' )
2017-11-05 10:51:25 +01:00
def test_possible_stream_names ( self ) - > None :
2017-09-15 00:25:38 +02:00
content = ''' #**test here**
This mentions #**Denmark** too.
#**garçon** #**천국** @**Ignore Person**
'''
self . assertEqual (
bugdown . possible_linked_stream_names ( content ) ,
{ ' test here ' , ' Denmark ' , ' garçon ' , ' 천국 ' }
)
2017-11-05 10:51:25 +01:00
def test_stream_unicode ( self ) - > None :
2017-01-04 05:30:48 +01:00
realm = get_realm ( ' zulip ' )
2016-10-26 20:56:17 +02:00
uni = Stream . objects . create ( name = u ' привет ' , realm = realm )
2017-05-07 17:21:26 +02:00
sender_user_profile = self . example_user ( ' othello ' )
2016-10-26 20:56:17 +02:00
msg = Message ( sender = sender_user_profile , sending_client = get_client ( " test " ) )
content = u " #**привет** "
2018-02-15 21:02:47 +01:00
quoted_name = ' .D0.BF.D1.80.D0.B8.D0.B2.D0.B5.D1.82 '
href = ' /#narrow/stream/ {stream_id} - {quoted_name} ' . format (
stream_id = uni . id ,
quoted_name = quoted_name )
2016-10-26 20:56:17 +02:00
self . assertEqual (
render_markdown ( msg , content ) ,
2018-02-15 21:02:47 +01:00
u ' <p><a class= " stream " data-stream-id= " {s.id} " href= " {href} " ># {s.name} </a></p> ' . format (
2016-10-26 20:56:17 +02:00
s = uni ,
2018-02-15 21:02:47 +01:00
href = href ,
2016-10-26 20:56:17 +02:00
) )
2017-11-05 10:51:25 +01:00
def test_stream_invalid ( self ) - > None :
2017-05-07 17:21:26 +02:00
sender_user_profile = self . example_user ( ' othello ' )
2016-10-26 20:56:17 +02:00
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 ( ) )
2017-11-05 10:51:25 +01:00
def test_in_app_modal_link ( self ) - > None :
2014-01-31 23:13:58 +01:00
msg = ' !modal_link(#settings, Settings page) '
converted = bugdown_convert ( msg )
self . assertEqual (
converted ,
' <p> '
2017-06-03 21:36:16 +02:00
' <a href= " #settings " title= " #settings " >Settings page</a> '
2014-01-31 23:13:58 +01:00
' </p> '
)
2017-11-05 10:51:25 +01:00
def test_image_preview_title ( self ) - > None :
2016-09-22 22:39:24 +02:00
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> '
)
2017-11-05 10:51:25 +01:00
def test_mit_rendering ( self ) - > None :
2016-09-09 22:53:36 +02:00
""" Test the markdown configs for the MIT Zephyr mirroring system;
verifies almost all inline patterns are disabled , but
inline_interesting_links is still enabled """
2014-01-31 23:13:58 +01:00
msg = " **test** "
2017-03-04 09:19:37 +01:00
realm = get_realm ( " zephyr " )
2017-01-22 06:29:11 +01:00
client = get_client ( " zephyr_mirror " )
message = Message ( sending_client = client ,
2017-05-23 01:27:31 +02:00
sender = self . mit_user ( " sipbtest " ) )
2017-01-22 06:29:11 +01:00
converted = bugdown . convert ( msg , message_realm = realm , message = message )
2014-01-31 23:13:58 +01:00
self . assertEqual (
converted ,
" <p>**test**</p> " ,
2017-01-24 06:34:26 +01:00
)
2014-02-04 23:37:21 +01:00
msg = " * test "
2017-01-22 06:29:11 +01:00
converted = bugdown . convert ( msg , message_realm = realm , message = message )
2014-02-04 23:37:21 +01:00
self . assertEqual (
converted ,
" <p>* test</p> " ,
2017-01-24 06:34:26 +01:00
)
2014-02-07 22:05:19 +01:00
msg = " https://lists.debian.org/debian-ctte/2014/02/msg00173.html "
2017-01-22 06:29:11 +01:00
converted = bugdown . convert ( msg , message_realm = realm , message = message )
2014-02-07 22:05:19 +01:00
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> ' ,
2017-01-24 06:34:26 +01:00
)
2014-01-31 23:13:58 +01:00
2017-11-05 10:51:25 +01:00
def test_url_to_a ( self ) - > None :
2017-07-23 00:34:48 +02:00
url = ' javascript://example.com/invalidURL '
converted = bugdown . url_to_a ( url , url )
self . assertEqual (
converted ,
' javascript://example.com/invalidURL ' ,
)
2017-11-05 10:51:25 +01:00
def test_disabled_code_block_processor ( self ) - > None :
2017-11-03 12:13:17 +01:00
msg = " Hello, \n \n " + \
" I am writing this message to test something. I am writing this message to test something. "
converted = bugdown_convert ( msg )
expected_output = ' <p>Hello,</p> \n ' + \
' <div class= " codehilite " ><pre><span></span>I am writing this message to test something. I am writing this message to test something. \n ' + \
' </pre></div> '
self . assertEqual ( converted , expected_output )
realm = Realm . objects . create ( string_id = ' code_block_processor_test ' )
2017-11-11 16:00:46 +01:00
bugdown . maybe_update_markdown_engines ( realm . id , True )
2017-11-03 12:13:17 +01:00
converted = bugdown . convert ( msg , message_realm = realm , email_gateway = True )
expected_output = ' <p>Hello,</p> \n ' + \
' <p>I am writing this message to test something. I am writing this message to test something.</p> '
self . assertEqual ( converted , expected_output )
2017-11-05 10:51:25 +01:00
def test_normal_link ( self ) - > None :
2017-10-31 22:03:39 +01:00
realm = get_realm ( " zulip " )
sender_user_profile = self . example_user ( ' othello ' )
message = Message ( sender = sender_user_profile , sending_client = get_client ( " test " ) )
msg = " http://example.com/#settings/ "
self . assertEqual (
bugdown . convert ( msg , message_realm = realm , message = message ) ,
' <p><a href= " http://example.com/#settings/ " target= " _blank " title= " http://example.com/#settings/ " >http://example.com/#settings/</a></p> '
)
2017-11-05 10:51:25 +01:00
def test_relative_link ( self ) - > None :
2017-10-31 22:03:39 +01:00
realm = get_realm ( " zulip " )
sender_user_profile = self . example_user ( ' othello ' )
message = Message ( sender = sender_user_profile , sending_client = get_client ( " test " ) )
2018-02-19 16:39:14 +01:00
msg = " http://zulip.testserver/#narrow/stream/999-hello "
2017-10-31 22:03:39 +01:00
self . assertEqual (
bugdown . convert ( msg , message_realm = realm , message = message ) ,
2018-02-19 16:39:14 +01:00
' <p><a href= " #narrow/stream/999-hello " title= " #narrow/stream/999-hello " >http://zulip.testserver/#narrow/stream/999-hello</a></p> '
2017-10-31 22:03:39 +01:00
)
2018-04-02 19:31:21 +02:00
def test_relative_link_streams_page ( self ) - > None :
realm = get_realm ( " zulip " )
sender_user_profile = self . example_user ( ' othello ' )
message = Message ( sender = sender_user_profile , sending_client = get_client ( " test " ) )
msg = " http://zulip.testserver/#streams/all "
self . assertEqual (
bugdown . convert ( msg , message_realm = realm , message = message ) ,
' <p><a href= " #streams/all " target= " _blank " title= " #streams/all " >http://zulip.testserver/#streams/all</a></p> '
)
2017-12-11 17:54:14 +01:00
def test_md_relative_link ( self ) - > None :
realm = get_realm ( " zulip " )
sender_user_profile = self . example_user ( ' othello ' )
message = Message ( sender = sender_user_profile , sending_client = get_client ( " test " ) )
2018-02-19 16:39:14 +01:00
msg = " [hello](http://zulip.testserver/#narrow/stream/999-hello) "
2017-12-11 17:54:14 +01:00
self . assertEqual (
bugdown . convert ( msg , message_realm = realm , message = message ) ,
2018-02-19 16:39:14 +01:00
' <p><a href= " #narrow/stream/999-hello " title= " #narrow/stream/999-hello " >hello</a></p> '
2017-12-11 17:54:14 +01:00
)
2016-09-19 20:44:15 +02:00
class BugdownApiTests ( ZulipTestCase ) :
2017-11-05 10:51:25 +01:00
def test_render_message_api ( self ) - > None :
2016-09-19 20:44:15 +02:00
content = ' That is a **bold** statement '
2017-12-14 19:02:31 +01:00
result = self . api_post (
self . example_email ( " othello " ) ,
2016-09-19 20:44:15 +02:00
' /api/v1/messages/render ' ,
2017-12-14 19:02:31 +01:00
dict ( content = content )
2016-09-19 20:44:15 +02:00
)
self . assert_json_success ( result )
2017-08-16 09:50:29 +02:00
self . assertEqual ( result . json ( ) [ ' rendered ' ] ,
2016-12-03 00:04:17 +01:00
u ' <p>That is a <strong>bold</strong> statement</p> ' )
2016-09-19 20:44:15 +02:00
2017-11-05 10:51:25 +01:00
def test_render_mention_stream_api ( self ) - > None :
2016-11-08 23:09:53 +01:00
""" Determines whether we ' re correctly passing the realm context """
2016-11-07 20:40:40 +01:00
content = ' This mentions #**Denmark** and @**King Hamlet**. '
2017-12-14 19:02:31 +01:00
result = self . api_post (
self . example_email ( " othello " ) ,
2016-11-07 20:40:40 +01:00
' /api/v1/messages/render ' ,
2017-12-14 19:02:31 +01:00
dict ( content = content )
2016-11-07 20:40:40 +01:00
)
self . assert_json_success ( result )
2017-05-07 17:21:26 +02:00
user_id = self . example_user ( ' hamlet ' ) . id
2018-02-15 21:02:47 +01:00
stream_id = get_stream ( ' Denmark ' , get_realm ( ' zulip ' ) ) . id
2017-08-16 09:50:29 +02:00
self . assertEqual ( result . json ( ) [ ' rendered ' ] ,
2018-01-21 06:33:42 +01:00
u ' <p>This mentions <a class= " stream " data-stream-id= " %s " href= " /#narrow/stream/ %s -Denmark " >#Denmark</a> and <span class= " user-mention " data-user-id= " %s " >@King Hamlet</span>.</p> ' % ( stream_id , stream_id , user_id ) )
2016-11-07 20:40:40 +01:00
2016-09-15 22:05:56 +02:00
class BugdownErrorTests ( ZulipTestCase ) :
2017-11-05 10:51:25 +01:00
def test_bugdown_error_handling ( self ) - > None :
2016-09-15 22:05:56 +02:00
with self . simulated_markdown_failure ( ) :
2016-09-15 22:23:25 +02:00
with self . assertRaises ( bugdown . BugdownRenderingException ) :
2016-12-31 03:08:43 +01:00
bugdown_convert ( ' ' )
2016-09-15 22:05:56 +02:00
2017-11-05 10:51:25 +01:00
def test_send_message_errors ( self ) - > None :
2016-09-15 22:05:56 +02:00
message = ' whatever '
with self . simulated_markdown_failure ( ) :
2016-12-16 02:11:42 +01:00
# We don't use assertRaisesRegex because it seems to not
2016-09-16 20:49:30 +02:00
# handle i18n properly here on some systems.
with self . assertRaises ( JsonableError ) :
2017-10-28 16:27:37 +02:00
self . send_stream_message ( self . example_email ( " othello " ) , " Denmark " , message )
2016-10-24 16:42:43 +02:00
2018-02-09 19:49:13 +01:00
def test_ultra_long_rendering ( self ) - > None :
""" A message with an ultra-long rendering throws an exception """
2018-04-13 08:23:21 +02:00
msg = u ' * a \n ' * MAX_MESSAGE_LENGTH # Rendering is >100K characters
2018-02-09 19:49:13 +01:00
with self . simulated_markdown_failure ( ) :
with self . assertRaises ( bugdown . BugdownRenderingException ) :
bugdown_convert ( msg )
2016-10-24 16:42:43 +02:00
class BugdownAvatarTestCase ( ZulipTestCase ) :
2017-11-05 10:51:25 +01:00
def test_possible_avatar_emails ( self ) - > None :
2017-09-14 22:11:34 +02:00
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 ' } ,
)
2017-11-05 10:51:25 +01:00
def test_avatar_with_id ( self ) - > None :
2017-05-07 17:21:26 +02:00
sender_user_profile = self . example_user ( ' othello ' )
2016-10-24 16:42:43 +02:00
message = Message ( sender = sender_user_profile , sending_client = get_client ( " test " ) )
2017-05-07 17:21:26 +02:00
user_profile = self . example_user ( ' hamlet ' )
2016-10-24 16:42:43 +02:00
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 ) )
2017-11-05 10:51:25 +01:00
def test_avatar_of_unregistered_user ( self ) - > None :
2017-05-07 17:21:26 +02:00
sender_user_profile = self . example_user ( ' othello ' )
2016-10-24 16:42:43 +02:00
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 ) )