Changeset - 0b86972de820
[Not reviewed]
rhodecode/controllers/settings.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.settings
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Settings controller for rhodecode
 

	
 
    :created_on: Jun 30, 2010
 
    :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 logging
 
import traceback
 
import formencode
 

	
 
from formencode import htmlfill
 

	
 
from pylons import tmpl_context as c, request, url
 
from pylons.controllers.util import redirect
 
from pylons.i18n.translation import _
 

	
 
import rhodecode.lib.helpers as h
 

	
 
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAllDecorator,\
 
    HasRepoPermissionAnyDecorator
 
from rhodecode.lib.base import BaseRepoController, render
 
from rhodecode.lib.utils import invalidate_cache, action_logger
 

	
 
from rhodecode.model.forms import RepoSettingsForm
 
from rhodecode.model.repo import RepoModel
 
from rhodecode.model.db import RepoGroup, Repository
 
from rhodecode.model.meta import Session
 
from rhodecode.model.scm import ScmModel
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class SettingsController(BaseRepoController):
 

	
 
    @LoginRequired()
 
    def __before__(self):
 
        super(SettingsController, self).__before__()
 

	
 
    def __load_defaults(self):
 
        c.repo_groups = RepoGroup.groups_choices(check_perms=True)
 
        c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
 

	
 
        repo_model = RepoModel()
 
        c.users_array = repo_model.get_users_js()
 
        c.users_groups_array = repo_model.get_users_groups_js()
 
        choices, c.landing_revs = ScmModel().get_repo_landing_revs()
 
        c.landing_revs_choices = choices
 

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

	
 
            return redirect(url('home'))
 

	
 
        self.__load_defaults()
 

	
 
        defaults = RepoModel()._get_defaults(repo_name)
 

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

	
 
    @HasRepoPermissionAllDecorator('repository.admin')
 
    def update(self, repo_name):
 
        repo_model = RepoModel()
 
        changed_name = repo_name
 

	
 
        self.__load_defaults()
 

	
 
        _form = RepoSettingsForm(edit=True,
 
                                 old_data={'repo_name': repo_name},
 
                                 repo_groups=c.repo_groups_choices,
 
                                 landing_revs=c.landing_revs_choices)()
 
        try:
 
            form_result = _form.to_python(dict(request.POST))
 

	
 
            repo_model.update(repo_name, form_result)
 
            invalidate_cache('get_repo_cached_%s' % repo_name)
 
            h.flash(_('Repository %s updated successfully') % repo_name,
 
                    category='success')
 
            changed_name = form_result['repo_name_full']
 
            action_logger(self.rhodecode_user, 'user_updated_repo',
 
                          changed_name, self.ip_addr, self.sa)
 
            Session().commit()
 
        except formencode.Invalid, errors:
 
            c.repo_info = repo_model.get_by_repo_name(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 occurred during update of repository %s') \
 
                    % repo_name, category='error')
 

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

	
 
    @HasRepoPermissionAllDecorator('repository.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_settings_delete', repo_name=ID),
 
        #           method='delete')
 
        # url('repo_settings_delete', repo_name=ID)
 

	
 
        repo_model = RepoModel()
 
        repo = repo_model.get_by_repo_name(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.ip_addr, self.sa)
 
            repo_model.delete(repo)
 
            invalidate_cache('get_repo_cached_%s' % repo_name)
 
            h.flash(_('deleted repository %s') % repo_name, category='success')
 
            Session().commit()
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during deletion of %s') % repo_name,
 
                    category='error')
 

	
 
        return redirect(url('home'))
 

	
 
    @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
 
    def toggle_locking(self, repo_name):
 
        """
 
        Toggle locking of repository by simple GET call to url
 

	
 
        :param repo_name:
 
        """
 

	
 
        try:
 
            repo = Repository.get_by_repo_name(repo_name)
 

	
 
            if repo.enable_locking:
 
                if repo.locked[0]:
 
                    Repository.unlock(repo)
 
                    action = _('unlocked')
 
                else:
 
                    Repository.lock(repo, c.rhodecode_user.user_id)
 
                    action = _('locked')
 

	
 
                h.flash(_('Repository has been %s') % action,
 
                        category='success')
 
        except Exception, e:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during unlocking'),
 
                    category='error')
 
        return redirect(url('summary_home', repo_name=repo_name))
 

	
rhodecode/lib/db_manage.py
Show inline comments
 
