diff --git a/kallithea/lib/helpers.py b/kallithea/lib/helpers.py
--- a/kallithea/lib/helpers.py
+++ b/kallithea/lib/helpers.py
@@ -17,7 +17,6 @@ Helper functions
Consists of functions to typically be used within templates, but also
available to Controllers. This module is available to both as 'h'.
"""
-import random
import hashlib
import StringIO
import math
@@ -30,7 +29,6 @@ from pygments.formatters.html import Htm
from pygments import highlight as code_highlight
from pylons import url
from pylons.i18n.translation import _, ungettext
-from hashlib import md5
from webhelpers.html import literal, HTML, escape
from webhelpers.html.tools import *
@@ -89,24 +87,23 @@ def canonical_hostname():
parts = url('home', qualified=True).split('://', 1)
return parts[1].split('/', 1)[0]
-def html_escape(text, html_escape_table=None):
- """Produce entities within text."""
- if not html_escape_table:
- html_escape_table = {
- "&": "&",
- '"': """,
- "'": "'",
- ">": ">",
- "<": "<",
- }
- return "".join(html_escape_table.get(c, c) for c in text)
+def html_escape(s):
+ """Return string with all html escaped.
+ This is also safe for javascript in html but not necessarily correct.
+ """
+ return (s
+ .replace('&', '&')
+ .replace(">", ">")
+ .replace("<", "<")
+ .replace('"', """)
+ .replace("'", "'")
+ )
-
-def shorter(text, size=20):
+def shorter(s, size=20):
postfix = '...'
- if len(text) > size:
- return text[:size - len(postfix)] + postfix
- return text
+ if len(s) > size:
+ return s[:size - len(postfix)] + postfix
+ return s
def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
@@ -131,7 +128,7 @@ def FID(raw_id, path):
:param path:
"""
- return 'C-%s-%s' % (short_id(raw_id), md5(safe_str(path)).hexdigest()[:12])
+ return 'C-%s-%s' % (short_id(raw_id), hashlib.md5(safe_str(path)).hexdigest()[:12])
class _GetError(object):
@@ -150,21 +147,6 @@ class _GetError(object):
get_error = _GetError()
-class _ToolTip(object):
-
- def __call__(self, tooltip_title, trim_at=50):
- """
- Special function just to wrap our text into nice formatted
- autowrapped text
-
- :param tooltip_title:
- """
- tooltip_title = escape(tooltip_title)
- tooltip_title = tooltip_title.replace('<', '<').replace('>', '>')
- return tooltip_title
-tooltip = _ToolTip()
-
-
class _FilesBreadCrumbs(object):
def __call__(self, repo_name, rev, paths):
@@ -355,12 +337,10 @@ def pygmentize_annotation(repo_name, fil
author = escape(changeset.author)
date = changeset.date
message = escape(changeset.message)
-
tooltip_html = ("
Author:"
" %s
Date: %s
Message:"
- " %s
")
+ " %s
") % (author, date, message)
- tooltip_html = tooltip_html % (author, date, message)
lnk_format = show_id(changeset)
uri = link_to(
lnk_format,
@@ -406,6 +386,25 @@ class _Message(object):
class Flash(_Flash):
+ def __call__(self, message, category=None, ignore_duplicate=False, logf=None):
+ """
+ Show a message to the user _and_ log it through the specified function
+
+ category: notice (default), warning, error, success
+ logf: a custom log function - such as log.debug
+
+ logf defaults to log.info, unless category equals 'success', in which
+ case logf defaults to log.debug.
+ """
+ if logf is None:
+ logf = log.info
+ if category == 'success':
+ logf = log.debug
+
+ logf('Flash %s: %s', category, message)
+
+ super(Flash, self).__call__(message, category, ignore_duplicate)
+
def pop_messages(self):
"""Return all accumulated messages and delete them from the session.
@@ -423,7 +422,7 @@ flash = Flash()
#==============================================================================
from kallithea.lib.vcs.utils import author_name, author_email
from kallithea.lib.utils2 import credentials_filter, age as _age
-from kallithea.model.db import User, ChangesetStatus
+from kallithea.model.db import User, ChangesetStatus, PullRequest
age = lambda x, y=False: _age(x, y)
capitalize = lambda x: x.capitalize()
@@ -447,7 +446,7 @@ def show_id(cs):
if show_rev:
return 'r%s:%s' % (cs.revision, raw_id)
else:
- return '%s' % (raw_id)
+ return raw_id
def fmt_date(date):
@@ -545,13 +544,13 @@ def desc_stylize(value):
if not value:
return ''
- value = re.sub(r'\[see\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
+ value = re.sub(r'\[see\ \=>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
'see => \\1
', value)
- value = re.sub(r'\[license\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
+ value = re.sub(r'\[license\ \=>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
'', value)
- value = re.sub(r'\[(requires|recommends|conflicts|base)\ \=\>\ *([a-zA-Z0-9\-\/]*)\]',
+ value = re.sub(r'\[(requires|recommends|conflicts|base)\ \=>\ *([a-zA-Z0-9\-\/]*)\]',
'', value)
- value = re.sub(r'\[(lang|language)\ \=\>\ *([a-zA-Z\-\/\#\+]*)\]',
+ value = re.sub(r'\[(lang|language)\ \=>\ *([a-zA-Z\-\/\#\+]*)\]',
'\\2
', value)
value = re.sub(r'\[([a-z]+)\]',
'\\1
', value)
@@ -601,32 +600,29 @@ def action_parser(user_log, feed=False,
repo_name = user_log.repository.repo_name
def lnk(rev, repo_name):
+ lazy_cs = False
+ title_ = None
+ url_ = '#'
if isinstance(rev, BaseChangeset) or isinstance(rev, AttributeDict):
- lazy_cs = True
- if getattr(rev, 'op', None) and getattr(rev, 'ref_name', None):
- lazy_cs = False
- lbl = '?'
+ if rev.op and rev.ref_name:
if rev.op == 'delete_branch':
- lbl = '%s' % _('Deleted branch: %s') % rev.ref_name
- title = ''
+ lbl = _('Deleted branch: %s') % rev.ref_name
elif rev.op == 'tag':
- lbl = '%s' % _('Created tag: %s') % rev.ref_name
- title = ''
- _url = '#'
-
+ lbl = _('Created tag: %s') % rev.ref_name
+ else:
+ lbl = 'Unknown operation %s' % rev.op
else:
- lbl = '%s' % (rev.short_id[:8])
- _url = url('changeset_home', repo_name=repo_name,
+ lazy_cs = True
+ lbl = rev.short_id[:8]
+ url_ = url('changeset_home', repo_name=repo_name,
revision=rev.raw_id)
- title = tooltip(rev.message)
else:
- ## changeset cannot be found/striped/removed etc.
- lbl = ('%s' % rev)[:12]
- _url = '#'
- title = _('Changeset not found')
+ # changeset cannot be found - it might have been stripped or removed
+ lbl = rev[:12]
+ title_ = _('Changeset not found')
if parse_cs:
- return link_to(lbl, _url, title=title, class_='tooltip')
- return link_to(lbl, _url, raw_id=rev.raw_id, repo_name=repo_name,
+ return link_to(lbl, url_, title=title_, class_='tooltip')
+ return link_to(lbl, url_, raw_id=rev.raw_id, repo_name=repo_name,
class_='lazy-cs' if lazy_cs else '')
def _get_op(rev_txt):
@@ -650,9 +646,8 @@ def action_parser(user_log, feed=False,
_rev = repo.get_changeset(rev)
revs.append(_rev)
except ChangesetDoesNotExistError:
- log.error('cannot find revision %s in this repo' % rev)
+ log.error('cannot find revision %s in this repo', rev)
revs.append(rev)
- continue
else:
_rev = AttributeDict({
'short_id': rev[:12],
@@ -679,7 +674,7 @@ def action_parser(user_log, feed=False,
url('changeset_home', repo_name=repo_name,
revision=_rev
),
- _('compare view')
+ _('Compare view')
)
)
@@ -723,8 +718,8 @@ def action_parser(user_log, feed=False,
def get_fork_name():
repo_name = action_params
- _url = url('summary_home', repo_name=repo_name)
- return _('fork name %s') % link_to(action_params, _url)
+ url_ = url('summary_home', repo_name=repo_name)
+ return _('Fork name %s') % link_to(action_params, url_)
def get_user_name():
user_name = action_params
@@ -736,12 +731,15 @@ def action_parser(user_log, feed=False,
def get_pull_request():
pull_request_id = action_params
+ nice_id = PullRequest.make_nice_id(pull_request_id)
+
deleted = user_log.repository is None
if deleted:
repo_name = user_log.repository_name
else:
repo_name = user_log.repository.repo_name
- return link_to(_('Pull request #%s') % pull_request_id,
+
+ return link_to(_('Pull request %s') % nice_id,
url('pullrequest_show', repo_name=repo_name,
pull_request_id=pull_request_id))
@@ -852,7 +850,7 @@ def gravatar(email_address, cls='', size
# here it makes sense to use style="width: ..." (instead of, say, a
# stylesheet) because we using this to generate a high-res (retina) size
- tmpl = """
"""
+ tmpl = '
'
# if src is empty then there was no gravatar, so we use a font icon
if not src:
@@ -940,32 +938,31 @@ class Page(_Page):
# and the currently displayed page range
if leftmost_page - self.first_page > 1:
# Wrap in a SPAN tag if nolink_attr is set
- text = '..'
+ text_ = '..'
if self.dotdot_attr:
- text = HTML.span(c=text, **self.dotdot_attr)
- nav_items.append(text)
+ text_ = HTML.span(c=text_, **self.dotdot_attr)
+ nav_items.append(text_)
for thispage in xrange(leftmost_page, rightmost_page + 1):
# Highlight the current page number and do not use a link
+ text_ = str(thispage)
if thispage == self.page:
- text = '%s' % (thispage,)
# Wrap in a SPAN tag if nolink_attr is set
if self.curpage_attr:
- text = HTML.span(c=text, **self.curpage_attr)
- nav_items.append(text)
+ text_ = HTML.span(c=text_, **self.curpage_attr)
+ nav_items.append(text_)
# Otherwise create just a link to that page
else:
- text = '%s' % (thispage,)
- nav_items.append(self._pagerlink(thispage, text))
+ nav_items.append(self._pagerlink(thispage, text_))
# Insert dots if there are pages between the displayed
# page numbers and the end of the page range
if self.last_page - rightmost_page > 1:
- text = '..'
+ text_ = '..'
# Wrap in a SPAN tag if nolink_attr is set
if self.dotdot_attr:
- text = HTML.span(c=text, **self.dotdot_attr)
- nav_items.append(text)
+ text_ = HTML.span(c=text_, **self.dotdot_attr)
+ nav_items.append(text_)
# Create a link to the very last page (unless we are on the last
# page or there would be no need to insert '..' spacers)
@@ -1128,7 +1125,7 @@ def changed_tooltip(nodes):
return literal(pref + '
'.join([safe_unicode(x.path)
for x in nodes[:30]]) + suf)
else:
- return ': ' + _('No Files')
+ return ': ' + _('No files')
def repo_link(groups_and_repos):
@@ -1213,7 +1210,7 @@ def fancy_file_stats(stats):
#import ipdb;ipdb.set_trace()
b_d = '%s
' % (bin_op, cgen('a', a_v='', d_v=0), lbl)
- b_a = ''
+ b_a = ''
return literal('%s%s
' % (width, b_a, b_d))
t = stats['added'] + stats['deleted']
@@ -1243,21 +1240,26 @@ def fancy_file_stats(stats):
return literal('%s%s
' % (width, d_a, d_d))
-def urlify_text(text_, safe=True):
+def _urlify_text(s):
"""
Extract urls from text and make html links out of them
-
- :param text_:
"""
-
def url_func(match_obj):
- url_full = match_obj.groups()[0]
+ url_full = match_obj.group(1)
return '%(url)s' % ({'url': url_full})
- _newtext = url_re.sub(url_func, text_)
- if safe:
- return literal(_newtext)
- return _newtext
+ return url_re.sub(url_func, s)
+def urlify_text(s, truncate=None, stylize=False, truncatef=truncate):
+ """
+ Extract urls from text and make literal html links out of them
+ """
+ if truncate is not None:
+ s = truncatef(s, truncate)
+ s = html_escape(s)
+ if stylize:
+ s = desc_stylize(s)
+ s = _urlify_text(s)
+ return literal(s)
def urlify_changesets(text_, repository):
"""
@@ -1298,14 +1300,13 @@ def urlify_commit(text_, repository, lin
:param repository:
:param link_: changeset link
"""
- def escaper(string):
- return string.replace('<', '<').replace('>', '>')
+ newtext = html_escape(text_)
# urlify changesets - extract revisions and make link out of them
- newtext = urlify_changesets(escaper(text_), repository)
+ newtext = urlify_changesets(newtext, repository)
# extract http/https links and make them real urls
- newtext = urlify_text(newtext, safe=False)
+ newtext = _urlify_text(newtext)
newtext = urlify_issues(newtext, repository, link_)
@@ -1323,19 +1324,19 @@ def urlify_issues(newtext, repository, l
]
if valid_indices:
- log.debug('found issue server suffixes `%s` during valuation of: %s'
- % (','.join(valid_indices), newtext))
+ log.debug('found issue server suffixes `%s` during valuation of: %s',
+ ','.join(valid_indices), newtext)
for pattern_index in valid_indices:
ISSUE_PATTERN = conf.get('issue_pat%s' % pattern_index)
ISSUE_SERVER_LNK = conf.get('issue_server_link%s' % pattern_index)
ISSUE_PREFIX = conf.get('issue_prefix%s' % pattern_index)
- log.debug('pattern suffix `%s` PAT:%s SERVER_LINK:%s PREFIX:%s'
- % (pattern_index, ISSUE_PATTERN, ISSUE_SERVER_LNK,
- ISSUE_PREFIX))
+ log.debug('pattern suffix `%s` PAT:%s SERVER_LINK:%s PREFIX:%s',
+ pattern_index, ISSUE_PATTERN, ISSUE_SERVER_LNK,
+ ISSUE_PREFIX)
- URL_PAT = re.compile(r'%s' % ISSUE_PATTERN)
+ URL_PAT = re.compile(ISSUE_PATTERN)
def url_func(match_obj):
pref = ''
@@ -1362,7 +1363,7 @@ def urlify_issues(newtext, repository, l
'serv': ISSUE_SERVER_LNK,
}
newtext = URL_PAT.sub(url_func, newtext)
- log.debug('processed prefix:`%s` => %s' % (pattern_index, newtext))
+ log.debug('processed prefix:`%s` => %s', pattern_index, newtext)
# if we actually did something above
if link_: