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

	
 
    pull requests controller for rhodecode for initializing pull requests
 

	
 
    :created_on: May 7, 2012
 
    :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 webob.exc import HTTPNotFound, HTTPForbidden
 
from collections import defaultdict
 
from itertools import groupby
 

	
 
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.compat import json
 
from rhodecode.lib.base import BaseRepoController, render
 
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator,\
 
    NotAnonymous
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib import diffs
 
from rhodecode.lib.utils import action_logger, jsonify
 
from rhodecode.lib.vcs.exceptions import EmptyRepositoryError
 
from rhodecode.lib.vcs.backends.base import EmptyChangeset
 
from rhodecode.lib.diffs import LimitedDiffContainer
 
from rhodecode.model.db import User, PullRequest, ChangesetStatus,\
 
    ChangesetComment
 
from rhodecode.model.pull_request import PullRequestModel
 
from rhodecode.model.meta import Session
 
from rhodecode.model.repo import RepoModel
 
from rhodecode.model.comment import ChangesetCommentsModel
 
from rhodecode.model.changeset_status import ChangesetStatusModel
 
from rhodecode.model.forms import PullRequestForm
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class PullrequestsController(BaseRepoController):
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def __before__(self):
 
        super(PullrequestsController, self).__before__()
 
        repo_model = RepoModel()
 
        c.users_array = repo_model.get_users_js()
 
        c.users_groups_array = repo_model.get_users_groups_js()
 

	
 
    def _get_repo_refs(self, repo):
 
        hist_l = []
 

	
 
        branches_group = ([('branch:%s:%s' % (k, v), k) for
 
                         k, v in repo.branches.iteritems()], _("Branches"))
 
        bookmarks_group = ([('book:%s:%s' % (k, v), k) for
 
                         k, v in repo.bookmarks.iteritems()], _("Bookmarks"))
 
        tags_group = ([('tag:%s:%s' % (k, v), k) for
 
                         k, v in repo.tags.iteritems()
 
                         if k != 'tip'], _("Tags"))
 

	
 
        tip = repo.tags['tip']
 
        tipref = 'tag:tip:%s' % tip
 
        colontip = ':' + tip
 
        tips = [x[1] for x in branches_group[0] + bookmarks_group[0] + tags_group[0]
 
                if x[0].endswith(colontip)]
 
        tags_group[0].append((tipref, 'tip (%s)' % ', '.join(tips)))
 

	
 
        hist_l.append(bookmarks_group)
 
        hist_l.append(branches_group)
 
        hist_l.append(tags_group)
 

	
 
        return hist_l, tipref
 

	
 
    def _get_is_allowed_change_status(self, pull_request):
 
        owner = self.rhodecode_user.user_id == pull_request.user_id
 
        reviewer = self.rhodecode_user.user_id in [x.user_id for x in
 
                                                   pull_request.reviewers]
 
        return (self.rhodecode_user.admin or owner or reviewer)
 

	
 
    def show_all(self, repo_name):
 
        c.pull_requests = PullRequestModel().get_all(repo_name)
 
        c.repo_name = repo_name
 
        return render('/pullrequests/pullrequest_show_all.html')
 

	
 
    @NotAnonymous()
 
    def index(self):
 
        org_repo = c.rhodecode_db_repo
 

	
 
        if org_repo.scm_instance.alias != 'hg':
 
            log.error('Review not available for GIT REPOS')
 
            raise HTTPNotFound
 

	
 
        try:
 
            org_repo.scm_instance.get_changeset()
 
        except EmptyRepositoryError, e:
 
            h.flash(h.literal(_('There are no changesets yet')),
 
                    category='warning')
 
            redirect(url('summary_home', repo_name=org_repo.repo_name))
 

	
 
        other_repos_info = {}
 

	
 
        c.org_repos = []
 
        c.org_repos.append((org_repo.repo_name, org_repo.repo_name))
 
        c.default_org_repo = org_repo.repo_name
 
        c.org_refs, c.default_org_ref = self._get_repo_refs(org_repo.scm_instance)
 

	
 
        c.other_repos = []
 
        # add org repo to other so we can open pull request against itself
 
        c.other_repos.extend(c.org_repos)
 
        c.default_other_repo = org_repo.repo_name
 
        c.default_other_refs, c.default_other_ref = self._get_repo_refs(org_repo.scm_instance)
 
        usr_data = lambda usr: dict(user_id=usr.user_id,
 
                                    username=usr.username,
 
                                    firstname=usr.firstname,
 
                                    lastname=usr.lastname,
 
                                    gravatar_link=h.gravatar_url(usr.email, 14))
 
        other_repos_info[org_repo.repo_name] = {
 
            'user': usr_data(org_repo.user),
 
            'description': org_repo.description,
 
            'revs': h.select('other_ref', c.default_other_ref,
 
                             c.default_other_refs, class_='refs')
 
        }
 

	
 
        # gather forks and add to this list ... even though it is rare to 
 
        # gather forks and add to this list ... even though it is rare to
 
        # request forks to pull their parent
 
        for fork in org_repo.forks:
 
            c.other_repos.append((fork.repo_name, fork.repo_name))
 
            refs, default_ref = self._get_repo_refs(fork.scm_instance)
 
            other_repos_info[fork.repo_name] = {
 
                'user': usr_data(fork.user),
 
                'description': fork.description,
 
                'revs': h.select('other_ref', default_ref, refs, class_='refs')
 
            }
 

	
 
        # add parents of this fork also, but only if it's not empty
 
        if org_repo.parent and org_repo.parent.scm_instance.revisions:
 
            c.default_other_repo = org_repo.parent.repo_name
 
            c.default_other_refs, c.default_other_ref = self._get_repo_refs(org_repo.parent.scm_instance)
 
            c.other_repos.append((org_repo.parent.repo_name, org_repo.parent.repo_name))
 
            other_repos_info[org_repo.parent.repo_name] = {
 
                'user': usr_data(org_repo.parent.user),
 
                'description': org_repo.parent.description,
 
                'revs': h.select('other_ref', c.default_other_ref,
 
                                 c.default_other_refs, class_='refs')
 
            }
 

	
 
        c.other_repos_info = json.dumps(other_repos_info)
 
        # other repo owner
 
        c.review_members = []
 
        return render('/pullrequests/pullrequest.html')
 

	
 
    @NotAnonymous()
 
    def create(self, repo_name):
 
        repo = RepoModel()._get_repo(repo_name)
 
        try:
 
            _form = PullRequestForm(repo.repo_id)().to_python(request.POST)
 
        except formencode.Invalid, errors:
 
            log.error(traceback.format_exc())
 
            if errors.error_dict.get('revisions'):
 
                msg = 'Revisions: %s' % errors.error_dict['revisions']
 
            elif errors.error_dict.get('pullrequest_title'):
 
                msg = _('Pull request requires a title with min. 3 chars')
 
            else:
 
                msg = _('error during creation of pull request')
 

	
 
            h.flash(msg, 'error')
 
            return redirect(url('pullrequest_home', repo_name=repo_name))
 

	
 
        org_repo = _form['org_repo']
 
        org_ref = _form['org_ref']
 
        other_repo = _form['other_repo']
 
        other_ref = _form['other_ref']
 
        revisions = _form['revisions']
 
        reviewers = _form['review_members']
 

	
 
        # if we have cherry picked pull request we don't care what is in
 
        # org_ref/other_ref
 
        rev_start = request.POST.get('rev_start')
 
        rev_end = request.POST.get('rev_end')
 

	
 
        if rev_start and rev_end:
 
            # this is swapped to simulate that rev_end is a revision from
 
            # parent of the fork
 
            org_ref = 'rev:%s:%s' % (rev_end, rev_end)
 
            other_ref = 'rev:%s:%s' % (rev_start, rev_start)
 

	
 
        title = _form['pullrequest_title']
 
        description = _form['pullrequest_desc']
 

	
 
        try:
 
            pull_request = PullRequestModel().create(
 
                self.rhodecode_user.user_id, org_repo, org_ref, other_repo,
 
                other_ref, revisions, reviewers, title, description
 
            )
 
            Session().commit()
 
            h.flash(_('Successfully opened new pull request'),
 
                    category='success')
 
        except Exception:
 
            h.flash(_('Error occurred during sending pull request'),
 
                    category='error')
 
            log.error(traceback.format_exc())
 
            return redirect(url('pullrequest_home', repo_name=repo_name))
 

	
 
        return redirect(url('pullrequest_show', repo_name=other_repo,
 
                            pull_request_id=pull_request.pull_request_id))
 

	
 
    @NotAnonymous()
 
    @jsonify
 
    def update(self, repo_name, pull_request_id):
 
        pull_request = PullRequest.get_or_404(pull_request_id)
 
        if pull_request.is_closed():
 
            raise HTTPForbidden()
 
        #only owner or admin can update it
 
        owner = pull_request.author.user_id == c.rhodecode_user.user_id
 
        if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
 
            reviewers_ids = map(int, filter(lambda v: v not in [None, ''],
 
                       request.POST.get('reviewers_ids', '').split(',')))
 

	
 
            PullRequestModel().update_reviewers(pull_request_id, reviewers_ids)
 
            Session().commit()
 
            return True
 
        raise HTTPForbidden()
 

	
 
    @NotAnonymous()
 
    @jsonify
 
    def delete(self, repo_name, pull_request_id):
 
        pull_request = PullRequest.get_or_404(pull_request_id)
 
        #only owner can delete it !
 
        if pull_request.author.user_id == c.rhodecode_user.user_id:
 
            PullRequestModel().delete(pull_request)
 
            Session().commit()
 
            h.flash(_('Successfully deleted pull request'),
 
                    category='success')
 
            return redirect(url('admin_settings_my_account', anchor='pullrequests'))
 
        raise HTTPForbidden()
 

	
 
    def _load_compare_data(self, pull_request, enable_comments=True):
 
        """
 
        Load context data needed for generating compare diff
 

	
 
        :param pull_request:
 
        :type pull_request:
 
        """
 
        rev_start = request.GET.get('rev_start')
 
        rev_end = request.GET.get('rev_end')
 

	
 
        org_repo = pull_request.org_repo
 
        (org_ref_type,
 
         org_ref_name,
 
         org_ref_rev) = pull_request.org_ref.split(':')
 

	
 
        other_repo = org_repo
 
        (other_ref_type,
 
         other_ref_name,
 
         other_ref_rev) = pull_request.other_ref.split(':')
 

	
 
        # despite opening revisions for bookmarks/branches/tags, we always
 
        # convert this to rev to prevent changes after book or branch change
 
        org_ref = ('rev', org_ref_rev)
 
        other_ref = ('rev', other_ref_rev)
 

	
 
        c.org_repo = org_repo
 
        c.other_repo = other_repo
 

	
 
        c.fulldiff = fulldiff = request.GET.get('fulldiff')
 

	
 
        c.cs_ranges = [org_repo.get_changeset(x) for x in pull_request.revisions]
 

	
 
        other_ref = ('rev', getattr(c.cs_ranges[0].parents[0]
 
                                  if c.cs_ranges[0].parents
 
                                  else EmptyChangeset(), 'raw_id'))
 

	
 
        c.statuses = org_repo.statuses([x.raw_id for x in c.cs_ranges])
 
        # defines that we need hidden inputs with changesets
 
        c.as_form = request.GET.get('as_form', False)
 

	
 
        c.org_ref = org_ref[1]
 
        c.org_ref_type = org_ref[0]
 
        c.other_ref = other_ref[1]
 
        c.other_ref_type = other_ref[0]
 

	
 
        diff_limit = self.cut_off_limit if not fulldiff else None
 

	
 
        #we swap org/other ref since we run a simple diff on one repo
 
        _diff = diffs.differ(org_repo, other_ref, other_repo, org_ref)
 

	
 
        diff_processor = diffs.DiffProcessor(_diff or '', format='gitdiff',
 
                                             diff_limit=diff_limit)
 
        _parsed = diff_processor.prepare()
 

	
 
        c.limited_diff = False
 
        if isinstance(_parsed, LimitedDiffContainer):
 
            c.limited_diff = True
 

	
 
        c.files = []
 
        c.changes = {}
 
        c.lines_added = 0
 
        c.lines_deleted = 0
 
        for f in _parsed:
 
            st = f['stats']
 
            if st[0] != 'b':
 
                c.lines_added += st[0]
 
                c.lines_deleted += st[1]
 
            fid = h.FID('', f['filename'])
 
            c.files.append([fid, f['operation'], f['filename'], f['stats']])
 
            diff = diff_processor.as_html(enable_comments=enable_comments,
 
                                          parsed_lines=[f])
 
            c.changes[fid] = [f['operation'], f['filename'], diff]
 

	
 
    def show(self, repo_name, pull_request_id):
 
        repo_model = RepoModel()
 
        c.users_array = repo_model.get_users_js()
 
        c.users_groups_array = repo_model.get_users_groups_js()
 
        c.pull_request = PullRequest.get_or_404(pull_request_id)
 
        c.allowed_to_change_status = self._get_is_allowed_change_status(c.pull_request)
 
        cc_model = ChangesetCommentsModel()
 
        cs_model = ChangesetStatusModel()
 
        _cs_statuses = cs_model.get_statuses(c.pull_request.org_repo,
 
                                            pull_request=c.pull_request,
 
                                            with_revisions=True)
 

	
 
        cs_statuses = defaultdict(list)
 
        for st in _cs_statuses:
 
            cs_statuses[st.author.username] += [st]
 

	
 
        c.pull_request_reviewers = []
 
        c.pull_request_pending_reviewers = []
 
        for o in c.pull_request.reviewers:
 
            st = cs_statuses.get(o.user.username, None)
 
            if st:
 
                sorter = lambda k: k.version
 
                st = [(x, list(y)[0])
 
                      for x, y in (groupby(sorted(st, key=sorter), sorter))]
 
            else:
 
                c.pull_request_pending_reviewers.append(o.user)
 
            c.pull_request_reviewers.append([o.user, st])
 

	
 
        # pull_requests repo_name we opened it against
 
        # ie. other_repo must match
 
        if repo_name != c.pull_request.other_repo.repo_name:
 
            raise HTTPNotFound
 

	
 
        # load compare data into template context
 
        enable_comments = not c.pull_request.is_closed()
 
        self._load_compare_data(c.pull_request, enable_comments=enable_comments)
 

	
 
        # inline comments
 
        c.inline_cnt = 0
 
        c.inline_comments = cc_model.get_inline_comments(
 
                                c.rhodecode_db_repo.repo_id,
 
                                pull_request=pull_request_id)
 
        # count inline comments
 
        for __, lines in c.inline_comments:
 
            for comments in lines.values():
 
                c.inline_cnt += len(comments)
 
        # comments
 
        c.comments = cc_model.get_comments(c.rhodecode_db_repo.repo_id,
 
                                           pull_request=pull_request_id)
 

	
 
        try:
 
            cur_status = c.statuses[c.pull_request.revisions[0]][0]
 
        except:
 
            log.error(traceback.format_exc())
 
            cur_status = 'undefined'
 
        if c.pull_request.is_closed() and 0:
 
            c.current_changeset_status = cur_status
 
        else:
 
            # changeset(pull-request) status calulation based on reviewers
 
            c.current_changeset_status = cs_model.calculate_status(
 
                                            c.pull_request_reviewers,
 
                                         )
 
        c.changeset_statuses = ChangesetStatus.STATUSES
 

	
 
        return render('/pullrequests/pullrequest_show.html')
 

	
 
    @NotAnonymous()
 
    @jsonify
 
    def comment(self, repo_name, pull_request_id):
 
        pull_request = PullRequest.get_or_404(pull_request_id)
 
        if pull_request.is_closed():
 
            raise HTTPForbidden()
 

	
 
        status = request.POST.get('changeset_status')
 
        change_status = request.POST.get('change_changeset_status')
 
        text = request.POST.get('text')
 

	
 
        allowed_to_change_status = self._get_is_allowed_change_status(pull_request)
 
        if status and change_status and allowed_to_change_status:
 
            text = text or (_('Status change -> %s')
 
                            % ChangesetStatus.get_status_lbl(status))
 
        comm = ChangesetCommentsModel().create(
 
            text=text,
 
            repo=c.rhodecode_db_repo.repo_id,
 
            user=c.rhodecode_user.user_id,
 
            pull_request=pull_request_id,
 
            f_path=request.POST.get('f_path'),
 
            line_no=request.POST.get('line'),
 
            status_change=(ChangesetStatus.get_status_lbl(status)
 
            if status and change_status and allowed_to_change_status else None)
 
        )
 

	
 
        action_logger(self.rhodecode_user,
 
                      'user_commented_pull_request:%s' % pull_request_id,
 
                      c.rhodecode_db_repo, self.ip_addr, self.sa)
 

	
 
        if allowed_to_change_status:
 
            # get status if set !
 
            if status and change_status:
 
                ChangesetStatusModel().set_status(
 
                    c.rhodecode_db_repo.repo_id,
 
                    status,
 
                    c.rhodecode_user.user_id,
 
                    comm,
 
                    pull_request=pull_request_id
 
                )
 

	
 
            if request.POST.get('save_close'):
 
                if status in ['rejected', 'approved']:
 
                    PullRequestModel().close_pull_request(pull_request_id)
 
                    action_logger(self.rhodecode_user,
 
                              'user_closed_pull_request:%s' % pull_request_id,
 
                              c.rhodecode_db_repo, self.ip_addr, self.sa)
 
                else:
 
                    h.flash(_('Closing pull request on other statuses than '
 
                              'rejected or approved forbidden'),
 
                            category='warning')
 

	
 
        Session().commit()
 

	
 
        if not request.environ.get('HTTP_X_PARTIAL_XHR'):
 
            return redirect(h.url('pullrequest_show', repo_name=repo_name,
 
                                  pull_request_id=pull_request_id))
 

	
 
        data = {
 
           'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
 
        }
 
        if comm:
 
            c.co = comm
 
            data.update(comm.get_dict())
 
            data.update({'rendered_text':
 
                         render('changeset/changeset_comment_block.html')})
 

	
 
        return data
 

	
 
    @NotAnonymous()
 
    @jsonify
 
    def delete_comment(self, repo_name, comment_id):
 
        co = ChangesetComment.get(comment_id)
 
        if co.pull_request.is_closed():
 
            #don't allow deleting comments on closed pull request
 
            raise HTTPForbidden()
 

	
 
        owner = co.author.user_id == c.rhodecode_user.user_id
 
        if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
 
            ChangesetCommentsModel().delete(comment=co)
 
            Session().commit()
 
            return True
 
        else:
 
            raise HTTPForbidden()
rhodecode/lib/vcs/backends/git/changeset.py
Show inline comments
 
import re
 
from itertools import chain
 
from dulwich import objects
 
from subprocess import Popen, PIPE
 
import rhodecode
 
from rhodecode.lib.vcs.conf import settings
 
from rhodecode.lib.vcs.exceptions import RepositoryError
 
from rhodecode.lib.vcs.exceptions import ChangesetError
 
from rhodecode.lib.vcs.exceptions import NodeDoesNotExistError
 
from rhodecode.lib.vcs.exceptions import VCSError
 
from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError
 
from rhodecode.lib.vcs.exceptions import ImproperArchiveTypeError
 
from rhodecode.lib.vcs.backends.base import BaseChangeset, EmptyChangeset
 
from rhodecode.lib.vcs.nodes import FileNode, DirNode, NodeKind, RootNode, \
 
    RemovedFileNode, SubModuleNode, ChangedFileNodesGenerator,\
 
    AddedFileNodesGenerator, RemovedFileNodesGenerator
 
from rhodecode.lib.vcs.utils import safe_unicode
 
from rhodecode.lib.vcs.utils import date_fromtimestamp
 
from rhodecode.lib.vcs.utils.lazy import LazyProperty
 

	
 

	
 
class GitChangeset(BaseChangeset):
 
    """
 
    Represents state of the repository at single revision.
 
    """
 

	
 
    def __init__(self, repository, revision):
 
        self._stat_modes = {}
 
        self.repository = repository
 

	
 
        try:
 
            commit = self.repository._repo.get_object(revision)
 
            if isinstance(commit, objects.Tag):
 
                revision = commit.object[1]
 
                commit = self.repository._repo.get_object(commit.object[1])
 
        except KeyError:
 
            raise RepositoryError("Cannot get object with id %s" % revision)
 
        self.raw_id = revision
 
        self.id = self.raw_id
 
        self.short_id = self.raw_id[:12]
 
        self._commit = commit
 

	
 
        self._tree_id = commit.tree
 
        self._commiter_property = 'committer'
 
        self._author_property = 'author'
 
        self._date_property = 'commit_time'
 
        self._date_tz_property = 'commit_timezone'
 
        self.revision = repository.revisions.index(revision)
 

	
 
        self.message = safe_unicode(commit.message)
 

	
 
        self.nodes = {}
 
        self._paths = {}
 

	
 
    @LazyProperty
 
    def commiter(self):
 
        return safe_unicode(getattr(self._commit, self._commiter_property))
 

	
 
    @LazyProperty
 
    def author(self):
 
        return safe_unicode(getattr(self._commit, self._author_property))
 

	
 
    @LazyProperty
 
    def date(self):
 
        return date_fromtimestamp(getattr(self._commit, self._date_property),
 
                                  getattr(self._commit, self._date_tz_property))
 

	
 
    @LazyProperty
 
    def _timestamp(self):
 
        return getattr(self._commit, self._date_property)
 

	
 
    @LazyProperty
 
    def status(self):
 
        """
 
        Returns modified, added, removed, deleted files for current changeset
 
        """
 
        return self.changed, self.added, self.removed
 

	
 
    @LazyProperty
 
    def tags(self):
 
        _tags = []
 
        for tname, tsha in self.repository.tags.iteritems():
 
            if tsha == self.raw_id:
 
                _tags.append(tname)
 
        return _tags
 

	
 
    @LazyProperty
 
    def branch(self):
 

	
 
        heads = self.repository._heads(reverse=False)
 

	
 
        ref = heads.get(self.raw_id)
 
        if ref:
 
            return safe_unicode(ref)
 

	
 
    def _fix_path(self, path):
 
        """
 
        Paths are stored without trailing slash so we need to get rid off it if
 
        needed.
 
        """
 
        if path.endswith('/'):
 
            path = path.rstrip('/')
 
        return path
 

	
 
    def _get_id_for_path(self, path):
 

	
 
        # FIXME: Please, spare a couple of minutes and make those codes cleaner;
 
        if not path in self._paths:
 
            path = path.strip('/')
 
            # set root tree
 
            tree = self.repository._repo[self._tree_id]
 
            if path == '':
 
                self._paths[''] = tree.id
 
                return tree.id
 
            splitted = path.split('/')
 
            dirs, name = splitted[:-1], splitted[-1]
 
            curdir = ''
 

	
 
            # initially extract things from root dir
 
            for item, stat, id in tree.iteritems():
 
                if curdir:
 
                    name = '/'.join((curdir, item))
 
                else:
 
                    name = item
 
                self._paths[name] = id
 
                self._stat_modes[name] = stat
 

	
 
            for dir in dirs:
 
                if curdir:
 
                    curdir = '/'.join((curdir, dir))
 
                else:
 
                    curdir = dir
 
                dir_id = None
 
                for item, stat, id in tree.iteritems():
 
                    if dir == item:
 
                        dir_id = id
 
                if dir_id:
 
                    # Update tree
 
                    tree = self.repository._repo[dir_id]
 
                    if not isinstance(tree, objects.Tree):
 
                        raise ChangesetError('%s is not a directory' % curdir)
 
                else:
 
                    raise ChangesetError('%s have not been found' % curdir)
 

	
 
                # cache all items from the given traversed tree
 
                for item, stat, id in tree.iteritems():
 
                    if curdir:
 
                        name = '/'.join((curdir, item))
 
                    else:
 
                        name = item
 
                    self._paths[name] = id
 
                    self._stat_modes[name] = stat
 
            if not path in self._paths:
 
                raise NodeDoesNotExistError("There is no file nor directory "
 
                    "at the given path %r at revision %r"
 
                    % (path, self.short_id))
 
        return self._paths[path]
 

	
 
    def _get_kind(self, path):
 
        obj = self.repository._repo[self._get_id_for_path(path)]
 
        if isinstance(obj, objects.Blob):
 
            return NodeKind.FILE
 
        elif isinstance(obj, objects.Tree):
 
            return NodeKind.DIR
 

	
 
    def _get_filectx(self, path):
 
        path = self._fix_path(path)
 
        if self._get_kind(path) != NodeKind.FILE:
 
            raise ChangesetError("File does not exist for revision %r at "
 
                " %r" % (self.raw_id, path))
 
        return path
 

	
 
    def _get_file_nodes(self):
 
        return chain(*(t[2] for t in self.walk()))
 

	
 
    @LazyProperty
 
    def parents(self):
 
        """
 
        Returns list of parents changesets.
 
        """
 
        return [self.repository.get_changeset(parent)
 
                for parent in self._commit.parents]
 

	
 
    @LazyProperty
 
    def children(self):
 
        """
 
        Returns list of children changesets.
 
        """
 
        so, se = self.repository.run_git_command(
 
            "rev-list --all --children | grep '^%s'" % self.raw_id
 
        )
 

	
 
        children = []
 
        for l in so.splitlines():
 
            childs = l.split(' ')[1:]
 
            children.extend(childs)
 
        return [self.repository.get_changeset(cs) for cs in children]
 

	
 
    def next(self, branch=None):
 

	
 
        if branch and self.branch != branch:
 
            raise VCSError('Branch option used on changeset not belonging '
 
                           'to that branch')
 

	
 
        def _next(changeset, branch):
 
            try:
 
                next_ = changeset.revision + 1
 
                next_rev = changeset.repository.revisions[next_]
 
            except IndexError:
 
                raise ChangesetDoesNotExistError
 
            cs = changeset.repository.get_changeset(next_rev)
 

	
 
            if branch and branch != cs.branch:
 
                return _next(cs, branch)
 

	
 
            return cs
 

	
 
        return _next(self, branch)
 

	
 
    def prev(self, branch=None):
 
        if branch and self.branch != branch:
 
            raise VCSError('Branch option used on changeset not belonging '
 
                           'to that branch')
 

	
 
        def _prev(changeset, branch):
 
            try:
 
                prev_ = changeset.revision - 1
 
                if prev_ < 0:
 
                    raise IndexError
 
                prev_rev = changeset.repository.revisions[prev_]
 
            except IndexError:
 
                raise ChangesetDoesNotExistError
 

	
 
            cs = changeset.repository.get_changeset(prev_rev)
 

	
 
            if branch and branch != cs.branch:
 
                return _prev(cs, branch)
 

	
 
            return cs
 

	
 
        return _prev(self, branch)
 

	
 
    def diff(self, ignore_whitespace=True, context=3):
 
        rev1 = self.parents[0] if self.parents else self.repository.EMPTY_CHANGESET
 
        rev2 = self
 
        return ''.join(self.repository.get_diff(rev1, rev2,
 
                                    ignore_whitespace=ignore_whitespace,
 
                                    context=context))
 

	
 
    def get_file_mode(self, path):
 
        """
 
        Returns stat mode of the file at the given ``path``.
 
        """
 
        # ensure path is traversed
 
        self._get_id_for_path(path)
 
        return self._stat_modes[path]
 

	
 
    def get_file_content(self, path):
 
        """
 
        Returns content of the file at given ``path``.
 
        """
 
        id = self._get_id_for_path(path)
 
        blob = self.repository._repo[id]
 
        return blob.as_pretty_string()
 

	
 
    def get_file_size(self, path):
 
        """
 
        Returns size of the file at given ``path``.
 
        """
 
        id = self._get_id_for_path(path)
 
        blob = self.repository._repo[id]
 
        return blob.raw_length()
 

	
 
    def get_file_changeset(self, path):
 
        """
 
        Returns last commit of the file at the given ``path``.
 
        """
 
        node = self.get_node(path)
 
        return node.history[0]
 

	
 
    def get_file_history(self, path):
 
        """
 
        Returns history of file as reversed list of ``Changeset`` objects for
 
        which file at given ``path`` has been modified.
 

	
 
        TODO: This function now uses os underlying 'git' and 'grep' commands
 
        which is generally not good. Should be replaced with algorithm
 
        iterating commits.
 
        """
 
        self._get_filectx(path)
 

	
 
        cmd = 'log --pretty="format: %%H" -s -p %s -- "%s"' % (
 
                  self.id, path
 
               )
 
        so, se = self.repository.run_git_command(cmd)
 
        ids = re.findall(r'[0-9a-fA-F]{40}', so)
 
        return [self.repository.get_changeset(id) for id in ids]
 

	
 
    def get_file_history_2(self, path):
 
        """
 
        Returns history of file as reversed list of ``Changeset`` objects for
 
        which file at given ``path`` has been modified.
 

	
 
        """
 
        self._get_filectx(path)
 
        from dulwich.walk import Walker
 
        include = [self.id]
 
        walker = Walker(self.repository._repo.object_store, include,
 
                        paths=[path], max_entries=1)
 
        return [self.repository.get_changeset(sha)
 
                for sha in (x.commit.id for x in walker)]
 

	
 
    def get_file_annotate(self, path):
 
        """
 
        Returns a generator of four element tuples with
 
            lineno, sha, changeset lazy loader and line
 

	
 
        TODO: This function now uses os underlying 'git' command which is
 
        generally not good. Should be replaced with algorithm iterating
 
        commits.
 
        """
 
        cmd = 'blame -l --root -r %s -- "%s"' % (self.id, path)
 
        # -l     ==> outputs long shas (and we need all 40 characters)
 
        # --root ==> doesn't put '^' character for bounderies
 
        # -r sha ==> blames for the given revision
 
        so, se = self.repository.run_git_command(cmd)
 

	
 
        for i, blame_line in enumerate(so.split('\n')[:-1]):
 
            ln_no = i + 1
 
            sha, line = re.split(r' ', blame_line, 1)
 
            yield (ln_no, sha, lambda: self.repository.get_changeset(sha), line)
 

	
 
    def fill_archive(self, stream=None, kind='tgz', prefix=None,
 
                     subrepos=False):
 
        """
 
        Fills up given stream.
 

	
 
        :param stream: file like object.
 
        :param kind: one of following: ``zip``, ``tgz`` or ``tbz2``.
 
            Default: ``tgz``.
 
        :param prefix: name of root directory in archive.
 
            Default is repository name and changeset's raw_id joined with dash
 
            (``repo-tip.<KIND>``).
 
        :param subrepos: include subrepos in this archive.
 

	
 
        :raise ImproperArchiveTypeError: If given kind is wrong.
 
        :raise VcsError: If given stream is None
 

	
 
        """
 
        allowed_kinds = settings.ARCHIVE_SPECS.keys()
 
        if kind not in allowed_kinds:
 
            raise ImproperArchiveTypeError('Archive kind not supported use one'
 
                'of %s', allowed_kinds)
 

	
 
        if prefix is None:
 
            prefix = '%s-%s' % (self.repository.name, self.short_id)
 
        elif prefix.startswith('/'):
 
            raise VCSError("Prefix cannot start with leading slash")
 
        elif prefix.strip() == '':
 
            raise VCSError("Prefix cannot be empty")
 

	
 
        if kind == 'zip':
 
            frmt = 'zip'
 
        else:
 
            frmt = 'tar'
 
        _git_path = rhodecode.CONFIG.get('git_path', 'git')
 
        cmd = '%s archive --format=%s --prefix=%s/ %s' % (_git_path, 
 
        cmd = '%s archive --format=%s --prefix=%s/ %s' % (_git_path,
 
                                                frmt, prefix, self.raw_id)
 
        if kind == 'tgz':
 
            cmd += ' | gzip -9'
 
        elif kind == 'tbz2':
 
            cmd += ' | bzip2 -9'
 

	
 
        if stream is None:
 
            raise VCSError('You need to pass in a valid stream for filling'
 
                           ' with archival data')
 
        popen = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True,
 
            cwd=self.repository.path)
 

	
 
        buffer_size = 1024 * 8
 
        chunk = popen.stdout.read(buffer_size)
 
        while chunk:
 
            stream.write(chunk)
 
            chunk = popen.stdout.read(buffer_size)
 
        # Make sure all descriptors would be read
 
        popen.communicate()
 

	
 
    def get_nodes(self, path):
 
        if self._get_kind(path) != NodeKind.DIR:
 
            raise ChangesetError("Directory does not exist for revision %r at "
 
                " %r" % (self.revision, path))
 
        path = self._fix_path(path)
 
        id = self._get_id_for_path(path)
 
        tree = self.repository._repo[id]
 
        dirnodes = []
 
        filenodes = []
 
        als = self.repository.alias
 
        for name, stat, id in tree.iteritems():
 
            if objects.S_ISGITLINK(stat):
 
                dirnodes.append(SubModuleNode(name, url=None, changeset=id,
 
                                              alias=als))
 
                continue
 

	
 
            obj = self.repository._repo.get_object(id)
 
            if path != '':
 
                obj_path = '/'.join((path, name))
 
            else:
 
                obj_path = name
 
            if obj_path not in self._stat_modes:
 
                self._stat_modes[obj_path] = stat
 
            if isinstance(obj, objects.Tree):
 
                dirnodes.append(DirNode(obj_path, changeset=self))
 
            elif isinstance(obj, objects.Blob):
 
                filenodes.append(FileNode(obj_path, changeset=self, mode=stat))
 
            else:
 
                raise ChangesetError("Requested object should be Tree "
 
                                     "or Blob, is %r" % type(obj))
 
        nodes = dirnodes + filenodes
 
        for node in nodes:
 
            if not node.path in self.nodes:
 
                self.nodes[node.path] = node
 
        nodes.sort()
 
        return nodes
 

	
 
    def get_node(self, path):
 
        if isinstance(path, unicode):
 
            path = path.encode('utf-8')
 
        path = self._fix_path(path)
 
        if not path in self.nodes:
 
            try:
 
                id_ = self._get_id_for_path(path)
 
            except ChangesetError:
 
                raise NodeDoesNotExistError("Cannot find one of parents' "
 
                    "directories for a given path: %s" % path)
 

	
 
            _GL = lambda m: m and objects.S_ISGITLINK(m)
 
            if _GL(self._stat_modes.get(path)):
 
                node = SubModuleNode(path, url=None, changeset=id_,
 
                                     alias=self.repository.alias)
 
            else:
 
                obj = self.repository._repo.get_object(id_)
 

	
 
                if isinstance(obj, objects.Tree):
 
                    if path == '':
 
                        node = RootNode(changeset=self)
 
                    else:
 
                        node = DirNode(path, changeset=self)
 
                    node._tree = obj
 
                elif isinstance(obj, objects.Blob):
 
                    node = FileNode(path, changeset=self)
 
                    node._blob = obj
 
                else:
 
                    raise NodeDoesNotExistError("There is no file nor directory "
 
                        "at the given path %r at revision %r"
 
                        % (path, self.short_id))
 
            # cache node
 
            self.nodes[path] = node
 
        return self.nodes[path]
 

	
 
    @LazyProperty
 
    def affected_files(self):
 
        """
 
        Get's a fast accessible file changes for given changeset
 
        """
 
        a, m, d = self._changes_cache
 
        return list(a.union(m).union(d))
 

	
 
    @LazyProperty
 
    def _diff_name_status(self):
 
        output = []
 
        for parent in self.parents:
 
            cmd = 'diff --name-status %s %s --encoding=utf8' % (parent.raw_id,
 
                                                                self.raw_id)
 
            so, se = self.repository.run_git_command(cmd)
 
            output.append(so.strip())
 
        return '\n'.join(output)
 

	
 
    @LazyProperty
 
    def _changes_cache(self):
 
        added = set()
 
        modified = set()
 
        deleted = set()
 
        _r = self.repository._repo
 

	
 
        parents = self.parents
 
        if not self.parents:
 
            parents = [EmptyChangeset()]
 
        for parent in parents:
 
            if isinstance(parent, EmptyChangeset):
 
                oid = None
 
            else:
 
                oid = _r[parent.raw_id].tree
 
            changes = _r.object_store.tree_changes(oid, _r[self.raw_id].tree)
 
            for (oldpath, newpath), (_, _), (_, _) in changes:
 
                if newpath and oldpath:
 
                    modified.add(newpath)
 
                elif newpath and not oldpath:
 
                    added.add(newpath)
 
                elif not newpath and oldpath:
 
                    deleted.add(oldpath)
 
        return added, modified, deleted
 

	
 
    def _get_paths_for_status(self, status):
 
        """
 
        Returns sorted list of paths for given ``status``.
 

	
 
        :param status: one of: *added*, *modified* or *deleted*
 
        """
 
        a, m, d = self._changes_cache
 
        return sorted({
 
            'added': list(a),
 
            'modified': list(m),
 
            'deleted': list(d)}[status]
 
        )
 

	
 
    @LazyProperty
 
    def added(self):
 
        """
 
        Returns list of added ``FileNode`` objects.
 
        """
 
        if not self.parents:
 
            return list(self._get_file_nodes())
 
        return AddedFileNodesGenerator([n for n in
 
                                self._get_paths_for_status('added')], self)
 

	
 
    @LazyProperty
 
    def changed(self):
 
        """
 
        Returns list of modified ``FileNode`` objects.
 
        """
 
        if not self.parents:
 
            return []
 
        return ChangedFileNodesGenerator([n for n in
 
                                self._get_paths_for_status('modified')], self)
 

	
 
    @LazyProperty
 
    def removed(self):
 
        """
 
        Returns list of removed ``FileNode`` objects.
 
        """
 
        if not self.parents:
 
            return []
 
        return RemovedFileNodesGenerator([n for n in
 
                                self._get_paths_for_status('deleted')], self)
rhodecode/templates/admin/repos/repo_edit.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
<%inherit file="/base/base.html"/>
 

	
 
<%def name="title()">
 
    ${_('Edit repository')} ${c.repo_info.repo_name} - ${c.rhodecode_name}
 
</%def>
 

	
 
<%def name="breadcrumbs_links()">
 
    ${h.link_to(_(u'Home'),h.url('/'))}
 
    &raquo;
 
    ${h.repo_link(c.rhodecode_db_repo.groups_and_repo)}
 
    &raquo;
 
    ${_('edit')}
 
</%def>
 

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

	
 
<%def name="main()">
 
<div class="box box-left">
 
    <!-- box / title -->
 
    <div class="title">
 
        ${self.breadcrumbs()}
 
    </div>
 
    ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='put')}
 
    <div class="form">
 
        <!-- fields -->
 
        <div class="fields">
 
            <div class="field">
 
                <div class="label">
 
                    <label for="repo_name">${_('Name')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('repo_name',class_="medium")}
 
                </div>
 
           </div>
 
           <div class="field">
 
               <div class="label">
 
                   <label for="clone_uri">${_('Clone uri')}:</label>
 
               </div>
 
               <div class="input">
 
                   ${h.text('clone_uri',class_="medium")}
 
                 <span class="help-block">${_('Optional http[s] url from which repository should be cloned.')}</span>
 
               </div>
 
            </div>
 
            <div class="field">
 
                <div class="label">
 
                    <label for="repo_group">${_('Repository group')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.select('repo_group','',c.repo_groups,class_="medium")}
 
                    <span class="help-block">${_('Optional select a group to put this repository into.')}</span>
 
                </div>
 
            </div>
 
            <div class="field">
 
                <div class="label">
 
                    <label for="repo_type">${_('Type')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.select('repo_type','hg',c.backends,class_="medium")}
 
                </div>
 
            </div>
 
            <div class="field">
 
                <div class="label">
 
                    <label for="repo_landing_rev">${_('Landing revision')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.select('repo_landing_rev','',c.landing_revs,class_="medium")}
 
                    <span class="help-block">${_('Default revision for files page, downloads, whoosh and readme')}</span>
 
                </div>
 
            </div>
 
            <div class="field">
 
                <div class="label label-textarea">
 
                    <label for="repo_description">${_('Description')}:</label>
 
                </div>
 
                <div class="textarea text-area editor">
 
                    ${h.textarea('repo_description')}
 
                    <span class="help-block">${_('Keep it short and to the point. Use a README file for longer descriptions.')}</span>
 
                </div>
 
            </div>
 

	
 
            <div class="field">
 
                <div class="label label-checkbox">
 
                    <label for="repo_private">${_('Private repository')}:</label>
 
                </div>
 
                <div class="checkboxes">
 
                    ${h.checkbox('repo_private',value="True")}
 
                    <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
 
                </div>
 
            </div>
 
            <div class="field">
 
                <div class="label label-checkbox">
 
                    <label for="repo_enable_statistics">${_('Enable statistics')}:</label>
 
                </div>
 
                <div class="checkboxes">
 
                    ${h.checkbox('repo_enable_statistics',value="True")}
 
                    <span class="help-block">${_('Enable statistics window on summary page.')}</span>
 
                </div>
 
            </div>
 
            <div class="field">
 
                <div class="label label-checkbox">
 
                    <label for="repo_enable_downloads">${_('Enable downloads')}:</label>
 
                </div>
 
                <div class="checkboxes">
 
                    ${h.checkbox('repo_enable_downloads',value="True")}
 
                    <span class="help-block">${_('Enable download menu on summary page.')}</span>
 
                </div>
 
            </div>
 
            <div class="field">
 
                <div class="label label-checkbox">
 
                    <label for="repo_enable_locking">${_('Enable locking')}:</label>
 
                </div>
 
                <div class="checkboxes">
 
                    ${h.checkbox('repo_enable_locking',value="True")}
 
                    <span class="help-block">${_('Enable lock-by-pulling on repository.')}</span>
 
                </div>
 
            </div>
 
            <div class="field">
 
                <div class="label">
 
                    <label for="user">${_('Owner')}:</label>
 
                </div>
 
                <div class="input input-medium ac">
 
                    <div class="perm_ac">
 
                       ${h.text('user',class_='yui-ac-input')}
 
                       <span class="help-block">${_('Change owner of this repository.')}</span>
 
                       <div id="owner_container"></div>
 
                    </div>
 
                </div>
 
             </div>
 
            %if c.visual.repository_fields:
 
              ## EXTRA FIELDS
 
              %for field in c.repo_fields:
 
                <div class="field">
 
                    <div class="label">
 
                        <label for="${field.field_key_prefixed}">${field.field_label} (${field.field_key}):</label>
 
                    </div>
 
                    <div class="input input-medium">
 
                        ${h.text(field.field_key_prefixed, field.field_value, class_='medium')}
 
                        %if field.field_desc:
 
                          <span class="help-block">${field.field_desc}</span>
 
                        %endif
 
                    </div>
 
                 </div>
 
              %endfor
 
            %endif
 
            <div class="field">
 
                <div class="label">
 
                    <label for="input">${_('Permissions')}:</label>
 
                </div>
 
                <div class="input">
 
                    <%include file="repo_edit_perms.html"/>
 
                </div>
 

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

	
 
<div class="box box-right">
 
    <div class="title">
 
        <h5>${_('Administration')}</h5>
 
    </div>
 

	
 
        <h3>${_('Statistics')}</h3>
 
        ${h.form(url('repo_stats', repo_name=c.repo_info.repo_name),method='delete')}
 
        <div class="form">
 
           <div class="fields">
 
               ${h.submit('reset_stats_%s' % c.repo_info.repo_name,_('Reset current statistics'),class_="ui-btn",onclick="return confirm('"+_('Confirm to remove current statistics')+"');")}
 
               <div class="field" style="border:none;color:#888">
 
               <ul>
 
                    <li>${_('Fetched to rev')}: ${c.stats_revision}/${c.repo_last_rev}</li>
 
                    <li>${_('Stats gathered')}: ${c.stats_percentage}%</li>
 
               </ul>
 
               </div>
 
           </div>
 
        </div>
 
        ${h.end_form()}
 

	
 
        %if c.repo_info.clone_uri:
 
        <h3>${_('Remote')}</h3>
 
        ${h.form(url('repo_pull', repo_name=c.repo_info.repo_name),method='put')}
 
        <div class="form">
 
           <div class="fields">
 
               ${h.submit('remote_pull_%s' % c.repo_info.repo_name,_('Pull changes from remote location'),class_="ui-btn",onclick="return confirm('"+_('Confirm to pull changes from remote side')+"');")}
 
               <div class="field" style="border:none">
 
               <ul>
 
                    <li><a href="${c.repo_info.clone_uri}">${c.repo_info.clone_uri}</a></li>
 
               </ul>
 
               </div>
 
           </div>
 
        </div>
 
        ${h.end_form()}
 
        %endif
 

	
 
        <h3>${_('Cache')}</h3>
 
        ${h.form(url('repo_cache', repo_name=c.repo_info.repo_name),method='delete')}
 
        <div class="form">
 
           <div class="fields">
 
               ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="ui-btn",onclick="return confirm('"+_('Confirm to invalidate repository cache')+"');")}
 
              <div class="field" style="border:none;color:#888">
 
              <ul>
 
                  <li>${_('Manually invalidate cache for this repository. On first access repository will be cached again')}
 
                  </li>
 
              </ul>
 
              </div>
 
              <div class="field" style="border:none;">
 
                ${_('List of cached values')}
 
                   <table>
 
                   <tr>
 
                    <th>${_('Prefix')}</th>
 
                    <th>${_('Key')}</th>
 
                    <th>${_('Active')}</th>
 
                    </tr>
 
                  %for cache in c.repo_info.cache_keys:
 
                      <tr>
 
                        <td>${cache.prefix or '-'}</td>
 
                        <td>${cache.cache_key}</td>
 
                        <td>${h.bool2icon(cache.cache_active)}</td>
 
                      </tr>
 
                  %endfor
 
                  </table>
 
              </div>
 
           </div>
 
        </div>
 
        ${h.end_form()}
 

	
 
        <h3>${_('Public journal')}</h3>
 
        ${h.form(url('repo_public_journal', repo_name=c.repo_info.repo_name),method='put')}
 
        <div class="form">
 
          ${h.hidden('auth_token',str(h.get_token()))}
 
          <div class="field">
 
          %if c.in_public_journal:
 
            ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Remove from public journal'),class_="ui-btn")}
 
          %else:
 
            ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Add to public journal'),class_="ui-btn")}
 
          %endif
 
          </div>
 
         <div class="field" style="border:none;color:#888">
 
         <ul>
 
              <li>${_('All actions made on this repository will be accessible to everyone in public journal')}
 
              </li>
 
         </ul>
 
         </div>
 
        </div>
 
        ${h.end_form()}
 

	
 
        <h3>${_('Locking')}</h3>
 
        ${h.form(url('repo_locking', repo_name=c.repo_info.repo_name),method='put')}
 
        <div class="form">
 
           <div class="fields">
 
              %if c.repo_info.locked[0]:
 
               ${h.submit('set_unlock' ,_('Unlock locked repo'),class_="ui-btn",onclick="return confirm('"+_('Confirm to unlock repository')+"');")}
 
               ${'Locked by %s on %s' % (h.person_by_id(c.repo_info.locked[0]),h.fmt_date(h.time_to_datetime(c.repo_info.locked[1])))}
 
              %else:
 
                ${h.submit('set_lock',_('lock repo'),class_="ui-btn",onclick="return confirm('"+_('Confirm to lock repository')+"');")}
 
                ${_('Repository is not locked')}
 
              %endif
 
           </div>
 
           <div class="field" style="border:none;color:#888">
 
           <ul>
 
                <li>${_('Force locking on repository. Works only when anonymous access is disabled')}
 
                </li>
 
           </ul>
 
           </div>
 
        </div>
 
        ${h.end_form()}
 

	
 
        <h3>${_('Set as fork of')}</h3>
 
        ${h.form(url('repo_as_fork', repo_name=c.repo_info.repo_name),method='put')}
 
        <div class="form">
 
           <div class="fields">
 
               ${h.select('id_fork_of','',c.repos_list,class_="medium")}
 
               ${h.submit('set_as_fork_%s' % c.repo_info.repo_name,_('set'),class_="ui-btn",)}
 
           </div>
 
               <div class="field" style="border:none;color:#888">
 
               <ul>
 
                    <li>${_('''Manually set this repository as a fork of another from the list''')}</li>
 
               </ul>
 
               </div>
 
        </div>
 
        ${h.end_form()}
 

	
 
        <h3>${_('Delete')}</h3>
 
        ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')}
 
        <div class="form">
 
           <div class="fields">
 
               ${h.submit('remove_%s' % c.repo_info.repo_name,_('Remove this repository'),class_="ui-btn red",onclick="return confirm('"+_('Confirm to delete this repository')+"');")}
 
              %if c.repo_info.forks.count():
 
                    - ${ungettext('this repository has %s fork', 'this repository has %s forks', c.repo_info.forks.count()) % c.repo_info.forks.count()} 
 
                    - ${ungettext('this repository has %s fork', 'this repository has %s forks', c.repo_info.forks.count()) % c.repo_info.forks.count()}
 
                    <input type="radio" name="forks" value="detach_forks" checked="checked"/> <label for="forks">${_('Detach forks')}</label>
 
                    <input type="radio" name="forks" value="delete_forks" /> <label for="forks">${_('Delete forks')}</label>
 
              %endif               
 
              %endif
 
           </div>
 
           <div class="field" style="border:none;color:#888">
 
           <ul>
 
                <li>${_('This repository will be renamed in a special way in order to be unaccesible for RhodeCode and VCS systems. If you need to fully delete it from file system please do it manually')}</li>
 
           </ul>
 
           </div>
 
        </div>
 
        ${h.end_form()}
 
</div>
 

	
 
##TODO: this should be controlled by the VISUAL setting
 
%if c.visual.repository_fields:
 
<div class="box box-left" style="clear:left">
 
    <!-- box / title -->
 
    <div class="title">
 
        <h5>${_('Extra fields')}</h5>
 
    </div>
 

	
 
    <div class="emails_wrap">
 
      <table class="noborder">
 
      %for field in c.repo_fields:
 
        <tr>
 
            <td>${field.field_label} (${field.field_key})</td>
 
            <td>${field.field_type}</td>
 
            <td>
 
              ${h.form(url('delete_repo_fields', repo_name=c.repo_info.repo_name, field_id=field.repo_field_id),method='delete')}
 
                  ${h.submit('remove_%s' % field.repo_field_id, _('delete'), id="remove_field_%s" % field.repo_field_id,
 
                  class_="delete_icon action_button", onclick="return confirm('"+_('Confirm to delete this field: %s') % field.field_key+"');")}
 
              ${h.end_form()}
 
            </td>
 
        </tr>
 
      %endfor
 
      </table>
 
    </div>
 

	
 
    ${h.form(url('create_repo_fields', repo_name=c.repo_info.repo_name),method='put')}
 
    <div class="form">
 
        <!-- fields -->
 
        <div class="fields">
 
             <div class="field">
 
                <div class="label">
 
                    <label for="new_field_key">${_('New field key')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('new_field_key', class_='small')}
 
                </div>
 
             </div>
 
             <div class="field">
 
                <div class="label">
 
                    <label for="new_field_label">${_('New field label')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('new_field_label', class_='small', placeholder=_('Enter short label'))}
 
                </div>
 
             </div>
 

	
 
             <div class="field">
 
                <div class="label">
 
                    <label for="new_field_desc">${_('New field description')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('new_field_desc', class_='small', placeholder=_('Enter description of a field'))}
 
                </div>
 
             </div>
 

	
 
            <div class="buttons">
 
              ${h.submit('save',_('Add'),class_="ui-btn large")}
 
              ${h.reset('reset',_('Reset'),class_="ui-btn large")}
 
            </div>
 
        </div>
 
    </div>
 
    ${h.end_form()}
 
</div>
 
%endif
 
</%def>
rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html
Show inline comments
 

	
 
<div class="pullrequests_section_head">${_('Opened by me')}</div>
 
<ul>
 
    %if c.my_pull_requests:
 
      %for pull_request in c.my_pull_requests:
 
      <li>
 
        <div style="height: 12px">
 
          <div style="float:left">
 
          %if pull_request.is_closed():
 
              <img src="${h.url('/images/icons/lock_go.png')}" title="${_('Closed')}"/>
 
          %endif
 
          <img src="${h.url('/images/icons/flag_status_%s.png' % str(pull_request.last_review_status))}" />          
 
          <img src="${h.url('/images/icons/flag_status_%s.png' % str(pull_request.last_review_status))}" />
 
          <a href="${h.url('pullrequest_show',repo_name=pull_request.other_repo.repo_name,pull_request_id=pull_request.pull_request_id)}">
 
          ${_('Pull request #%s opened on %s') % (pull_request.pull_request_id, h.fmt_date(pull_request.created_on))}
 
          </a>
 
          </div>
 
          <div style="float:left;margin-top: -5px">
 
            ${h.form(url('pullrequest_delete', repo_name=pull_request.other_repo.repo_name, pull_request_id=pull_request.pull_request_id),method='delete')}
 
              ${h.submit('remove_%s' % pull_request.pull_request_id,'',class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this pull request')+"');")}
 
            ${h.end_form()}
 
          </div>
 
        </div>
 
      </li>
 
      %endfor
 
   %else:
 
    <li><span class="empty_data">${_('Nothing here yet')}</span></li>
 
   %endif
 
</ul>
 

	
 
<div class="pullrequests_section_head" style="clear:both">${_('I participate in')}</div>
 
<ul>
 
    %if c.participate_in_pull_requests:
 
      %for pull_request in c.participate_in_pull_requests:
 
      <li>
 
        <div style="height: 12px">
 
        %if pull_request.is_closed():
 
            <img src="${h.url('/images/icons/lock_go.png')}" title="${_('Closed')}"/>
 
        %endif
 
        <img src="${h.url('/images/icons/flag_status_%s.png' % str(pull_request.last_review_status))}" />          
 
        <img src="${h.url('/images/icons/flag_status_%s.png' % str(pull_request.last_review_status))}" />
 
        <a href="${h.url('pullrequest_show',repo_name=pull_request.other_repo.repo_name,pull_request_id=pull_request.pull_request_id)}">
 
        ${_('Pull request #%s opened by %s on %s') % (pull_request.pull_request_id, pull_request.author.full_name, h.fmt_date(pull_request.created_on))}
 
        </a>
 
      </div>
 
      </li>
 
      %endfor
 
    %else:
 
     <li><span class="empty_data">${_('Nothing here yet')}</span></li>
 
    %endif
 
</ul>
rhodecode/templates/base/base.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
<%inherit file="root.html"/>
 

	
 
<!-- HEADER -->
 
<div id="header-dd"></div>
 
<div id="header">
 
    <div id="header-inner" class="title">
 
        <div id="logo">
 
            <h1><a href="${h.url('home')}">${c.rhodecode_name}</a></h1>
 
        </div>
 
        <!-- MENU -->
 
        ${self.page_nav()}
 
        <!-- END MENU -->
 
        ${self.body()}
 
    </div>
 
</div>
 
<!-- END HEADER -->
 

	
 
<!-- CONTENT -->
 
<div id="content">
 
    <div class="flash_msg">
 
        <% messages = h.flash.pop_messages() %>
 
        % if messages:
 
        <ul id="flash-messages">
 
            % for message in messages:
 
            <li class="${message.category}_msg">${message}</li>
 
            % endfor
 
        </ul>
 
        % endif
 
    </div>
 
    <div id="main">
 
        ${next.main()}
 
    </div>
 
</div>
 
<!-- END CONTENT -->
 

	
 
<!-- FOOTER -->
 
<div id="footer">
 
   <div id="footer-inner" class="title">
 
       <div>
 
           <p class="footer-link">
 
                <a href="${h.url('bugtracker')}">${_('Submit a bug')}</a>
 
           </p>
 
           <p class="footer-link-right">
 
               <a href="${h.url('rhodecode_official')}">RhodeCode${'-%s' % c.rhodecode_instanceid if c.rhodecode_instanceid else ''}</a>
 
               ${c.rhodecode_version} &copy; 2010-${h.datetime.today().year} by Marcin Kuzminski
 
           </p>
 
       </div>
 
   </div>
 
</div>
 
<!-- END FOOTER -->
 

	
 
### MAKO DEFS ###
 
<%def name="page_nav()">
 
    ${self.menu()}
 
</%def>
 

	
 
<%def name="breadcrumbs()">
 
    <div class="breadcrumbs">
 
    ${self.breadcrumbs_links()}
 
    </div>
 
</%def>
 

	
 
<%def name="usermenu()">
 
    ## USER MENU
 
    <li>
 
      <a class="menu_link" id="quick_login_link">
 
          <span class="icon" style="padding:5px 5px 0px 5px">
 
             <img src="${h.gravatar_url(c.rhodecode_user.email,20)}" alt="avatar">
 
          </span>
 
          %if c.rhodecode_user.username != 'default':
 
            <span class="menu_link_user">${c.rhodecode_user.username}</span>
 
            %if c.unread_notifications != 0:
 
              <span class="menu_link_notifications">${c.unread_notifications}</span>
 
            %endif
 
          %else:
 
              <span>${_('Not logged in')}</span>
 
          %endif
 
      </a>
 

	
 
  <div class="user-menu">
 
      <div id="quick_login">
 
        %if c.rhodecode_user.username == 'default':
 
            <h4>${_('Login to your account')}</h4>
 
            ${h.form(h.url('login_home',came_from=h.url.current()))}
 
            <div class="form">
 
                <div class="fields">
 
                    <div class="field">
 
                        <div class="label">
 
                            <label for="username">${_('Username')}:</label>
 
                        </div>
 
                        <div class="input">
 
                            ${h.text('username',class_='focus',size=40)}
 
                        </div>
 

	
 
                    </div>
 
                    <div class="field">
 
                        <div class="label">
 
                            <label for="password">${_('Password')}:</label>
 
                        </div>
 
                        <div class="input">
 
                            ${h.password('password',class_='focus',size=40)}
 
                        </div>
 

	
 
                    </div>
 
                    <div class="buttons">
 
                        <div class="password_forgoten">${h.link_to(_('Forgot password ?'),h.url('reset_password'))}</div>
 
                        <div class="register">
 
                        %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
 
                         ${h.link_to(_("Don't have an account ?"),h.url('register'))}
 
                        %endif
 
                        </div>
 
                        <div class="submit">
 
                            ${h.submit('sign_in',_('Log In'),class_="ui-btn xsmall")}
 
                        </div>
 
                    </div>
 
                </div>
 
            </div>
 
            ${h.end_form()}
 
        %else:
 
            <div class="links_left">
 
                <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
 
                <div class="email">${c.rhodecode_user.email}</div>
 
                <div class="big_gravatar"><img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,48)}" /></div>
 
                <div class="notifications"><a href="${h.url('notifications')}">${_('Notifications')}</a></div>
 
                <div class="unread"><a href="${h.url('notifications')}">${_('Unread')}: ${c.unread_notifications}</a></div>
 
            </div>
 
            <div class="links_right">
 
            <ol class="links">
 
              <li>${h.link_to(_(u'Home'),h.url('home'))}</li>
 
              <li>${h.link_to(_(u'Journal'),h.url('journal'))}</li>
 
              <li>${h.link_to(_(u'My account'),h.url('admin_settings_my_account'))}</li>
 
              <li class="logout">${h.link_to(_(u'Log Out'),h.url('logout_home'))}</li>
 
            </ol>
 
            </div>
 
        %endif
 
      </div>
 
  </div>
 

	
 
    </li>
 
</%def>
 

	
 
<%def name="menu(current=None)">
 
        <%
 
        def is_current(selected):
 
            if selected == current:
 
                return h.literal('class="current"')
 
        %>
 
        <ul id="quick">
 
          <!-- repo switcher -->
 
          <li ${is_current('home')}>
 
              <a class="menu_link" id="repo_switcher" title="${_('Switch repository')}" href="${h.url('home')}">
 
              <span class="icon">
 
                  <img src="${h.url('/images/icons/database.png')}" alt="${_('Products')}" />
 
              </span>
 
              <span>${_('Repositories')}</span>
 
              </a>
 
              <ul id="repo_switcher_list" class="repo_switcher">
 
                  <li>
 
                      <a href="#">${_('loading...')}</a>
 
                  </li>
 
              </ul>
 
          </li>
 
        ## we render this menu only not for those pages
 
        %if current not in ['home','admin', 'search', 'journal']:
 
            ##REGULAR MENU
 
            <li ${is_current('summary')}>
 
               <a class="menu_link" title="${_('Summary page')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
 
               <span class="icon">
 
                   <img src="${h.url('/images/icons/clipboard_16.png')}" alt="${_('Summary')}" />
 
               </span>
 
               <span>${_('Summary')}</span>
 
               </a>
 
            </li>
 
            <li ${is_current('changelog')}>
 
               <a class="menu_link" title="${_('Changeset list')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
 
               <span class="icon">
 
                   <img src="${h.url('/images/icons/time.png')}" alt="${_('Changelog')}" />
 
               </span>
 
               <span>${_('Changelog')}</span>
 
               </a>
 
            </li>
 
            <li ${is_current('switch_to')}>
 
               <a class="menu_link" id="branch_tag_switcher" title="${_('Switch to')}" href="#">
 
               <span class="icon">
 
                   <img src="${h.url('/images/icons/arrow_switch.png')}" alt="${_('Switch to')}" />
 
               </span>
 
               <span>${_('Switch to')}</span>
 
               </a>
 
                <ul id="switch_to_list" class="switch_to">
 
                    <li><a href="#">${_('loading...')}</a></li>
 
                </ul>
 
            </li>
 
            <li ${is_current('files')}>
 
               <a class="menu_link" title="${_('Show repository content')}" href="${h.url('files_home',repo_name=c.repo_name)}">
 
               <span class="icon">
 
                   <img src="${h.url('/images/icons/file.png')}" alt="${_('Files')}" />
 
               </span>
 
               <span>${_('Files')}</span>
 
               </a>
 
            </li>
 
            <li ${is_current('options')}>
 
               <a class="menu_link" title="${_('Options')}" href="#">
 
               <span class="icon">
 
                   <img src="${h.url('/images/icons/table_gear.png')}" alt="${_('Admin')}" />
 
               </span>
 
               <span>${_('Options')}</span>
 
               </a>
 
               <ul>
 
               %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
 
                 %if h.HasPermissionAll('hg.admin')('access settings on repository'):
 
                     <li>${h.link_to(_('repository settings'),h.url('edit_repo',repo_name=c.repo_name),class_='settings')}</li>
 
                 %else:
 
                     <li>${h.link_to(_('repository settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
 
                 %endif
 
               %endif
 

	
 
                <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
 
                %if h.is_hg(c.rhodecode_repo):
 
                 <li>${h.link_to(_('open new pull request'),h.url('pullrequest_home',repo_name=c.repo_name),class_='pull_request')}</li>
 
                %endif
 
                %if c.rhodecode_db_repo.fork:
 
                 <li>${h.link_to(_('compare fork'),h.url('compare_url',repo_name=c.rhodecode_db_repo.fork.repo_name,org_ref_type='branch',org_ref='default',other_repo=c.repo_name,other_ref_type='branch',other_ref=request.GET.get('branch') or 'default'),class_='compare_request')}</li>
 
                %endif
 
                <li>${h.link_to(_('lightweight changelog'),h.url('shortlog_home',repo_name=c.repo_name),class_='shortlog')}</li>
 
                <li>${h.link_to(_('search'),h.url('search_repo',repo_name=c.repo_name),class_='search')}</li>
 

	
 
                %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking:
 
                  %if c.rhodecode_db_repo.locked[0]:
 
                    <li>${h.link_to(_('unlock'), h.url('toggle_locking',repo_name=c.repo_name),class_='locking_del')}</li>
 
                  %else:
 
                    <li>${h.link_to(_('lock'), h.url('toggle_locking',repo_name=c.repo_name),class_='locking_add')}</li>
 
                  %endif
 
                %endif
 

	
 
                % if h.HasPermissionAll('hg.admin')('access admin main page'):
 
                   <li>
 
                     ${h.link_to(_('admin'),h.url('admin_home'),class_='admin')}
 
                      <%def name="admin_menu()">
 
                      <ul>
 
                          <li>${h.link_to(_('admin journal'),h.url('admin_home'),class_='journal')}</li>
 
                          <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
 
                          <li>${h.link_to(_('repositories groups'),h.url('repos_groups'),class_='repos_groups')}</li>
 
                          <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
 
                          <li>${h.link_to(_('users groups'),h.url('users_groups'),class_='groups')}</li>
 
                          <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
 
                          <li>${h.link_to(_('ldap'),h.url('ldap_home'),class_='ldap')}</li>
 
                          <li>${h.link_to(_('defaults'),h.url('defaults'),class_='defaults')}</li>
 
                          <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
 
                      </ul>
 
                      </%def>
 
                      ## ADMIN MENU
 
                      ${admin_menu()}
 
                   </li>
 
                ## if you're a admin of any groups, show admin menu for it
 
                % elif c.rhodecode_user.groups_admin:
 
                   <li>
 
                     ${h.link_to(_('admin'),h.url('admin_home'),class_='admin')}
 
                      <%def name="admin_menu_simple()">
 
                      <ul>
 
                          <li>${h.link_to(_('repositories groups'),h.url('repos_groups'),class_='repos_groups')}</li>
 
                      </ul>
 
                      </%def>
 
                      ## ADMIN MENU
 
                      ${admin_menu_simple()}
 
                   </li>
 
                % endif
 
               </ul>
 
            </li>
 
            <li>
 
                <a class="menu_link" title="${_('Followers')}" href="${h.url('repo_followers_home',repo_name=c.repo_name)}">
 
                <span class="icon_short">
 
                    <img src="${h.url('/images/icons/heart.png')}" alt="${_('Followers')}" />
 
                </span>
 
                <span id="current_followers_count" class="short">${c.repository_followers}</span>
 
                </a>
 
            </li>
 
            <li>
 
                <a class="menu_link" title="${_('Forks')}" href="${h.url('repo_forks_home',repo_name=c.repo_name)}">
 
                <span class="icon_short">
 
                    <img src="${h.url('/images/icons/arrow_divide.png')}" alt="${_('Forks')}" />
 
                </span>
 
                <span class="short">${c.repository_forks}</span>
 
                </a>
 
            </li>
 
            <li>
 
                <a class="menu_link" title="${_('Pull requests')}" href="${h.url('pullrequest_show_all',repo_name=c.repo_name)}">
 
                <span class="icon_short">
 
                    <img src="${h.url('/images/icons/arrow_join.png')}" alt="${_('Pull requests')}" />
 
                </span>
 
                <span class="short">${c.repository_pull_requests}</span>
 
                </a>
 
            </li>
 
            ${usermenu()}
 
            <script type="text/javascript">
 
                YUE.on('branch_tag_switcher','mouseover',function(){
 
                   var loaded = YUD.hasClass('branch_tag_switcher','loaded');
 
                   if(!loaded){
 
                       YUD.addClass('branch_tag_switcher','loaded');
 
                       ypjax("${h.url('branch_tag_switcher',repo_name=c.repo_name)}",'switch_to_list',
 
                           function(o){},
 
                           function(o){YUD.removeClass('branch_tag_switcher','loaded');}
 
                           ,null);
 
                   }
 
                   return false;
 
                });
 
            </script>
 
        %else:
 
            ##ROOT MENU
 
            %if c.rhodecode_user.username != 'default':
 
             <li ${is_current('journal')}>
 
                <a class="menu_link" title="${_('Show recent activity')}"  href="${h.url('journal')}">
 
                <span class="icon">
 
                    <img src="${h.url('/images/icons/book.png')}" alt="${_('Journal')}" />
 
                </span>
 
                <span>${_('Journal')}</span>
 
                </a>
 
             </li>
 
            %else:
 
             <li ${is_current('journal')}>
 
                <a class="menu_link" title="${_('Public journal')}"  href="${h.url('public_journal')}">
 
                <span class="icon">
 
                    <img src="${h.url('/images/icons/book.png')}" alt="${_('Public journal')}" />
 
                </span>
 
                <span>${_('Public journal')}</span>
 
                </a>
 
             </li>
 
            %endif
 
            <li ${is_current('search')}>
 
                <a class="menu_link" title="${_('Search in repositories')}"  href="${h.url('search')}">
 
                <span class="icon">
 
                    <img src="${h.url('/images/icons/search_16.png')}" alt="${_('Search')}" />
 
                </span>
 
                <span>${_('Search')}</span>
 
                </a>
 
            </li>
 
            % if h.HasPermissionAll('hg.admin')('access admin main page'):
 
            <li ${is_current('admin')}>
 
               <a class="menu_link" title="${_('Admin')}" href="${h.url('admin_home')}">
 
               <span class="icon">
 
                   <img src="${h.url('/images/icons/cog_edit.png')}" alt="${_('Admin')}" />
 
               </span>
 
               <span>${_('Admin')}</span>
 
               </a>
 
                ${admin_menu()}
 
            </li>
 
            % elif c.rhodecode_user.groups_admin:
 
            <li ${is_current('admin')}>
 
               <a class="menu_link" title="${_('Admin')}" href="${h.url('admin_home')}">
 
               <span class="icon">
 
                   <img src="${h.url('/images/icons/cog_edit.png')}" alt="${_('Admin')}" />
 
               </span>
 
               <span>${_('Admin')}</span>
 
               </a>
 
                ${admin_menu_simple()}
 
            </li>                
 
            </li>
 
            % endif
 
            ${usermenu()}
 
        %endif
 
<script type="text/javascript">
 
    YUE.on('repo_switcher','mouseover',function(){
 
      var target = 'q_filter_rs';
 
      var qfilter_activate = function(){
 
          var nodes = YUQ('ul#repo_switcher_list li a.repo_name');
 
          var func = function(node){
 
              return node.parentNode;
 
          }
 
          q_filter(target,nodes,func);
 
      }
 

	
 
      var loaded = YUD.hasClass('repo_switcher','loaded');
 
      if(!loaded){
 
         YUD.addClass('repo_switcher','loaded');
 
         ypjax("${h.url('repo_switcher')}",'repo_switcher_list',
 
             function(o){qfilter_activate();YUD.get(target).focus()},
 
             function(o){YUD.removeClass('repo_switcher','loaded');}
 
             ,null);
 
      }else{
 
         YUD.get(target).focus();
 
      }
 
      return false;
 
     });
 

	
 
     YUE.on('header-dd', 'click',function(e){
 
         YUD.addClass('header-inner', 'hover');
 
         YUD.addClass('content', 'hover');
 
     });
 

	
 
</script>
 
</%def>
rhodecode/templates/base/root.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
<!DOCTYPE html>
 
<html xmlns="http://www.w3.org/1999/xhtml">
 
    <head>
 
        <title>${self.title()}</title>
 
        <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
 
        <meta name="robots" content="index, nofollow"/>
 
        <link rel="icon" href="${h.url('/images/icons/database_gear.png')}" type="image/png" />
 

	
 
        ## CSS ###
 
        <%def name="css()">
 
            <link rel="stylesheet" type="text/css" href="${h.url('/css/style.css', ver=c.rhodecode_version)}" media="screen"/>
 
            <link rel="stylesheet" type="text/css" href="${h.url('/css/pygments.css', ver=c.rhodecode_version)}"/>
 
            ## EXTRA FOR CSS
 
            ${self.css_extra()}
 
        </%def>
 
        <%def name="css_extra()">
 
        </%def>
 

	
 
        ${self.css()}
 

	
 
        %if c.ga_code:
 
        <!-- Analytics -->
 
        <script type="text/javascript">
 
            var _gaq = _gaq || [];
 
            _gaq.push(['_setAccount', '${c.ga_code}']);
 
            _gaq.push(['_trackPageview']);
 

	
 
            (function() {
 
                var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
 
                ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
 
                var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
 
                })();
 
        </script>
 
        %endif
 

	
 
        ## JAVASCRIPT ##
 
        <%def name="js()">
 
            <script type="text/javascript">
 
            //JS translations map
 
            var TRANSLATION_MAP = {
 
                'add another comment':'${_("add another comment")}',
 
                'Stop following this repository':"${_('Stop following this repository')}",
 
                'Start following this repository':"${_('Start following this repository')}",
 
                'Group':"${_('Group')}",
 
                'members':"${_('members')}",
 
                'loading...':"${_('loading...')}",
 
                'search truncated': "${_('search truncated')}",
 
                'no matching files': "${_('no matching files')}",
 
                'Open new pull request': "${_('Open new pull request')}",
 
                'Open new pull request for selected changesets':  "${_('Open new pull request for selected changesets')}",
 
                'Show selected changes __S -> __E': "${_('Show selected changes __S -> __E')}",
 
                'Selection link': "${_('Selection link')}",
 
            };
 
            var _TM = TRANSLATION_MAP;
 

	
 
            var TOGGLE_FOLLOW_URL  = "${h.url('toggle_following')}";
 

	
 
            </script>
 
            <script type="text/javascript" src="${h.url('/js/yui.2.9.js', ver=c.rhodecode_version)}"></script>
 
            <!--[if lt IE 9]>
 
               <script language="javascript" type="text/javascript" src="${h.url('/js/excanvas.min.js')}"></script>
 
            <![endif]-->
 
            <script type="text/javascript" src="${h.url('/js/yui.flot.js', ver=c.rhodecode_version)}"></script>
 
            <script type="text/javascript" src="${h.url('/js/native.history.js', ver=c.rhodecode_version)}"></script>
 
            <script type="text/javascript" src="${h.url('/js/pyroutes_map.js', ver=c.rhodecode_version)}"></script>
 
            <script type="text/javascript" src="${h.url('/js/rhodecode.js', ver=c.rhodecode_version)}"></script>
 
           ## EXTRA FOR JS
 
           ${self.js_extra()}
 
            <script type="text/javascript">
 
            (function(window,undefined){
 
                // Prepare
 
                var History = window.History; // Note: We are using a capital H instead of a lower h
 
                if ( !History.enabled ) {
 
                     // History.js is disabled for this browser.
 
                     // This is because we can optionally choose to support HTML4 browsers or not.
 
                    return false;
 
                }
 
            })(window);
 

	
 
            YUE.onDOMReady(function(){
 
              tooltip_activate();
 
              show_more_event();
 
              show_changeset_tooltip();
 
              // routes registration
 
              pyroutes.register('toggle_following', "${h.url('toggle_following')}");
 
              pyroutes.register('changeset_info', "${h.url('changeset_info', repo_name='%(repo_name)s', revision='%(revision)s')}", ['repo_name', 'revision']);
 
              pyroutes.register('repo_size', "${h.url('repo_size', repo_name='%(repo_name)s')}", ['repo_name']);              
 
              pyroutes.register('repo_size', "${h.url('repo_size', repo_name='%(repo_name)s')}", ['repo_name']);
 
           })
 
            </script>
 
        </%def>
 
        <%def name="js_extra()"></%def>
 
        ${self.js()}
 
        <%def name="head_extra()"></%def>
 
        ${self.head_extra()}
 
    </head>
 
    <body id="body">
 
     ## IE hacks
 
      <!--[if IE 7]>
 
      <script>YUD.addClass(document.body,'ie7')</script>
 
      <![endif]-->
 
      <!--[if IE 8]>
 
      <script>YUD.addClass(document.body,'ie8')</script>
 
      <![endif]-->
 
      <!--[if IE 9]>
 
      <script>YUD.addClass(document.body,'ie9')</script>
 
      <![endif]-->
 

	
 
      ${next.body()}
 
    </body>
 
</html>
rhodecode/templates/index_base.html
Show inline comments
 
<%page args="parent" />
 
    <div class="box">
 
        <!-- box / title -->
 
        <div class="title">
 
            <h5>
 
            <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/> ${parent.breadcrumbs()} <span id="repo_count">0</span> ${_('repositories')}
 
            </h5>
 
            %if c.rhodecode_user.username != 'default':
 
              <ul class="links">
 
                %if h.HasPermissionAny('hg.admin','hg.create.repository')() or h.HasReposGroupPermissionAny('group.write', 'group.admin')(c.group.group_name if c.group else None):
 
                  <li>
 
                  %if c.group:
 
                        <span>${h.link_to(_('Add repository'),h.url('admin_settings_create_repository',parent_group=c.group.group_id))}</span>
 
                        %if h.HasPermissionAny('hg.admin')() or h.HasReposGroupPermissionAny('group.admin')(c.group.group_name):
 
                         <span>${h.link_to(_(u'Add group'),h.url('new_repos_group', parent_group=c.group.group_id))}</span>
 
                        %endif                        
 
                        %endif
 
                  %else:
 
                    <span>${h.link_to(_('Add repository'),h.url('admin_settings_create_repository'))}</span>
 
                    %if h.HasPermissionAny('hg.admin')():
 
                     <span>${h.link_to(_(u'Add group'),h.url('new_repos_group'))}</span>
 
                    %endif
 
                  %endif
 
                  </li>
 
                %endif
 
                %if c.group and h.HasReposGroupPermissionAny('group.admin')(c.group.group_name):
 
                <li>
 
                    <span>${h.link_to(_('Edit group'),h.url('edit_repos_group',group_name=c.group.group_name), title=_('You have admin right to this group, and can edit it'))}</span>
 
                </li>
 
                %endif
 
              </ul>
 
            %endif
 
        </div>
 
        <!-- end box / title -->
 
        <div class="table">
 
           % if c.groups:
 
            <div id='groups_list_wrap' class="yui-skin-sam">
 
              <table id="groups_list">
 
                  <thead>
 
                      <tr>
 
                          <th class="left"><a href="#">${_('Group name')}</a></th>
 
                          <th class="left"><a href="#">${_('Description')}</a></th>
 
                          ##<th class="left"><a href="#">${_('Number of repositories')}</a></th>
 
                      </tr>
 
                  </thead>
 

	
 
                  ## REPO GROUPS
 
                  % for gr in c.groups:
 
                    <tr>
 
                        <td>
 
                            <div style="white-space: nowrap">
 
                            <img class="icon" alt="${_('Repositories group')}" src="${h.url('/images/icons/database_link.png')}"/>
 
                            ${h.link_to(gr.name,url('repos_group_home',group_name=gr.group_name))}
 
                            </div>
 
                        </td>
 
                        %if c.visual.stylify_metatags:
 
                            <td>${h.urlify_text(h.desc_stylize(gr.group_description))}</td>
 
                        %else:
 
                            <td>${gr.group_description}</td>
 
                        %endif
 
                        ## this is commented out since for multi nested repos can be HEAVY!
 
                        ## in number of executed queries during traversing uncomment at will
 
                        ##<td><b>${gr.repositories_recursive_count}</b></td>
 
                    </tr>
 
                  % endfor
 
              </table>
 
            </div>
 
            <div id="group-user-paginator" style="padding: 0px 0px 0px 0px"></div>
 
            <div style="height: 20px"></div>
 
            % endif
 
            <div id="welcome" style="display:none;text-align:center">
 
                <h1><a href="${h.url('home')}">${c.rhodecode_name} ${c.rhodecode_version}</a></h1>
 
            </div>
 
             <%cnt=0%>
 
             <%namespace name="dt" file="/data_table/_dt_elements.html"/>
 
            % if c.visual.lightweight_dashboard is False:
 
              ## old full detailed version
 
            <div id='repos_list_wrap' class="yui-skin-sam">
 
            <table id="repos_list">
 
            <thead>
 
                <tr>
 
                    <th class="left"></th>
 
                    <th class="left">${_('Name')}</th>
 
                    <th class="left">${_('Description')}</th>
 
                    <th class="left">${_('Last change')}</th>
 
                    <th class="left">${_('Tip')}</th>
 
                    <th class="left">${_('Owner')}</th>
 
                    <th class="left">${_('Atom')}</th>
 
                </tr>
 
            </thead>
 
            <tbody>
 
            %for cnt,repo in enumerate(c.repos_list):
 
                <tr class="parity${(cnt+1)%2}">
 
                    ##QUICK MENU
 
                    <td class="quick_repo_menu">
 
                      ${dt.quick_menu(repo['name'])}
 
                    </td>
 
                    ##REPO NAME AND ICONS
 
                    <td class="reponame">
 
                      ${dt.repo_name(repo['name'],repo['dbrepo']['repo_type'],repo['dbrepo']['private'],h.AttributeDict(repo['dbrepo_fork']),pageargs.get('short_repo_names'))}
 
                    </td>
 
                    ##DESCRIPTION
 
                    <td><span class="tooltip" title="${h.tooltip(repo['description'])}">
 
                       %if c.visual.stylify_metatags:
 
                       ${h.urlify_text(h.desc_stylize(h.truncate(repo['description'],60)))}</span>
 
                       %else:
 
                       ${h.truncate(repo['description'],60)}</span>
 
                       %endif
 
                    </td>
 
                    ##LAST CHANGE DATE
 
                    <td>
 
                      ${dt.last_change(repo['last_change'])}
 
                    </td>
 
                    ##LAST REVISION
 
                    <td>
 
                        ${dt.revision(repo['name'],repo['rev'],repo['tip'],repo['author'],repo['last_msg'])}
 
                    </td>
 
                    ##
 
                    <td title="${repo['contact']}">${h.person(repo['contact'])}</td>
 
                    <td>
 
                      ${dt.atom(repo['name'])}
 
                    </td>
 
                </tr>
 
            %endfor
 
            </tbody>
 
            </table>
 
            </div>
 
            % else:
 
              ## lightweight version
 
                <div class="yui-skin-sam" id="repos_list_wrap"></div>
 
                <div id="user-paginator" style="padding: 0px 0px 0px 0px"></div>
 
            % endif
 
        </div>
 
    </div>
 
    % if c.visual.lightweight_dashboard is False:
 
    <script>
 
      YUD.get('repo_count').innerHTML = ${cnt+1 if cnt else 0};
 

	
 
      // groups table sorting
 
      var myColumnDefs = [
 
          {key:"name",label:"${_('Group name')}",sortable:true,
 
              sortOptions: { sortFunction: groupNameSort }},
 
          {key:"desc",label:"${_('Description')}",sortable:true},
 
      ];
 

	
 
      var myDataSource = new YAHOO.util.DataSource(YUD.get("groups_list"));
 

	
 
      myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
 
      myDataSource.responseSchema = {
 
          fields: [
 
              {key:"name"},
 
              {key:"desc"},
 
          ]
 
      };
 

	
 
      var myDataTable = new YAHOO.widget.DataTable("groups_list_wrap", myColumnDefs, myDataSource,{
 
          sortedBy:{key:"name",dir:"asc"},
 
          paginator: new YAHOO.widget.Paginator({
 
              rowsPerPage: 50,
 
              alwaysVisible: false,
 
              template : "{PreviousPageLink} {FirstPageLink} {PageLinks} {LastPageLink} {NextPageLink}",
 
              pageLinks: 5,
 
              containerClass: 'pagination-wh',
 
              currentPageClass: 'pager_curpage',
 
              pageLinkClass: 'pager_link',
 
              nextPageLinkLabel: '&gt;',
 
              previousPageLinkLabel: '&lt;',
 
              firstPageLinkLabel: '&lt;&lt;',
 
              lastPageLinkLabel: '&gt;&gt;',
 
              containers:['group-user-paginator']
 
          }),
 
          MSG_SORTASC:"${_('Click to sort ascending')}",
 
          MSG_SORTDESC:"${_('Click to sort descending')}"
 
      });
 

	
 
      // 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:"desc",label:"${_('Description')}",sortable:true},
 
          {key:"last_change",label:"${_('Last Change')}",sortable:true,
 
              sortOptions: { sortFunction: ageSort }},
 
          {key:"tip",label:"${_('Tip')}",sortable:true,
 
              sortOptions: { sortFunction: revisionSort }},
 
          {key:"owner",label:"${_('Owner')}",sortable:true},
 
          {key:"atom",label:"",sortable:false},
 
      ];
 

	
 
      var myDataSource = new YAHOO.util.DataSource(YUD.get("repos_list"));
 

	
 
      myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
 

	
 
      myDataSource.responseSchema = {
 
          fields: [
 
              {key:"menu"},
 
              //{key:"raw_name"},
 
              {key:"name"},
 
              {key:"desc"},
 
              {key:"last_change"},
 
              {key:"tip"},
 
              {key:"owner"},
 
              {key:"atom"},
 
          ]
 
      };
 

	
 
      var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,
 
              {
 
               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...')}",
 
              }
 
      );
 
      myDataTable.subscribe('postRenderEvent',function(oArgs) {
 
          tooltip_activate();
 
          quick_repo_menu();
 
          var func = function(node){
 
              return node.parentNode.parentNode.parentNode.parentNode;
 
          }
 
          q_filter('q_filter',YUQ('div.table tr td a.repo_name'),func);
 
      });
 

	
 
    </script>
 
    % else:
 
      <script>
 
        var data = ${c.data|n};
 
        var myDataSource = new YAHOO.util.DataSource(data);
 
        myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
 

	
 
        myDataSource.responseSchema = {
 
            resultsList: "records",
 
            fields: [
 
               {key:"menu"},
 
               {key:"raw_name"},
 
               {key:"name"},
 
               {key:"desc"},
 
               {key:"last_change"},
 
               {key:"last_changeset"},
 
               {key:"owner"},
 
               {key:"atom"},
 
            ]
 
         };
 
        myDataSource.doBeforeCallback = function(req,raw,res,cb) {
 
            // This is the filter function
 
            var data     = res.results || [],
 
                filtered = [],
 
                i,l;
 

	
 
            if (req) {
 
                req = req.toLowerCase();
 
                for (i = 0; i<data.length; i++) {
 
                    var pos = data[i].raw_name.toLowerCase().indexOf(req)
 
                    if (pos != -1) {
 
                        filtered.push(data[i]);
 
                    }
 
                }
 
                res.results = filtered;
 
            }
 
            YUD.get('repo_count').innerHTML = res.results.length;
 
            return res;
 
        }
 

	
 
        // 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:"desc",label:"${_('Description')}",sortable:true},
 
            {key:"last_change",label:"${_('Last Change')}",sortable:true,
 
                sortOptions: { sortFunction: ageSort }},
 
            {key:"last_changeset",label:"${_('Tip')}",sortable:true,
 
                sortOptions: { sortFunction: revisionSort }},
 
            {key:"owner",label:"${_('Owner')}",sortable:true},
 
            {key:"atom",label:"",sortable:false},
 
        ];
 

	
 
        var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,{
 
          sortedBy:{key:"name",dir:"asc"},
 
          paginator: new YAHOO.widget.Paginator({
 
              rowsPerPage: ${c.visual.lightweight_dashboard_items},
 
              alwaysVisible: false,
 
              template : "{PreviousPageLink} {FirstPageLink} {PageLinks} {LastPageLink} {NextPageLink}",
 
              pageLinks: 5,
 
              containerClass: 'pagination-wh',
 
              currentPageClass: 'pager_curpage',
 
              pageLinkClass: 'pager_link',
 
              nextPageLinkLabel: '&gt;',
 
              previousPageLinkLabel: '&lt;',
 
              firstPageLinkLabel: '&lt;&lt;',
 
              lastPageLinkLabel: '&gt;&gt;',
 
              containers:['user-paginator']
 
          }),
 

	
 
          MSG_SORTASC:"${_('Click to sort ascending')}",
 
          MSG_SORTDESC:"${_('Click to sort descending')}",
 
          MSG_EMPTY:"${_('No records found.')}",
 
          MSG_ERROR:"${_('Data error.')}",
 
          MSG_LOADING:"${_('Loading...')}",
 
        }
 
        );
 
        myDataTable.subscribe('postRenderEvent',function(oArgs) {
 
            tooltip_activate();
 
            quick_repo_menu();
 
        });
 

	
 
        var filterTimeout = null;
 

	
 
        updateFilter  = function () {
 
            // Reset timeout
 
            filterTimeout = null;
 

	
 
            // Reset sort
 
            var state = myDataTable.getState();
 
            state.sortedBy = {key:'name', dir:YAHOO.widget.DataTable.CLASS_ASC};
 

	
 
            // Get filtered data
 
            myDataSource.sendRequest(YUD.get('q_filter').value,{
 
                success : myDataTable.onDataReturnInitializeTable,
 
                failure : myDataTable.onDataReturnInitializeTable,
 
                scope   : myDataTable,
 
                argument: state
 
            });
 

	
 
        };
 
        YUE.on('q_filter','click',function(){
 
            if(!YUD.hasClass('q_filter', 'loaded')){
 
                YUD.get('q_filter').value = '';
 
                //TODO: load here full list later to do search within groups
 
                YUD.addClass('q_filter', 'loaded');
 
            }
 
         });
 

	
 
        YUE.on('q_filter','keyup',function (e) {
 
            clearTimeout(filterTimeout);
 
            filterTimeout = setTimeout(updateFilter,600);
 
        });
 
      </script>
 
    % endif
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>${_('Review 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>
 
            %endif
 
          </div>
 
         </div>
 
         <div class="field">
 
          <div class="label-summary">
 
              <label>${_('Origin repository')}:</label>
 
          </div>
 
          <div class="input">
 
              <div>
 
             ##%if h.is_hg(c.pull_request.org_repo):
 
             ##  <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/>
 
             ##%elif h.is_git(c.pull_request.org_repo):
 
             ##  <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
 
             ##%endif
 
              <span class="spantag">${c.pull_request.org_ref_parts[0]}: ${c.pull_request.org_ref_parts[1]}</span>
 
              <span><a href="${h.url('summary_home', repo_name=c.pull_request.org_repo.repo_name)}">${c.pull_request.org_repo.clone_url()}</a></span>
 
              </div>
 
          </div>
 
         </div>
 
         <div class="field">
 
          <div class="label-summary">
 
              <label>${_('Summary')}:</label>
 
          </div>
 
          <div class="input">
 
              <div style="white-space:pre-wrap">${h.literal(c.pull_request.description)}</div>
 
          </div>
 
         </div>
 
         <div class="field">
 
          <div class="label-summary">
 
              <label>${_('Created on')}:</label>
 
          </div>
 
          <div class="input">
 
              <div>${h.fmt_date(c.pull_request.created_on)}</div>
 
          </div>
 
         </div>
 
      </div>
 
    </div>
 

	
 
    <div style="overflow: auto;">
 
      ##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">${ungettext('Showing %s commit','Showing %s commits', len(c.cs_ranges)) % len(c.cs_ranges)}</div>
 
              <%include file="/compare/compare_cs.html" />
 

	
 
              ## FILES
 
              <div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">
 

	
 
              % if c.limited_diff:
 
                  ${ungettext('%s file changed', '%s files changed', len(c.files)) % len(c.files)}
 
              % else:
 
                  ${ungettext('%s file changed with %s insertions and %s deletions','%s files changed with %s insertions and %s deletions', len(c.files)) % (len(c.files),c.lines_added,c.lines_deleted)}:
 
              %endif
 

	
 
              </div>
 
              <div class="cs_files">
 
                %if not c.files:
 
                   <span class="empty_data">${_('No files')}</span>
 
                %endif
 
                %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>
 
              % if c.limited_diff:
 
                <h5>${_('Changeset was too big and was cut off...')} <a href="${h.url.current(fulldiff=1, **request.GET.mixed())}" onclick="return confirm('${_("confirm to show potentially huge diff")}')">${_('Show full diff')}</a></h5>
 
              % endif
 
          </div>
 
      </div>
 
      ## REVIEWERS
 
       <div style="float:left; border-left:1px dashed #eee">
 
       <h4>${_('Pull request reviewers')}</h4>
 
        <div id="reviewers" style="padding:0px 0px 5px 10px">
 
          ## members goes here !
 
          <div class="group_members_wrap" style="min-height:45px">
 
            <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') if c.pull_request.user_id == member.user_id else _('reviewer')})</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.user_id == c.rhodecode_user.user_id):
 
                  <span class="delete_icon action_button" onclick="removeReviewMember(${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 or remove 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 changes')}</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};
 
    // TODO: switch this to pyroutes
 
    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__')}";
 

	
 
    pyroutes.register('pullrequest_comment', "${url('pullrequest_comment',repo_name='%(repo_name)s',pull_request_id='%(pull_request_id)s')}", ['repo_name', 'pull_request_id']);
 
    pyroutes.register('pullrequest_comment_delete', "${url('pullrequest_comment_delete',repo_name='%(repo_name)s',comment_id='%(comment_id)s')}", ['repo_name', 'comment_id']);
 
    pyroutes.register('pullrequest_update', "${url('pullrequest_update',repo_name='%(repo_name)s',pull_request_id='%(pull_request_id)s')}", ['repo_name', '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
 
    % if c.limited_diff:
 
      <h4>${_('Changeset was too big and was cut off...')} <a href="${h.url.current(fulldiff=1, **request.GET.mixed())}" onclick="return confirm('${_("confirm to show potentially huge diff")}')">${_('Show full diff')}</a></h4>
 
    % endif
 

	
 

	
 
    ## 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(include_pr=True)}
 

	
 
    % 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, change_status=c.allowed_to_change_status)}
 
    %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){
 
              updateReviewers(undefined, "${c.repo_name}", "${c.pull_request.pull_request_id}");
 
          })
 
      })
 
    </script>
 

	
 