@@ -478,193 +478,193 @@ class DbManage(object):
 
            # get default perm
 
            default = UserRepoGroupToPerm.query()\
 
                .filter(UserRepoGroupToPerm.group == g)\
 
                .filter(UserRepoGroupToPerm.user == def_usr)\
 
                .scalar()
 

	
 
            if default is None:
 
                log.debug('missing default permission for group %s adding' % g)
 
                ReposGroupModel()._create_default_perms(g)
 

	
 
    def reset_permissions(self, username):
 
        """
 
        Resets permissions to default state, usefull when old systems had
 
        bad permissions, we must clean them up
 

	
 
        :param username:
 
        :type username:
 
        """
 
        default_user = User.get_by_username(username)
 
        if not default_user:
 
            return
 

	
 
        u2p = UserToPerm.query()\
 
            .filter(UserToPerm.user == default_user).all()
 
        fixed = False
 
        if len(u2p) != len(User.DEFAULT_PERMISSIONS):
 
            for p in u2p:
 
                Session().delete(p)
 
            fixed = True
 
            self.populate_default_permissions()
 
        return fixed
 

	
 
    def config_prompt(self, test_repo_path='', retries=3, defaults={}):
 
        _path = defaults.get('repos_location')
 
        if retries == 3:
 
            log.info('Setting up repositories config')
 

	
 
        if _path is not None:
 
            path = _path
 
        elif not self.tests and not test_repo_path:
 
            path = raw_input(
 
                 'Enter a valid absolute path to store repositories. '
 
                 'All repositories in that path will be added automatically:'
 
            )
 
        else:
 
            path = test_repo_path
 
        path_ok = True
 

	
 
        # check proper dir
 
        if not os.path.isdir(path):
 
            path_ok = False
 
            log.error('Given path %s is not a valid directory' % path)
 

	
 
        elif not os.path.isabs(path):
 
            path_ok = False
 
            log.error('Given path %s is not an absolute path' % path)
 

	
 
        # check write access
 
        elif not os.access(path, os.W_OK) and path_ok:
 
            path_ok = False
 
            log.error('No write permission to given path %s' % path)
 

	
 
        if retries == 0:
 
            sys.exit('max retries reached')
 
        if path_ok is False:
 
            retries -= 1
 
            return self.config_prompt(test_repo_path, retries)
 

	
 
        real_path = os.path.realpath(path)
 

	
 
        if real_path != path:
 
            if not ask_ok(('Path looks like a symlink, Rhodecode will store '
 
                           'given path as %s ? [y/n]') % (real_path)):
 
                log.error('Canceled by user')
 
                sys.exit(-1)
 

	
 
        return real_path
 

	
 
    def create_settings(self, path):
 

	
 
        self.create_ui_settings()
 

	
 
        #HG UI OPTIONS
 
        web1 = RhodeCodeUi()
 
        web1.ui_section = 'web'
 
        web1.ui_key = 'push_ssl'
 
        web1.ui_value = 'false'
 

	
 
        web2 = RhodeCodeUi()
 
        web2.ui_section = 'web'
 
        web2.ui_key = 'allow_archive'
 
        web2.ui_value = 'gz zip bz2'
 

	
 
        web3 = RhodeCodeUi()
 
        web3.ui_section = 'web'
 
        web3.ui_key = 'allow_push'
 
        web3.ui_value = '*'
 

	
 
        web4 = RhodeCodeUi()
 
        web4.ui_section = 'web'
 
        web4.ui_key = 'baseurl'
 
        web4.ui_value = '/'
 

	
 
        paths = RhodeCodeUi()
 
        paths.ui_section = 'paths'
 
        paths.ui_key = '/'
 
        paths.ui_value = path
 

	
 
        phases = RhodeCodeUi()
 
        phases.ui_section = 'phases'
 
        phases.ui_key = 'publish'
 
        phases.ui_value = False
 

	
 
        sett1 = RhodeCodeSetting('realm', 'RhodeCode authentication')
 
        sett2 = RhodeCodeSetting('title', 'RhodeCode')
 
        sett3 = RhodeCodeSetting('ga_code', '')
 

	
 
        sett4 = RhodeCodeSetting('show_public_icon', True)
 
        sett5 = RhodeCodeSetting('show_private_icon', True)
 
        sett6 = RhodeCodeSetting('stylify_metatags', False)
 

	
 
        self.sa.add(web1)
 
        self.sa.add(web2)
 
        self.sa.add(web3)
 
        self.sa.add(web4)
 
        self.sa.add(paths)
 
        self.sa.add(sett1)
 
        self.sa.add(sett2)
 
        self.sa.add(sett3)
 
        self.sa.add(sett4)
 
        self.sa.add(sett5)
 
        self.sa.add(sett6)
 

	
 
        self.create_ldap_options()
 

	
 
        log.info('created ui config')
 

	
 
    def create_user(self, username, password, email='', admin=False):
 
        log.info('creating user %s' % username)
 
        UserModel().create_or_update(username, password, email,
 
                                     firstname='RhodeCode', lastname='Admin',
 
                                     active=True, admin=admin)
 

	
 
    def create_default_user(self):
 
        log.info('creating default user')
 
        # create default user for handling default permissions.
 
        UserModel().create_or_update(username='default',
 
                              password=str(uuid.uuid1())[:8],
 
                              email='anonymous@rhodecode.org',
 
                              firstname='Anonymous', lastname='User')
 

	
 
    def create_permissions(self):
 
        # module.(access|create|change|delete)_[name]
 
        # module.(none|read|write|admin)
 

	
 
        for p in Permission.PERMS:
 
            if not Permission.get_by_key(p[0]):
 
                new_perm = Permission()
 
                new_perm.permission_name = p[0]
 
                new_perm.permission_longname = p[0]
 
                self.sa.add(new_perm)
 

	
 
    def populate_default_permissions(self):
 
        log.info('creating default user permissions')
 

	
 
        default_user = User.get_by_username('default')
 

	
 
        for def_perm in User.DEFAULT_PERMISSIONS:
 

	
 
            perm = self.sa.query(Permission)\
 
             .filter(Permission.permission_name == def_perm)\
 
             .scalar()
 
            if not perm:
 
                raise Exception(
 
                  'CRITICAL: permission %s not found inside database !!'
 
                  % def_perm
 
                )
 
            if not UserToPerm.query()\
 
                .filter(UserToPerm.permission == perm)\
 
                .filter(UserToPerm.user == default_user).scalar():
 
                reg_perm = UserToPerm()
 
                reg_perm.user = default_user
 
                reg_perm.permission = perm
 
                self.sa.add(reg_perm)
 

	
 
    def finish(self):
 
        """
 
        Function executed at the end of setup
 
        """
 
        if not __py_version__ >= (2, 6):
 
            notify('Python2.5 detected, please switch '
 
                   'egg:waitress#main -> egg:Paste#http '
 
                   'in your .ini file')
 
\ No newline at end of file
 
                   'in your .ini file')
rhodecode/templates/admin/users/user_edit_my_account.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
<%inherit file="/base/base.html"/>
 

	
 
<%def name="title()">
 
    ${_('My account')} ${c.rhodecode_user.username} - ${c.rhodecode_name}
 
</%def>
 

	
 
<%def name="breadcrumbs_links()">
 
    ${_('My Account')}
 
</%def>
 

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

	
 
<%def name="main()">
 

	
 
<div class="box box-left">
 
    <!-- box / title -->
 
    <div class="title">
 
        ${self.breadcrumbs()}
 
    </div>
 
    <!-- end box / title -->
 
    ${c.form|n}
 
</div>
 

	
 
<div class="box box-right">
 
    <!-- box / title -->
 
    <div class="title">
 
        <h5>
 
        <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}" style="display: none"/>
 
        </h5>
 
         <ul class="links" style="color:#DADADA">
 
           <li>
 
             <span><a id="show_perms" class="link-white current" href="#perms">${_('My permissions')}</a> </span>
 
           </li>
 
           <li>
 
             <span><a id="show_my" class="link-white" href="#my">${_('My repos')}</a> </span>
 
           </li>
 
           <li>
 
             <span><a id="show_pullrequests" class="link-white" href="#pullrequests">${_('My pull requests')}</a> </span>
 
           </li>
 
           %if h.HasPermissionAny('hg.admin','hg.create.repository')():
 
             <li>
 
               <span>${h.link_to(_('Add repo'),h.url('admin_settings_create_repository'))}</span>
 
             </li>
 
           %endif
 
         </ul>
 
    </div>
 
    <!-- end box / title -->
 
    <div id="perms" class="table">
 
           %for section in sorted(c.rhodecode_user.permissions.keys()):
 
            <div class="perms_section_head">${section.replace("_"," ").capitalize()}</div>
 

	
 
            <div id='tbl_list_wrap_${section}' class="yui-skin-sam">
 
            <table id="tbl_list_${section}">
 
              <thead>
 
                  <tr>
 
                  <th class="left">${_('Name')}</th>
 
                  <th class="left">${_('Permission')}</th>
 
              </thead>
 
              <tbody>
 
            %for k in c.rhodecode_user.permissions[section]:
 
           <%
 
           if section != 'global':
 
               section_perm = c.rhodecode_user.permissions[section].get(k)
 
               _perm = section_perm.split('.')[-1]
 
           else:
 
               _perm = section_perm = None
 
           %>
 
            %if _perm not in ['none']:
 
                <tr>
 
                    <td>
 
                        %if section == 'repositories':
 
                            <a href="${h.url('summary_home',repo_name=k)}">${k}</a>
 
                        %elif section == 'repositories_groups':
 
                            <a href="${h.url('repos_group_home',group_name=k)}">${k}</a>
 
                        %else:
 
                            ${k}
 
                        %endif
 
                    </td>
 
                    <td>
 
                        %if section == 'global':
 
                         ${h.bool2icon(True)}
 
                        %else:
 
                        <span class="perm_tag ${_perm}">${section_perm}</span>
 
                        %endif
 
                     </td>
 
                </tr>
 
             %endif
 
            %endfor
 
            </tbody>
 
            </table>
 
            </div>
 
           %endfor
 
    </div>
 
    <div id="my" class="table" style="display:none">
 
    </div>
 
    <div id="pullrequests" class="table" style="display:none"></div>
 
</div>
 

	
 

	
 

	
 
<script type="text/javascript">
 
var filter_activate = function(){
 
    var nodes = YUQ('#my tr td a.repo_name');
 
    var func = function(node){
 
        return node.parentNode.parentNode.parentNode.parentNode;
 
    }
 
    q_filter('q_filter',YUQ('#my tr td a.repo_name'),func);
 
}
 

	
 
