Changeset - 4753a3445ff7
[Not reviewed]
Merge codereview
0 3 0
Marcin Kuzminski - 13 years ago 2012-06-11 23:28:22
marcin@python-works.com
merge with beta
3 files changed with 9 insertions and 8 deletions:
0 comments (0 inline, 0 general)
rhodecode/lib/helpers.py
Show inline comments
 
"""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 urllib
 
import math
 
import logging
 

	
 
from datetime import datetime
 
from pygments.formatters.html import HtmlFormatter
 
from pygments import highlight as code_highlight
 
from pylons import url, request, config
 
from pylons.i18n.translation import _, ungettext
 
from hashlib import md5
 

	
 
from webhelpers.html import literal, HTML, escape
 
from webhelpers.html.tools import *
 
from webhelpers.html.builder import make_tag
 
from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
 
    end_form, file, form, hidden, image, javascript_link, link_to, \
 
    link_to_if, link_to_unless, ol, required_legend, select, stylesheet_link, \
 
    submit, text, password, textarea, title, ul, xml_declaration, radio
 
from webhelpers.html.tools import auto_link, button_to, highlight, \
 
    js_obfuscate, mail_to, strip_links, strip_tags, tag_re
 
from webhelpers.number import format_byte_size, format_bit_size
 
from webhelpers.pylonslib import Flash as _Flash
 
from webhelpers.pylonslib.secure_form import secure_form
 
from webhelpers.text import chop_at, collapse, convert_accented_entities, \
 
    convert_misc_entities, lchop, plural, rchop, remove_formatting, \
 
    replace_whitespace, urlify, truncate, wrap_paragraphs
 
from webhelpers.date import time_ago_in_words
 
from webhelpers.paginate import Page
 
from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
 
    convert_boolean_attrs, NotGiven, _make_safe_id_component
 

	
 
from rhodecode.lib.annotate import annotate_highlight
 
from rhodecode.lib.utils import repo_name_slug
 
from rhodecode.lib.utils2 import str2bool, safe_unicode, safe_str, \
 
    get_changeset_safe
 
from rhodecode.lib.markup_renderer import MarkupRenderer
 
from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError
 
from rhodecode.lib.vcs.backends.base import BaseChangeset
 
from rhodecode.config.conf import DATE_FORMAT, DATETIME_FORMAT
 
from rhodecode.model.changeset_status import ChangesetStatusModel
 
from rhodecode.model.db import URL_SEP
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
def shorter(text, size=20):
 
    postfix = '...'
 
    if len(text) > size:
 
        return text[:size - len(postfix)] + postfix
 
    return text
 

	
 

	
 
def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
 
    """
 
    Reset button
 
    """
 
    _set_input_attrs(attrs, type, name, value)
 
    _set_id_attr(attrs, id, name)
 
    convert_boolean_attrs(attrs, ["disabled"])
 
    return HTML.input(**attrs)
 

	
 
reset = _reset
 
safeid = _make_safe_id_component
 

	
 

	
 
def FID(raw_id, path):
 
    """
 
    Creates a uniqe ID for filenode based on it's hash of path and revision
 
    it's safe to use in urls
 

	
 
    :param raw_id:
 
    :param path:
 
    """
 

	
 
    return 'C-%s-%s' % (short_id(raw_id), md5(safe_str(path)).hexdigest()[:12])
 

	
 

	
 
def get_token():
 
    """Return the current authentication token, creating one if one doesn't
 
    already exist.
 
    """
 
    token_key = "_authentication_token"
 
    from pylons import session
 
    if not token_key in session:
 
        try:
 
            token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
 
        except AttributeError:  # Python < 2.4
 
@@ -306,98 +307,98 @@ def pygmentize_annotation(repo_name, fil
 
            date = changeset.date
 
            message = tooltip(changeset.message)
 

	
 
            tooltip_html = ("<div style='font-size:0.8em'><b>Author:</b>"
 
                            " %s<br/><b>Date:</b> %s</b><br/><b>Message:"
 
                            "</b> %s<br/></div>")
 

	
 
            tooltip_html = tooltip_html % (author, date, message)
 
            lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
 
                                     short_id(changeset.raw_id))
 
            uri = link_to(
 
                    lnk_format,
 
                    url('changeset_home', repo_name=repo_name,
 
                        revision=changeset.raw_id),
 
                    style=get_color_string(changeset.raw_id),
 
                    class_='tooltip',
 
                    title=tooltip_html
 
                  )
 

	
 
            uri += '\n'
 
            return uri
 
        return _url_func
 

	
 
    return literal(annotate_highlight(filenode, url_func(repo_name), **kwargs))
 

	
 

	
 
def is_following_repo(repo_name, user_id):
 
    from rhodecode.model.scm import ScmModel
 
    return ScmModel().is_following_repo(repo_name, user_id)
 

	
 
flash = _Flash()
 

	
 
#==============================================================================
 
# SCM FILTERS available via h.
 
#==============================================================================
 
from rhodecode.lib.vcs.utils import author_name, author_email
 
from rhodecode.lib.utils2 import credentials_filter, age as _age
 
from rhodecode.model.db import User, ChangesetStatus
 

	
 
age = lambda  x: _age(x)
 
capitalize = lambda x: x.capitalize()
 
email = author_email
 
short_id = lambda x: x[:12]
 
hide_credentials = lambda x: ''.join(credentials_filter(x))
 

	
 

	
 
def fmt_date(date):
 
    if date:
 
        return (date.strftime(_(u"%a, %d %b %Y %H:%M:%S").encode('utf8'))
 
            .decode('utf8'))
 
        _fmt = _(u"%a, %d %b %Y %H:%M:%S").encode('utf8')
 
        return date.strftime(_fmt).decode('utf8')
 

	
 
    return ""
 

	
 

	
 
def is_git(repository):
 
    if hasattr(repository, 'alias'):
 
        _type = repository.alias
 
    elif hasattr(repository, 'repo_type'):
 
        _type = repository.repo_type
 
    else:
 
        _type = repository
 
    return _type == 'git'
 

	
 

	
 
def is_hg(repository):
 
    if hasattr(repository, 'alias'):
 
        _type = repository.alias
 
    elif hasattr(repository, 'repo_type'):
 
        _type = repository.repo_type
 
    else:
 
        _type = repository
 
    return _type == 'hg'
 

	
 

	
 
def email_or_none(author):
 
    _email = email(author)
 
    if _email != '':
 
        return _email
 

	
 
    # See if it contains a username we can get an email from
 
    user = User.get_by_username(author_name(author), case_insensitive=True,
 
                                cache=True)
 
    if user is not None:
 
        return user.email
 

	
 
    # No valid email, not a valid user in the system, none!
 
    return None
 

	
 

	
 
def person(author):
 
    # attr to return from fetched user
 
    person_getter = lambda usr: usr.username
 

	
 
    # Valid email in the attribute passed, see if they're in the system
 
    _email = email(author)
 
    if _email != '':
 
        user = User.get_by_email(_email, case_insensitive=True, cache=True)
 
        if user is not None:
rhodecode/model/notification.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.notification
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Model for notifications
 

	
 

	
 
    :created_on: Nov 20, 2011
 
    :author: marcink
 
    :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
import os
 
import logging
 
import traceback
 
import datetime
 

	
 
from pylons.i18n.translation import _
 

	
 
import rhodecode
 
from rhodecode.config.conf import DATETIME_FORMAT
 
from rhodecode.lib import helpers as h
 
from rhodecode.model import BaseModel
 
from rhodecode.model.db import Notification, User, UserNotification
 
from sqlalchemy.orm import joinedload
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class NotificationModel(BaseModel):
 

	
 
    def __get_notification(self, notification):
 
        if isinstance(notification, Notification):
 
            return notification
 
        elif isinstance(notification, (int, long)):
 
            return Notification.get(notification)
 
        else:
 
            if notification:
 
                raise Exception('notification must be int, long or Instance'
 
                                ' of Notification got %s' % type(notification))
 

	
 
    def create(self, created_by, subject, body, recipients=None,
 
               type_=Notification.TYPE_MESSAGE, with_email=True,
 
               email_kwargs={}):
 
        """
 

	
 
        Creates notification of given type
 

	
 
        :param created_by: int, str or User instance. User who created this
 
            notification
 
        :param subject:
 
        :param body:
 
        :param recipients: list of int, str or User objects, when None
 
            is given send to all admins
 
        :param type_: type of notification
 
        :param with_email: send email with this notification
 
        :param email_kwargs: additional dict to pass as args to email template
 
        """
 
        from rhodecode.lib.celerylib import tasks, run_task
 

	
 
        if recipients and not getattr(recipients, '__iter__', False):
 
            raise Exception('recipients must be a list of iterable')
 

	
 
        created_by_obj = self._get_user(created_by)
 

	
 
        if recipients:
 
            recipients_objs = []
 
            for u in recipients:
 
                obj = self._get_user(u)
 
@@ -164,95 +163,95 @@ class NotificationModel(BaseModel):
 
            .filter(UserNotification.read == False)\
 
            .join((Notification, UserNotification.notification_id ==
 
                                 Notification.notification_id))
 
        if filter_:
 
            q = q.filter(Notification.type_ == filter_.get('type'))
 

	
 
        # this is a little inefficient but sqlalchemy doesn't support
 
        # update on joined tables :(
 
        for obj in q.all():
 
            obj.read = True
 
            self.sa.add(obj)
 

	
 
    def get_unread_cnt_for_user(self, user):
 
        user = self._get_user(user)
 
        return UserNotification.query()\
 
                .filter(UserNotification.read == False)\
 
                .filter(UserNotification.user == user).count()
 

	
 
    def get_unread_for_user(self, user):
 
        user = self._get_user(user)
 
        return [x.notification for x in UserNotification.query()\
 
                .filter(UserNotification.read == False)\
 
                .filter(UserNotification.user == user).all()]
 

	
 
    def get_user_notification(self, user, notification):
 
        user = self._get_user(user)
 
        notification = self.__get_notification(notification)
 

	
 
        return UserNotification.query()\
 
            .filter(UserNotification.notification == notification)\
 
            .filter(UserNotification.user == user).scalar()
 

	
 
    def make_description(self, notification, show_age=True):
 
        """
 
        Creates a human readable description based on properties
 
        of notification object
 
        """
 
        #alias
 
        _n = notification
 
        _map = {
 
            _n.TYPE_CHANGESET_COMMENT: _('commented on commit'),
 
            _n.TYPE_MESSAGE: _('sent message'),
 
            _n.TYPE_MENTION: _('mentioned you'),
 
            _n.TYPE_REGISTRATION: _('registered in RhodeCode'),
 
            _n.TYPE_PULL_REQUEST: _('opened new pull request'),
 
            _n.TYPE_PULL_REQUEST_COMMENT: _('commented on pull request')
 
        }
 

	
 
        tmpl = "%(user)s %(action)s %(when)s"
 
        # action == _map string
 
        tmpl = "%(user)s %(action)s at %(when)s"
 
        if show_age:
 
            when = h.age(notification.created_on)
 
        else:
 
            DTF = lambda d: datetime.datetime.strftime(d, DATETIME_FORMAT)
 
            when = DTF(notification.created_on)
 
            when = h.fmt_date(notification.created_on)
 

	
 
        data = dict(
 
            user=notification.created_by_user.username,
 
            action=_map[notification.type_], when=when,
 
        )
 
        return tmpl % data
 

	
 

	
 
class EmailNotificationModel(BaseModel):
 

	
 
    TYPE_CHANGESET_COMMENT = Notification.TYPE_CHANGESET_COMMENT
 
    TYPE_PASSWORD_RESET = 'passoword_link'
 
    TYPE_REGISTRATION = Notification.TYPE_REGISTRATION
 
    TYPE_PULL_REQUEST = Notification.TYPE_PULL_REQUEST
 
    TYPE_DEFAULT = 'default'
 

	
 
    def __init__(self):
 
        self._template_root = rhodecode.CONFIG['pylons.paths']['templates'][0]
 
        self._tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup
 

	
 
        self.email_types = {
 
         self.TYPE_CHANGESET_COMMENT: 'email_templates/changeset_comment.html',
 
         self.TYPE_PASSWORD_RESET: 'email_templates/password_reset.html',
 
         self.TYPE_REGISTRATION: 'email_templates/registration.html',
 
         self.TYPE_DEFAULT: 'email_templates/default.html'
 
        }
 

	
 
    def get_email_tmpl(self, type_, **kwargs):
 
        """
 
        return generated template for email based on given type
 

	
 
        :param type_:
 
        """
 

	
 
        base = self.email_types.get(type_, self.email_types[self.TYPE_DEFAULT])
 
        email_template = self._tmpl_lookup.get_template(base)
 
        # translator inject
 
        _kwargs = {'_': _}
 
        _kwargs.update(kwargs)
 
        log.debug('rendering tmpl %s with kwargs %s' % (base, _kwargs))
 
        return email_template.render(**_kwargs)
rhodecode/templates/changeset/changeset_range.html
Show inline comments
 
@@ -9,86 +9,87 @@
 
    ${h.link_to(u'Home',h.url('/'))}
 
    &raquo;
 
    ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
 
    &raquo;
 
    ${_('Changesets')} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)}
 
</%def>
 

	
 
<%def name="page_nav()">
 
    ${self.menu('changelog')}
 
</%def>
 

	
 
<%def name="main()">
 
<div class="box">
 
    <!-- box / title -->
 
    <div class="title">
 
        ${self.breadcrumbs()}
 
    </div>
 
    <div class="table">
 
		<div id="body" class="diffblock">
 
			<div class="code-header cv">
 
		        <h3 class="code-header-title">${_('Compare View')}</h3>
 
                <div>
 
				${_('Changesets')} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)}
 
				</div>
 
			</div>
 
		</div>
 
	    <div id="changeset_compare_view_content">
 
			<div class="container">
 
			<table class="compare_view_commits noborder">
 
            %for cnt,cs in enumerate(c.cs_ranges):
 
                <tr>
 
                <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(h.email(cs.author),14)}"/></div></td>
 
                <td>${h.link_to('r%s:%s' % (cs.revision,h.short_id(cs.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</td>
 
                <td><div class="author">${h.person(cs.author)}</div></td>
 
                <td><span class="tooltip" title="${h.age(cs.date)}">${cs.date}</span></td>
 
                <td>
 
                  %if c.statuses:
 
                    <div title="${h.tooltip(_('Changeset status'))}" class="changeset-status-ico"><img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses[cnt])}" /></div>
 
                  %endif
 
                </td>
 
                <td><div class="message">${h.urlify_commit(h.wrap_paragraphs(cs.message),c.repo_name)}</div></td>
 
                </tr>
 
            %endfor
 
            </table>
 
	        </div>
 
	        <div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">${_('Files affected')}</div>
 
	        <div class="cs_files">
 
	               %for cs in c.cs_ranges:
 
	                   <div class="cur_cs">r${cs}</div>
 
	                   <div class="cur_cs">${h.link_to('r%s:%s' % (cs.revision,h.short_id(cs.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div>
 
	                %for change,filenode,diff,cs1,cs2,st in c.changes[cs.raw_id]:
 
	                    <div class="cs_${change}">${h.link_to(h.safe_unicode(filenode.path),h.url.current(anchor=h.FID(cs.raw_id,filenode.path)))}</div>
 
	                %endfor
 
	               %endfor
 
	        </div>
 
	    </div>
 

	
 
    </div>
 
    <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
 
    <%namespace name="diff_block" file="/changeset/diff_block.html"/>
 
     %for cs in c.cs_ranges:
 
          ##${comment.comment_inline_form(cs)}
 
          ## diff block
 
          <h3 style="border:none;padding-top:8px;">${'r%s:%s' % (cs.revision,h.short_id(cs.raw_id))}</h3>
 
          <h3 style="padding-top:8px;">${h.link_to('r%s:%s' % (cs.revision,h.short_id(cs.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</h3>
 
          
 
          ${diff_block.diff_block(c.changes[cs.raw_id])}
 
          ##${comment.comments(cs)}
 

	
 
     %endfor
 
     <script type="text/javascript">
 

	
 
      YUE.onDOMReady(function(){
 

	
 
          YUE.on(YUQ('.diff-menu-activate'),'click',function(e){
 
              var act = e.currentTarget.nextElementSibling;
 

	
 
              if(YUD.hasClass(act,'active')){
 
                  YUD.removeClass(act,'active');
 
                  YUD.setStyle(act,'display','none');
 
              }else{
 
                  YUD.addClass(act,'active');
 
                  YUD.setStyle(act,'display','');
 
              }
 
          });
 
      })
 
    </script>
 
    </div>
 
</%def>
0 comments (0 inline, 0 general)