Changeset - 3cef2caf44f3
[Not reviewed]
default
0 9 0
Mads Kiilerich (mads) - 5 years ago 2020-11-13 17:11:20
mads@kiilerich.com
Grafted from: 1e8e18e583df
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.
9 files changed with 155 insertions and 145 deletions:
0 comments (0 inline, 0 general)
kallithea/controllers/admin/users.py
Show inline comments
 
@@ -33,26 +33,26 @@ from formencode import htmlfill
 
from sqlalchemy.sql.expression import func
 
from tg import app_globals, request
 
from tg import tmpl_context as c
 
from tg.i18n import ugettext as _
 
from webob.exc import HTTPFound, HTTPNotFound
 

	
 
import kallithea
 
import kallithea.lib.helpers as h
 
from kallithea.controllers import base
 
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
 
from kallithea.model.ssh_key import SshKeyModel, SshKeyModelException
 
from kallithea.model.user import UserModel
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class UsersController(base.BaseController):
 

	
kallithea/controllers/feed.py
Show inline comments
 
@@ -30,43 +30,43 @@ import logging
 

	
 
from beaker.cache import cache_region
 
from tg import response
 
from tg import tmpl_context as c
 
from tg.i18n import ugettext as _
 

	
 
import kallithea
 
import kallithea.lib.helpers as h
 
from kallithea.controllers import base
 
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__)
 

	
 

	
 
class FeedController(base.BaseRepoController):
 

	
 
    @LoginRequired(allow_default_user=True)
 
    @HasRepoPermissionLevelDecorator('read')
 
    def _before(self, *args, **kwargs):
 
        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))) + '<br/>']
 
                     % (h.person(cs.author), webutils.fmt_date(cs.date))) + '<br/>']
 
        # branches, tags, bookmarks
 
        for branch in cs.branches:
 
            desc_msg.append('branch: %s<br/>' % branch)
 
        for book in cs.bookmarks:
 
            desc_msg.append('bookmark: %s<br/>' % book)
 
        for tag in cs.tags:
 
            desc_msg.append('tag: %s<br/>' % tag)
 

	
 
        changes = []
 
        diff_limit = safe_int(kallithea.CONFIG.get('rss_cut_off_limit', 32 * 1024))
 
        raw_diff = cs.diff()
 
        diff_processor = DiffProcessor(raw_diff,
kallithea/lib/helpers.py
Show inline comments
 
@@ -25,72 +25,71 @@ import urllib.parse
 

	
 
from beaker.cache import cache_region
 
from pygments import highlight as code_highlight
 
from pygments.formatters.html import HtmlFormatter
 
from tg import tmpl_context as c
 
from tg.i18n import ugettext as _
 

	
 
import kallithea
 
from kallithea.lib.annotate import annotate_highlight
 
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
 

	
 

	
 
# 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
 
assert js
 
assert jshtml
 
assert password
 
assert pop_flash_messages
 
assert radio
 
assert render_w_mentions
 
assert reset
 
assert safeid
 
assert select
 
assert session_csrf_secret_name
 
assert session_csrf_secret_token
 
assert shorter
 
assert submit
 
assert text
 
assert textarea
 
assert urlify_text
 
assert wrap_paragraphs
 
# from kallithea.lib.auth
 
assert HasPermissionAny
 
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
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
def FID(raw_id, path):
 
    """
 
    Creates a unique ID for filenode based on it's hash of path and revision
 
    it's safe to use in urls
kallithea/lib/utils2.py
Show inline comments
 
@@ -33,30 +33,27 @@ import hashlib
 
import json
 
import logging
 
import os
 
import re
 
import string
 
import sys
 
import time
 
import urllib.parse
 
from distutils.version import StrictVersion
 

	
 
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
 

	
 
import kallithea
 
from kallithea.lib import webutils
 
from kallithea.lib.vcs.backends.base import BaseRepository, EmptyChangeset
 
from kallithea.lib.vcs.backends.git.repository import GitRepository
 
from kallithea.lib.vcs.conf import settings
 
from kallithea.lib.vcs.exceptions import RepositoryError
 
from kallithea.lib.vcs.utils import ascii_bytes, ascii_str, safe_bytes, safe_str  # re-export
 
from kallithea.lib.vcs.utils.lazy import LazyProperty
 

	
 
@@ -162,142 +159,24 @@ def safe_int(val, default=None):
 
def remove_suffix(s, suffix):
 
    if s.endswith(suffix):
 
        s = s[:-1 * len(suffix)]
 
    return s
 

	
 

	
 
def remove_prefix(s, prefix):
 
    if s.startswith(prefix):
 
        s = s[len(prefix):]
 
    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
 

	
 
    :param uri:
 
    :rtype: str
 
    :returns: filtered list of strings
 
    """
 
    if not uri:
 
        return []
 

	
 
    proto = ''
kallithea/lib/webutils.py
Show inline comments
 
@@ -11,30 +11,34 @@
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
"""
 
kallithea.lib.webutils
 
~~~~~~~~~~~~~~~~~~~~~~
 

	
 
Helper functions that may rely on the current WSGI request, exposed in the TG2
 
thread-local "global" variables. It should have few dependencies so it can be
 
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
 
from webhelpers2.html.tags import checkbox, end_form
 
from webhelpers2.html.tags import form as insecure_form
 
from webhelpers2.html.tags import hidden, link_to, password, radio
 
from webhelpers2.html.tags import select as webhelpers2_select
 
from webhelpers2.html.tags import submit, text, textarea
 
from webhelpers2.number import format_byte_size
 
from webhelpers2.text import chop_at, truncate, wrap_paragraphs
 

	
 
import kallithea
 
@@ -523,12 +527,142 @@ def _urlify_issues(newtext, repo_name):
 
        _urlify_issues_f = tmp_urlify_issues_f
 

	
 
    return _urlify_issues_f(newtext)
 

	
 

	
 
def render_w_mentions(source, repo_name=None):
 
    """
 
    Render plain text with revision hashes and issue references urlified
 
    and with @mention highlighting.
 
    """
 
    s = urlify_text(source, repo_name=repo_name)
 
    return literal('<div class="formatted-fixed">%s</div>' % 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]
kallithea/model/comment.py
Show inline comments
 
@@ -21,25 +21,24 @@ This file was forked by the Kallithea pr
 
Original author and date, and relevant copyright and licensing information is below:
 
:created_on: Nov 11, 2011
 
:author: marcink
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 

	
 
import logging
 
from collections import defaultdict
 

	
 
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
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
def _list_changeset_commenters(revision):
 
    return (meta.Session().query(db.User)
 
        .join(db.ChangesetComment.author)
 
        .filter(db.ChangesetComment.revision == revision)
 
        .all())
 

	
 
@@ -77,25 +76,25 @@ class ChangesetCommentsModel(object):
 
                # use repo owner if we cannot extract the author correctly
 
                # FIXME: just use committer name even if not a user
 
                cs_author = repo.owner
 
            recipients.append(cs_author)
 

	
 
            email_kwargs = {
 
                'status_change': status_change,
 
                'cs_comment_user': author.full_name_and_username,
 
                'cs_target_repo': webutils.canonical_url('summary_home', repo_name=repo.repo_name),
 
                '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,
 
                'short_id': revision[:12],
 
                'branch': cs.branch,
 
                'threading': threading,
 
            }
 
        # pull request
 
        elif pull_request:
 
            notification_type = notification.NotificationModel.TYPE_PULL_REQUEST_COMMENT
 
            _org_ref_type, org_ref_name, _org_rev = comment.pull_request.org_ref.split(':')
 
            _other_ref_type, other_ref_name, _other_rev = comment.pull_request.other_ref.split(':')
 
@@ -107,25 +106,25 @@ class ChangesetCommentsModel(object):
 
                                                          pull_request.pull_request_id, line_no,
 
                                                          webutils.canonical_hostname()))
 
            comment_url = pull_request.url(canonical=True,
 
                anchor='comment-%s' % comment.comment_id)
 
            # get the current participants of this pull request
 
            recipients = _list_pull_request_commenters(pull_request)
 
            recipients.append(pull_request.owner)
 
            recipients += pull_request.get_reviewer_users()
 

	
 
            # 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,
 
                'pr_comment_url': comment_url,
 
                'pr_url': pull_request.url(canonical=True),
 
                'pr_comment_user': author.full_name_and_username,
 
                'pr_target_repo': webutils.canonical_url('summary_home',
 
                                   repo_name=pull_request.other_repo.repo_name),
 
                'pr_target_branch': other_ref_name,
 
                'pr_source_repo': webutils.canonical_url('summary_home',
 
                                   repo_name=pull_request.org_repo.repo_name),
 
                'pr_source_branch': org_ref_name,
kallithea/model/notification.py
Show inline comments
 
@@ -25,25 +25,24 @@ Original author and date, and relevant c
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 

	
 
import datetime
 
import logging
 

	
 
from tg import app_globals
 
from tg import tmpl_context as c
 
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
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class NotificationModel(object):
 

	
 
    TYPE_CHANGESET_COMMENT = 'cs_comment'
 
    TYPE_MESSAGE = 'message'
 
    TYPE_MENTION = 'mention' # not used
 
    TYPE_REGISTRATION = 'registration'
 
@@ -92,25 +91,25 @@ class NotificationModel(object):
 
            )
 
        #else: silently skip notification mails?
 

	
 
        if not with_email:
 
            return
 

	
 
        headers = {}
 
        headers['X-Kallithea-Notification-Type'] = type_
 
        if 'threading' in email_kwargs:
 
            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,
 
                  'user': created_by_obj.username,
 
                  }
 

	
 
        txt_kwargs = {
 
                  'body': body,
 
                  'when': created_on,
 
                  'user': created_by_obj.username,
 
                  }
 

	
kallithea/model/pull_request.py
Show inline comments
 
@@ -25,25 +25,25 @@ Original author and date, and relevant c
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 

	
 
import datetime
 
import logging
 
import re
 

	
 
from tg import request
 
from tg.i18n import ugettext as _
 

	
 
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
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
def _assert_valid_reviewers(seq):
 
    """Sanity check: elements are actual User objects, and not the default user."""
 
    assert not any(user.is_default_user for user in seq)
 

	
 

	
 
class PullRequestModel(object):
 
@@ -76,25 +76,25 @@ class PullRequestModel(object):
 
        # notification to reviewers
 
        pr_url = pr.url(canonical=True)
 
        threading = ['%s-pr-%s@%s' % (pr.other_repo.repo_name,
 
                                      pr.pull_request_id,
 
                                      webutils.canonical_hostname())]
 
        body = pr.description
 
        _org_ref_type, org_ref_name, _org_rev = pr.org_ref.split(':')
 
        _other_ref_type, other_ref_name, _other_rev = pr.other_ref.split(':')
 
        revision_data = [(x.raw_id, x.message)
 
                         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,
 
            'pr_revisions': revision_data,
 
            'repo_name': pr.other_repo.repo_name,
 
            'org_repo_name': pr.org_repo.repo_name,
 
            'pr_nice_id': pr.nice_id(),
 
            'pr_target_repo': webutils.canonical_url('summary_home',
 
                               repo_name=pr.other_repo.repo_name),
 
            'pr_target_branch': other_ref_name,
 
            'pr_source_repo': webutils.canonical_url('summary_home',
 
                               repo_name=pr.org_repo.repo_name),
 
@@ -336,25 +336,25 @@ class CreatePullRequestIterationAction(o
 
        if lost:
 
            infos.append(_('Missing changesets since the previous iteration:'))
 
            for r in old_pull_request.revisions:
 
                if r in lost:
 
                    rev_desc = org_repo.get_changeset(r).message.split('\n')[0]
 
                    infos.append('  %s %s' % (r[:12], rev_desc))
 

	
 
        if new_revisions:
 
            infos.append(_('New changesets on %s %s since the previous iteration:') % (org_ref_type, org_ref_name))
 
            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:"))
 
                infos.append(webutils.canonical_url('compare_url',
 
                                 repo_name=org_repo.repo_name, # other_repo is always same as repo_name
 
                                 org_ref_type='rev', org_ref_name=org_rev[:12], # use old org_rev as base
 
                                 other_ref_type='rev', other_ref_name=new_org_rev[:12],
 
                                 )) # note: linear diff, merge or not doesn't matter
 
            else:
 
                infos.append(_('This iteration is based on another %s revision and there is no simple diff.') % other_ref_name)
 
        else:
 
            infos.append(_('No changes found on %s %s since previous iteration.') % (org_ref_type, org_ref_name))
kallithea/tests/other/test_libs.py
Show inline comments
 
@@ -132,67 +132,67 @@ class TestLibs(base.TestController):
 
        (dict(hours= -24), '1 day ago'),
 
        (dict(hours= -24 * 5), '5 days ago'),
 
        (dict(months= -1), '1 month ago'),
 
        (dict(months= -1, days= -2), '1 month and 2 days ago'),
 
        (dict(months= -1, days= -20), '1 month and 19 days ago'),
 
        (dict(years= -1, months= -1), '1 year and 1 month ago'),
 
        (dict(years= -1, months= -10), '1 year and 10 months ago'),
 
        (dict(years= -2, months= -4), '2 years and 4 months ago'),
 
        (dict(years= -2, months= -11), '2 years and 11 months ago'),
 
        (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)
 
            assert age(n + delt(**age_args), now=n) == expected
 

	
 
    @base.parametrize('age_args,expected', [
 
        (dict(), 'just now'),
 
        (dict(seconds= -1), '1 second ago'),
 
        (dict(seconds= -60 * 2), '2 minutes ago'),
 
        (dict(hours= -1), '1 hour ago'),
 
        (dict(hours= -24), '1 day ago'),
 
        (dict(hours= -24 * 5), '5 days ago'),
 
        (dict(months= -1), '1 month ago'),
 
        (dict(months= -1, days= -2), '1 month ago'),
 
        (dict(months= -1, days= -20), '1 month ago'),
 
        (dict(years= -1, months= -1), '13 months ago'),
 
        (dict(years= -1, months= -10), '22 months ago'),
 
        (dict(years= -2, months= -4), '2 years ago'),
 
        (dict(years= -2, months= -11), '3 years ago'),
 
        (dict(years= -3, months= -2), '3 years ago'),
 
        (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)
 
            assert age(n + delt(**age_args), show_short_version=True, now=n) == expected
 

	
 
    @base.parametrize('age_args,expected', [
 
        (dict(), 'just now'),
 
        (dict(seconds=1), 'in 1 second'),
 
        (dict(seconds=60 * 2), 'in 2 minutes'),
 
        (dict(hours=1), 'in 1 hour'),
 
        (dict(hours=24), 'in 1 day'),
 
        (dict(hours=24 * 5), 'in 5 days'),
 
        (dict(months=1), 'in 1 month'),
 
        (dict(months=1, days=1), 'in 1 month and 1 day'),
 
        (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)
 
            assert age(n + delt(**age_args), now=n) == expected
 

	
 
    def test_tag_extractor(self):
 
        sample = (
 
            "hello pta[tag] gog [[]] [[] sda ero[or]d [me =>>< sa]"
 
            "[requires] [stale] [see<>=>] [see => http://example.com]"
 
            "[requires => url] [lang => python] [just a tag]"
 
            "[,d] [ => ULR ] [obsolete] [desc]]"
 
        )
0 comments (0 inline, 0 general)