var show_perms = function(e){
 
    YUD.addClass('show_perms', 'current');
 
    YUD.removeClass('show_my','current');
 
    YUD.removeClass('show_pullrequests','current');
 

	
 
    YUD.setStyle('my','display','none');
 
    YUD.setStyle('pullrequests','display','none');
 
    YUD.setStyle('perms','display','');
 
    YUD.setStyle('q_filter','display','none');	
 
    YUD.setStyle('q_filter','display','none');
 
}
 
YUE.on('show_perms','click',function(e){
 
    show_perms();
 
})
 

	
 
var show_my = function(e){
 
    YUD.addClass('show_my', 'current');
 
    YUD.removeClass('show_perms','current');
 
    YUD.removeClass('show_pullrequests','current');
 

	
 
    YUD.setStyle('perms','display','none');
 
    YUD.setStyle('pullrequests','display','none');
 
    YUD.setStyle('my','display','');
 
    YUD.setStyle('q_filter','display','');
 

	
 
    
 

	
 
    var url = "${h.url('admin_settings_my_repos')}";
 
    ypjax(url, 'my', function(){
 
        table_sort();
 
        filter_activate();
 
    });	
 
    });
 
}
 
YUE.on('show_my','click',function(e){
 
	show_my(e);
 
})
 

	
 
var show_pullrequests = function(e){
 
    YUD.addClass('show_pullrequests', 'current');
 
    YUD.removeClass('show_my','current');
 
    YUD.removeClass('show_perms','current');
 

	
 
    YUD.setStyle('my','display','none');
 
    YUD.setStyle('perms','display','none');
 
    YUD.setStyle('pullrequests','display','');
 
    YUD.setStyle('q_filter','display','none');
 
    
 

	
 
    var url = "${h.url('admin_settings_my_pullrequests')}";
 
    ypjax(url, 'pullrequests');	
 
    ypjax(url, 'pullrequests');
 
}
 
YUE.on('show_pullrequests','click',function(e){
 
	show_pullrequests(e)
 
})
 

	
 
var tabs = {
 
    'perms': show_perms,
 
    'my': show_my,
 
    'pullrequests': show_pullrequests
 
}
 
var url = location.href.split('#'); 
 
if (url[1]) { 
 
    //We have a hash 
 
var url = location.href.split('#');
 
if (url[1]) {
 
    //We have a hash
 
    var tabHash = url[1];
 
    console.log(tabs, tabHash)
 
    tabs[tabHash]();   
 
    tabs[tabHash]();
 
}
 

	
 
// main table sorting
 
var myColumnDefs = [
 
    {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"},
 
    {key:"name",label:"${_('Name')}",sortable:true,
 
        sortOptions: { sortFunction: nameSort }},
 
    {key:"tip",label:"${_('Tip')}",sortable:true,
 
        sortOptions: { sortFunction: revisionSort }},
 
    {key:"action1",label:"",sortable:false},
 
    {key:"action2",label:"",sortable:false},
 
];
 

	
 
function table_sort(){
 
var myDataSource = new YAHOO.util.DataSource(YUD.get("repos_list"));
 
myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
 
myDataSource.responseSchema = {
 
    fields: [
 
        {key:"menu"},
 
        {key:"name"},
 
        {key:"tip"},
 
        {key:"action1"},
 
        {key:"action2"},
 
    ]
 
};
 
var trans_defs =  {
 
    sortedBy:{key:"name",dir:"asc"},
 
    MSG_SORTASC:"${_('Click to sort ascending')}",
 
    MSG_SORTDESC:"${_('Click to sort descending')}",
 
    MSG_EMPTY:"${_('No records found.')}",
 
    MSG_ERROR:"${_('Data error.')}",
 
    MSG_LOADING:"${_('Loading...')}",
 
}
 
var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,trans_defs);
 
myDataTable.subscribe('postRenderEvent',function(oArgs) {
 
    tooltip_activate();
 
    quick_repo_menu();
 
    filter_activate();
 
});
 

	
 
var permsColumnDefs = [
 
    {key:"name",label:"${_('Name')}",sortable:true, sortOptions: { sortFunction: permNameSort }},
 
    {key:"perm",label:"${_('Permission')}",sortable:false,},
 
];
 

	
 
// perms repos table
 
var myDataSource2 = new YAHOO.util.DataSource(YUD.get("tbl_list_repositories"));
 
myDataSource2.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
 
myDataSource2.responseSchema = {
 
    fields: [
 
        {key:"name"},
 
        {key:"perm"},
 
    ]
 
};
 

	
 
new YAHOO.widget.DataTable("tbl_list_wrap_repositories", permsColumnDefs, myDataSource2, trans_defs);
 

	
 
//perms groups table
 
var myDataSource3 = new YAHOO.util.DataSource(YUD.get("tbl_list_repositories_groups"));
 
myDataSource3.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
 
myDataSource3.responseSchema = {
 
    fields: [
 
        {key:"name"},
 
        {key:"perm"},
 
    ]
 
};
 

	
 
new YAHOO.widget.DataTable("tbl_list_wrap_repositories_groups", permsColumnDefs, myDataSource3, trans_defs);
 
}
 
</script>
 
</%def>
rhodecode/templates/pullrequests/pullrequest.html
Show inline comments
 
<%inherit file="/base/base.html"/>
 

	
 
<%def name="title()">
 
    ${c.repo_name} ${_('New pull request')}
 
</%def>
 

	
 
<%def name="breadcrumbs_links()">
 
    ${h.link_to(_(u'Home'),h.url('/'))}
 
    &raquo;
 
    ${h.link_to(c.repo_name,h.url('changelog_home',repo_name=c.repo_name))}
 
    &raquo;
 
    ${_('New pull request')}
 
</%def>
 

	
 
<%def name="main()">
 

	
 
<div class="box">
 
    <!-- box / title -->
 
    <div class="title">
 
        ${self.breadcrumbs()}
 
    </div>
 
    ${h.form(url('pullrequest', repo_name=c.repo_name), method='post', id='pull_request_form')}
 
    <div style="float:left;padding:0px 30px 30px 30px">
 

	
 
        ##ORG
 
        <div style="float:left">
 
            <div class="fork_user">
 
                <div class="gravatar">
 
                    <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_db_repo.user.email,24)}"/>
 
                </div>
 
                <span style="font-size: 20px">
 
                ${h.select('org_repo','',c.org_repos,class_='refs')}:${h.select('org_ref','',c.org_refs,class_='refs')}
 
                </span>
 
                 <div style="padding:5px 3px 3px 42px;">${c.rhodecode_db_repo.description}</div>
 
            </div>
 
            <div style="clear:both;padding-top: 10px"></div>
 
        </div>
 
          <div style="float:left;font-size:24px;padding:0px 20px">
 
          <img height=32 width=32 src="${h.url('/images/arrow_right_64.png')}"/>
 
          </div>
 

	
 
        ##OTHER, most Probably the PARENT OF THIS FORK
 
        <div style="float:left">
 
            <div class="fork_user">
 
                <div class="gravatar">
 
                    <img id="other_repo_gravatar" alt="gravatar" src=""/>
 
                </div>
 
                <span style="font-size: 20px">
 
                ${h.select('other_repo',c.default_pull_request ,c.other_repos,class_='refs')}:${h.select('other_ref',c.default_pull_request_rev,c.default_revs,class_='refs')}
 
                </span>
 
         <span style="padding:3px">
 
           <a id="refresh" href="#" class="tooltip" title="${h.tooltip(_('refresh overview'))}">
 
             <img style="margin:3px" class="icon" title="${_('Refresh')}" alt="${_('Refresh')}" src="${h.url('/images/icons/arrow_refresh.png')}"/>
 
           </a>
 
         </span>
 
                 <div id="other_repo_desc" style="padding:5px 3px 3px 42px;"></div>
 
            </div>
 
            <div style="clear:both;padding-top: 10px"></div>
 
        </div>
 
       <div style="clear:both;padding-top: 10px"></div>
 
       ## overview pulled by ajax
 
       <div style="float:left" id="pull_request_overview"></div>
 
       <div style="float:left;clear:both;padding:10px 10px 10px 0px;display:none">
 
            <a id="pull_request_overview_url" href="#">${_('Detailed compare view')}</a>
 
       </div>
 
     </div>
 
    <div style="float:left; border-left:1px dashed #eee">
 
        <h4>${_('Pull request reviewers')}</h4>
 
        <div id="reviewers" style="padding:0px 0px 0px 15px">
 
          ## members goes here !
 
          <div class="group_members_wrap">
 
            <ul id="review_members" class="group_members">
 
            %for member in c.review_members:
 
              <li id="reviewer_${member.user_id}">
 
                <div class="reviewers_member">
 
                  <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(member.email,14)}"/> </div>
 
                  <div style="float:left">${member.full_name} (${_('owner')})</div>
 
                  <input type="hidden" value="${member.user_id}" name="review_members" />
 
                  <span class="delete_icon action_button" onclick="removeReviewer(${member.user_id})"></span>
 
                </div>
 
              </li>
 
            %endfor
 
            </ul>
 
          </div>
 

	
 
          <div class='ac'>
 
            <div class="reviewer_ac">
 
               ${h.text('user', class_='yui-ac-input')}
 
               <span class="help-block">${_('Add reviewer to this pull request.')}</span>
 
               <div id="reviewers_container"></div>
 
            </div>
 
          </div>
 
        </div>
 
    </div>
 
    <h3>${_('Create new pull request')}</h3>
 

	
 
    <div class="form">
 
        <!-- fields -->
 

	
 
        <div class="fields">
 

	
 
             <div class="field">
 
                <div class="label">
 
                    <label for="pullrequest_title">${_('Title')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('pullrequest_title',size=30)}
 
                </div>
 
             </div>
 

	
 
            <div class="field">
 
                <div class="label label-textarea">
 
                    <label for="pullrequest_desc">${_('description')}:</label>
 
                </div>
 
                <div class="textarea text-area editor">
 
                    ${h.textarea('pullrequest_desc',size=30)}
 
                </div>
 
            </div>
 

	
 
            <div class="buttons">
 
                ${h.submit('save',_('Send pull request'),class_="ui-btn large")}
 
                ${h.reset('reset',_('Reset'),class_="ui-btn large")}
 
           </div>
 
        </div>
 
    </div>
 
    ${h.end_form()}
 

	
 
