Changeset - df61378032f3
[Not reviewed]
beta
0 4 0
Marcin Kuzminski - 15 years ago 2010-11-05 22:36:51
marcin@python-works.com
#48 rewrote action logger, translated action logger messages, added some extra messages. Linked and showed pushed revisions in logs
4 files changed with 52 insertions and 9 deletions:
0 comments (0 inline, 0 general)
rhodecode/controllers/admin/repos.py
Show inline comments
 
#!/usr/bin/env python
 
# encoding: utf-8
 
# repos controller for pylons
 
# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
 
#
 
# 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; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
# 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, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
"""
 
Created on April 7, 2010
 
admin controller for pylons
 
@author: marcink
 
"""
 
from formencode import htmlfill
 
from operator import itemgetter
 
from paste.httpexceptions import HTTPInternalServerError
 
from pylons import request, response, session, tmpl_context as c, url
 
from pylons.controllers.util import abort, redirect
 
from pylons.i18n.translation import _
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
 
    HasPermissionAnyDecorator
 
from rhodecode.lib.base import BaseController, render
 
from rhodecode.lib.utils import invalidate_cache, action_logger
 
from rhodecode.model.db import User
 
from rhodecode.model.forms import RepoForm
 
from rhodecode.model.hg import HgModel
 
from rhodecode.model.repo import RepoModel
 
import formencode
 
import logging
 
import traceback
 

	
 
log = logging.getLogger(__name__)
 

	
 
class ReposController(BaseController):
 
    """REST Controller styled on the Atom Publishing Protocol"""
 
    # To properly map this controller, ensure your config/routing.py
 
    # file has a resource setup:
 
    #     map.resource('repo', 'repos')
 

	
 
    @LoginRequired()
 
    @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
 
    def __before__(self):
 
        c.admin_user = session.get('admin_user')
 
        c.admin_username = session.get('admin_username')
 
        super(ReposController, self).__before__()
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def index(self, format='html'):
 
        """GET /repos: All items in the collection"""
 
        # url('repos')
 
        cached_repo_list = HgModel().get_repos()
 
        c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
 
        return render('admin/repos/repos.html')
 

	
 
    @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
 
    def create(self):
 
        """POST /repos: Create a new item"""
 
        # url('repos')
 
        repo_model = RepoModel()
 
        _form = RepoForm()()
 
        form_result = {}
 
        try:
 
            form_result = _form.to_python(dict(request.POST))
 
            repo_model.create(form_result, c.rhodecode_user)
 
            invalidate_cache('cached_repo_list')
 
            h.flash(_('created repository %s') % form_result['repo_name'],
 
                    category='success')
 

	
 
            if request.POST.get('user_created'):
 
                action_logger(self.rhodecode_user, 'user_created_repo',
 
                              form_result['repo_name'], '', self.sa)
 
            else:
 
                action_logger(self.rhodecode_user, 'admin_created_repo',
 
                              form_result['repo_name'], '', self.sa)
 

	
 
        except formencode.Invalid, errors:
 
            c.new_repo = errors.value['repo_name']
 

	
 
            if request.POST.get('user_created'):
 
                r = render('admin/repos/repo_add_create_repository.html')
 
            else:
 
                r = render('admin/repos/repo_add.html')
 

	
 
            return htmlfill.render(
 
                r,
 
                defaults=errors.value,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8")
 

	
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            msg = _('error occured during creation of repository %s') \
 
                    % form_result.get('repo_name')
 
            h.flash(msg, category='error')
 
        if request.POST.get('user_created'):
 
            return redirect(url('home'))
 
        return redirect(url('repos'))
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def new(self, format='html'):
 
        """GET /repos/new: Form to create a new item"""
 
        new_repo = request.GET.get('repo', '')
 
        c.new_repo = h.repo_name_slug(new_repo)
 

	
 
        return render('admin/repos/repo_add.html')
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def update(self, repo_name):
 
        """PUT /repos/repo_name: Update an existing item"""
 
        # Forms posted to this method should contain a hidden field:
 
        #    <input type="hidden" name="_method" value="PUT" />
 
        # Or using helpers:
 
        #    h.form(url('repo', repo_name=ID),
 
        #           method='put')
 
        # url('repo', repo_name=ID)
 
        repo_model = RepoModel()
 
        changed_name = repo_name
 
        _form = RepoForm(edit=True, old_data={'repo_name':repo_name})()
 

	
 
        try:
 
            form_result = _form.to_python(dict(request.POST))
 
            repo_model.update(repo_name, form_result)
 
            invalidate_cache('cached_repo_list')
 
            h.flash(_('Repository %s updated succesfully' % repo_name),
 
                    category='success')
 
            changed_name = form_result['repo_name']
 
            action_logger(self.rhodecode_user, 'admin_updated_repo',
 
                              changed_name, '', self.sa)
 

	
 
        except formencode.Invalid, errors:
 
            c.repo_info = repo_model.get(repo_name)
 
            c.users_array = repo_model.get_users_js()
 
            errors.value.update({'user':c.repo_info.user.username})
 
            return htmlfill.render(
 
                render('admin/repos/repo_edit.html'),
 
                defaults=errors.value,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8")
 

	
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('error occured during update of repository %s') \
 
                    % repo_name, category='error')
 

	
 
        return redirect(url('edit_repo', repo_name=changed_name))
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def delete(self, repo_name):
 
        """DELETE /repos/repo_name: Delete an existing item"""
 
        # Forms posted to this method should contain a hidden field:
 
        #    <input type="hidden" name="_method" value="DELETE" />
 
        # Or using helpers:
 
        #    h.form(url('repo', repo_name=ID),
 
        #           method='delete')
 
        # url('repo', repo_name=ID)
 

	
 
        repo_model = RepoModel()
 
        repo = repo_model.get(repo_name)
 
        if not repo:
 
            h.flash(_('%s repository is not mapped to db perhaps'
 
                      ' it was moved or renamed  from the filesystem'
 
                      ' please run the application again'
 
                      ' in order to rescan repositories') % repo_name,
 
                      category='error')
 

	
 
            return redirect(url('repos'))
 
        try:
 
            action_logger(self.rhodecode_user, 'admin_deleted_repo',
 
                              repo_name, '', self.sa)
 
            repo_model.delete(repo)
 
            invalidate_cache('cached_repo_list')
 
            h.flash(_('deleted repository %s') % repo_name, category='success')
 

	
 
        except Exception, e:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occured during deletion of %s') % repo_name,
 
                    category='error')
 

	
 
        return redirect(url('repos'))
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def delete_perm_user(self, repo_name):
 
        """
 
        DELETE an existing repository permission user
 
        :param repo_name:
 
        """
 

	
 
        try:
 
            repo_model = RepoModel()
 
            repo_model.delete_perm_user(request.POST, repo_name)
 
        except Exception, e:
 
            h.flash(_('An error occured during deletion of repository user'),
 
                    category='error')
 
            raise HTTPInternalServerError()
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def show(self, repo_name, format='html'):
 
        """GET /repos/repo_name: Show a specific item"""
 
        # url('repo', repo_name=ID)
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def edit(self, repo_name, format='html'):
 
        """GET /repos/repo_name/edit: Form to edit an existing item"""
 
        # url('edit_repo', repo_name=ID)
 
        repo_model = RepoModel()
 
        c.repo_info = repo = repo_model.get(repo_name)
 
        if not repo:
 
            h.flash(_('%s repository is not mapped to db perhaps'
 
                      ' it was created or renamed from the filesystem'
 
                      ' please run the application again'
 
                      ' in order to rescan repositories') % repo_name,
 
                      category='error')
 

	
 
            return redirect(url('repos'))
 
        defaults = c.repo_info.__dict__
 
        if c.repo_info.user:
 
            defaults.update({'user':c.repo_info.user.username})
 
        else:
 
            replacement_user = self.sa.query(User)\
 
            .filter(User.admin == True).first().username
 
            defaults.update({'user':replacement_user})
 

	
 
        c.users_array = repo_model.get_users_js()
 

	
 
        for p in c.repo_info.repo_to_perm:
 
            defaults.update({'perm_%s' % p.user.username:
 
                             p.permission.permission_name})
 

	
 
        return htmlfill.render(
 
            render('admin/repos/repo_edit.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False
 
        )
rhodecode/controllers/settings.py
Show inline comments
 
#!/usr/bin/env python
 
# encoding: utf-8
 
# settings controller for pylons
 
# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
 
# 
 
# 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; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
# 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, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
"""
 
Created on June 30, 2010
 
settings controller for pylons
 
@author: marcink
 
"""
 
from formencode import htmlfill
 
from pylons import tmpl_context as c, request, url
 
from pylons.controllers.util import redirect
 
from pylons.i18n.translation import _
 
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAllDecorator
 
from rhodecode.lib.base import BaseController, render
 
from rhodecode.lib.utils import invalidate_cache, action_logger
 
from rhodecode.model.forms import RepoSettingsForm, RepoForkForm
 
from rhodecode.model.repo import RepoModel
 
import formencode
 
import logging
 
import rhodecode.lib.helpers as h
 
import traceback
 

	
 
log = logging.getLogger(__name__)
 

	
 
class SettingsController(BaseController):
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAllDecorator('repository.admin')
 
    def __before__(self):
 
        super(SettingsController, self).__before__()
 

	
 
    def index(self, repo_name):
 
        repo_model = RepoModel()
 
        c.repo_info = repo = repo_model.get(repo_name)
 
        if not repo:
 
            h.flash(_('%s repository is not mapped to db perhaps'
 
                      ' it was created or renamed from the filesystem'
 
                      ' please run the application again'
 
                      ' in order to rescan repositories') % repo_name,
 
                      category='error')
 

	
 
            return redirect(url('home'))
 
        defaults = c.repo_info.__dict__
 
        defaults.update({'user':c.repo_info.user.username})
 
        c.users_array = repo_model.get_users_js()
 

	
 
        for p in c.repo_info.repo_to_perm:
 
            defaults.update({'perm_%s' % p.user.username:
 
                             p.permission.permission_name})
 

	
 
        return htmlfill.render(
 
            render('settings/repo_settings.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False
 
        )
 

	
 
    def update(self, repo_name):
 
        repo_model = RepoModel()
 
        changed_name = repo_name
 
        _form = RepoSettingsForm(edit=True, old_data={'repo_name':repo_name})()
 
        try:
 
            form_result = _form.to_python(dict(request.POST))
 
            repo_model.update(repo_name, form_result)
 
            invalidate_cache('cached_repo_list')
 
            h.flash(_('Repository %s updated successfully' % repo_name),
 
                    category='success')
 
            changed_name = form_result['repo_name']
 
            action_logger(self.rhodecode_user, 'user_updated_repo',
 
                              changed_name, '', self.sa)
 
        except formencode.Invalid, errors:
 
            c.repo_info = repo_model.get(repo_name)
 
            c.users_array = repo_model.get_users_js()
 
            errors.value.update({'user':c.repo_info.user.username})
 
            return htmlfill.render(
 
                render('settings/repo_settings.html'),
 
                defaults=errors.value,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8")
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('error occured during update of repository %s') \
 
                    % repo_name, category='error')
 

	
 
        return redirect(url('repo_settings_home', repo_name=changed_name))
 

	
 

	
 

	
 
    def delete(self, repo_name):
 
        """DELETE /repos/repo_name: Delete an existing item"""
 
        # Forms posted to this method should contain a hidden field:
 
        #    <input type="hidden" name="_method" value="DELETE" />
 
        # Or using helpers:
 
        #    h.form(url('repo_settings_delete', repo_name=ID),
 
        #           method='delete')
 
        # url('repo_settings_delete', repo_name=ID)
 

	
 
        repo_model = RepoModel()
 
        repo = repo_model.get(repo_name)
 
        if not repo:
 
            h.flash(_('%s repository is not mapped to db perhaps'
 
                      ' it was moved or renamed  from the filesystem'
 
                      ' please run the application again'
 
                      ' in order to rescan repositories') % repo_name,
 
                      category='error')
 

	
 
            return redirect(url('home'))
 
        try:
 
            action_logger(self.rhodecode_user, 'user_deleted_repo',
 
                              repo_name, '', self.sa)
 
            repo_model.delete(repo)
 
            invalidate_cache('cached_repo_list')
 
            h.flash(_('deleted repository %s') % repo_name, category='success')
 
        except Exception:
 
            h.flash(_('An error occurred during deletion of %s') % repo_name,
 
                    category='error')
 

	
 
        return redirect(url('home'))
 

	
 
    def fork(self, repo_name):
 
        repo_model = RepoModel()
 
        c.repo_info = repo = repo_model.get(repo_name)
 
        if not repo:
 
            h.flash(_('%s repository is not mapped to db perhaps'
 
                      ' it was created or renamed from the filesystem'
 
                      ' please run the application again'
 
                      ' in order to rescan repositories') % repo_name,
 
                      category='error')
 

	
 
            return redirect(url('home'))
 

	
 
        return render('settings/repo_fork.html')
 

	
 

	
 

	
 
    def fork_create(self, repo_name):
 
        repo_model = RepoModel()
 
        c.repo_info = repo_model.get(repo_name)
 
        _form = RepoForkForm(old_data={'repo_type':c.repo_info.repo_type})()
 
        form_result = {}
 
        try:
 
            form_result = _form.to_python(dict(request.POST))
 
            form_result.update({'repo_name':repo_name})
 
            repo_model.create_fork(form_result, c.rhodecode_user)
 
            h.flash(_('fork %s repository as %s task added') \
 
                      % (repo_name, form_result['fork_name']),
 
                    category='success')
 
            action_logger(self.rhodecode_user, 'user_forked_repo',
 
                            repo_name, '', self.sa)
 
        except formencode.Invalid, errors:
 
            c.new_repo = errors.value['fork_name']
 
            r = render('settings/repo_fork.html')
 

	
 
            return htmlfill.render(
 
                r,
 
                defaults=errors.value,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8")
 
        return redirect(url('home'))
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'.
 
"""
 
from pygments.formatters import HtmlFormatter
 
from pygments import highlight as code_highlight
 
from pylons import url, app_globals as g
 
from pylons.i18n.translation import _, ungettext
 
from vcs.utils.annotate import annotate_highlight
 
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
 

	
 
#Custom helpers here :)
 
class _Link(object):
 
    '''
 
    Make a url based on label and url with help of url_for
 
    :param label:name of link    if not defined url is used
 
    :param url: the url for link
 
    '''
 

	
 
    def __call__(self, label='', *url_, **urlargs):
 
        if label is None or '':
 
            label = url
 
        link_fn = link_to(label, url(*url_, **urlargs))
 
        return link_fn
 

	
 
link = _Link()
 

	
 
class _GetError(object):
 

	
 
    def __call__(self, field_name, form_errors):
 
        tmpl = """<span class="error_msg">%s</span>"""
 
        if form_errors and form_errors.has_key(field_name):
 
            return literal(tmpl % form_errors.get(field_name))
 

	
 
get_error = _GetError()
 

	
 
def recursive_replace(str, replace=' '):
 
    """
 
    Recursive replace of given sign to just one instance
 
    :param str: given string
 
    :param replace:char to find and replace multiple instances
 
        
 
    Examples::
 
    >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
 
    'Mighty-Mighty-Bo-sstones'
 
    """
 

	
 
    if str.find(replace * 2) == -1:
 
        return str
 
    else:
 
        str = str.replace(replace * 2, replace)
 
        return recursive_replace(str, replace)
 

	
 
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:
 
        """
 

	
 
        return wrap_paragraphs(escape(tooltip_title), trim_at)\
 
                       .replace('\n', '<br/>')
 

	
 
    def activate(self):
 
        """
 
        Adds tooltip mechanism to the given Html all tooltips have to have 
 
        set class tooltip and set attribute tooltip_title.
 
        Then a tooltip will be generated based on that
 
        All with yui js tooltip
 
        """
 

	
 
        js = '''
 
        YAHOO.util.Event.onDOMReady(function(){
 
            function toolTipsId(){
 
                var ids = [];
 
                var tts = YAHOO.util.Dom.getElementsByClassName('tooltip');
 
                
 
                for (var i = 0; i < tts.length; i++) {
 
                    //if element doesn not have and id autgenerate one for tooltip
 
                    
 
                    if (!tts[i].id){
 
                        tts[i].id='tt'+i*100;
 
                    }
 
                    ids.push(tts[i].id);
 
                }
 
                return ids        
 
            };
 
            var myToolTips = new YAHOO.widget.Tooltip("tooltip", { 
 
                context: toolTipsId(),
 
                monitorresize:false,
 
                xyoffset :[0,0],
 
                autodismissdelay:300000,
 
                hidedelay:5,
 
                showdelay:20,
 
            });
 
            
 
            //Mouse Over event disabled for new repositories since they dont
 
            //have last commit message
 
            myToolTips.contextMouseOverEvent.subscribe(
 
                function(type, args) {
 
                    var context = args[0];
 
                    var txt = context.getAttribute('tooltip_title');
 
                    if(txt){                                       
 
                        return true;
 
                    }
 
                    else{
 
                        return false;
 
                    }
 
                });
 
            
 
                            
 
            // Set the text for the tooltip just before we display it. Lazy method
 
            myToolTips.contextTriggerEvent.subscribe( 
 
                 function(type, args) { 
 

	
 
                 
 
                        var context = args[0]; 
 
                        
 
                        var txt = context.getAttribute('tooltip_title');
 
                        this.cfg.setProperty("text", txt);
 
                        
 
                        
 
                        // positioning of tooltip
 
                        var tt_w = this.element.clientWidth;
 
                        var tt_h = this.element.clientHeight;
 
                        
 
                        var context_w = context.offsetWidth;
 
                        var context_h = context.offsetHeight;
 
                        
 
                        var pos_x = YAHOO.util.Dom.getX(context);
 
                        var pos_y = YAHOO.util.Dom.getY(context);
 

	
 
                        var display_strategy = 'top';
 
                        var xy_pos = [0,0];
 
                        switch (display_strategy){
 
                        
 
                            case 'top':
 
                                var cur_x = (pos_x+context_w/2)-(tt_w/2);
 
                                var cur_y = pos_y-tt_h-4;
 
                                xy_pos = [cur_x,cur_y];                                
 
                                break;
 
                            case 'bottom':
 
                                var cur_x = (pos_x+context_w/2)-(tt_w/2);
 
                                var cur_y = pos_y+context_h+4;
 
                                xy_pos = [cur_x,cur_y];                                
 
                                break;
 
                            case 'left':
 
                                var cur_x = (pos_x-tt_w-4);
 
                                var cur_y = pos_y-((tt_h/2)-context_h/2);
 
                                xy_pos = [cur_x,cur_y];                                
 
                                break;
 
                            case 'right':
 
                                var cur_x = (pos_x+context_w+4);
 
                                var cur_y = pos_y-((tt_h/2)-context_h/2);
 
                                xy_pos = [cur_x,cur_y];                                
 
                                break;
 
                             default:
 
                                var cur_x = (pos_x+context_w/2)-(tt_w/2);
 
                                var cur_y = pos_y-tt_h-4;
 
                                xy_pos = [cur_x,cur_y];                                
 
                                break;                             
 
                                 
 
                        }
 

	
 
                        this.cfg.setProperty("xy",xy_pos);
 

	
 
                  });
 
                  
 
            //Mouse out 
 
            myToolTips.contextMouseOutEvent.subscribe(
 
                function(type, args) {
 
                    var context = args[0];
 
                    
 
                });
 
        });
 
        '''
 
        return literal(js)
 

	
 
tooltip = _ToolTip()
 

	
 
class _FilesBreadCrumbs(object):
 

	
 
    def __call__(self, repo_name, rev, paths):
 
        url_l = [link_to(repo_name, url('files_home',
 
                                        repo_name=repo_name,
 
                                        revision=rev, f_path=''))]
 
        paths_l = paths.split('/')
 

	
 
        for cnt, p in enumerate(paths_l, 1):
 
            if p != '':
 
                url_l.append(link_to(p, url('files_home',
 
                                            repo_name=repo_name,
 
                                            revision=rev,
 
                                            f_path='/'.join(paths_l[:cnt]))))
 

	
 
        return literal('/'.join(url_l))
 

	
 
files_breadcrumbs = _FilesBreadCrumbs()
 
class CodeHtmlFormatter(HtmlFormatter):
 

	
 
    def wrap(self, source, outfile):
 
        return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
 

	
 
    def _wrap_code(self, source):
 
        for cnt, it in enumerate(source, 1):
 
            i, t = it
 
            t = '<div id="#S-%s">%s</div>' % (cnt, t)
 
            yield i, t
 
def pygmentize(filenode, **kwargs):
 
    """
 
    pygmentize function using pygments
 
    :param filenode:
 
    """
 
    return literal(code_highlight(filenode.content,
 
                                  filenode.lexer, CodeHtmlFormatter(**kwargs)))
 

	
 
def pygmentize_annotation(filenode, **kwargs):
 
    """
 
    pygmentize function for annotation
 
    :param filenode:
 
    """
 

	
 
    color_dict = {}
 
    def gen_color():
 
        """generator for getting 10k of evenly distibuted colors using hsv color
 
        and golden ratio.
 
        """
 
        import colorsys
 
        n = 10000
 
        golden_ratio = 0.618033988749895
 
        h = 0.22717784590367374
 
        #generate 10k nice web friendly colors in the same order
 
        for c in xrange(n):
 
            h += golden_ratio
 
            h %= 1
 
            HSV_tuple = [h, 0.95, 0.95]
 
            RGB_tuple = colorsys.hsv_to_rgb(*HSV_tuple)
 
            yield map(lambda x:str(int(x * 256)), RGB_tuple)
 

	
 
    cgenerator = gen_color()
 

	
 
    def get_color_string(cs):
 
        if color_dict.has_key(cs):
 
            col = color_dict[cs]
 
        else:
 
            col = color_dict[cs] = cgenerator.next()
 
        return "color: rgb(%s)! important;" % (', '.join(col))
 

	
 
    def url_func(changeset):
 
        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 % (changeset.author,
 
                                               changeset.date,
 
                                               tooltip(changeset.message))
 
        lnk_format = 'r%-5s:%s' % (changeset.revision,
 
                                 changeset.raw_id)
 
        uri = link_to(
 
                lnk_format,
 
                url('changeset_home', repo_name=changeset.repository.name,
 
                    revision=changeset.raw_id),
 
                style=get_color_string(changeset.raw_id),
 
                class_='tooltip',
 
                tooltip_title=tooltip_html
 
              )
 

	
 
        uri += '\n'
 
        return uri
 
    return literal(annotate_highlight(filenode, url_func, **kwargs))
 

	
 
def repo_name_slug(value):
 
    """Return slug of name of repository
 
    This function is called on each creation/modification
 
    of repository to prevent bad names in repo
 
    """
 
    slug = remove_formatting(value)
 
    slug = strip_tags(slug)
 

	
 
    for c in """=[]\;'"<>,/~!@#$%^&*()+{}|: """:
 
        slug = slug.replace(c, '-')
 
    slug = recursive_replace(slug, '-')
 
    slug = collapse(slug, '-')
 
    return slug
 

	
 
def get_changeset_safe(repo, rev):
 
    from vcs.backends.base import BaseRepository
 
    from vcs.exceptions import RepositoryError
 
    if not isinstance(repo, BaseRepository):
 
        raise Exception('You must pass an Repository '
 
                        'object as first argument got %s', type(repo))
 

	
 
    try:
 
        cs = repo.get_changeset(rev)
 
    except RepositoryError:
 
        from rhodecode.lib.utils import EmptyChangeset
 
        cs = EmptyChangeset()
 
    return cs
 

	
 

	
 
flash = _Flash()
 

	
 

	
 
#==============================================================================
 
# MERCURIAL FILTERS available via h.
 
#==============================================================================
 
from mercurial import util
 
from mercurial.templatefilters import person as _person
 

	
 

	
 

	
 
def _age(curdate):
 
    """turns a datetime into an age string."""
 
    
 
    if not curdate:
 
        return ''
 

	
 
    from datetime import timedelta, datetime
 

	
 
    agescales = [("year", 3600 * 24 * 365),
 
                 ("month", 3600 * 24 * 30),
 
                 ("day", 3600 * 24),
 
                 ("hour", 3600),
 
                 ("minute", 60),
 
                 ("second", 1), ]
 

	
 
    age = datetime.now() - curdate
 
    age_seconds = (age.days * agescales[2][1]) + age.seconds
 
    pos = 1
 
    for scale in agescales:
 
        if scale[1] <= age_seconds:
 
            if pos == 6:pos = 5
 
            return time_ago_in_words(curdate, agescales[pos][0])
 
        pos += 1
 

	
 
age = lambda  x:_age(x)
 
capitalize = lambda x: x.capitalize()
 
email = util.email
 
email_or_none = lambda x: util.email(x) if util.email(x) != x else None
 
person = lambda x: _person(x)
 
short_id = lambda x: x[:12]
 

	
 

	
 
def action_parser(user_log):
 
    """
 
    This helper will map the specified string action into translated
 
    fancy names with icons and links
 
    
 
    @param action:
 
    """
 
    action = user_log.action
 
    action_params = None
 
    cs_links = ''
 

	
 
    x = action.split(':')
 

	
 
    if len(x) > 1:
 
        action, action_params = x
 

	
 
    if action == 'push':
 
        revs_limit = 5
 
        revs = action_params.split(',')
 
        cs_links = " " + ', '.join ([link(rev,
 
                url('changeset_home',
 
                repo_name=user_log.repository.repo_name,
 
                revision=rev)) for rev in revs[:revs_limit] ])
 
        if len(revs) > revs_limit:
 
            html_tmpl = '<span title="%s"> %s </span>'
 
            cs_links += html_tmpl % (', '.join(r for r in revs[revs_limit:]),
 
                                     _('and %s more revisions') % (len(revs) - revs_limit))
 

	
 
    map = {'user_deleted_repo':_('User deleted repository'),
 
           'user_created_repo':_('User created repository'),
 
           'user_forked_repo':_('User forked repository'),
 
           'user_updated_repo':_('User updated repository'),
 
           'admin_deleted_repo':_('Admin delete repository'),
 
           'admin_created_repo':_('Admin created repository'),
 
           'admin_forked_repo':_('Admin forked repository'),
 
           'admin_updated_repo':_('Admin updated repository'),
 
           'push':_('Pushed') + literal(cs_links),
 
           'pull':_('Pulled'), }
 

	
 
    print action, action_params
 
    return map.get(action, action)
 

	
 

	
 
#==============================================================================
 
# PERMS
 
#==============================================================================
 
from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
 
HasRepoPermissionAny, HasRepoPermissionAll
 

	
 
#==============================================================================
 
# GRAVATAR URL
 
#==============================================================================
 
import hashlib
 
import urllib
 
from pylons import request
 

	
 
def gravatar_url(email_address, size=30):
 
    ssl_enabled = 'https' == request.environ.get('HTTP_X_URL_SCHEME')
 
    default = 'identicon'
 
    baseurl_nossl = "http://www.gravatar.com/avatar/"
 
    baseurl_ssl = "https://secure.gravatar.com/avatar/"
 
    baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
 

	
 

	
 
    # construct the url
 
    gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
 
    gravatar_url += urllib.urlencode({'d':default, 's':str(size)})
 

	
 
    return gravatar_url
 

	
 
def safe_unicode(str):
 
    """safe unicode function. In case of UnicodeDecode error we try to return
 
    unicode with errors replace, if this failes we return unicode with 
 
    string_escape decoding """
 

	
 
    try:
 
        u_str = unicode(str)
 
    except UnicodeDecodeError:
 
        try:
 
            u_str = unicode(str, 'utf-8', 'replace')
 
        except UnicodeDecodeError:
 
            #incase we have a decode error just represent as byte string
 
            u_str = unicode(str(str).encode('string_escape'))
 

	
 
    return u_str
rhodecode/templates/admin/admin_log.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
%if c.users_log:
 
<table>
 
	<tr>
 
		<th class="left">${_('Username')}</th>
 
		<th class="left">${_('Action')}</th>
 
		<th class="left">${_('Repository')}</th>
 
		<th class="left">${_('Action')}</th>
 
		<th class="left">${_('Date')}</th>
 
		<th class="left">${_('From IP')}</th>
 
	</tr>
 

	
 
	%for cnt,l in enumerate(c.users_log):
 
	<tr class="parity${cnt%2}">
 
		<td>${h.link_to(l.user.username,h.url('edit_user', id=l.user.user_id))}</td>
 
		<td>${h.action_parser(l)}</td>
 
		<td>
 
		%if l.repository:
 
		  ${h.link_to(l.repository.repo_name,h.url('summary_home',repo_name=l.repository.repo_name))}
 
		%else:
 
		  ${l.repository_name}
 
		%endif
 
		</td>
 
		<td>
 
		% if l.action == 'push' and l.revision:
 
		  ${h.link_to('%s - %s' % (l.action,l.revision),
 
		  h.url('changeset_home',repo_name=l.repository.repo_name,revision=l.revision))}
 
		%else:
 
		  ${l.action}
 
		%endif
 
		</td>
 
		
 
		<td>${l.action_date}</td>
 
		<td>${l.user_ip}</td>
 
	</tr>
 
	%endfor
 
</table>
 

	
 
<script type="text/javascript">
 
  var data_div = 'user_log';
 
  YAHOO.util.Event.onDOMReady(function(){
 
	YAHOO.util.Event.addListener(YAHOO.util.Dom.getElementsByClassName('pager_link'),"click",function(){
 
			YAHOO.util.Dom.setStyle('shortlog_data','opacity','0.3');});});
 
</script>
 
		
 
		
 
<div class="pagination-wh pagination-left">
 
${c.users_log.pager('$link_previous ~2~ $link_next',
 
onclick="""YAHOO.util.Connect.asyncRequest('GET','$partial_url',{
 
success:function(o){YAHOO.util.Dom.get(data_div).innerHTML=o.responseText;
 
YAHOO.util.Event.addListener(YAHOO.util.Dom.getElementsByClassName('pager_link'),"click",function(){
 
		YAHOO.util.Dom.setStyle(data_div,'opacity','0.3');});		
 
YAHOO.util.Dom.setStyle(data_div,'opacity','1');}},null); return false;""")}
 
</div>
 
%else: 
 
	${_('No actions yet')} 
 
%endif
0 comments (0 inline, 0 general)