changeset 6336:6f89cdc7c938

issue2551108 - fix markdown formatted designator links Designators like 'issue1' are automatically hyperlinked. However if typed as [issue1](issue1) or [issue1](https://example.com/issue1) they get mangled. Stop that mangling.
author John Rouillard <rouilj@ieee.org>
date Fri, 12 Mar 2021 01:30:22 -0500
parents 09678e50018c
children 316c2c32dace
files CHANGES.txt roundup/cgi/templating.py test/test_templating.py
diffstat 3 files changed, 50 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES.txt	Wed Mar 10 17:09:16 2021 -0500
+++ b/CHANGES.txt	Fri Mar 12 01:30:22 2021 -0500
@@ -70,6 +70,8 @@
   with postgresql. This turns of client-side cursor handling and avoids
   *large* roundup process (or wsgi process) in case of large results.
   Fixes issue2551114.
+- issue2551108 - fix handling of designator links when formatted
+  as markdown links. (Reported by Cedric Krier; John Rouillard)
 
 Features:
 - issue2550522 - Add 'filter' command to command-line
--- a/roundup/cgi/templating.py	Wed Mar 10 17:09:16 2021 -0500
+++ b/roundup/cgi/templating.py	Fri Mar 12 01:30:22 2021 -0500
@@ -1691,6 +1691,23 @@
                 s = match.group(group)
                 return '<%s>' % s
         if match.group('id') and len(match.group('id')) < 10:
+            # Pass through markdown style links:
+            #     [issue1](https://....)
+            #     [issue1](issue1)
+            # as 'issue1'. Don't convert issue1 into a link.
+            # https://issues.roundup-tracker.org/issue2551108
+            start = match.start('item') - 1
+            end = match.end('item')
+            if start >= 0:
+                prefix = match.string[start]
+                if end < len(match.string):
+                    suffix = match.string[end]
+                    if (prefix, suffix) in {('[', ']')}:
+                        if match.string[end+1] == '(': # find following (
+                            return match.group(0)
+                    if (prefix, suffix) in {('(',')')}:
+                        if match.string[start-1] == ']':
+                            return match.group(0)
             return self._hyper_repl_item(match,'[%(item)s](%(cls)s%(id)s)')
         else:
             # just return the matched text
--- a/test/test_templating.py	Wed Mar 10 17:09:16 2021 -0500
+++ b/test/test_templating.py	Fri Mar 12 01:30:22 2021 -0500
@@ -44,6 +44,9 @@
 
 class MockDatabase(MockNull):
     def getclass(self, name):
+        # Class returned must have hasnode(id) method that returns true
+        # otherwise designators like 'issue1' can't be hyperlinked.
+        self.classes[name].hasnode = lambda id: True
         return self.classes[name]
 
     # setup for csrf testing of otks database api
@@ -468,6 +471,34 @@
         p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'A link <http://localhost>'))
         self.assertEqual(p.markdown().strip(), u2s(u'<p>A link <a href="http://localhost">http://localhost</a></p>'))
 
+    def test_string_markdown_link_item(self):
+        """ The link formats for the different markdown engines changes.
+            Order of attributes, value for rel (noopener, nofollow etc)
+            is different. So most tests check for a substring that indicates
+            success rather than the entire returned string.
+        """
+        p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'An issue1 link'))
+        self.assertIn( u2s(u'href="issue1"'), p.markdown().strip())
+        # just verify that plain linking is working
+        self.assertIn( u2s(u'href="issue1"'), p.plain(hyperlink=1))
+
+        p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'An [issue1](issue1) link'))
+        self.assertIn( u2s(u'href="issue1"'), p.markdown().strip())
+        # just verify that plain linking is working
+        self.assertIn( u2s(u'href="issue1"'), p.plain(hyperlink=1))
+
+        p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'An [issue1](https://example.com/issue1) link'))
+        self.assertIn( u2s(u'href="https://example.com/issue1"'), p.markdown().strip())
+
+        p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'An [issue1] (https://example.com/issue1) link'))
+        self.assertIn( u2s(u'href="issue1"'), p.markdown().strip())
+        if type(self) == MistuneTestCase:
+            # mistune makes the https url into a real link
+            self.assertIn( u2s(u'href="https://example.com/issue1"'), p.markdown().strip())
+        else:
+            # the other two engines leave the parenthesized url as is.
+            self.assertIn( u2s(u' (https://example.com/issue1) link'), p.markdown().strip())
+
     def test_string_markdown_link(self):
         # markdown2 and markdown escape the email address
         try:

Roundup Issue Tracker: http://roundup-tracker.org/