</div>
 

	
 
</%def>
rhodecode/tests/test_libs.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.tests.test_libs
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 

	
 
    Package for testing various lib/helper functions in rhodecode
 

	
 
    :created_on: Jun 9, 2011
 
    :copyright: (C) 2011-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/>.
 
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):
 

	
 
    @parameterized.expand(TEST_URLS)
 
    def test_uri_filter(self, test_url, expected, expected_creds):
 
        from rhodecode.lib.utils2 import uri_filter
 
        self.assertEqual(uri_filter(test_url), expected)
 

	
 
    @parameterized.expand(TEST_URLS)
 
    def test_credentials_filter(self, test_url, expected, expected_creds):
 
        from rhodecode.lib.utils2 import credentials_filter
 
        self.assertEqual(credentials_filter(test_url), expected_creds)
 

	
 
    @parameterized.expand([('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)
 
    ])
 
    def test_str2bool(self, str_bool, expected):
 
        from rhodecode.lib.utils2 import str2bool
 
        self.assertEqual(str2bool(str_bool), expected)
 

	
 
    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):
 
        from rhodecode.lib.utils2 import age
 
        from dateutil import relativedelta
 
        n = datetime.datetime.now()
 
        delt = lambda *args, **kwargs: relativedelta.relativedelta(*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(months=-1)), u'1 month ago')
 
        self.assertEqual(age(n + delt(months=-1, days=-2)), u'1 month and 2 days ago')
 
        self.assertEqual(age(n + delt(years=-1, months=-1)), u'1 year and 1 month ago')
 

	
 
    def test_age_in_future(self):
 
        from rhodecode.lib.utils2 import age
 
        from dateutil import relativedelta
 
        n = datetime.datetime.now()
 
        delt = lambda *args, **kwargs: relativedelta.relativedelta(*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(months=1)), u'in 1 month')
 
        self.assertEqual(age(n + delt(months=1, days=1)), u'in 1 month and 1 day')
 
        self.assertEqual(age(n + delt(years=1, months=1)), 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)
 

	
 
    @parameterized.expand([
 
      ("",
 
       ""),
 
      ("git-svn-id: https://svn.apache.org/repos/asf/libcloud/trunk@1441655 13f79535-47bb-0310-9956-ffa450edef68",
 
       "git-svn-id: https://svn.apache.org/repos/asf/libcloud/trunk@1441655 13f79535-47bb-0310-9956-ffa450edef68"),
 
      ("from rev 000000000000",
 
       "from rev url[000000000000]"),
 
      ("from rev 000000000000123123 also rev 000000000000",
 
       "from rev url[000000000000123123] also rev url[000000000000]"),
 
      ("this should-000 00",
 
       "this should-000 00"),
 
      ("longtextffffffffff rev 123123123123",
 
       "longtextffffffffff rev url[123123123123]"),
 
      ("rev ffffffffffffffffffffffffffffffffffffffffffffffffff",
 
       "rev ffffffffffffffffffffffffffffffffffffffffffffffffff"),
 
      ("ffffffffffff some text traalaa",
 
       "url[ffffffffffff] some text traalaa"),
 
       ("""Multi line
 
       123123123123 
 
       123123123123
 
       some text 123123123123""",
 
       """Multi line
 
       url[123123123123] 
 
       url[123123123123]
 
       some text url[123123123123]""")
 
    ])
 
    def test_urlify_changesets(self, sample, expected):
 
        import re
 

	
 
        def fake_url(self, *args, **kwargs):
 
            return '/some-url'
 

	
 
        #quickly change expected url[] into a link
 
        URL_PAT = re.compile(r'(?:url\[)(.+?)(?:\])')
 

	
 
        def url_func(match_obj):
 
            _url = match_obj.groups()[0]
 
            tmpl = """<a class="revision-link" href="/some-url">%s</a>"""
 
            return tmpl % _url
 

	
 
        expected = URL_PAT.sub(url_func, expected)
 

	
 
        with mock.patch('pylons.url', fake_url):
 
            from rhodecode.lib.helpers import urlify_changesets
 
            self.assertEqual(urlify_changesets(sample, 'repo_name'), expected)
0 comments (0 inline, 0 general)