Changeset - 7c0b55fb3a85
[Not reviewed]
default
0 4 0
Søren Løvborg - 9 years ago 2016-09-05 18:08:14
sorenl@unity3d.com
controllers: remove redundant Repository database lookups

BaseRepoController already provides the repository object in c.db_repo
(may be None) and BaseController already provides the repository name
in c.repo_name (as given in the URL).

(Arguably, that's a bad design, and we should revisit that decision in
the future. For now, the code just performs slightly better.)
4 files changed with 24 insertions and 29 deletions:
0 comments (0 inline, 0 general)
kallithea/controllers/admin/repos.py
Show inline comments
 
@@ -20,126 +20,124 @@ Repositories controller for Kallithea
 
This file was forked by the Kallithea project in July 2014.
 
Original author and date, and relevant copyright and licensing information is below:
 
:created_on: Apr 7, 2010
 
:author: marcink
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 

	
 
import logging
 
import traceback
 
import formencode
 
from formencode import htmlfill
 
from pylons import request, tmpl_context as c
 
from pylons.i18n.translation import _
 
from sqlalchemy.sql.expression import func
 
from webob.exc import HTTPFound, HTTPInternalServerError, HTTPForbidden, HTTPNotFound
 

	
 
from kallithea.config.routing import url
 
from kallithea.lib import helpers as h
 
from kallithea.lib.auth import LoginRequired, \
 
    HasRepoPermissionAnyDecorator, NotAnonymous, HasPermissionAny
 
from kallithea.lib.base import BaseRepoController, render
 
from kallithea.lib.utils import action_logger, jsonify
 
from kallithea.lib.vcs import RepositoryError
 
from kallithea.model.meta import Session
 
from kallithea.model.db import User, Repository, UserFollowing, RepoGroup, \
 
    Setting, RepositoryField
 
from kallithea.model.forms import RepoForm, RepoFieldForm, RepoPermsForm
 
from kallithea.model.scm import ScmModel, AvailableRepoGroupChoices, RepoList
 
from kallithea.model.repo import RepoModel
 
from kallithea.lib.compat import json
 
from kallithea.lib.exceptions import AttachedForksError
 
from kallithea.lib.utils2 import safe_int
 

	
 
log = logging.getLogger(__name__)
 

	
 

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

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

	
 
    def _load_repo(self, repo_name):
 
        repo_obj = Repository.get_by_repo_name(repo_name)
 
    def _load_repo(self):
 
        repo_obj = c.db_repo
 

	
 
        if repo_obj is None:
 
            h.not_mapped_error(repo_name)
 
            h.not_mapped_error(c.repo_name)
 
            raise HTTPFound(location=url('repos'))
 

	
 
        return repo_obj
 

	
 
    def __load_defaults(self, repo=None):
 
        top_perms = ['hg.create.repository']
 
        repo_group_perms = ['group.admin']
 
        if HasPermissionAny('hg.create.write_on_repogroup.true')():
 
            repo_group_perms.append('group.write')
 
        extras = [] if repo is None else [repo.group]
 

	
 
        c.repo_groups = AvailableRepoGroupChoices(top_perms, repo_group_perms, extras)
 

	
 
        c.landing_revs_choices, c.landing_revs = ScmModel().get_repo_landing_revs(repo)
 

	
 
    def __load_data(self, repo_name=None):
 
    def __load_data(self):
 
        """
 
        Load defaults settings for edit, and update
 

	
 
        :param repo_name:
 
        """
 
        c.repo_info = self._load_repo(repo_name)
 
        c.repo_info = self._load_repo()
 
        self.__load_defaults(c.repo_info)
 

	
 
        defaults = RepoModel()._get_defaults(repo_name)
 
        defaults = RepoModel()._get_defaults(c.repo_name)
 
        defaults['clone_uri'] = c.repo_info.clone_uri_hidden # don't show password
 

	
 
        return defaults
 

	
 
    def index(self, format='html'):
 
        _list = Repository.query() \
 
                        .order_by(func.lower(Repository.repo_name)) \
 
                        .all()
 

	
 
        c.repos_list = RepoList(_list, perm_set=['repository.admin'])
 
        repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
 
                                                   admin=True,
 
                                                   super_user_actions=True)
 
        #json used to render the grid
 
        c.data = json.dumps(repos_data)
 

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

	
 
    @NotAnonymous()
 
    def create(self):
 
        self.__load_defaults()
 
        form_result = {}
 
        try:
 
            # CanWriteGroup validators checks permissions of this POST
 
            form_result = RepoForm(repo_groups=c.repo_groups,
 
                                   landing_revs=c.landing_revs_choices)() \
 
                            .to_python(dict(request.POST))
 

	
 
            # create is done sometimes async on celery, db transaction
 
            # management is handled there.
 
            task = RepoModel().create(form_result, self.authuser.user_id)
 
            task_id = task.task_id
 
        except formencode.Invalid as errors:
 
            log.info(errors)
 
            return htmlfill.render(
 
                render('admin/repos/repo_add.html'),
 
                defaults=errors.value,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                force_defaults=False,
 
                encoding="UTF-8")
 

	
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            msg = (_('Error creating repository %s')
 
                   % form_result.get('repo_name'))
 
            h.flash(msg, category='error')
 
            raise HTTPFound(location=url('home'))
 
