# HG changeset patch # User Mads Kiilerich # Date 1605283880 -3600 # Node ID 3cef2caf44f37c2121a08d4e2026768cc746883b # Parent 603876bbf79b8ff84c7237bf8487274bac0d51c0 lib: move some template filter functions from utils2 to webutils While quite Kallithea specific, we prefer to have these functions in webutils where they soon can be exposed when templates don't need the whole helpers module. diff -r 603876bbf79b -r 3cef2caf44f3 kallithea/controllers/admin/users.py --- a/kallithea/controllers/admin/users.py Fri Dec 18 21:35:51 2020 +0100 +++ b/kallithea/controllers/admin/users.py Fri Nov 13 17:11:20 2020 +0100 @@ -42,8 +42,8 @@ from kallithea.lib import auth_modules, webutils from kallithea.lib.auth import AuthUser, HasPermissionAnyDecorator, LoginRequired from kallithea.lib.exceptions import DefaultUserException, UserCreationError, UserOwnsReposException -from kallithea.lib.utils2 import datetime_to_time, fmt_date, generate_api_key, safe_int -from kallithea.lib.webutils import url +from kallithea.lib.utils2 import datetime_to_time, generate_api_key, safe_int +from kallithea.lib.webutils import fmt_date, url from kallithea.model import db, meta, userlog from kallithea.model.api_key import ApiKeyModel from kallithea.model.forms import CustomDefaultPermissionsForm, UserForm diff -r 603876bbf79b -r 3cef2caf44f3 kallithea/controllers/feed.py --- a/kallithea/controllers/feed.py Fri Dec 18 21:35:51 2020 +0100 +++ b/kallithea/controllers/feed.py Fri Nov 13 17:11:20 2020 +0100 @@ -39,7 +39,7 @@ from kallithea.lib import feeds, webutils from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired from kallithea.lib.diffs import DiffProcessor -from kallithea.lib.utils2 import asbool, fmt_date, safe_int, safe_str, shorter +from kallithea.lib.utils2 import asbool, safe_int, safe_str log = logging.getLogger(__name__) @@ -53,11 +53,11 @@ super(FeedController, self)._before(*args, **kwargs) def _get_title(self, cs): - return shorter(cs.message, 160) + return webutils.shorter(cs.message, 160) def __get_desc(self, cs): desc_msg = [(_('%s committed on %s') - % (h.person(cs.author), fmt_date(cs.date))) + '
'] + % (h.person(cs.author), webutils.fmt_date(cs.date))) + '
'] # branches, tags, bookmarks for branch in cs.branches: desc_msg.append('branch: %s
' % branch) diff -r 603876bbf79b -r 3cef2caf44f3 kallithea/lib/helpers.py --- a/kallithea/lib/helpers.py Fri Dec 18 21:35:51 2020 +0100 +++ b/kallithea/lib/helpers.py Fri Nov 13 17:11:20 2020 +0100 @@ -34,14 +34,13 @@ from kallithea.lib.auth import HasPermissionAny, HasRepoGroupPermissionLevel, HasRepoPermissionLevel from kallithea.lib.diffs import BIN_FILENODE, CHMOD_FILENODE, DEL_FILENODE, MOD_FILENODE, NEW_FILENODE, RENAMED_FILENODE from kallithea.lib.pygmentsutils import get_custom_lexer -from kallithea.lib.utils2 import (AttributeDict, age, asbool, credentials_filter, fmt_date, link_to_ref, safe_bytes, safe_int, safe_str, shorter, - time_to_datetime) +from kallithea.lib.utils2 import AttributeDict, asbool, credentials_filter, link_to_ref, safe_bytes, safe_int, safe_str, time_to_datetime from kallithea.lib.vcs.backends.base import BaseChangeset, EmptyChangeset from kallithea.lib.vcs.exceptions import ChangesetDoesNotExistError from kallithea.lib.vcs.utils import author_email, author_name -from kallithea.lib.webutils import (HTML, Option, canonical_url, checkbox, chop_at, end_form, escape, form, format_byte_size, hidden, js, jshtml, link_to, - literal, password, pop_flash_messages, radio, render_w_mentions, reset, safeid, select, session_csrf_secret_name, - session_csrf_secret_token, submit, text, textarea, url, urlify_text, wrap_paragraphs) +from kallithea.lib.webutils import (HTML, Option, age, canonical_url, checkbox, chop_at, end_form, escape, fmt_date, form, format_byte_size, hidden, js, jshtml, + link_to, literal, password, pop_flash_messages, radio, render_w_mentions, reset, safeid, select, session_csrf_secret_name, + session_csrf_secret_token, shorter, submit, text, textarea, url, urlify_text, wrap_paragraphs) from kallithea.model import db from kallithea.model.changeset_status import ChangesetStatusModel @@ -49,10 +48,12 @@ # mute pyflakes "imported but unused" # from webutils assert Option +assert age assert canonical_url assert checkbox assert chop_at assert end_form +assert fmt_date assert form assert format_byte_size assert hidden @@ -67,6 +68,7 @@ assert select assert session_csrf_secret_name assert session_csrf_secret_token +assert shorter assert submit assert text assert textarea @@ -77,11 +79,8 @@ assert HasRepoGroupPermissionLevel assert HasRepoPermissionLevel # from utils2 -assert age assert credentials_filter -assert fmt_date assert link_to_ref -assert shorter assert time_to_datetime # from vcs assert EmptyChangeset diff -r 603876bbf79b -r 3cef2caf44f3 kallithea/lib/utils2.py --- a/kallithea/lib/utils2.py Fri Dec 18 21:35:51 2020 +0100 +++ b/kallithea/lib/utils2.py Fri Nov 13 17:11:20 2020 +0100 @@ -42,12 +42,9 @@ import bcrypt import urlobject -from dateutil import relativedelta from sqlalchemy.engine import url as sa_url from sqlalchemy.exc import ArgumentError from tg import tmpl_context -from tg.i18n import ugettext as _ -from tg.i18n import ungettext from tg.support.converters import asbool, aslist from webhelpers2.text import collapse, remove_formatting, strip_tags @@ -171,124 +168,6 @@ return s -def shorter(s, size=20, firstline=False, postfix='...'): - """Truncate s to size, including the postfix string if truncating. - If firstline, truncate at newline. - """ - if firstline: - s = s.split('\n', 1)[0].rstrip() - if len(s) > size: - return s[:size - len(postfix)] + postfix - return s - - -def age(prevdate, show_short_version=False, now=None): - """ - turns a datetime into an age string. - If show_short_version is True, then it will generate a not so accurate but shorter string, - example: 2days ago, instead of 2 days and 23 hours ago. - - :param prevdate: datetime object - :param show_short_version: if it should approximate the date and return a shorter string - :rtype: str - :returns: str words describing age - """ - now = now or datetime.datetime.now() - order = ['year', 'month', 'day', 'hour', 'minute', 'second'] - deltas = {} - future = False - - if prevdate > now: - now, prevdate = prevdate, now - future = True - if future: - prevdate = prevdate.replace(microsecond=0) - # Get date parts deltas - for part in order: - d = relativedelta.relativedelta(now, prevdate) - deltas[part] = getattr(d, part + 's') - - # Fix negative offsets (there is 1 second between 10:59:59 and 11:00:00, - # not 1 hour, -59 minutes and -59 seconds) - for num, length in [(5, 60), (4, 60), (3, 24)]: # seconds, minutes, hours - part = order[num] - carry_part = order[num - 1] - - if deltas[part] < 0: - deltas[part] += length - deltas[carry_part] -= 1 - - # Same thing for days except that the increment depends on the (variable) - # number of days in the month - month_lengths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] - if deltas['day'] < 0: - if prevdate.month == 2 and (prevdate.year % 4 == 0 and - (prevdate.year % 100 != 0 or prevdate.year % 400 == 0) - ): - deltas['day'] += 29 - else: - deltas['day'] += month_lengths[prevdate.month - 1] - - deltas['month'] -= 1 - - if deltas['month'] < 0: - deltas['month'] += 12 - deltas['year'] -= 1 - - # In short version, we want nicer handling of ages of more than a year - if show_short_version: - if deltas['year'] == 1: - # ages between 1 and 2 years: show as months - deltas['month'] += 12 - deltas['year'] = 0 - if deltas['year'] >= 2: - # ages 2+ years: round - if deltas['month'] > 6: - deltas['year'] += 1 - deltas['month'] = 0 - - # Format the result - fmt_funcs = { - 'year': lambda d: ungettext('%d year', '%d years', d) % d, - 'month': lambda d: ungettext('%d month', '%d months', d) % d, - 'day': lambda d: ungettext('%d day', '%d days', d) % d, - 'hour': lambda d: ungettext('%d hour', '%d hours', d) % d, - 'minute': lambda d: ungettext('%d minute', '%d minutes', d) % d, - 'second': lambda d: ungettext('%d second', '%d seconds', d) % d, - } - - for i, part in enumerate(order): - value = deltas[part] - if value == 0: - continue - - if i < 5: - sub_part = order[i + 1] - sub_value = deltas[sub_part] - else: - sub_value = 0 - - if sub_value == 0 or show_short_version: - if future: - return _('in %s') % fmt_funcs[part](value) - else: - return _('%s ago') % fmt_funcs[part](value) - if future: - return _('in %s and %s') % (fmt_funcs[part](value), - fmt_funcs[sub_part](sub_value)) - else: - return _('%s and %s ago') % (fmt_funcs[part](value), - fmt_funcs[sub_part](sub_value)) - - return _('just now') - - -def fmt_date(date): - if date: - return date.strftime("%Y-%m-%d %H:%M:%S") - return "" - - def uri_filter(uri): """ Removes user:password from given url string diff -r 603876bbf79b -r 3cef2caf44f3 kallithea/lib/webutils.py --- a/kallithea/lib/webutils.py Fri Dec 18 21:35:51 2020 +0100 +++ b/kallithea/lib/webutils.py Fri Nov 13 17:11:20 2020 +0100 @@ -20,12 +20,16 @@ imported anywhere - just like the global variables can be used everywhere. """ +import datetime import json import logging import random import re +from dateutil import relativedelta from tg import request, session +from tg.i18n import ugettext as _ +from tg.i18n import ungettext from webhelpers2.html import HTML, escape, literal from webhelpers2.html.tags import NotGiven, Option, Options, _input from webhelpers2.html.tags import _make_safe_id_component as safeid @@ -532,3 +536,133 @@ """ s = urlify_text(source, repo_name=repo_name) return literal('
%s
' % s) + + +# +# Simple filters +# + +def shorter(s, size=20, firstline=False, postfix='...'): + """Truncate s to size, including the postfix string if truncating. + If firstline, truncate at newline. + """ + if firstline: + s = s.split('\n', 1)[0].rstrip() + if len(s) > size: + return s[:size - len(postfix)] + postfix + return s + + +def age(prevdate, show_short_version=False, now=None): + """ + turns a datetime into an age string. + If show_short_version is True, then it will generate a not so accurate but shorter string, + example: 2days ago, instead of 2 days and 23 hours ago. + + :param prevdate: datetime object + :param show_short_version: if it should approximate the date and return a shorter string + :rtype: str + :returns: str words describing age + """ + now = now or datetime.datetime.now() + order = ['year', 'month', 'day', 'hour', 'minute', 'second'] + deltas = {} + future = False + + if prevdate > now: + now, prevdate = prevdate, now + future = True + if future: + prevdate = prevdate.replace(microsecond=0) + # Get date parts deltas + for part in order: + d = relativedelta.relativedelta(now, prevdate) + deltas[part] = getattr(d, part + 's') + + # Fix negative offsets (there is 1 second between 10:59:59 and 11:00:00, + # not 1 hour, -59 minutes and -59 seconds) + for num, length in [(5, 60), (4, 60), (3, 24)]: # seconds, minutes, hours + part = order[num] + carry_part = order[num - 1] + + if deltas[part] < 0: + deltas[part] += length + deltas[carry_part] -= 1 + + # Same thing for days except that the increment depends on the (variable) + # number of days in the month + month_lengths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] + if deltas['day'] < 0: + if prevdate.month == 2 and (prevdate.year % 4 == 0 and + (prevdate.year % 100 != 0 or prevdate.year % 400 == 0) + ): + deltas['day'] += 29 + else: + deltas['day'] += month_lengths[prevdate.month - 1] + + deltas['month'] -= 1 + + if deltas['month'] < 0: + deltas['month'] += 12 + deltas['year'] -= 1 + + # In short version, we want nicer handling of ages of more than a year + if show_short_version: + if deltas['year'] == 1: + # ages between 1 and 2 years: show as months + deltas['month'] += 12 + deltas['year'] = 0 + if deltas['year'] >= 2: + # ages 2+ years: round + if deltas['month'] > 6: + deltas['year'] += 1 + deltas['month'] = 0 + + # Format the result + fmt_funcs = { + 'year': lambda d: ungettext('%d year', '%d years', d) % d, + 'month': lambda d: ungettext('%d month', '%d months', d) % d, + 'day': lambda d: ungettext('%d day', '%d days', d) % d, + 'hour': lambda d: ungettext('%d hour', '%d hours', d) % d, + 'minute': lambda d: ungettext('%d minute', '%d minutes', d) % d, + 'second': lambda d: ungettext('%d second', '%d seconds', d) % d, + } + + for i, part in enumerate(order): + value = deltas[part] + if value == 0: + continue + + if i < 5: + sub_part = order[i + 1] + sub_value = deltas[sub_part] + else: + sub_value = 0 + + if sub_value == 0 or show_short_version: + if future: + return _('in %s') % fmt_funcs[part](value) + else: + return _('%s ago') % fmt_funcs[part](value) + if future: + return _('in %s and %s') % (fmt_funcs[part](value), + fmt_funcs[sub_part](sub_value)) + else: + return _('%s and %s ago') % (fmt_funcs[part](value), + fmt_funcs[sub_part](sub_value)) + + return _('just now') + + +def fmt_date(date): + if date: + return date.strftime("%Y-%m-%d %H:%M:%S") + return "" + + +def capitalize(x): + return x.capitalize() + + +def short_id(x): + return x[:12] diff -r 603876bbf79b -r 3cef2caf44f3 kallithea/model/comment.py --- a/kallithea/model/comment.py Fri Dec 18 21:35:51 2020 +0100 +++ b/kallithea/model/comment.py Fri Nov 13 17:11:20 2020 +0100 @@ -30,7 +30,6 @@ from kallithea.lib import webutils from kallithea.lib.utils import extract_mentioned_users -from kallithea.lib.utils2 import shorter from kallithea.model import db, meta, notification @@ -86,7 +85,7 @@ 'cs_comment_url': comment_url, 'cs_url': webutils.canonical_url('changeset_home', repo_name=repo.repo_name, revision=revision), 'message': cs.message, - 'message_short': shorter(cs.message, 50, firstline=True), + 'message_short': webutils.shorter(cs.message, 50, firstline=True), 'cs_author': cs_author, 'cs_author_username': cs_author.username, 'repo_name': repo.repo_name, @@ -116,7 +115,7 @@ # set some variables for email notification email_kwargs = { 'pr_title': pull_request.title, - 'pr_title_short': shorter(pull_request.title, 50), + 'pr_title_short': webutils.shorter(pull_request.title, 50), 'pr_nice_id': pull_request.nice_id(), 'status_change': status_change, 'closing_pr': closing_pr, diff -r 603876bbf79b -r 3cef2caf44f3 kallithea/model/notification.py --- a/kallithea/model/notification.py Fri Dec 18 21:35:51 2020 +0100 +++ b/kallithea/model/notification.py Fri Nov 13 17:11:20 2020 +0100 @@ -34,7 +34,6 @@ from tg.i18n import ugettext as _ from kallithea.lib import webutils -from kallithea.lib.utils2 import fmt_date from kallithea.model import async_tasks, db @@ -101,7 +100,7 @@ headers['References'] = ' '.join('<%s>' % x for x in email_kwargs['threading']) # this is passed into template - created_on = fmt_date(datetime.datetime.now()) + created_on = webutils.fmt_date(datetime.datetime.now()) html_kwargs = { 'body': None if body is None else webutils.render_w_mentions(body, repo_name), 'when': created_on, diff -r 603876bbf79b -r 3cef2caf44f3 kallithea/model/pull_request.py --- a/kallithea/model/pull_request.py Fri Dec 18 21:35:51 2020 +0100 +++ b/kallithea/model/pull_request.py Fri Nov 13 17:11:20 2020 +0100 @@ -34,7 +34,7 @@ from kallithea.lib import auth, hooks, webutils from kallithea.lib.utils import extract_mentioned_users -from kallithea.lib.utils2 import ascii_bytes, short_ref_name, shorter +from kallithea.lib.utils2 import ascii_bytes, short_ref_name from kallithea.model import changeset_status, comment, db, meta, notification @@ -85,7 +85,7 @@ for x in map(pr.org_repo.get_changeset, pr.revisions)] email_kwargs = { 'pr_title': pr.title, - 'pr_title_short': shorter(pr.title, 50), + 'pr_title_short': webutils.shorter(pr.title, 50), 'pr_user_created': user.full_name_and_username, 'pr_repo_url': webutils.canonical_url('summary_home', repo_name=pr.other_repo.repo_name), 'pr_url': pr_url, @@ -345,7 +345,7 @@ for r in reversed(revisions): if r in new_revisions: rev_desc = org_repo.get_changeset(r).message.split('\n')[0] - infos.append(' %s %s' % (r[:12], shorter(rev_desc, 80))) + infos.append(' %s %s' % (r[:12], webutils.shorter(rev_desc, 80))) if self.create_action.other_ref == old_pull_request.other_ref: infos.append(_("Ancestor didn't change - diff since previous iteration:")) diff -r 603876bbf79b -r 3cef2caf44f3 kallithea/tests/other/test_libs.py --- a/kallithea/tests/other/test_libs.py Fri Dec 18 21:35:51 2020 +0100 +++ b/kallithea/tests/other/test_libs.py Fri Nov 13 17:11:20 2020 +0100 @@ -141,7 +141,7 @@ (dict(years= -3, months= -2), '3 years and 2 months ago'), ]) def test_age(self, age_args, expected): - from kallithea.lib.utils2 import age + from kallithea.lib.webutils import age with test_context(self.app): n = datetime.datetime(year=2012, month=5, day=17) delt = lambda *args, **kwargs: relativedelta.relativedelta(*args, **kwargs) @@ -165,7 +165,7 @@ (dict(years= -4, months= -8), '5 years ago'), ]) def test_age_short(self, age_args, expected): - from kallithea.lib.utils2 import age + from kallithea.lib.webutils import age with test_context(self.app): n = datetime.datetime(year=2012, month=5, day=17) delt = lambda *args, **kwargs: relativedelta.relativedelta(*args, **kwargs) @@ -183,7 +183,7 @@ (dict(years=1, months=1), 'in 1 year and 1 month') ]) def test_age_in_future(self, age_args, expected): - from kallithea.lib.utils2 import age + from kallithea.lib.webutils import age with test_context(self.app): n = datetime.datetime(year=2012, month=5, day=17) delt = lambda *args, **kwargs: relativedelta.relativedelta(*args, **kwargs)