</div>
 

	
 
<script type="text/javascript">
 
  var _USERS_AC_DATA = ${c.users_array|n};
 
  var _GROUPS_AC_DATA = ${c.users_groups_array|n};
 
  PullRequestAutoComplete('user', 'reviewers_container', _USERS_AC_DATA, _GROUPS_AC_DATA);
 

	
 
  var other_repos_info = ${c.other_repos_info|n};
 
  
 

	
 
  var loadPreview = function(){
 
	  YUD.setStyle(YUD.get('pull_request_overview_url').parentElement,'display','none');
 
      var url = "${h.url('compare_url',
 
    	                 repo_name='org_repo',
 
    	                 org_ref_type='org_ref_type', org_ref='org_ref',
 
                         other_ref_type='other_ref_type', other_ref='other_ref',
 
                         repo='other_repo',
 
                         as_form=True, bundle=False)}";
 

	
 
      var select_refs = YUQ('#pull_request_form select.refs')
 
      var rev_data = {}; // gather the org/other ref and repo here
 
      for(var i=0;i<select_refs.length;i++){
 
        var select_ref = select_refs[i];
 
        var select_ref_data = select_ref.value.split(':');
 
        var key = null;
 
        var val = null;
 
        
 

	
 
        if(select_ref_data.length>1){
 
          key = select_ref.name+"_type";
 
          val = select_ref_data[0];
 
          url = url.replace(key,val);
 
          rev_data[key] = val;
 
          
 

	
 
          key = select_ref.name;
 
          val = select_ref_data[1];
 
          url = url.replace(key,val);
 
          rev_data[key] = val;
 
          
 

	
 
        }else{
 
          key = select_ref.name;
 
          val = select_ref.value;
 
          url = url.replace(key,val);
 
          rev_data[key] = val;
 
        }
 
      }
 

	
 
      YUE.on('other_repo', 'change', function(e){
 
    	  var repo_name = e.currentTarget.value;
 
    	  // replace the <select> of changed repo
 
    	  YUD.get('other_ref').innerHTML = other_repos_info[repo_name]['revs'];
 
      });
 
      
 

	
 
      ypjax(url,'pull_request_overview', function(data){
 
    	  var sel_box = YUQ('#pull_request_form #other_repo')[0];
 
    	  var repo_name = sel_box.options[sel_box.selectedIndex].value;
 
    	  YUD.get('pull_request_overview_url').href = url;
 
    	  YUD.setStyle(YUD.get('pull_request_overview_url').parentElement,'display','');
 
    	  YUD.get('other_repo_gravatar').src = other_repos_info[repo_name]['gravatar'];
 
    	  YUD.get('other_repo_desc').innerHTML = other_repos_info[repo_name]['description'];
 
    	  YUD.get('other_ref').innerHTML = other_repos_info[repo_name]['revs'];
 
    	  // select back the revision that was just compared
 
    	  setSelectValue(YUD.get('other_ref'), rev_data['other_ref']);
 
      })
 
  }
 
  YUE.on('refresh','click',function(e){
 
     loadPreview()
 
  })
 

	
 
  //lazy load overview after 0.5s
 
  setTimeout(loadPreview, 500)
 

	
 
</script>
 

	
 
</%def>
rhodecode/templates/pullrequests/pullrequest_show.html
Show inline comments
 
<%inherit file="/base/base.html"/>
 

	
 
<%def name="title()">
 
    ${c.repo_name} ${_('Pull request #%s') % c.pull_request.pull_request_id}
 
</%def>
 

	
 
<%def name="breadcrumbs_links()">
 
    ${h.link_to(_(u'Home'),h.url('/'))}
 
    &raquo;
 
    ${h.link_to(c.repo_name,h.url('changelog_home',repo_name=c.repo_name))}
 
    &raquo;
 
    ${_('Pull request #%s') % c.pull_request.pull_request_id}
 
</%def>
 

	
 
<%def name="main()">
 

	
 
