diff --git a/ckan/controllers/api.py b/ckan/controllers/api.py index ee1f34f6ebd..45ecd0029c9 100644 --- a/ckan/controllers/api.py +++ b/ckan/controllers/api.py @@ -572,7 +572,7 @@ def _get_search_params(cls, request_params): def markdown(self, ver=None): raw_markdown = request.params.get('q', '') - results = ckan.misc.MarkdownFormat().to_html(raw_markdown) + results = h.render_markdown(raw_markdown) return self._finish_ok(results) diff --git a/ckan/controllers/group.py b/ckan/controllers/group.py index ba204cc4cae..614b6e350a6 100644 --- a/ckan/controllers/group.py +++ b/ckan/controllers/group.py @@ -176,14 +176,7 @@ def read(self, id): else: q += ' groups: "%s"' % c.group_dict.get('name') - try: - description_formatted = ckan.misc.MarkdownFormat().to_html( - c.group_dict.get('description', '')) - c.description_formatted = genshi.HTML(description_formatted) - except Exception, e: - error_msg = "%s" %\ - _("Cannot render description") - c.description_formatted = genshi.HTML(error_msg) + c.description_formatted = h.render_markdown(c.group_dict.get('description')) context['return_query'] = True diff --git a/ckan/controllers/user.py b/ckan/controllers/user.py index 7a4ef42f7df..e8b9232f42c 100644 --- a/ckan/controllers/user.py +++ b/ckan/controllers/user.py @@ -3,11 +3,9 @@ from pylons import session, c, g, request, config from pylons.i18n import _ -import genshi import ckan.lib.i18n as i18n import ckan.lib.base as base -import ckan.misc as misc import ckan.model as model import ckan.lib.helpers as h import ckan.new_authz as new_authz @@ -73,7 +71,7 @@ def _setup_template_variables(self, context, data_dict): abort(401, _('Not authorized to see this page')) c.user_dict = user_dict c.is_myself = user_dict['name'] == c.user - c.about_formatted = self._format_about(user_dict['about']) + c.about_formatted = h.render_markdown(user_dict['about']) ## end hooks @@ -620,13 +618,3 @@ def unfollow(self, id): or e.error_dict) h.flash_error(error_message) h.redirect_to(controller='user', action='read', id=id) - - def _format_about(self, about): - about_formatted = misc.MarkdownFormat().to_html(about) - try: - html = genshi.HTML(about_formatted) - except genshi.ParseError, e: - log.error('Could not print "about" field Field: %r Error: %r', - about, e) - html = _('Error: Could not parse About text') - return html diff --git a/ckan/lib/dictization/model_dictize.py b/ckan/lib/dictization/model_dictize.py index d61c68e73b1..d2a74071923 100644 --- a/ckan/lib/dictization/model_dictize.py +++ b/ckan/lib/dictization/model_dictize.py @@ -4,7 +4,6 @@ from pylons import config from sqlalchemy.sql import select -import ckan.misc as misc import ckan.logic as logic import ckan.plugins as plugins import ckan.lib.helpers as h @@ -530,7 +529,7 @@ def package_to_api(pkg, context): dictized['license'] = pkg.license.title if pkg.license else None dictized['ratings_average'] = pkg.get_average_rating() dictized['ratings_count'] = len(pkg.ratings) - dictized['notes_rendered'] = misc.MarkdownFormat().to_html(pkg.notes) + dictized['notes_rendered'] = h.render_markdown(pkg.notes) site_url = config.get('ckan.site_url', None) if site_url: diff --git a/ckan/lib/package_saver.py b/ckan/lib/package_saver.py index 1a1a9a8e7f6..5b3f876151f 100644 --- a/ckan/lib/package_saver.py +++ b/ckan/lib/package_saver.py @@ -1,4 +1,3 @@ -import genshi from sqlalchemy import orm import ckan.lib.helpers as h from ckan.lib.base import * @@ -22,12 +21,8 @@ def render_package(cls, pkg, context): render. Note that the actual calling of render('package/read') is left to the caller.''' - try: - notes_formatted = ckan.misc.MarkdownFormat().to_html(pkg.get('notes','')) - c.pkg_notes_formatted = genshi.HTML(notes_formatted) - except Exception, e: - error_msg = "%s" % _("Cannot render package description") - c.pkg_notes_formatted = genshi.HTML(error_msg) + c.pkg_notes_formatted = h.render_markdown(pkg.get('notes')) + c.current_rating, c.num_ratings = ckan.rating.get_rating(context['package']) url = pkg.get('url', '') c.pkg_url_link = h.link_to(url, url, rel='foaf:homepage', target='_blank') \ diff --git a/ckan/misc.py b/ckan/misc.py deleted file mode 100644 index 29f3ae6447b..00000000000 --- a/ckan/misc.py +++ /dev/null @@ -1,95 +0,0 @@ -import re -import logging -import urllib -import webhelpers.markdown - -from pylons.i18n import _ - -log = logging.getLogger(__name__) - -class TextFormat(object): - - def to_html(self, instr): - raise NotImplementedError() - - -class MarkdownFormat(TextFormat): - internal_link = re.compile('(dataset|package|group):([a-z0-9\-_]+)') - - # tag names are allowed more characters, including spaces. So are - # treated specially. - internal_tag_link = re.compile(\ - r"""(tag): # group 1 - ( # capture name (inc. quotes) (group 2) - (")? # optional quotes for multi-word name (group 3) - ( # begin capture of the name w/o quotes (group 4) - (?(3) # if the quotes matched in group 3 - [ \w\-.] # then capture spaces (as well as other things) - | # else - [\w\-.] # don't capture spaces - ) # end - +) # end capture of the name w/o quotes (group 4) - (?(3)") # close opening quote if necessary - ) # end capture of the name with quotes (group 2) - """, re.VERBOSE|re.UNICODE) - normal_link = re.compile('<(http:[^>]+)>') - - html_whitelist = 'b center li ol p table td tr ul'.split(' ') - whitelist_elem = re.compile(r'<(\/?((%s)(\s[^>]*)?))>' % "|".join(html_whitelist), re.IGNORECASE) - whitelist_escp = re.compile(r'\\xfc\\xfd(\/?((%s)(\s[^>]*?)?))\\xfd\\xfc' % "|".join(html_whitelist), re.IGNORECASE) - normal_link = re.compile(r']*?href="([^"]*?)"[^>]*?>', re.IGNORECASE) - abbrev_link = re.compile(r'<(http://[^>]*)>', re.IGNORECASE) - any_link = re.compile(r']*?>', re.IGNORECASE) - close_link = re.compile(r'<(\/a[^>]*)>', re.IGNORECASE) - link_escp = re.compile(r'\\xfc\\xfd(\/?(%s)[^>]*?)\\xfd\\xfc' % "|".join(['a']), re.IGNORECASE) - web_address = re.compile(r'(\s|

)((http|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?)', re.IGNORECASE) - - def to_html(self, text): - if text is None: - return '' - # Encode whitelist elements. - text = self.whitelist_elem.sub(r'\\\\xfc\\\\xfd\1\\\\xfd\\\\xfc', text) - - # Encode links only in an acceptable format (guard against spammers) - text = self.normal_link.sub(r'\\\\xfc\\\\xfda href="\1" target="_blank" rel="nofollow"\\\\xfd\\\\xfc', text) - text = self.abbrev_link.sub(r'\\\\xfc\\\\xfda href="\1" target="_blank" rel="nofollow"\\\\xfd\\\\xfc\1', text) - text = self.any_link.sub(r'\\\\xfc\\\\xfda href="TAG MALFORMED" target="_blank" rel="nofollow"\\\\xfd\\\\xfc', text) - text = self.close_link.sub(r'\\\\xfc\\\\xfd\1\\\\xfd\\\\xfc', text) - - # Convert internal tag links - text = self.internal_tag_link.sub(self._create_tag_link, text) - - # Convert internal links. - text = self.internal_link.sub(r'[\1:\2] (/\1/\2)', text) - - # Convert to markdown format. - text = self.normal_link.sub(r'[\1] (\1)', text) - - # Convert to markdown format. - text = self.normal_link.sub(r'[\1] (\1)', text) - - # Markdown to HTML. - text = webhelpers.markdown.markdown(text, safe_mode=True) - - # Remaining unlinked web addresses to become addresses - text = self.web_address.sub(r'\1\2', text) - - # Decode whitelist elements. - text = self.whitelist_escp.sub(r'<\1>', text) - text = self.link_escp.sub(r'<\1>', text) - - return text - - def _create_tag_link(self, match_object): - """ - A callback used to create the internal tag link. - - The reason for this is that webhelpers.markdown does not percent-escape - spaces, nor does it encode unicode characters correctly. - - This is only applied to the tag substitution since only tags may - have spaces or unicode characters. - """ - g = match_object.group - url = urllib.quote(g(4).encode('utf8')) - return r'[%s:%s] (/%s/%s)' % (g(1), g(2), g(1), url) diff --git a/ckan/model/package.py b/ckan/model/package.py index ec49bbab019..bce320bde98 100644 --- a/ckan/model/package.py +++ b/ckan/model/package.py @@ -17,7 +17,6 @@ import activity import extension -import ckan.misc import ckan.lib.dictization __all__ = ['Package', 'package_table', 'package_revision_table', @@ -216,7 +215,8 @@ def as_dict(self, ref_package_by='name', ref_group_by='name'): if self.metadata_modified else None _dict['metadata_created'] = self.metadata_created.isoformat() \ if self.metadata_created else None - _dict['notes_rendered'] = ckan.misc.MarkdownFormat().to_html(self.notes) + import ckan.lib.helpers as h + _dict['notes_rendered'] = h.render_markdown(self.notes) _dict['type'] = self.type or u'dataset' #tracking import ckan.model as model diff --git a/ckan/templates_legacy/package/read_core.html b/ckan/templates_legacy/package/read_core.html index 9868845a8ec..427775a8d42 100644 --- a/ckan/templates_legacy/package/read_core.html +++ b/ckan/templates_legacy/package/read_core.html @@ -10,7 +10,7 @@

-
+
${c.pkg_notes_formatted}