def standard_text_html_representation(value, linkify_text=True): """Render a string for html display. For this we obfuscate email and render as html. """ if value is None: return '' nomail = FormattersAPI(value).obfuscate_email() return FormattersAPI(nomail).text_to_html(linkify_text=linkify_text)
def test_doesnt_linkify_for_non_developers(self): # OOPS IDs won't be linkified for non-developers. oops_id = 'OOPS-12345TEST' formatter = FormattersAPI(oops_id) formatted_string = formatter.oops_id() self.assertEqual( oops_id, formatted_string, "Formatted string should be '%s', was '%s'" % ( oops_id, formatted_string))
def test_doesnt_linkify_for_non_developers(self): # OOPS IDs won't be linkified for non-developers. oops_id = 'OOPS-12345TEST' formatter = FormattersAPI(oops_id) formatted_string = formatter.oops_id() self.assertEqual( oops_id, formatted_string, "Formatted string should be '%s', was '%s'" % (oops_id, formatted_string))
def test_protocol_alone_does_not_link(self): test_string = "This doesn't link: apt:" html = FormattersAPI(test_string).text_to_html() expected_html = "<p>This doesn't link: apt:</p>" self.assertEqual(expected_html, html) test_string = "This doesn't link: http://" html = FormattersAPI(test_string).text_to_html() expected_html = "<p>This doesn't link: http://</p>" self.assertEqual(expected_html, html)
def obfuscate_email(user, text): """Obfuscate email addresses if the user is not logged in.""" if not text: # If there is nothing to obfuscate, the FormattersAPI # will blow up, so just return. return text formatter = FormattersAPI(text) if user: return text else: return formatter.obfuscate_email()
def test_linkifies_for_developers(self): # OOPS IDs will be linkified for Launchpad developers. oops_id = 'OOPS-12345TEST' formatter = FormattersAPI(oops_id) self._setDeveloper(True) formatted_string = formatter.oops_id() expected_string = '<a href="%s">%s</a>' % ( config.launchpad.oops_root_url + oops_id, oops_id) self.assertEqual( expected_string, formatted_string, "Formatted string should be '%s', was '%s'" % (expected_string, formatted_string))
def test_linkifies_for_developers(self): # OOPS IDs will be linkified for Launchpad developers. oops_id = 'OOPS-12345TEST' formatter = FormattersAPI(oops_id) self._setDeveloper(True) formatted_string = formatter.oops_id() expected_string = '<a href="%s">%s</a>' % ( config.launchpad.oops_root_url + oops_id, oops_id) self.assertEqual( expected_string, formatted_string, "Formatted string should be '%s', was '%s'" % ( expected_string, formatted_string))
def toTerm(self, watch): if watch.url.startswith('mailto:'): user = getUtility(ILaunchBag).user if user is None: title = html_escape( FormattersAPI(watch.bugtracker.title).obfuscate_email()) else: url = watch.url if url in watch.bugtracker.title: title = html_escape(watch.bugtracker.title).replace( html_escape(url), structured( '<a href="%s">%s</a>', url, url).escapedtext) else: title = structured( '%s <<a href="%s">%s</a>>', watch.bugtracker.title, url, url[7:]).escapedtext else: title = structured( '%s <a href="%s">#%s</a>', watch.bugtracker.title, watch.url, watch.remotebug).escapedtext # title is already HTML-escaped. return SimpleTerm(watch, watch.id, title)
def test_cssClasses_git(self): # Git diffs look slightly different, so check that they also end up # with the correct CSS classes. diff = dedent('''\ diff --git a/tales.py b/tales.py index aaaaaaa..bbbbbbb 100644 --- a/tales.py +++ b/tales.py @@ -2435,6 +2435,8 @@ def format_diff(self): - removed this line + added this line -------- a sql style comment ++++++++ a line of pluses ''') html = FormattersAPI(diff).format_diff() line_numbers = find_tags_by_class(html, 'line-no') self.assertEqual( ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'], [tag.renderContents() for tag in line_numbers]) text = find_tags_by_class(html, 'text') self.assertEqual( ['diff-file text', 'diff-file text', 'diff-header text', 'diff-header text', 'diff-chunk text', 'text', 'diff-removed text', 'diff-added text', 'diff-removed text', 'diff-added text'], [str(tag['class']) for tag in text])
def test_format_unicode(self): # Sometimes the strings contain unicode, those should work too. self.assertEqual( u'<table class="diff unidiff"><tr id="diff-line-1">' u'<td class="line-no unselectable">1</td><td class="text">' u'Unicode \u1010</td></tr></table>', FormattersAPI(u'Unicode \u1010').format_diff())
def test_almostEmptyString(self): # White space doesn't count as empty, and is formatted. self.assertEqual( '<table class="diff unidiff"><tr id="diff-line-1">' '<td class="line-no unselectable">1</td><td class="text"> ' '</td></tr></table>', FormattersAPI(' ').format_diff())
def test_no_link_html_code_with_linkify_text_false(self): test_string = '<a href="http://example.com/">http://example.com/</a>' html = FormattersAPI(test_string).text_to_html(linkify_text=False) expected_html = ( '<p><a href="http://example.com/">' 'http://example.com/</a></p>') self.assertEqual(expected_html, html)
def test_file_is_not_linked(self): test_string = "This doesn't become a link: file://some/file.txt" html = FormattersAPI(test_string).text_to_html() expected_html = ( "<p>This doesn't become a link: " "file://<wbr />some/file.<wbr />txt</p>") self.assertEqual(expected_html, html)
def test_parens_handled_well(self): test_strings = [ '(http://example.com)', 'http://example.com/path_(with_parens)', '(http://example.com/path_(with_parens))', '(http://example.com/path_(with_parens)and_stuff)', 'http://example.com/path_(with_parens', ] expected_html = [ ('<p>(<a rel="nofollow" href="http://example.com">' 'http://<wbr />example.<wbr />com</a>)</p>'), ('<p><a rel="nofollow" ' 'href="http://example.com/path_(with_parens)">' 'http://<wbr />example.<wbr />com/path_' '<wbr />(with_parens)</a></p>'), ('<p>(<a rel="nofollow" ' 'href="http://example.com/path_(with_parens)">' 'http://<wbr />example.<wbr />com/path_' '<wbr />(with_parens)</a>)</p>'), ('<p>(<a rel="nofollow" ' 'href="http://example.com/path_(with_parens)and_stuff">' 'http://<wbr />example.<wbr />com' '/path_<wbr />(with_parens)<wbr />and_stuff</a>)</p>'), ('<p><a rel="nofollow" ' 'href="http://example.com/path_(with_parens">' 'http://<wbr />example.<wbr />com' '/path_<wbr />(with_parens</a></p>'), ] self.assertEqual( expected_html, [FormattersAPI(text).text_to_html() for text in test_strings])
def test_cssClasses(self): # Different parts of the diff have different css classes. diff = dedent('''\ === modified file 'tales.py' --- tales.py +++ tales.py @@ -2435,6 +2435,8 @@ def format_diff(self): - removed this line + added this line -------- a sql style comment ++++++++ a line of pluses ######## # A merge directive comment. ''') html = FormattersAPI(diff).format_diff() line_numbers = find_tags_by_class(html, 'line-no') self.assertEqual( ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11'], [tag.renderContents() for tag in line_numbers]) text = find_tags_by_class(html, 'text') self.assertEqual([ 'diff-file text', 'diff-header text', 'diff-header text', 'diff-chunk text', 'text', 'diff-removed text', 'diff-added text', 'diff-removed text', 'diff-added text', 'diff-comment text', 'diff-comment text' ], [str(tag['class']) for tag in text])
def test_apt_is_linked(self): test_string = 'This becomes a link: apt:some-package' html = FormattersAPI(test_string).text_to_html() expected_html = ( '<p>This becomes a link: ' '<a rel="nofollow" ' 'href="apt:some-package">apt:some-<wbr />package</a></p>') self.assertEqual(expected_html, html) # Do it again for apt:// test_string = 'This becomes a link: apt://some-package' html = FormattersAPI(test_string).text_to_html() expected_html = ( '<p>This becomes a link: ' '<a rel="nofollow" ' 'href="apt://some-package">apt://some-<wbr />package</a></p>') self.assertEqual(expected_html, html)
def test_config_value_limits_line_count(self): # The config.diff.max_line_format contains the maximum number of lines # to format. diff = dedent('''\ === modified file 'tales.py' --- tales.py +++ tales.py @@ -2435,6 +2435,8 @@ def format_diff(self): - removed this line + added this line ######## # A merge directive comment. ''') self.pushConfig("diff", max_format_lines=3) html = FormattersAPI(diff).format_diff() line_count = html.count('<td class="line-no">') self.assertEqual(3, line_count)
def test_double_email_in_linkify_email(self): person = self.factory.makePerson(email='*****@*****.**') test_string = ( ' * Foo. <[email protected]>\n * Bar <[email protected]>') html = FormattersAPI(test_string).linkify_email() url = canonical_url(person) expected_html = ( ' * Foo. <<a href="%s" class="sprite person">[email protected]' '</a>>\n * Bar <<a href="%s" class="sprite person">' '[email protected]</a>>' % (url, url)) self.assertEqual(expected_html, html)
def change_action(self, action, data): original_rules = self.request.features.rule_source.getAllRulesAsText() rules_text = data.get('feature_rules') or '' logger = logging.getLogger(self.logger_name) logger.warning("Change feature rules to: %s" % (rules_text, )) logger.warning("Previous feature rules were: %s" % (original_rules, )) self.request.features.rule_source.setAllRulesFromText(rules_text) # Why re-fetch the rules here? This way we get them reformatted # (whitespace normalized) and ordered consistently so the diff is # minimal. new_rules = self.request.features.rule_source.getAllRulesAsText() diff = u'\n'.join(self.diff_rules(original_rules, new_rules)) comment = data['comment'] ChangeLog.append(diff, comment, self.user) self.diff = FormattersAPI(diff).format_diff()
def test_things_do_not_link_if_they_should_not(self): test_strings = [ "bugnumber.4", "bug number.4", "bugno.4", "bug no.4", ] expected_html = [ "<p>bugnumber.4</p>", "<p>bug number.4</p>", "<p>bugno.4</p>", "<p>bug no.4</p>", ] self.assertEqual( expected_html, [FormattersAPI(text).text_to_html() for text in test_strings])
def test_regular_bug_case_works(self): test_strings = [ "bug 34434", "bugnumber 34434", "bug number 34434", ] expected_html = [ '<p><a href="/bugs/34434" ' 'class="bug-link">bug 34434</a></p>', '<p><a href="/bugs/34434" ' 'class="bug-link">bugnumber 34434</a></p>', '<p><a href="/bugs/34434" ' 'class="bug-link">bug number 34434</a></p>', ] self.assertEqual( expected_html, [FormattersAPI(text).text_to_html() for text in test_strings])
def itemToFeedEntry(self, announcement): """See `IFeed`.""" # Given an instance of an announcement, create a FeedEntry out of it # and return. # The title for the FeedEntry is an IFeedTypedData instance and may be # plain text or html. title = self._entryTitle(announcement) # The link_alternate for the entry is the human-readable alternate URL # for the entry. For example: # http://launchpad.net/ubuntu/+announcment/12 entry_link_alternate = "%s%s" % (canonical_url( announcement.target, rootsite=self.rootsite), "/+announcement/%d" % announcement.id) # The content of the entry is the text displayed as the body in the # feed reader. For announcements it is plain text but it must be # escaped to account for any special characters the user may have # entered, such as '&' and '<' because it will be embedded in the XML # document. formatted_summary = FormattersAPI(announcement.summary).text_to_html() content = FeedTypedData(formatted_summary, content_type="html", root_url=self.root_url) # The entry for an announcement has distinct dates for created, # updated, and published. For some data, the created and published # dates will be the same. The announcements also only have a singe # author. entry_id = 'tag:launchpad.net,%s:/+announcement/%d' % ( announcement.date_created.date().isoformat(), announcement.id) entry = FeedEntry( title=title, link_alternate=entry_link_alternate, date_created=announcement.date_created, date_updated=announcement.date_updated, date_published=announcement.date_announced, authors=[FeedPerson(announcement.registrant, rootsite="mainsite")], content=content, id_=entry_id) return entry
def test_normal_set(self): test_strings = [ "http://example.com", "http://example.com/", "http://example.com/path", "http://example.com/path/", ] expected_strings = [ ('<p><a rel="nofollow" href="http://example.com">' 'http://<wbr />example.<wbr />com</a></p>'), ('<p><a rel="nofollow" href="http://example.com/">' 'http://<wbr />example.<wbr />com/</a></p>'), ('<p><a rel="nofollow" href="http://example.com/path">' 'http://<wbr />example.<wbr />com/path</a></p>'), ('<p><a rel="nofollow" href="http://example.com/path/">' 'http://<wbr />example.<wbr />com/path/</a></p>'), ] self.assertEqual( expected_strings, [FormattersAPI(text).text_to_html() for text in test_strings])
def text_xhtml_representation(context, field, request): """Render text as XHTML using the webservice.""" return lambda text: ('' if text is None else FormattersAPI(text). text_to_html(linkify_text=True))
def linkify_email(text, preloaded_person_data): """Email addresses are linkified to point to the person's profile.""" formatter = FormattersAPI(text) return formatter.linkify_email(preloaded_person_data)
def match(self, input_string): return Equals(self.expected_html).match( FormattersAPI(input_string).markdown())
def input_id(self): """This is used to ensure the widget id contains only valid chars.""" return FormattersAPI(self.name).zope_css_id()
def value(self): text = getattr(self.context, self.attribute_name, self.default_text) if text is None: return self.default_text else: return FormattersAPI(text).obfuscate_email()
def test_emptyString(self): # An empty string gives an empty string. self.assertEqual('', FormattersAPI('').format_diff())
def test_last_paragraph_class(self): self.assertEqual( '<p>Foo</p>\n<p class="last">Bar</p>', FormattersAPI("Foo\n\nBar").text_to_html( last_paragraph_class="last"))
def test_no_link_with_linkify_text_false(self): test_string = "This doesn't become a link: http://www.example.com/" html = FormattersAPI(test_string).text_to_html(linkify_text=False) expected_html = ( "<p>This doesn't become a link: http://www.example.com/</p>") self.assertEqual(expected_html, html)