<div class="box">
 
    <!-- box / title -->
 
    <div class="title">
 
        ${self.breadcrumbs()}
 
    </div>
 
        %if c.pull_request.is_closed():
 
        <div style="padding:10px; font-size:22px;width:100%;text-align: center; color:#88D882">${_('Closed %s') % (h.age(c.pull_request.updated_on))} ${_('with status %s') % h.changeset_status_lbl(c.current_changeset_status)}</div>
 
        %endif
 
    <h3>${_('Title')}: ${c.pull_request.title}</h3>
 

	
 
    <div class="form">
 
      <div id="summary" class="fields">
 
         <div class="field">
 
          <div class="label-summary">
 
              <label>${_('Status')}:</label>
 
          </div>
 
          <div class="input">
 
            <div class="changeset-status-container" style="float:none;clear:both">
 
            %if c.current_changeset_status:
 
              <div title="${_('Pull request status')}" class="changeset-status-lbl">[${h.changeset_status_lbl(c.current_changeset_status)}]</div>
 
              <div class="changeset-status-ico" style="padding:1px 4px"><img src="${h.url('/images/icons/flag_status_%s.png' % c.current_changeset_status)}" /></div>
 
            %endif
 
            </div>
 
          </div>
 
         </div>
 
         <div class="field">
 
          <div class="label-summary">
 
              <label>${_('Still not reviewed by')}:</label>
 
          </div>
 
          <div class="input">
 
            % if len(c.pull_request_pending_reviewers) > 0:
 
                <div class="tooltip" title="${h.tooltip(','.join([x.username for x in c.pull_request_pending_reviewers]))}">${ungettext('%d reviewer', '%d reviewers',len(c.pull_request_pending_reviewers)) % len(c.pull_request_pending_reviewers)}</div>
 
            %else:
 
                <div>${_('pull request was reviewed by all reviewers')}</div>            
 
                <div>${_('pull request was reviewed by all reviewers')}</div>
 
            %endif
 
          </div>
 
         </div>
 
      </div>
 
    </div>
 
    <div style="white-space:pre-wrap;padding:3px 3px 5px 20px">${h.literal(c.pull_request.description)}</div>
 
    <div style="padding:4px 4px 10px 20px">
 
      <div>${_('Created on')}: ${h.fmt_date(c.pull_request.created_on)}</div>
 
    </div>
 

	
 
    <div style="min-height:160px">
 
      ##DIFF
 
      <div class="table" style="float:left;clear:none">
 
          <div id="body" class="diffblock">
 
              <div style="white-space:pre-wrap;padding:5px">${_('Compare view')}</div>
 
          </div>
 
          <div id="changeset_compare_view_content">
 
              ##CS
 
              <div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">${_('Incoming changesets')}</div>
 
              <%include file="/compare/compare_cs.html" />
 

	
 
              ## FILES
 
              <div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">${_('Files affected')}</div>
 
              <div class="cs_files">
 
                %for fid, change, f, stat in c.files:
 
                    <div class="cs_${change}">
 
                      <div class="node">${h.link_to(h.safe_unicode(f),h.url.current(anchor=fid))}</div>
 
                      <div class="changes">${h.fancy_file_stats(stat)}</div>
 
                    </div>
 
                %endfor
 
              </div>
 
          </div>
 
      </div>
 
      ## REVIEWERS
 
       <div style="float:left; border-left:1px dashed #eee">
 
       <h4>${_('Pull request reviewers')}</h4>
 
        <div id="reviewers" style="padding:0px 0px 0px 15px">
 
          ## members goes here !
 
          <div class="group_members_wrap">
 
            <ul id="review_members" class="group_members">
 
            %for member,status in c.pull_request_reviewers:
 
              <li id="reviewer_${member.user_id}">
 
                <div class="reviewers_member">
 
                    <div style="float:left;padding:0px 3px 0px 0px" class="tooltip" title="${h.tooltip(h.changeset_status_lbl(status[0][1].status if status else 'not_reviewed'))}">
 
                      <img src="${h.url(str('/images/icons/flag_status_%s.png' % (status[0][1].status if status else 'not_reviewed')))}"/>
 
                    </div>
 
                  <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(member.email,14)}"/> </div>
 
                  <div style="float:left">${member.full_name} (${_('owner')})</div>
 
                  <input type="hidden" value="${member.user_id}" name="review_members" />
 
                  %if not c.pull_request.is_closed() and (h.HasPermissionAny('hg.admin', 'repository.admin')() or c.pull_request.author.user_id == c.rhodecode_user.user_id):
 
                  <span class="delete_icon action_button" onclick="removeReviewer(${member.user_id})"></span>
 
                  %endif
 
                </div>
 
              </li>
 
            %endfor
 
            </ul>
 
          </div>
 
          %if not c.pull_request.is_closed():
 
          <div class='ac'>
 
            %if h.HasPermissionAny('hg.admin', 'repository.admin')() or c.pull_request.author.user_id == c.rhodecode_user.user_id:
 
            <div class="reviewer_ac">
 
               ${h.text('user', class_='yui-ac-input')}
 
               <span class="help-block">${_('Add reviewer to this pull request.')}</span>
 
               <div id="reviewers_container"></div>
 
            </div>
 
            <div style="padding:0px 10px">
 
             <span id="update_pull_request" class="ui-btn xsmall">${_('save')}</span>
 
            </div>
 
            %endif
 
          </div>
 
          %endif
 
        </div>
 
       </div>
 
    </div>
 
    <script>
 
    var _USERS_AC_DATA = ${c.users_array|n};
 
    var _GROUPS_AC_DATA = ${c.users_groups_array|n};
 
    AJAX_COMMENT_URL = "${url('pullrequest_comment',repo_name=c.repo_name,pull_request_id=c.pull_request.pull_request_id)}";
 
    AJAX_COMMENT_DELETE_URL = "${url('pullrequest_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}";
 
    AJAX_UPDATE_PULLREQUEST = "${url('pullrequest_update',repo_name=c.repo_name,pull_request_id=c.pull_request.pull_request_id)}"
 
    </script>
 

	
 
    ## diff block
 
    <%namespace name="diff_block" file="/changeset/diff_block.html"/>
 
    %for fid, change, f, stat in c.files:
 
      ${diff_block.diff_block_simple([c.changes[fid]])}
 
    %endfor
 

	
 
    ## template for inline comment form
 
    <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
 
    ${comment.comment_inline_form()}
 

	
 
    ## render comments and inlines
 
    ${comment.generate_comments()}
 

	
 
    % if not c.pull_request.is_closed():
 
      ## main comment form and it status
 
      ${comment.comments(h.url('pullrequest_comment', repo_name=c.repo_name,
 
                                pull_request_id=c.pull_request.pull_request_id),
 
                                c.current_changeset_status,
 
                                close_btn=True)}
 
    %endif
 

	
 
    <script type="text/javascript">
 
      YUE.onDOMReady(function(){
 
    	  PullRequestAutoComplete('user', 'reviewers_container', _USERS_AC_DATA, _GROUPS_AC_DATA);
 

	
 
          YUE.on(YUQ('.show-inline-comments'),'change',function(e){
 
              var show = 'none';
 
              var target = e.currentTarget;
 
              if(target.checked){
 
                  var show = ''
 
              }
 
              var boxid = YUD.getAttribute(target,'id_for');
 
              var comments = YUQ('#{0} .inline-comments'.format(boxid));
 
              for(c in comments){
 
                 YUD.setStyle(comments[c],'display',show);
 
              }
 
              var btns = YUQ('#{0} .inline-comments-button'.format(boxid));
 
              for(c in btns){
 
                  YUD.setStyle(btns[c],'display',show);
 
               }
 
          })
 

	
 
          YUE.on(YUQ('.line'),'click',function(e){
 
              var tr = e.currentTarget;
 
              injectInlineForm(tr);
 
          });
 

	
 
          // inject comments into they proper positions
 
          var file_comments = YUQ('.inline-comment-placeholder');
 
          renderInlineComments(file_comments);
 

	
 
          YUE.on(YUD.get('update_pull_request'),'click',function(e){
 

	
 
        	  var reviewers_ids = [];
 
        	  var ids = YUQ('#review_members input');
 
        	  for(var i=0; i<ids.length;i++){
 
        		  var id = ids[i].value
 
        		  reviewers_ids.push(id);
 
        	  }
 
        	  updateReviewers(reviewers_ids);
 
          })
 
      })
 
    </script>
 

	
 
