markdown: Make raw urls in topic names navigable.

We reuse the link regexes we use elsewhere inn markdown
for parsing links in topic names and add a button to open
them in new tabs similar to our behavior with linkifiers
in topic names.

Fixes #12391.
This commit is contained in:
Rohitt Vashishtha
2019-05-25 19:40:30 +05:30
committed by Tim Abbott
parent 96d7c1f3b0
commit 047086b81c
4 changed files with 47 additions and 0 deletions

View File

@@ -425,6 +425,18 @@ run_test('topic_links', () => {
assert.equal(util.get_topic_links(message).length, 1); assert.equal(util.get_topic_links(message).length, 1);
assert.equal(util.get_topic_links(message)[0], "https://zone_45.zulip.net/ticket/123"); assert.equal(util.get_topic_links(message)[0], "https://zone_45.zulip.net/ticket/123");
message = {type: 'stream', topic: "Hello https://google.com"};
markdown.add_topic_links(message);
assert.equal(util.get_topic_links(message).length, 1);
assert.equal(util.get_topic_links(message)[0], "https://google.com");
message = {type: 'stream', topic: "#456 https://google.com https://github.com"};
markdown.add_topic_links(message);
assert.equal(util.get_topic_links(message).length, 3);
assert(util.get_topic_links(message).indexOf("https://google.com") !== -1);
assert(util.get_topic_links(message).indexOf("https://github.com") !== -1);
assert(util.get_topic_links(message).indexOf("https://trac.zulip.net/ticket/456") !== -1);
message = {type: "not-stream"}; message = {type: "not-stream"};
markdown.add_topic_links(message); markdown.add_topic_links(message);
assert.equal(util.get_topic_links(message).length, 0); assert.equal(util.get_topic_links(message).length, 0);

View File

@@ -160,6 +160,14 @@ exports.add_topic_links = function (message) {
links.push(link_url); links.push(link_url);
} }
}); });
// Also make raw urls navigable
var url_re = /\b(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/g; // Slightly modified from third/marked.js
var match = topic.match(url_re);
if (match) {
links = links.concat(match);
}
util.set_topic_links(message, links); util.set_topic_links(message, links);
}; };

View File

@@ -1969,6 +1969,10 @@ def build_engine(realm_filters: List[Tuple[str, str, int]],
]) ])
return engine return engine
# Split the topic name into multiple sections so that we can easily use
# our common single link matching regex on it.
basic_link_splitter = re.compile(r'[ !;\?\),\'\"]')
# Security note: We don't do any HTML escaping in this # Security note: We don't do any HTML escaping in this
# function on the URLs; they are expected to be HTML-escaped when # function on the URLs; they are expected to be HTML-escaped when
# rendered by clients (just as links rendered into message bodies # rendered by clients (just as links rendered into message bodies
@@ -1982,6 +1986,13 @@ def topic_links(realm_filters_key: int, topic_name: str) -> List[str]:
pattern = prepare_realm_pattern(realm_filter[0]) pattern = prepare_realm_pattern(realm_filter[0])
for m in re.finditer(pattern, topic_name): for m in re.finditer(pattern, topic_name):
matches += [realm_filter[1] % m.groupdict()] matches += [realm_filter[1] % m.groupdict()]
# Also make raw urls navigable.
for sub_string in basic_link_splitter.split(topic_name):
link_match = re.match(get_web_link_regex(), sub_string)
if link_match:
matches.append(link_match.group('url'))
return matches return matches
def maybe_update_markdown_engines(realm_filters_key: Optional[int], email_gateway: bool) -> None: def maybe_update_markdown_engines(realm_filters_key: Optional[int], email_gateway: bool) -> None:

View File

@@ -787,6 +787,18 @@ class BugdownTest(ZulipTestCase):
converted = bugdown_convert(msg) converted = bugdown_convert(msg)
self.assertEqual(converted, unicode_converted) self.assertEqual(converted, unicode_converted)
def test_links_in_topic_name(self) -> None:
realm = get_realm('zulip')
msg = Message(sender=self.example_user('othello'))
msg.set_topic_name("https://google.com/hello-world")
converted_topic = bugdown.topic_links(realm.id, msg.topic_name())
self.assertEqual(converted_topic, [u'https://google.com/hello-world'])
msg.set_topic_name("Try out http://ftp.debian.org, https://google.com/ and https://google.in/.")
converted_topic = bugdown.topic_links(realm.id, msg.topic_name())
self.assertEqual(converted_topic, [u'http://ftp.debian.org', 'https://google.com/', 'https://google.in/'])
def test_realm_patterns(self) -> None: def test_realm_patterns(self) -> None:
realm = get_realm('zulip') realm = get_realm('zulip')
url_format_string = r"https://trac.zulip.net/ticket/%(id)s" url_format_string = r"https://trac.zulip.net/ticket/%(id)s"
@@ -811,6 +823,10 @@ class BugdownTest(ZulipTestCase):
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, '<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_topic, [u'https://trac.zulip.net/ticket/444']) self.assertEqual(converted_topic, [u'https://trac.zulip.net/ticket/444'])
msg.set_topic_name("#444 https://google.com")
converted_topic = bugdown.topic_links(realm.id, msg.topic_name())
self.assertEqual(converted_topic, [u'https://trac.zulip.net/ticket/444', u'https://google.com'])
RealmFilter(realm=realm, pattern=r'#(?P<id>[a-zA-Z]+-[0-9]+)', RealmFilter(realm=realm, pattern=r'#(?P<id>[a-zA-Z]+-[0-9]+)',
url_format_string=r'https://trac.zulip.net/ticket/%(id)s').save() url_format_string=r'https://trac.zulip.net/ticket/%(id)s').save()
msg = Message(sender=self.example_user('hamlet')) msg = Message(sender=self.example_user('hamlet'))