@@ -173,292 +171,292 @@ class ReposController(BaseRepoController
 
            force_defaults=False)
 

	
 
    @LoginRequired()
 
    @NotAnonymous()
 
    def repo_creating(self, repo_name):
 
        c.repo = repo_name
 
        c.task_id = request.GET.get('task_id')
 
        if not c.repo:
 
            raise HTTPNotFound()
 
        return render('admin/repos/repo_creating.html')
 

	
 
    @LoginRequired()
 
    @NotAnonymous()
 
    @jsonify
 
    def repo_check(self, repo_name):
 
        c.repo = repo_name
 
        task_id = request.GET.get('task_id')
 

	
 
        if task_id and task_id not in ['None']:
 
            from kallithea import CELERY_ON
 
            from kallithea.lib import celerypylons
 
            if CELERY_ON:
 
                task = celerypylons.result.AsyncResult(task_id)
 
                if task.failed():
 
                    raise HTTPInternalServerError(task.traceback)
 

	
 
        repo = Repository.get_by_repo_name(repo_name)
 
        if repo and repo.repo_state == Repository.STATE_CREATED:
 
            if repo.clone_uri:
 
                h.flash(_('Created repository %s from %s')
 
                        % (repo.repo_name, repo.clone_uri_hidden), category='success')
 
            else:
 
                repo_url = h.link_to(repo.repo_name,
 
                                     h.url('summary_home',
 
                                           repo_name=repo.repo_name))
 
                fork = repo.fork
 
                if fork is not None:
 
                    fork_name = fork.repo_name
 
                    h.flash(h.literal(_('Forked repository %s as %s')
 
                            % (fork_name, repo_url)), category='success')
 
                else:
 
                    h.flash(h.literal(_('Created repository %s') % repo_url),
 
                            category='success')
 
            return {'result': True}
 
        return {'result': False}
 

	
 
    @HasRepoPermissionAnyDecorator('repository.admin')
 
    def update(self, repo_name):
 
        c.repo_info = self._load_repo(repo_name)
 
        c.repo_info = self._load_repo()
 
        self.__load_defaults(c.repo_info)
 
        c.active = 'settings'
 
        c.repo_fields = RepositoryField.query() \
 
            .filter(RepositoryField.repository == c.repo_info).all()
 

	
 
        repo_model = RepoModel()
 
        changed_name = repo_name
 
        repo = Repository.get_by_repo_name(repo_name)
 
        old_data = {
 
            'repo_name': repo_name,
 
            'repo_group': repo.group.get_dict() if repo.group else {},
 
            'repo_type': repo.repo_type,
 
        }
 
        _form = RepoForm(edit=True, old_data=old_data,
 
                         repo_groups=c.repo_groups,
 
                         landing_revs=c.landing_revs_choices)()
 

	
 
        try:
 
            form_result = _form.to_python(dict(request.POST))
 
            repo = repo_model.update(repo_name, **form_result)
 
            ScmModel().mark_for_invalidation(repo_name)
 
            h.flash(_('Repository %s updated successfully') % repo_name,
 
                    category='success')
 
            changed_name = repo.repo_name
 
            action_logger(self.authuser, 'admin_updated_repo',
 
                              changed_name, self.ip_addr, self.sa)
 
            Session().commit()
 
        except formencode.Invalid as errors:
 
            log.info(errors)
 
            defaults = self.__load_data(repo_name)
 
            defaults = self.__load_data()
 
            defaults.update(errors.value)
 
            c.users_array = repo_model.get_users_js()
 
            return htmlfill.render(
 
                render('admin/repos/repo_edit.html'),
 
                defaults=defaults,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8",
 
                force_defaults=False)
 

	
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('Error occurred during update of repository %s') \
 
                    % repo_name, category='error')
 
        raise HTTPFound(location=url('edit_repo', repo_name=changed_name))
 

	
 
    @HasRepoPermissionAnyDecorator('repository.admin')
 
    def delete(self, repo_name):
 
        repo_model = RepoModel()
 
        repo = repo_model.get_by_repo_name(repo_name)
 
        if not repo:
 
            h.not_mapped_error(repo_name)
 
            raise HTTPFound(location=url('repos'))
 
        try:
 
            _forks = repo.forks.count()
 
            handle_forks = None
 
            if _forks and request.POST.get('forks'):
 
                do = request.POST['forks']
 
                if do == 'detach_forks':
 
                    handle_forks = 'detach'
 
                    h.flash(_('Detached %s forks') % _forks, category='success')
 
                elif do == 'delete_forks':
 
                    handle_forks = 'delete'
 
                    h.flash(_('Deleted %s forks') % _forks, category='success')
 
            repo_model.delete(repo, forks=handle_forks)
 
            action_logger(self.authuser, 'admin_deleted_repo',
 
                  repo_name, self.ip_addr, self.sa)
 
            ScmModel().mark_for_invalidation(repo_name)
 
            h.flash(_('Deleted repository %s') % repo_name, category='success')
 
            Session().commit()
 
        except AttachedForksError:
 
            h.flash(_('Cannot delete repository %s which still has forks')
 
                        % repo_name, category='warning')
 

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

	
 
        if repo.group:
 
            raise HTTPFound(location=url('repos_group_home', group_name=repo.group.group_name))
 
        raise HTTPFound(location=url('repos'))
 

	
 
    @HasRepoPermissionAnyDecorator('repository.admin')
 
    def edit(self, repo_name):
 
        defaults = self.__load_data(repo_name)
 
        defaults = self.__load_data()
 
        c.repo_fields = RepositoryField.query() \
 
            .filter(RepositoryField.repository == c.repo_info).all()
 
        repo_model = RepoModel()
 
        c.users_array = repo_model.get_users_js()
 
        c.active = 'settings'
 
        return htmlfill.render(
 
            render('admin/repos/repo_edit.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False)
 

	
 
    @HasRepoPermissionAnyDecorator('repository.admin')
 
    def edit_permissions(self, repo_name):
 
        c.repo_info = self._load_repo(repo_name)
 
        c.repo_info = self._load_repo()
 
        repo_model = RepoModel()
 
        c.users_array = repo_model.get_users_js()
 
        c.user_groups_array = repo_model.get_user_groups_js()
 
        c.active = 'permissions'
 
        defaults = RepoModel()._get_defaults(repo_name)
 

	
 
        return htmlfill.render(
 
            render('admin/repos/repo_edit.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False)
 

	
 
    def edit_permissions_update(self, repo_name):
 
        form = RepoPermsForm()().to_python(request.POST)
 
        RepoModel()._update_permissions(repo_name, form['perms_new'],
 
                                        form['perms_updates'])
 
        #TODO: implement this
 
        #action_logger(self.authuser, 'admin_changed_repo_permissions',
 
        #              repo_name, self.ip_addr, self.sa)
 
        Session().commit()
 
        h.flash(_('Repository permissions updated'), category='success')
 
        raise HTTPFound(location=url('edit_repo_perms', repo_name=repo_name))
 

	
 
    def edit_permissions_revoke(self, repo_name):
 
        try:
 
            obj_type = request.POST.get('obj_type')
 
            obj_id = None
 
            if obj_type == 'user':
 
                obj_id = safe_int(request.POST.get('user_id'))
 
            elif obj_type == 'user_group':
 
                obj_id = safe_int(request.POST.get('user_group_id'))
 

	
 
            if obj_type == 'user':
 
                RepoModel().revoke_user_permission(repo=repo_name, user=obj_id)
 
            elif obj_type == 'user_group':
 
                RepoModel().revoke_user_group_permission(
 
                    repo=repo_name, group_name=obj_id
 
                )
 
            #TODO: implement this
 
            #action_logger(self.authuser, 'admin_revoked_repo_permissions',
 
            #              repo_name, self.ip_addr, self.sa)
 
            Session().commit()
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during revoking of permission'),
 
                    category='error')
 
            raise HTTPInternalServerError()
 

	
 
    @HasRepoPermissionAnyDecorator('repository.admin')
 
    def edit_fields(self, repo_name):
 
        c.repo_info = self._load_repo(repo_name)
 
        c.repo_info = self._load_repo()
 
        c.repo_fields = RepositoryField.query() \
 
            .filter(RepositoryField.repository == c.repo_info).all()
 
        c.active = 'fields'
 
        if request.POST:
 

	
 
            raise HTTPFound(location=url('repo_edit_fields'))
 
        return render('admin/repos/repo_edit.html')
 

	
 
    @HasRepoPermissionAnyDecorator('repository.admin')
 
    def create_repo_field(self, repo_name):
 
        try:
 
            form_result = RepoFieldForm()().to_python(dict(request.POST))
 
            new_field = RepositoryField()
 
            new_field.repository = Repository.get_by_repo_name(repo_name)
 
            new_field.field_key = form_result['new_field_key']
 
            new_field.field_type = form_result['new_field_type']  # python type
 
            new_field.field_value = form_result['new_field_value']  # set initial blank value
 
            new_field.field_desc = form_result['new_field_desc']
 
            new_field.field_label = form_result['new_field_label']
 
            Session().add(new_field)
 
            Session().commit()
 
        except Exception as e:
 
            log.error(traceback.format_exc())
 
            msg = _('An error occurred during creation of field')
 
            if isinstance(e, formencode.Invalid):
 
                msg += ". " + e.msg
 
            h.flash(msg, category='error')
 
        raise HTTPFound(location=url('edit_repo_fields', repo_name=repo_name))
 

	
 
    @HasRepoPermissionAnyDecorator('repository.admin')
 
    def delete_repo_field(self, repo_name, field_id):
 
        field = RepositoryField.get_or_404(field_id)
 
        try:
 
            Session().delete(field)
 
            Session().commit()
 
        except Exception as e:
 
            log.error(traceback.format_exc())
 
            msg = _('An error occurred during removal of field')
 
            h.flash(msg, category='error')
 
        raise HTTPFound(location=url('edit_repo_fields', repo_name=repo_name))
 

	
 
    @HasRepoPermissionAnyDecorator('repository.admin')
 
    def edit_advanced(self, repo_name):
 
        c.repo_info = self._load_repo(repo_name)
 
        c.repo_info = self._load_repo()
 
        c.default_user_id = User.get_default_user().user_id
 
        c.in_public_journal = UserFollowing.query() \
 
            .filter(UserFollowing.user_id == c.default_user_id) \
 
            .filter(UserFollowing.follows_repository == c.repo_info).scalar()
 

	
 
        _repos = Repository.query().order_by(Repository.repo_name).all()
 
        read_access_repos = RepoList(_repos)
 
        c.repos_list = [(None, _('-- Not a fork --'))]
 
        c.repos_list += [(x.repo_id, x.repo_name)
 
                         for x in read_access_repos
 
                         if x.repo_id != c.repo_info.repo_id]
 

	
 
        defaults = {
 
            'id_fork_of': c.repo_info.fork.repo_id if c.repo_info.fork else ''
 
        }
 

	
 
        c.active = 'advanced'
 
        if request.POST:
 
            raise HTTPFound(location=url('repo_edit_advanced'))
 
        return htmlfill.render(
 
            render('admin/repos/repo_edit.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False)
 

	
 
    @HasRepoPermissionAnyDecorator('repository.admin')
 
    def edit_advanced_journal(self, repo_name):
 
        """
 
        Sets this repository to be visible in public journal,
 
        in other words asking default user to follow this repo
 

	
 
        :param repo_name:
 
        """
 

	
 
        try:
 
            repo_id = Repository.get_by_repo_name(repo_name).repo_id
 
            user_id = User.get_default_user().user_id
 
            self.scm_model.toggle_following_repo(repo_id, user_id)
 
            h.flash(_('Updated repository visibility in public journal'),
 
                    category='success')
 
            Session().commit()
 
        except Exception:
 
            h.flash(_('An error occurred during setting this'
 
                      ' repository in public journal'),
 
                    category='error')
 
        raise HTTPFound(location=url('edit_repo_advanced', repo_name=repo_name))
 

	
 

	
 
@@ -484,110 +482,110 @@ class ReposController(BaseRepoController
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during this operation'),
 
                    category='error')
 

	
 
        raise HTTPFound(location=url('edit_repo_advanced', repo_name=repo_name))
 

	
 
    @HasRepoPermissionAnyDecorator('repository.admin')
 
    def edit_advanced_locking(self, repo_name):
 
        """
 
        Unlock repository when it is locked !
 

	
 
        :param repo_name:
 
        """
 
        try:
 
            repo = Repository.get_by_repo_name(repo_name)
 
            if request.POST.get('set_lock'):
 
                Repository.lock(repo, c.authuser.user_id)
 
                h.flash(_('Repository has been locked'), category='success')
 
            elif request.POST.get('set_unlock'):
 
                Repository.unlock(repo)
 
                h.flash(_('Repository has been unlocked'), category='success')
 
        except Exception as e:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during unlocking'),
 
                    category='error')
 
        raise HTTPFound(location=url('edit_repo_advanced', repo_name=repo_name))
 

	
 
    @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
 
    def toggle_locking(self, repo_name):
 
        try:
 
            repo = Repository.get_by_repo_name(repo_name)
 

	
 
            if repo.enable_locking:
 
                if repo.locked[0]:
 
                    Repository.unlock(repo)
 
                    h.flash(_('Repository has been unlocked'), category='success')
 
                else:
 
                    Repository.lock(repo, c.authuser.user_id)
 
                    h.flash(_('Repository has been locked'), category='success')
 

	
 
        except Exception as e:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during unlocking'),
 
                    category='error')
 
        raise HTTPFound(location=url('summary_home', repo_name=repo_name))
 

	
 
    @HasRepoPermissionAnyDecorator('repository.admin')
 
    def edit_caches(self, repo_name):
 
        c.repo_info = self._load_repo(repo_name)
 
        c.repo_info = self._load_repo()
 
        c.active = 'caches'
 
        if request.POST:
 
            try:
 
                ScmModel().mark_for_invalidation(repo_name)
 
                Session().commit()
 
                h.flash(_('Cache invalidation successful'),
 
                        category='success')
 
            except Exception as e:
 
                log.error(traceback.format_exc())
 
                h.flash(_('An error occurred during cache invalidation'),
 
                        category='error')
 

	
 
            raise HTTPFound(location=url('edit_repo_caches', repo_name=c.repo_name))
 
        return render('admin/repos/repo_edit.html')
 

	
 
    @HasRepoPermissionAnyDecorator('repository.admin')
 
    def edit_remote(self, repo_name):
 
        c.repo_info = self._load_repo(repo_name)
 
        c.repo_info = self._load_repo()
 
        c.active = 'remote'
 
        if request.POST:
 
            try:
 
                ScmModel().pull_changes(repo_name, self.authuser.username)
 
                h.flash(_('Pulled from remote location'), category='success')
 
            except Exception as e:
 
                log.error(traceback.format_exc())
 
                h.flash(_('An error occurred during pull from remote location'),
 
                        category='error')
 
            raise HTTPFound(location=url('edit_repo_remote', repo_name=c.repo_name))
 
        return render('admin/repos/repo_edit.html')
 

	
 
    @HasRepoPermissionAnyDecorator('repository.admin')
 
    def edit_statistics(self, repo_name):
 
        c.repo_info = self._load_repo(repo_name)
 
        c.repo_info = self._load_repo()
 
        repo = c.repo_info.scm_instance
 

	
 
        if c.repo_info.stats:
 
            # this is on what revision we ended up so we add +1 for count
 
            last_rev = c.repo_info.stats.stat_on_revision + 1
 
        else:
 
            last_rev = 0
 
        c.stats_revision = last_rev
 

	
 
        c.repo_last_rev = repo.count() if repo.revisions else 0
 

	
 
        if last_rev == 0 or c.repo_last_rev == 0:
 
            c.stats_percentage = 0
 
        else:
 
            c.stats_percentage = '%.2f' % ((float((last_rev)) / c.repo_last_rev) * 100)
 

	
 
        c.active = 'statistics'
 
        if request.POST:
 
            try:
 
                RepoModel().delete_stats(repo_name)
 
                Session().commit()
 
            except Exception as e:
 
                log.error(traceback.format_exc())
 
                h.flash(_('An error occurred during deletion of repository stats'),
 
                        category='error')
 
            raise HTTPFound(location=url('edit_repo_statistics', repo_name=c.repo_name))
 

	
 
        return render('admin/repos/repo_edit.html')
kallithea/controllers/files.py
Show inline comments
 
@@ -381,97 +381,97 @@ class FilesController(BaseRepoController
 

	
 
        r_post = request.POST
 

	
 
        c.cs = self.__get_cs(revision)
 
        c.file = self.__get_filenode(c.cs, f_path)
 

	
 
        if c.file.is_binary:
 
            raise HTTPFound(location=url('files_home', repo_name=c.repo_name,
 
                            revision=c.cs.raw_id, f_path=f_path))
 
        c.default_message = _('Edited file %s via Kallithea') % (f_path)
 
        c.f_path = f_path
 

	
 
        if r_post:
 

	
 
            old_content = c.file.content
 
            sl = old_content.splitlines(1)
 
            first_line = sl[0] if sl else ''
 
            # modes:  0 - Unix, 1 - Mac, 2 - DOS
 
            mode = detect_mode(first_line, 0)
 
            content = convert_line_endings(r_post.get('content', ''), mode)
 

	
 
            message = r_post.get('message') or c.default_message
 
            author = self.authuser.full_contact
 

	
 
            if content == old_content:
 
                h.flash(_('No changes'), category='warning')
 
                raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name,
 
                                    revision='tip'))
 
            try:
 
                self.scm_model.commit_change(repo=c.db_repo_scm_instance,
 
                                             repo_name=repo_name, cs=c.cs,
 
                                             user=self.authuser.user_id,
 
                                             author=author, message=message,
 
                                             content=content, f_path=f_path)
 
                h.flash(_('Successfully committed to %s') % f_path,
 
                        category='success')
 
            except Exception:
 
                log.error(traceback.format_exc())
 
                h.flash(_('Error occurred during commit'), category='error')
 
            raise HTTPFound(location=url('changeset_home',
 
                                repo_name=c.repo_name, revision='tip'))
 

	
 
        return render('files/files_edit.html')
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
 
    def add(self, repo_name, revision, f_path):
 

	
 
        repo = Repository.get_by_repo_name(repo_name)
 
        repo = c.db_repo
 
        if repo.enable_locking and repo.locked[0]:
 
            h.flash(_('This repository has been locked by %s on %s')
 
                % (h.person_by_id(repo.locked[0]),
 
                   h.fmt_date(h.time_to_datetime(repo.locked[1]))),
 
                  'warning')
 
            raise HTTPFound(location=h.url('files_home',
 
                                  repo_name=repo_name, revision='tip'))
 

	
 
        r_post = request.POST
 
        c.cs = self.__get_cs(revision, silent_empty=True)
 
        if c.cs is None:
 
            c.cs = EmptyChangeset(alias=c.db_repo_scm_instance.alias)
 
        c.default_message = (_('Added file via Kallithea'))
 
        c.f_path = f_path
 

	
 
        if r_post:
 
            unix_mode = 0
 
            content = convert_line_endings(r_post.get('content', ''), unix_mode)
 

	
 
            message = r_post.get('message') or c.default_message
 
            filename = r_post.get('filename')
 
            location = r_post.get('location', '')
 
            file_obj = r_post.get('upload_file', None)
 

	
 
            if file_obj is not None and hasattr(file_obj, 'filename'):
 
                filename = file_obj.filename
 
                content = file_obj.file
 

	
 
                if hasattr(content, 'file'):
 
                    # non posix systems store real file under file attr
 
                    content = content.file
 

	
 
            if not content:
 
                h.flash(_('No content'), category='warning')
 
                raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name,
 
                                    revision='tip'))
 
            if not filename:
 
                h.flash(_('No filename'), category='warning')
 
                raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name,
 
                                    revision='tip'))
 
            #strip all crap out of file, just leave the basename
 
            filename = os.path.basename(filename)
 
            node_path = posixpath.join(location, filename)
 
            author = self.authuser.full_contact
 

	
 
            try:
 
                nodes = {
 
                    node_path: {
kallithea/controllers/forks.py
Show inline comments
 
@@ -20,171 +20,169 @@ forks controller for Kallithea
 
This file was forked by the Kallithea project in July 2014.
 
Original author and date, and relevant copyright and licensing information is below:
 
:created_on: Apr 23, 2011
 
:author: marcink
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 

	
 
import logging
 
import formencode
 
import traceback
 
from formencode import htmlfill
 

	
 
from pylons import tmpl_context as c, request
 
from pylons.i18n.translation import _
 
from webob.exc import HTTPFound
 

	
 
import kallithea.lib.helpers as h
 

	
 
from kallithea.config.routing import url
 
from kallithea.lib.helpers import Page
 
from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator, \
 
    NotAnonymous, HasRepoPermissionAny, HasPermissionAnyDecorator, HasPermissionAny
 
from kallithea.lib.base import BaseRepoController, render
 
from kallithea.model.db import Repository, UserFollowing, User, Ui
 
from kallithea.model.repo import RepoModel
 
from kallithea.model.forms import RepoForkForm
 
from kallithea.model.scm import ScmModel, AvailableRepoGroupChoices
 
from kallithea.lib.utils2 import safe_int
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class ForksController(BaseRepoController):
 

	
 
    def __before__(self):
 
        super(ForksController, self).__before__()
 

	
 
    def __load_defaults(self):
 
        repo_group_perms = ['group.admin']
 
        if HasPermissionAny('hg.create.write_on_repogroup.true')():
 
            repo_group_perms.append('group.write')
 
        c.repo_groups = AvailableRepoGroupChoices(['hg.create.repository'], repo_group_perms)
 

	
 
        c.landing_revs_choices, c.landing_revs = ScmModel().get_repo_landing_revs()
 

	
 
        c.can_update = Ui.get_by_key('hooks', Ui.HOOK_UPDATE).ui_active
 

	
 
    def __load_data(self, repo_name=None):
 
    def __load_data(self):
 
        """
 
        Load defaults settings for edit, and update
 

	
 
        :param repo_name:
 
        """
 
        self.__load_defaults()
 

	
 
        c.repo_info = db_repo = Repository.get_by_repo_name(repo_name)
 
        repo = db_repo.scm_instance
 
        c.repo_info = c.db_repo
 
        repo = c.db_repo.scm_instance
 

	
 
        if c.repo_info is None:
 
            h.not_mapped_error(repo_name)
 
            h.not_mapped_error(c.repo_name)
 
            raise HTTPFound(location=url('repos'))
 

	
 
        c.default_user_id = User.get_default_user().user_id
 
        c.in_public_journal = UserFollowing.query() \
 
            .filter(UserFollowing.user_id == c.default_user_id) \
 
            .filter(UserFollowing.follows_repository == c.repo_info).scalar()
 

	
 
        if c.repo_info.stats:
 
            last_rev = c.repo_info.stats.stat_on_revision+1
 
        else:
 
            last_rev = 0
 
        c.stats_revision = last_rev
 

	
 
        c.repo_last_rev = repo.count() if repo.revisions else 0
 

	
 
        if last_rev == 0 or c.repo_last_rev == 0:
 
            c.stats_percentage = 0
 
        else:
 
            c.stats_percentage = '%.2f' % ((float((last_rev)) /
 
                                            c.repo_last_rev) * 100)
 

	
 
        defaults = RepoModel()._get_defaults(repo_name)
 
        defaults = RepoModel()._get_defaults(c.repo_name)
 
        # alter the description to indicate a fork
 
        defaults['description'] = ('fork of repository: %s \n%s'
 
                                   % (defaults['repo_name'],
 
                                      defaults['description']))
 
        # add suffix to fork
 
        defaults['repo_name'] = '%s-fork' % defaults['repo_name']
 

	
 
        return defaults
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def forks(self, repo_name):
 
        p = safe_int(request.GET.get('page'), 1)
 
        repo_id = c.db_repo.repo_id
 
        d = []
 
        for r in Repository.get_repo_forks(repo_id):
 
            if not HasRepoPermissionAny(
 
                'repository.read', 'repository.write', 'repository.admin'
 
            )(r.repo_name, 'get forks check'):
 
                continue
 
            d.append(r)
 
        c.forks_pager = Page(d, page=p, items_per_page=20)
 

	
 
        if request.environ.get('HTTP_X_PARTIAL_XHR'):
 
            return render('/forks/forks_data.html')
 

	
 
        return render('/forks/forks.html')
 

	
 
    @LoginRequired()
 
    @NotAnonymous()
 
    @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def fork(self, repo_name):
 
        c.repo_info = Repository.get_by_repo_name(repo_name)
 
        if not c.repo_info:
 
            h.not_mapped_error(repo_name)
 
            raise HTTPFound(location=url('home'))
 

	
 
        defaults = self.__load_data(repo_name)
 
        defaults = self.__load_data()
 

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

	
 
    @LoginRequired()
 
    @NotAnonymous()
 
    @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def fork_create(self, repo_name):
 
        self.__load_defaults()
 
        c.repo_info = Repository.get_by_repo_name(repo_name)
 
        _form = RepoForkForm(old_data={'repo_type': c.repo_info.repo_type},
 
                             repo_groups=c.repo_groups,
 
                             landing_revs=c.landing_revs_choices)()
 
        form_result = {}
 
        task_id = None
 
        try:
 
            form_result = _form.to_python(dict(request.POST))
 

	
 
            # an approximation that is better than nothing
 
            if not Ui.get_by_key('hooks', Ui.HOOK_UPDATE).ui_active:
 
                form_result['update_after_clone'] = False
 

	
 
            # create fork is done sometimes async on celery, db transaction
 
            # management is handled there.
 
            task = RepoModel().create_fork(form_result, self.authuser.user_id)
 
            task_id = task.task_id
 
        except formencode.Invalid as errors:
 
            return htmlfill.render(
 
                render('forks/fork.html'),
 
                defaults=errors.value,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8",
 
                force_defaults=False)
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during repository forking %s') %
 
                    repo_name, category='error')
 

	
 
        raise HTTPFound(location=h.url('repo_creating_home',
 
                              repo_name=form_result['repo_name_full'],
 
                              task_id=task_id))
kallithea/controllers/pullrequests.py
Show inline comments
 
@@ -151,97 +151,96 @@ class PullrequestsController(BaseRepoCon
 
            specials = [(selected, '%s: %s' % (_("Changeset"), rev[:12]))]
 

	
 
        # prio 3: most recent peer branch
 
        if peers and not selected:
 
            selected = peers[0][0]
 

	
 
        # prio 4: tip revision
 
        if not selected:
 
            if h.is_hg(repo):
 
                if tipbranch:
 
                    selected = 'branch:%s:%s' % (tipbranch, tiprev)
 
                else:
 
                    selected = 'tag:null:' + repo.EMPTY_CHANGESET
 
                    tags.append((selected, 'null'))
 
            else:
 
                if 'master' in repo.branches:
 
                    selected = 'branch:master:%s' % repo.branches['master']
 
                else:
 
                    k, v = repo.branches.items()[0]
 
                    selected = 'branch:%s:%s' % (k, v)
 

	
 
        groups = [(specials, _("Special")),
 
                  (peers, _("Peer branches")),
 
                  (bookmarks, _("Bookmarks")),
 
                  (branches, _("Branches")),
 
                  (tags, _("Tags")),
 
                  ]
 
        return [g for g in groups if g[0]], selected
 

	
 
    def _get_is_allowed_change_status(self, pull_request):
 
        if pull_request.is_closed():
 
            return False
 

	
 
        owner = self.authuser.user_id == pull_request.user_id
 
        reviewer = PullRequestReviewers.query() \
 
            .filter(PullRequestReviewers.pull_request == pull_request) \
 
            .filter(PullRequestReviewers.user_id == self.authuser.user_id) \
 
            .count() != 0
 

	
 
        return self.authuser.admin or owner or reviewer
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def show_all(self, repo_name):
 
        c.from_ = request.GET.get('from_') or ''
 
        c.closed = request.GET.get('closed') or ''
 
        c.pull_requests = PullRequestModel().get_all(repo_name, from_=c.from_, closed=c.closed)
 
        c.repo_name = repo_name
 
        p = safe_int(request.GET.get('page'), 1)
 

	
 
        c.pullrequests_pager = Page(c.pull_requests, page=p, items_per_page=100)
 

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

	
 
    @LoginRequired()
 
    @NotAnonymous()
 
    def show_my(self):
 
        c.closed = request.GET.get('closed') or ''
 

	
 
        def _filter(pr):
 
            s = sorted(pr, key=lambda o: o.created_on, reverse=True)
 
            if not c.closed:
 
                s = filter(lambda p: p.status != PullRequest.STATUS_CLOSED, s)
 
            return s
 

	
 
        c.my_pull_requests = _filter(PullRequest.query() \
 
                                .filter(PullRequest.user_id ==
 
                                        self.authuser.user_id) \
 
                                .all())
 

	
 
        c.participate_in_pull_requests = []
 
        c.participate_in_pull_requests_todo = []
 
        done_status = set([ChangesetStatus.STATUS_APPROVED, ChangesetStatus.STATUS_REJECTED])
 
        for pr in _filter(PullRequest.query()
 
                                .join(PullRequestReviewers)
 
                                .filter(PullRequestReviewers.user_id ==
 
                                        self.authuser.user_id)
 
                         ):
 
            status = pr.user_review_status(c.authuser.user_id) # very inefficient!!!
 
            if status in done_status:
 
                c.participate_in_pull_requests.append(pr)
 
            else:
 
                c.participate_in_pull_requests_todo.append(pr)
 

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

	
 
    @LoginRequired()
 
    @NotAnonymous()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def index(self):
 
        org_repo = c.db_repo
 
        org_scm_instance = org_repo.scm_instance
 
        try:
 
            org_scm_instance.get_changeset()
 
        except EmptyRepositoryError as e:
 
@@ -253,110 +252,110 @@ class PullrequestsController(BaseRepoCon
 
        # rev_start is not directly useful - its parent could however be used
 
        # as default for other and thus give a simple compare view
 
        rev_start = request.GET.get('rev_start')
 
        other_rev = None
 
        if rev_start:
 
            starters = org_repo.get_changeset(rev_start).parents
 
            if starters:
 
                other_rev = starters[0].raw_id
 
            else:
 
                other_rev = org_repo.scm_instance.EMPTY_CHANGESET
 
        branch = request.GET.get('branch')
 

	
 
        c.cs_repos = [(org_repo.repo_name, org_repo.repo_name)]
 
        c.default_cs_repo = org_repo.repo_name
 
        c.cs_refs, c.default_cs_ref = self._get_repo_refs(org_scm_instance, rev=org_rev, branch=branch)
 

	
 
        default_cs_ref_type, default_cs_branch, default_cs_rev = c.default_cs_ref.split(':')
 
        if default_cs_ref_type != 'branch':
 
            default_cs_branch = org_repo.get_changeset(default_cs_rev).branch
 

	
 
        # add org repo to other so we can open pull request against peer branches on itself
 
        c.a_repos = [(org_repo.repo_name, '%s (self)' % org_repo.repo_name)]
 

	
 
        if org_repo.parent:
 
            # add parent of this fork also and select it.
 
            # use the same branch on destination as on source, if available.
 
            c.a_repos.append((org_repo.parent.repo_name, '%s (parent)' % org_repo.parent.repo_name))
 
            c.a_repo = org_repo.parent
 
            c.a_refs, c.default_a_ref = self._get_repo_refs(
 
                    org_repo.parent.scm_instance, branch=default_cs_branch, rev=other_rev)
 

	
 
        else:
 
            c.a_repo = org_repo
 
            c.a_refs, c.default_a_ref = self._get_repo_refs(org_scm_instance, rev=other_rev)
 

	
 
        # gather forks and add to this list ... even though it is rare to
 
        # request forks to pull from their parent
 
        for fork in org_repo.forks:
 
            c.a_repos.append((fork.repo_name, fork.repo_name))
 

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

	
 
    @LoginRequired()
 
    @NotAnonymous()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    @jsonify
 
    def repo_info(self, repo_name):
 
        repo = RepoModel()._get_repo(repo_name)
 
        repo = c.db_repo
 
        refs, selected_ref = self._get_repo_refs(repo.scm_instance)
 
        return {
 
            'description': repo.description.split('\n', 1)[0],
 
            'selected_ref': selected_ref,
 
            'refs': refs,
 
            }
 

	
 
    @LoginRequired()
 
    @NotAnonymous()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def create(self, repo_name):
 
        repo = RepoModel()._get_repo(repo_name)
 
        repo = c.db_repo
 
        try:
 
            _form = PullRequestForm(repo.repo_id)().to_python(request.POST)
 
        except formencode.Invalid as errors:
 
            log.error(traceback.format_exc())
 
            log.error(str(errors))
 
            msg = _('Error creating pull request: %s') % errors.msg
 
            h.flash(msg, 'error')
 
            raise HTTPBadRequest
 

	
 
        # heads up: org and other might seem backward here ...
 
        org_repo_name = _form['org_repo']
 
        org_ref = _form['org_ref'] # will have merge_rev as rev but symbolic name
 
        org_repo = RepoModel()._get_repo(org_repo_name)
 
        (org_ref_type,
 
         org_ref_name,
 
         org_rev) = org_ref.split(':')
 
        if org_ref_type == 'rev':
 
            org_ref_type = 'branch'
 
            cs = org_repo.scm_instance.get_changeset(org_rev)
 
            org_ref = '%s:%s:%s' % (org_ref_type, cs.branch, cs.raw_id)
 

	
 
        other_repo_name = _form['other_repo']
 
        other_ref = _form['other_ref'] # will have symbolic name and head revision
 
        other_repo = RepoModel()._get_repo(other_repo_name)
 
        (other_ref_type,
 
         other_ref_name,
 
         other_rev) = other_ref.split(':')
 
        if other_ref_type == 'rev':
 
            cs = other_repo.scm_instance.get_changeset(other_rev)
 
            other_ref_name = cs.raw_id[:12]
 
            other_ref = '%s:%s:%s' % (other_ref_type, other_ref_name, cs.raw_id)
 

	
 
        cs_ranges, _cs_ranges_not, ancestor_rev = \
 
            CompareController._get_changesets(org_repo.scm_instance.alias,
 
                                              other_repo.scm_instance, other_rev, # org and other "swapped"
 
                                              org_repo.scm_instance, org_rev,
 
                                              )
 
        if ancestor_rev is None:
 
            ancestor_rev = org_repo.scm_instance.EMPTY_CHANGESET
 
        revisions = [cs_.raw_id for cs_ in cs_ranges]
 

	
 
        # hack: ancestor_rev is not an other_rev but we want to show the
 
        # requested destination and have the exact ancestor
 
        other_ref = '%s:%s:%s' % (other_ref_type, other_ref_name, ancestor_rev)
 

	
 
        reviewers = _form['review_members']
 

	
 
        title = _form['pullrequest_title']
0 comments (0 inline, 0 general)