</div>
 

	
 
</%def>
rhodecode/templates/shortlog/shortlog_data.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
%if c.repo_changesets:
 
<table class="table_disp">
 
	<tr>
 
	    <th class="left">${_('revision')}</th>
 
        <th class="left">${_('commit message')}</th>
 
		<th class="left">${_('age')}</th>
 
		<th class="left">${_('author')}</th>
 
		<th class="left">${_('branch')}</th>
 
		<th class="left">${_('tags')}</th>
 
	</tr>
 
%for cnt,cs in enumerate(c.repo_changesets):
 
	<tr class="parity${cnt%2}">
 
        <td>
 
          <div>
 
            <div class="changeset-status-container">
 
              %if c.statuses.get(cs.raw_id):
 
                <div class="changeset-status-ico">
 
                %if c.statuses.get(cs.raw_id)[2]:
 
                  <a class="tooltip" title="${_('Click to open associated pull request')}" href="${h.url('pullrequest_show',repo_name=c.statuses.get(cs.raw_id)[3],pull_request_id=c.statuses.get(cs.raw_id)[2])}">
 
                    <img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" />
 
                  </a>
 
                %else:
 
                  <img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" />
 
                %endif
 
                </div>
 
              %endif
 
            </div>            
 
            </div>
 
            <pre><a href="${h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id)}">r${cs.revision}:${h.short_id(cs.raw_id)}</a></pre>
 
         </div>
 
        </td>
 
        <td>
 
            ${h.link_to(h.truncate(cs.message,50) or _('No commit message'),
 
            h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id),
 
            title=cs.message)}
 
        </td>
 
        <td><span class="tooltip" title="${h.tooltip(h.fmt_date(cs.date))}">
 
                      ${h.age(cs.date)}</span>
 
        </td>
 
		<td title="${cs.author}">${h.person(cs.author)}</td>
 
		<td>
 
			<span class="logtags">
 
                %if cs.branch:
 
				<span class="branchtag">
 
                    ${cs.branch}
 
                </span>
 
                %endif
 
			</span>
 
		</td>
 
		<td>
 
			<span class="logtags">
 
				%for tag in cs.tags:
 
					<span class="tagtag">${tag}</span>
 
				%endfor
 
			</span>
 
		</td>
 
	</tr>
 
%endfor
 

	
 
</table>
 

	
 
<script type="text/javascript">
 
  YUE.onDOMReady(function(){
 
    YUE.delegate("shortlog_data","click",function(e, matchedEl, container){
 
        ypjax(e.target.href,"shortlog_data",function(){tooltip_activate();});
 
        YUE.preventDefault(e);
 
    },'.pager_link');
 
  });
 
</script>
 

	
 
<div class="pagination-wh pagination-left">
 
${c.repo_changesets.pager('$link_previous ~2~ $link_next')}
 
</div>
 
%else:
 

	
 
%if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
 
<h4>${_('Add or upload files directly via RhodeCode')}</h4>
 
<div style="margin: 20px 30px;">
 
  <div id="add_node_id" class="add_node">
 
      <a class="ui-btn" href="${h.url('files_add_home',repo_name=c.repo_name,revision=0,f_path='')}">${_('add new file')}</a>
 
  </div>
 
</div>
 
%endif
 

	
 

	
 
<h4>${_('Push new repo')}</h4>
 
<pre>
 
    ${c.rhodecode_repo.alias} clone ${c.clone_repo_url}
 
    ${c.rhodecode_repo.alias} add README # add first file
 
    ${c.rhodecode_repo.alias} commit -m "Initial" # commit with message
 
    ${c.rhodecode_repo.alias} push ${'origin master' if h.is_git(c.rhodecode_repo) else ''} # push changes back
 
</pre>
 

	
 
<h4>${_('Existing repository?')}</h4>
 
<pre>
 
%if h.is_git(c.rhodecode_repo):
 
    git remote add origin ${c.clone_repo_url}
 
    git push -u origin master
 
%else:
 
    hg push ${c.clone_repo_url}
 
%endif
 
</pre>
 
%endif
rhodecode/tests/functional/test_compare.py
Show inline comments
 
@@ -211,193 +211,193 @@ class TestCompareController(TestControll
 
        self.assertEqual(repo1.scm_instance.revisions, [cs0.raw_id])
 
        #fork the repo1
 
        repo2 = RepoModel().create_repo(repo_name='one-fork', repo_type='hg',
 
                                description='compare-test',
 
                                clone_uri=repo1.repo_full_path,
 
                                owner=TEST_USER_ADMIN_LOGIN, fork_of='one')
 
        Session().commit()
 
        self.assertEqual(repo2.scm_instance.revisions, [cs0.raw_id])
 
        r2_id = repo2.repo_id
 
        r2_name = repo2.repo_name
 

	
 
        #make 3 new commits in fork
 
        cs1 = ScmModel().create_node(
 
            repo=repo2.scm_instance, repo_name=r2_name,
 
            cs=repo2.scm_instance[-1], user=TEST_USER_ADMIN_LOGIN,
 
            author=TEST_USER_ADMIN_LOGIN,
 
            message='commit1-fork',
 
            content='file1-line1-from-fork',
 
            f_path='file1-fork'
 
        )
 
        cs2 = ScmModel().create_node(
 
            repo=repo2.scm_instance, repo_name=r2_name,
 
            cs=cs1, user=TEST_USER_ADMIN_LOGIN,
 
            author=TEST_USER_ADMIN_LOGIN,
 
            message='commit2-fork',
 
            content='file2-line1-from-fork',
 
            f_path='file2-fork'
 
        )
 
        cs3 = ScmModel().create_node(
 
            repo=repo2.scm_instance, repo_name=r2_name,
 
            cs=cs2, user=TEST_USER_ADMIN_LOGIN,
 
            author=TEST_USER_ADMIN_LOGIN,
 
            message='commit3-fork',
 
            content='file3-line1-from-fork',
 
            f_path='file3-fork'
 
        )
 

	
 
        #compare !
 
        rev1 = 'default'
 
        rev2 = 'default'
 
        response = self.app.get(url(controller='compare', action='index',
 
                                    repo_name=r2_name,
 
                                    org_ref_type="branch",
 
                                    org_ref=rev1,
 
                                    other_ref_type="branch",
 
                                    other_ref=rev2,
 
                                    repo=r1_name,
 
                                    bundle=True,
 
                                    ))
 

	
 
        try:
 
            response.mustcontain('%s@%s -> %s@%s' % (r2_name, rev1, r1_name, rev2))
 
            response.mustcontain("""file1-line1-from-fork""")
 
            response.mustcontain("""file2-line1-from-fork""")
 
            response.mustcontain("""file3-line1-from-fork""")
 

	
 
            #add new commit into parent !
 
            cs0 = ScmModel().create_node(
 
                repo=repo1.scm_instance, repo_name=r1_name,
 
                cs=EmptyChangeset(alias='hg'), user=TEST_USER_ADMIN_LOGIN,
 
                author=TEST_USER_ADMIN_LOGIN,
 
                message='commit2',
 
                content='line1-from-new-parent',
 
                f_path='file2'
 
            )
 
            #compare !
 
            rev1 = 'default'
 
            rev2 = 'default'
 
            response = self.app.get(url(controller='compare', action='index',
 
                                        repo_name=r2_name,
 
                                        org_ref_type="branch",
 
                                        org_ref=rev1,
 
                                        other_ref_type="branch",
 
                                        other_ref=rev2,
 
                                        repo=r1_name,
 
                                        bundle=True,
 
                                        ))
 

	
 
            response.mustcontain('%s@%s -> %s@%s' % (r2_name, rev1, r1_name, rev2))
 
            response.mustcontain("""<a href="#">file2</a>""")  # new commit from parent
 
            response.mustcontain("""line1-from-new-parent""")
 
            response.mustcontain("""file1-line1-from-fork""")
 
            response.mustcontain("""file2-line1-from-fork""")
 
            response.mustcontain("""file3-line1-from-fork""")
 
        finally:
 
            RepoModel().delete(r2_id)
 
            RepoModel().delete(r1_id)
 

	
 
    def test_org_repo_new_commits_after_forking_simple_diff(self):
 
        self.log_user()
 

	
 
        repo1 = RepoModel().create_repo(repo_name='one', repo_type='hg',
 
                                        description='diff-test',
 
                                        owner=TEST_USER_ADMIN_LOGIN)
 

	
 
        Session().commit()
 
        r1_id = repo1.repo_id
 
        r1_name = repo1.repo_name
 

	
 
        #commit something initially !
 
        cs0 = ScmModel().create_node(
 
            repo=repo1.scm_instance, repo_name=r1_name,
 
            cs=EmptyChangeset(alias='hg'), user=TEST_USER_ADMIN_LOGIN,
 
            author=TEST_USER_ADMIN_LOGIN,
 
            message='commit1',
 
            content='line1',
 
            f_path='file1'
 
        )
 
        Session().commit()
 
        self.assertEqual(repo1.scm_instance.revisions, [cs0.raw_id])
 
        #fork the repo1
 
        repo2 = RepoModel().create_repo(repo_name='one-fork', repo_type='hg',
 
                                description='compare-test',
 
                                clone_uri=repo1.repo_full_path,
 
                                owner=TEST_USER_ADMIN_LOGIN, fork_of='one')
 
        Session().commit()
 
        self.assertEqual(repo2.scm_instance.revisions, [cs0.raw_id])
 
        r2_id = repo2.repo_id
 
        r2_name = repo2.repo_name
 

	
 
        #make 3 new commits in fork
 
        cs1 = ScmModel().create_node(
 
            repo=repo2.scm_instance, repo_name=r2_name,
 
            cs=repo2.scm_instance[-1], user=TEST_USER_ADMIN_LOGIN,
 
            author=TEST_USER_ADMIN_LOGIN,
 
            message='commit1-fork',
 
            content='file1-line1-from-fork',
 
            f_path='file1-fork'
 
        )
 
        cs2 = ScmModel().create_node(
 
            repo=repo2.scm_instance, repo_name=r2_name,
 
            cs=cs1, user=TEST_USER_ADMIN_LOGIN,
 
            author=TEST_USER_ADMIN_LOGIN,
 
            message='commit2-fork',
 
            content='file2-line1-from-fork',
 
            f_path='file2-fork'
 
        )
 
        cs3 = ScmModel().create_node(
 
            repo=repo2.scm_instance, repo_name=r2_name,
 
            cs=cs2, user=TEST_USER_ADMIN_LOGIN,
 
            author=TEST_USER_ADMIN_LOGIN,
 
            message='commit3-fork',
 
            content='file3-line1-from-fork',
 
            f_path='file3-fork'
 
        )
 

	
 
        #compare !
 
        rev1 = 'default'
 
        rev2 = 'default'
 
        response = self.app.get(url(controller='compare', action='index',
 
                                    repo_name=r2_name,
 
                                    org_ref_type="branch",
 
                                    org_ref=rev1,
 
                                    other_ref_type="branch",
 
                                    other_ref=rev2,
 
                                    repo=r1_name,
 
                                    bundle=False,
 
                                    ))
 

	
 
        try:
 
            #response.mustcontain('%s@%s -> %s@%s' % (r2_name, rev1, r1_name, rev2))
 

	
 
            #add new commit into parent !
 
            cs0 = ScmModel().create_node(
 
                repo=repo1.scm_instance, repo_name=r1_name,
 
                cs=EmptyChangeset(alias='hg'), user=TEST_USER_ADMIN_LOGIN,
 
                author=TEST_USER_ADMIN_LOGIN,
 
                message='commit2',
 
                content='line1',
 
                f_path='file2'
 
            )
 
            #compare !
 
            rev1 = 'default'
 
            rev2 = 'default'
 
            response = self.app.get(url(controller='compare', action='index',
 
                                        repo_name=r2_name,
 
                                        org_ref_type="branch",
 
                                        org_ref=rev1,
 
                                        other_ref_type="branch",
 
                                        other_ref=rev2,
 
                                        repo=r1_name,
 
                                        bundle=False
 
                                        ))
 
            rev2 = cs0.parents[0].raw_id
 
            response.mustcontain('%s@%s -> %s@%s' % (r2_name, rev1, r1_name, rev2))
 
            response.mustcontain("""file1-line1-from-fork""")
 
            response.mustcontain("""file2-line1-from-fork""")
 
            response.mustcontain("""file3-line1-from-fork""")
 
            self.assertFalse("""<a href="#">file2</a>""" in response.body)  # new commit from parent
 
            self.assertFalse("""line1-from-new-parent"""  in response.body)
 
        finally:
 
            RepoModel().delete(r2_id)
 
            RepoModel().delete(r1_id)
 
\ No newline at end of file
 
            RepoModel().delete(r1_id)
rhodecode/tests/test_libs.py
Show inline comments
 
@@ -21,193 +21,192 @@
 
# 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/>.
 
from __future__ import with_statement
 
import unittest
 
import datetime
 
import hashlib
 
import mock
 
from rhodecode.tests import *
 

	
 
proto = 'http'
 
TEST_URLS = [
 
    ('%s://127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
 
     '%s://127.0.0.1' % proto),
 
    ('%s://marcink@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
 
     '%s://127.0.0.1' % proto),
 
    ('%s://marcink:pass@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
 
     '%s://127.0.0.1' % proto),
 
    ('%s://127.0.0.1:8080' % proto, ['%s://' % proto, '127.0.0.1', '8080'],
 
     '%s://127.0.0.1:8080' % proto),
 
    ('%s://domain.org' % proto, ['%s://' % proto, 'domain.org'],
 
     '%s://domain.org' % proto),
 
    ('%s://user:pass@domain.org:8080' % proto, ['%s://' % proto, 'domain.org',
 
                                                '8080'],
 
     '%s://domain.org:8080' % proto),
 
]
 

	
 
proto = 'https'
 
TEST_URLS += [
 
    ('%s://127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
 
     '%s://127.0.0.1' % proto),
 
    ('%s://marcink@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
 
     '%s://127.0.0.1' % proto),
 
    ('%s://marcink:pass@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
 
     '%s://127.0.0.1' % proto),
 
    ('%s://127.0.0.1:8080' % proto, ['%s://' % proto, '127.0.0.1', '8080'],
 
     '%s://127.0.0.1:8080' % proto),
 
    ('%s://domain.org' % proto, ['%s://' % proto, 'domain.org'],
 
     '%s://domain.org' % proto),
 
    ('%s://user:pass@domain.org:8080' % proto, ['%s://' % proto, 'domain.org',
 
                                                '8080'],
 
     '%s://domain.org:8080' % proto),
 
]
 

	
 

	
 
class TestLibs(unittest.TestCase):
 

	
 
    def test_uri_filter(self):
 
        from rhodecode.lib.utils2 import uri_filter
 

	
 
        for url in TEST_URLS:
 
            self.assertEqual(uri_filter(url[0]), url[1])
 

	
 
    def test_credentials_filter(self):
 
        from rhodecode.lib.utils2 import credentials_filter
 

	
 
        for url in TEST_URLS:
 
            self.assertEqual(credentials_filter(url[0]), url[2])
 

	
 
    def test_str2bool(self):
 
        from rhodecode.lib.utils2 import str2bool
 
        test_cases = [
 
            ('t', True),
 
            ('true', True),
 
            ('y', True),
 
            ('yes', True),
 
            ('on', True),
 
            ('1', True),
 
            ('Y', True),
 
            ('yeS', True),
 
            ('Y', True),
 
            ('TRUE', True),
 
            ('T', True),
 
            ('False', False),
 
            ('F', False),
 
            ('FALSE', False),
 
            ('0', False),
 
            ('-1', False),
 
            ('', False), ]
 

	
 
        for case in test_cases:
 
            self.assertEqual(str2bool(case[0]), case[1])
 

	
 
    def test_mention_extractor(self):
 
        from rhodecode.lib.utils2 import extract_mentioned_users
 
        sample = (
 
            "@first hi there @marcink here's my email marcin@email.com "
 
            "@lukaszb check @one_more22 it pls @ ttwelve @D[] @one@two@three "
 
            "@MARCIN    @maRCiN @2one_more22 @john please see this http://org.pl "
 
            "@marian.user just do it @marco-polo and next extract @marco_polo "
 
            "user.dot  hej ! not-needed maril@domain.org"
 
        )
 

	
 
        s = sorted([
 
        'first', 'marcink', 'lukaszb', 'one_more22', 'MARCIN', 'maRCiN', 'john',
 
        'marian.user', 'marco-polo', 'marco_polo'
 
        ], key=lambda k: k.lower())
 
        self.assertEqual(s, extract_mentioned_users(sample))
 

	
 
    def test_age(self):
 
        import calendar
 
        from rhodecode.lib.utils2 import age
 
        n = datetime.datetime.now()
 
        delt = lambda *args, **kwargs: datetime.timedelta(*args, **kwargs)
 
        self.assertEqual(age(n), u'just now')
 
        self.assertEqual(age(n - delt(seconds=1)), u'1 second ago')
 
        self.assertEqual(age(n - delt(seconds=60 * 2)), u'2 minutes ago')
 
        self.assertEqual(age(n - delt(hours=1)), u'1 hour ago')
 
        self.assertEqual(age(n - delt(hours=24)), u'1 day ago')
 
        self.assertEqual(age(n - delt(hours=24 * 5)), u'5 days ago')
 
        self.assertEqual(age(n - delt(hours=24 * (calendar.mdays[n.month - 1] + 2))),
 
                         u'1 month and 2 days ago')
 
        self.assertEqual(age(n - delt(hours=24 * 400)), u'1 year and 1 month ago')
 

	
 
    def test_age_in_future(self):
 
        import calendar
 
        from rhodecode.lib.utils2 import age
 
        n = datetime.datetime.now()
 
        delt = lambda *args, **kwargs: datetime.timedelta(*args, **kwargs)
 
        self.assertEqual(age(n), u'just now')
 
        self.assertEqual(age(n + delt(seconds=1)), u'in 1 second')
 
        self.assertEqual(age(n + delt(seconds=60 * 2)), u'in 2 minutes')
 
        self.assertEqual(age(n + delt(hours=1)), u'in 1 hour')
 
        self.assertEqual(age(n + delt(hours=24)), u'in 1 day')
 
        self.assertEqual(age(n + delt(hours=24 * 5)), u'in 5 days')
 
        self.assertEqual(age(n + delt(hours=24 * (calendar.mdays[n.month - 1] + 2))),
 
                         u'in 1 month and 1 day')
 
        self.assertEqual(age(n + delt(hours=24 * 400)), u'in 1 year and 1 month')
 

	
 
    def test_tag_exctrator(self):
 
        sample = (
 
            "hello pta[tag] gog [[]] [[] sda ero[or]d [me =>>< sa]"
 
            "[requires] [stale] [see<>=>] [see => http://url.com]"
 
            "[requires => url] [lang => python] [just a tag]"
 
            "[,d] [ => ULR ] [obsolete] [desc]]"
 
        )
 
        from rhodecode.lib.helpers import desc_stylize
 
        res = desc_stylize(sample)
 
        self.assertTrue('<div class="metatag" tag="tag">tag</div>' in res)
 
        self.assertTrue('<div class="metatag" tag="obsolete">obsolete</div>' in res)
 
        self.assertTrue('<div class="metatag" tag="stale">stale</div>' in res)
 
        self.assertTrue('<div class="metatag" tag="lang">python</div>' in res)
 
        self.assertTrue('<div class="metatag" tag="requires">requires =&gt; <a href="/url">url</a></div>' in res)
 
        self.assertTrue('<div class="metatag" tag="tag">tag</div>' in res)
 

	
 
    def test_alternative_gravatar(self):
 
        from rhodecode.lib.helpers import gravatar_url
 
        _md5 = lambda s: hashlib.md5(s).hexdigest()
 

	
 
        def fake_conf(**kwargs):
 
            from pylons import config
 
            config['app_conf'] = {}
 
            config['app_conf']['use_gravatar'] = True
 
            config['app_conf'].update(kwargs)
 
            return config
 

	
 
        class fake_url():
 
            @classmethod
 
            def current(cls, *args, **kwargs):
 
                return 'https://server.com'
 

	
 
        with mock.patch('pylons.url', fake_url):
 
            fake = fake_conf(alternative_gravatar_url='http://test.com/{email}')
 
            with mock.patch('pylons.config', fake):
 
                    from pylons import url
 
                    assert url.current() == 'https://server.com'
 
                    grav = gravatar_url(email_address='test@foo.com', size=24)
 
                    assert grav == 'http://test.com/test@foo.com'
 

	
 
            fake = fake_conf(alternative_gravatar_url='http://test.com/{email}')
 
            with mock.patch('pylons.config', fake):
 
                grav = gravatar_url(email_address='test@foo.com', size=24)
 
                assert grav == 'http://test.com/test@foo.com'
 

	
 
            fake = fake_conf(alternative_gravatar_url='http://test.com/{md5email}')
 
            with mock.patch('pylons.config', fake):
 
                em = 'test@foo.com'
 
                grav = gravatar_url(email_address=em, size=24)
 
                assert grav == 'http://test.com/%s' % (_md5(em))
 

	
 
            fake = fake_conf(alternative_gravatar_url='http://test.com/{md5email}/{size}')
 
            with mock.patch('pylons.config', fake):
 
                em = 'test@foo.com'
 
                grav = gravatar_url(email_address=em, size=24)
 
                assert grav == 'http://test.com/%s/%s' % (_md5(em), 24)
 

	
 
            fake = fake_conf(alternative_gravatar_url='{scheme}://{netloc}/{md5email}/{size}')
 
            with mock.patch('pylons.config', fake):
 
                em = 'test@foo.com'
 
                grav = gravatar_url(email_address=em, size=24)
 
                assert grav == 'https://server.com/%s/%s' % (_md5(em), 24)
 

	
0 comments (0 inline, 0 general)