Changeset - b095e2fbba44
[Not reviewed]
default
0 60 0
Mads Kiilerich (mads) - 5 years ago 2020-10-12 11:21:15
mads@kiilerich.com
Grafted from: 55a778cd6b38
model: always import whole meta module - also when referencing Session
60 files changed with 507 insertions and 510 deletions:
0 comments (0 inline, 0 general)
kallithea/alembic/env.py
Show inline comments
 
@@ -12,25 +12,25 @@
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
# Alembic migration environment (configuration).
 

	
 
import logging
 
import os
 
from logging.config import fileConfig
 

	
 
from alembic import context
 
from sqlalchemy import engine_from_config, pool
 

	
 
from kallithea.model import db
 
from kallithea.model import meta
 

	
 

	
 
# The alembic.config.Config object, which wraps the current .ini file.
 
config = context.config
 

	
 
# Default to use the main Kallithea database string in [app:main].
 
# For advanced uses, this can be overridden by specifying an explicit
 
# [alembic] sqlalchemy.url.
 
database_url = (
 
    config.get_main_option('sqlalchemy.url') or
 
    config.get_section_option('app:main', 'sqlalchemy.url')
 
)
 
@@ -84,25 +84,25 @@ def run_migrations_online():
 
    cfg['sqlalchemy.url'] = database_url
 
    connectable = engine_from_config(
 
        cfg,
 
        prefix='sqlalchemy.',
 
        poolclass=pool.NullPool)
 

	
 
    with connectable.connect() as connection:
 
        context.configure(
 
            connection=connection,
 

	
 
            # Support autogeneration of migration scripts based on "diff" between
 
            # current database schema and kallithea.model.db schema.
 
            target_metadata=db.Base.metadata,
 
            target_metadata=meta.Base.metadata,
 
            include_object=include_in_autogeneration,
 
            render_as_batch=True, # batch mode is needed for SQLite support
 
        )
 

	
 
        with context.begin_transaction():
 
            context.run_migrations()
 

	
 

	
 
if context.is_offline_mode():
 
    run_migrations_offline()
 
else:
 
    run_migrations_online()
kallithea/bin/kallithea_cli_db.py
Show inline comments
 
@@ -7,25 +7,25 @@
 
# 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 click
 

	
 
import kallithea
 
import kallithea.bin.kallithea_cli_base as cli_base
 
from kallithea.lib.db_manage import DbManage
 
from kallithea.model.meta import Session
 
from kallithea.model import meta
 

	
 

	
 
@cli_base.register_command(needs_config_file=True, config_file_initialize_app=True)
 
@click.option('--reuse/--no-reuse', default=False,
 
        help='Reuse and clean existing database instead of dropping and creating (default: no reuse)')
 
@click.option('--user', help='Username of administrator account.')
 
@click.option('--password', help='Password for administrator account.')
 
@click.option('--email', help='Email address of administrator account.')
 
@click.option('--repos', help='Absolute path to repositories location.')
 
@click.option('--force-yes', is_flag=True, help='Answer yes to every question.')
 
@click.option('--force-no', is_flag=True, help='Answer no to every question.')
 
@click.option('--public-access/--no-public-access', default=True,
 
@@ -58,24 +58,24 @@ def db_create(user, password, email, rep
 
                force_ask=force_ask,
 
                public_access=public_access,
 
        )
 
        dbmanage = DbManage(dbconf=dbconf, root=config['here'],
 
                            tests=False, cli_args=cli_args)
 
        dbmanage.create_tables(reuse_database=reuse)
 
        repo_root_path = dbmanage.prompt_repo_root_path(None)
 
        dbmanage.create_settings(repo_root_path)
 
        dbmanage.create_default_user()
 
        dbmanage.create_admin_user()
 
        dbmanage.create_permissions()
 
        dbmanage.populate_default_permissions()
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    else:  # then called again after app initialization
 
        added, _ = kallithea.lib.utils.repo2db_mapper(kallithea.model.scm.ScmModel().repo_scan())
 
        if added:
 
            click.echo('Initial repository scan: added following repositories:')
 
            click.echo('\t%s' % '\n\t'.join(added))
 
        else:
 
            click.echo('Initial repository scan: no repositories found.')
 

	
 
        click.echo('Database set up successfully.')
 
        click.echo("Don't forget to build the front-end using 'kallithea-cli front-end-build'.")
kallithea/bin/kallithea_cli_repo.py
Show inline comments
 
@@ -21,26 +21,26 @@ Original author and date, and relevant c
 
"""
 
import datetime
 
import os
 
import re
 
import shutil
 

	
 
import click
 

	
 
import kallithea
 
import kallithea.bin.kallithea_cli_base as cli_base
 
from kallithea.lib.utils import REMOVED_REPO_PAT, repo2db_mapper
 
from kallithea.lib.utils2 import ask_ok
 
from kallithea.model import meta
 
from kallithea.model.db import Repository
 
from kallithea.model.meta import Session
 
from kallithea.model.scm import ScmModel
 

	
 

	
 
@cli_base.register_command(config_file_initialize_app=True)
 
@click.option('--remove-missing', is_flag=True,
 
        help='Remove missing repositories from the Kallithea database.')
 
def repo_scan(remove_missing):
 
    """Scan filesystem for repositories.
 

	
 
    Search the configured repository root for new repositories and add them
 
    into Kallithea.
 
    Additionally, report repositories that were previously known to Kallithea
 
@@ -77,25 +77,25 @@ def repo_update_metadata(repositories):
 
    else:
 
        repo_names = [n.strip() for n in repositories]
 
        repo_list = list(Repository.query()
 
                        .filter(Repository.repo_name.in_(repo_names)))
 

	
 
    for repo in repo_list:
 
        # update latest revision metadata in database
 
        repo.update_changeset_cache()
 
        # invalidate in-memory VCS object cache... will be repopulated on
 
        # first access
 
        repo.set_invalidate()
 

	
 
    Session().commit()
 
    meta.Session().commit()
 

	
 
    click.echo('Updated database with information about latest change in the following %s repositories:' % (len(repo_list)))
 
    click.echo('\n'.join(repo.repo_name for repo in repo_list))
 

	
 
@cli_base.register_command(config_file_initialize_app=True)
 
@click.option('--ask/--no-ask', default=True, help='Ask for confirmation or not. Default is --ask.')
 
@click.option('--older-than',
 
        help="""Only purge repositories that have been removed at least the given time ago.
 
        For example, '--older-than=30d' purges repositories deleted 30 days ago or longer.
 
        Possible suffixes: d (days), h (hours), m (minutes), s (seconds).""")
 
def repo_purge_deleted(ask, older_than):
 
    """Purge backups of deleted repositories.
kallithea/controllers/admin/auth_settings.py
Show inline comments
 
@@ -28,27 +28,27 @@ import traceback
 

	
 
import formencode.htmlfill
 
from tg import request
 
from tg import tmpl_context as c
 
from tg.i18n import ugettext as _
 
from webob.exc import HTTPFound
 

	
 
from kallithea.lib import auth_modules
 
from kallithea.lib import helpers as h
 
from kallithea.lib.auth import HasPermissionAnyDecorator, LoginRequired
 
from kallithea.lib.base import BaseController, render
 
from kallithea.lib.webutils import url
 
from kallithea.model import meta
 
from kallithea.model.db import Setting
 
from kallithea.model.forms import AuthSettingsForm
 
from kallithea.model.meta import Session
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class AuthSettingsController(BaseController):
 

	
 
    @LoginRequired()
 
    @HasPermissionAnyDecorator('hg.admin')
 
    def _before(self, *args, **kwargs):
 
        super(AuthSettingsController, self)._before(*args, **kwargs)
 

	
 
@@ -123,25 +123,25 @@ class AuthSettingsController(BaseControl
 

	
 
        # Next, parse everything including plugin settings.
 
        _form = AuthSettingsForm(c.enabled_plugin_names)()
 

	
 
        try:
 
            form_result = _form.to_python(dict(request.POST))
 
            for k, v in form_result.items():
 
                if k == 'auth_plugins':
 
                    # we want to store it comma separated inside our settings
 
                    v = ','.join(v)
 
                log.debug("%s = %s", k, str(v))
 
                setting = Setting.create_or_update(k, v)
 
            Session().commit()
 
            meta.Session().commit()
 
            h.flash(_('Auth settings updated successfully'),
 
                       category='success')
 
        except formencode.Invalid as errors:
 
            log.error(traceback.format_exc())
 
            e = errors.error_dict or {}
 
            return self.__render(
 
                defaults=errors.value,
 
                errors=e,
 
            )
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('error occurred during update of auth settings'),
kallithea/controllers/admin/defaults.py
Show inline comments
 
@@ -29,27 +29,27 @@ import logging
 
import traceback
 

	
 
import formencode
 
from formencode import htmlfill
 
from tg import request
 
from tg.i18n import ugettext as _
 
from webob.exc import HTTPFound
 

	
 
from kallithea.lib import helpers as h
 
from kallithea.lib.auth import HasPermissionAnyDecorator, LoginRequired
 
from kallithea.lib.base import BaseController, render
 
from kallithea.lib.webutils import url
 
from kallithea.model import meta
 
from kallithea.model.db import Setting
 
from kallithea.model.forms import DefaultsForm
 
from kallithea.model.meta import Session
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class DefaultsController(BaseController):
 

	
 
    @LoginRequired()
 
    @HasPermissionAnyDecorator('hg.admin')
 
    def _before(self, *args, **kwargs):
 
        super(DefaultsController, self)._before(*args, **kwargs)
 

	
 
@@ -61,25 +61,25 @@ class DefaultsController(BaseController)
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False
 
        )
 

	
 
    def update(self, id):
 
        _form = DefaultsForm()()
 

	
 
        try:
 
            form_result = _form.to_python(dict(request.POST))
 
            for k, v in form_result.items():
 
                setting = Setting.create_or_update(k, v)
 
            Session().commit()
 
            meta.Session().commit()
 
            h.flash(_('Default settings updated successfully'),
 
                    category='success')
 

	
 
        except formencode.Invalid as errors:
 
            defaults = errors.value
 

	
 
            return htmlfill.render(
 
                render('admin/defaults/defaults.html'),
 
                defaults=defaults,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8",
kallithea/controllers/admin/gists.py
Show inline comments
 
@@ -33,28 +33,28 @@ from sqlalchemy.sql.expression import or
 
from tg import request, response
 
from tg import tmpl_context as c
 
from tg.i18n import ugettext as _
 
from webob.exc import HTTPForbidden, HTTPFound, HTTPNotFound
 

	
 
from kallithea.lib import helpers as h
 
from kallithea.lib.auth import LoginRequired
 
from kallithea.lib.base import BaseController, jsonify, render
 
from kallithea.lib.page import Page
 
from kallithea.lib.utils2 import safe_int, safe_str, time_to_datetime
 
from kallithea.lib.vcs.exceptions import NodeNotChangedError, VCSError
 
from kallithea.lib.webutils import url
 
from kallithea.model import meta
 
from kallithea.model.db import Gist
 
from kallithea.model.forms import GistForm
 
from kallithea.model.gist import GistModel
 
from kallithea.model.meta import Session
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class GistsController(BaseController):
 

	
 
    def __load_defaults(self, extra_values=None):
 
        c.lifetime_values = [
 
            (str(-1), _('Forever')),
 
            (str(5), _('5 minutes')),
 
            (str(60), _('1 hour')),
 
@@ -120,25 +120,25 @@ class GistsController(BaseController):
 
                }
 
            }
 
            _public = form_result['public']
 
            gist_type = Gist.GIST_PUBLIC if _public else Gist.GIST_PRIVATE
 
            gist = GistModel().create(
 
                description=form_result['description'],
 
                owner=request.authuser.user_id,
 
                ip_addr=request.ip_addr,
 
                gist_mapping=nodes,
 
                gist_type=gist_type,
 
                lifetime=form_result['lifetime']
 
            )
 
            Session().commit()
 
            meta.Session().commit()
 
            new_gist_id = gist.gist_access_id
 
        except formencode.Invalid as errors:
 
            defaults = errors.value
 

	
 
            return formencode.htmlfill.render(
 
                render('admin/gists/new.html'),
 
                defaults=defaults,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8",
 
                force_defaults=False)
 

	
 
@@ -150,25 +150,25 @@ class GistsController(BaseController):
 

	
 
    @LoginRequired()
 
    def new(self, format='html'):
 
        self.__load_defaults()
 
        return render('admin/gists/new.html')
 

	
 
    @LoginRequired()
 
    def delete(self, gist_id):
 
        gist = GistModel().get_gist(gist_id)
 
        owner = gist.owner_id == request.authuser.user_id
 
        if h.HasPermissionAny('hg.admin')() or owner:
 
            GistModel().delete(gist)
 
            Session().commit()
 
            meta.Session().commit()
 
            h.flash(_('Deleted gist %s') % gist.gist_access_id, category='success')
 
        else:
 
            raise HTTPForbidden()
 

	
 
        raise HTTPFound(location=url('gists'))
 

	
 
    @LoginRequired(allow_default_user=True)
 
    def show(self, gist_id, revision='tip', format='html', f_path=None):
 
        c.gist = Gist.get_or_404(gist_id)
 

	
 
        if c.gist.is_expired:
 
            log.error('Gist expired at %s',
 
@@ -223,30 +223,30 @@ class GistsController(BaseController):
 
                }
 
            try:
 
                GistModel().update(
 
                    gist=c.gist,
 
                    description=rpost['description'],
 
                    owner=c.gist.owner, # FIXME: request.authuser.user_id ?
 
                    ip_addr=request.ip_addr,
 
                    gist_mapping=nodes,
 
                    gist_type=c.gist.gist_type,
 
                    lifetime=rpost['lifetime']
 
                )
 

	
 
                Session().commit()
 
                meta.Session().commit()
 
                h.flash(_('Successfully updated gist content'), category='success')
 
            except NodeNotChangedError:
 
                # raised if nothing was changed in repo itself. We anyway then
 
                # store only DB stuff for gist
 
                Session().commit()
 
                meta.Session().commit()
 
                h.flash(_('Successfully updated gist data'), category='success')
 
            except Exception:
 
                log.error(traceback.format_exc())
 
                h.flash(_('Error occurred during update of gist %s') % gist_id,
 
                        category='error')
 

	
 
            raise HTTPFound(location=url('gist', gist_id=gist_id))
 

	
 
        return rendered
 

	
 
    @LoginRequired()
 
    @jsonify
kallithea/controllers/admin/my_account.py
Show inline comments
 
@@ -32,59 +32,59 @@ import formencode
 
from formencode import htmlfill
 
from tg import request
 
from tg import tmpl_context as c
 
from tg.i18n import ugettext as _
 
from webob.exc import HTTPFound
 

	
 
from kallithea.lib import auth_modules
 
from kallithea.lib import helpers as h
 
from kallithea.lib.auth import AuthUser, LoginRequired
 
from kallithea.lib.base import BaseController, IfSshEnabled, render
 
from kallithea.lib.utils2 import generate_api_key, safe_int
 
from kallithea.lib.webutils import url
 
from kallithea.model import meta
 
from kallithea.model.api_key import ApiKeyModel
 
from kallithea.model.db import Repository, User, UserEmailMap, UserFollowing
 
from kallithea.model.forms import PasswordChangeForm, UserForm
 
from kallithea.model.meta import Session
 
from kallithea.model.repo import RepoModel
 
from kallithea.model.ssh_key import SshKeyModel, SshKeyModelException
 
from kallithea.model.user import UserModel
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class MyAccountController(BaseController):
 

	
 
    @LoginRequired()
 
    def _before(self, *args, **kwargs):
 
        super(MyAccountController, self)._before(*args, **kwargs)
 

	
 
    def __load_data(self):
 
        c.user = User.get(request.authuser.user_id)
 
        if c.user.is_default_user:
 
            h.flash(_("You can't edit this user since it's"
 
                      " crucial for entire application"), category='warning')
 
            raise HTTPFound(location=url('users'))
 

	
 
    def _load_my_repos_data(self, watched=False):
 
        if watched:
 
            admin = False
 
            repos_list = Session().query(Repository) \
 
            repos_list = meta.Session().query(Repository) \
 
                         .join(UserFollowing) \
 
                         .filter(UserFollowing.user_id ==
 
                                 request.authuser.user_id).all()
 
        else:
 
            admin = True
 
            repos_list = Session().query(Repository) \
 
            repos_list = meta.Session().query(Repository) \
 
                         .filter(Repository.owner_id ==
 
                                 request.authuser.user_id).all()
 

	
 
        return RepoModel().get_repos_as_dict(repos_list, admin=admin)
 

	
 
    def my_account(self):
 
        c.active = 'profile'
 
        self.__load_data()
 
        c.perm_user = AuthUser(user_id=request.authuser.user_id)
 
        managed_fields = auth_modules.get_managed_fields(c.user)
 
        def_user_perms = AuthUser(dbuser=User.get_default_user()).global_permissions
 
        if 'hg.register.none' in def_user_perms:
 
@@ -104,25 +104,25 @@ class MyAccountController(BaseController
 
                post_data['new_password'] = ''
 
                post_data['password_confirmation'] = ''
 
                form_result = _form.to_python(post_data)
 
                # skip updating those attrs for my account
 
                skip_attrs = ['admin', 'active', 'extern_type', 'extern_name',
 
                              'new_password', 'password_confirmation',
 
                             ] + managed_fields
 

	
 
                UserModel().update(request.authuser.user_id, form_result,
 
                                   skip_attrs=skip_attrs)
 
                h.flash(_('Your account was updated successfully'),
 
                        category='success')
 
                Session().commit()
 
                meta.Session().commit()
 
                update = True
 

	
 
            except formencode.Invalid as errors:
 
                return htmlfill.render(
 
                    render('admin/my_account/my_account.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())
 
@@ -139,25 +139,25 @@ class MyAccountController(BaseController
 
    def my_account_password(self):
 
        c.active = 'password'
 
        self.__load_data()
 

	
 
        managed_fields = auth_modules.get_managed_fields(c.user)
 
        c.can_change_password = 'password' not in managed_fields
 

	
 
        if request.POST and c.can_change_password:
 
            _form = PasswordChangeForm(request.authuser.username)()
 
            try:
 
                form_result = _form.to_python(request.POST)
 
                UserModel().update(request.authuser.user_id, form_result)
 
                Session().commit()
 
                meta.Session().commit()
 
                h.flash(_("Successfully updated password"), category='success')
 
            except formencode.Invalid as errors:
 
                return htmlfill.render(
 
                    render('admin/my_account/my_account.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(_('Error occurred during update of user password'),
 
@@ -191,101 +191,101 @@ class MyAccountController(BaseController
 
        c.active = 'emails'
 
        self.__load_data()
 

	
 
        c.user_email_map = UserEmailMap.query() \
 
            .filter(UserEmailMap.user == c.user).all()
 
        return render('admin/my_account/my_account.html')
 

	
 
    def my_account_emails_add(self):
 
        email = request.POST.get('new_email')
 

	
 
        try:
 
            UserModel().add_extra_email(request.authuser.user_id, email)
 
            Session().commit()
 
            meta.Session().commit()
 
            h.flash(_("Added email %s to user") % email, category='success')
 
        except formencode.Invalid as error:
 
            msg = error.error_dict['email']
 
            h.flash(msg, category='error')
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during email saving'),
 
                    category='error')
 
        raise HTTPFound(location=url('my_account_emails'))
 

	
 
    def my_account_emails_delete(self):
 
        email_id = request.POST.get('del_email_id')
 
        user_model = UserModel()
 
        user_model.delete_extra_email(request.authuser.user_id, email_id)
 
        Session().commit()
 
        meta.Session().commit()
 
        h.flash(_("Removed email from user"), category='success')
 
        raise HTTPFound(location=url('my_account_emails'))
 

	
 
    def my_account_api_keys(self):
 
        c.active = 'api_keys'
 
        self.__load_data()
 
        show_expired = True
 
        c.lifetime_values = [
 
            (str(-1), _('Forever')),
 
            (str(5), _('5 minutes')),
 
            (str(60), _('1 hour')),
 
            (str(60 * 24), _('1 day')),
 
            (str(60 * 24 * 30), _('1 month')),
 
        ]
 
        c.lifetime_options = [(c.lifetime_values, _("Lifetime"))]
 
        c.user_api_keys = ApiKeyModel().get_api_keys(request.authuser.user_id,
 
                                                     show_expired=show_expired)
 
        return render('admin/my_account/my_account.html')
 

	
 
    def my_account_api_keys_add(self):
 
        lifetime = safe_int(request.POST.get('lifetime'), -1)
 
        description = request.POST.get('description')
 
        ApiKeyModel().create(request.authuser.user_id, description, lifetime)
 
        Session().commit()
 
        meta.Session().commit()
 
        h.flash(_("API key successfully created"), category='success')
 
        raise HTTPFound(location=url('my_account_api_keys'))
 

	
 
    def my_account_api_keys_delete(self):
 
        api_key = request.POST.get('del_api_key')
 
        if request.POST.get('del_api_key_builtin'):
 
            user = User.get(request.authuser.user_id)
 
            user.api_key = generate_api_key()
 
            Session().commit()
 
            meta.Session().commit()
 
            h.flash(_("API key successfully reset"), category='success')
 
        elif api_key:
 
            ApiKeyModel().delete(api_key, request.authuser.user_id)
 
            Session().commit()
 
            meta.Session().commit()
 
            h.flash(_("API key successfully deleted"), category='success')
 

	
 
        raise HTTPFound(location=url('my_account_api_keys'))
 

	
 
    @IfSshEnabled
 
    def my_account_ssh_keys(self):
 
        c.active = 'ssh_keys'
 
        self.__load_data()
 
        c.user_ssh_keys = SshKeyModel().get_ssh_keys(request.authuser.user_id)
 
        return render('admin/my_account/my_account.html')
 

	
 
    @IfSshEnabled
 
    def my_account_ssh_keys_add(self):
 
        description = request.POST.get('description')
 
        public_key = request.POST.get('public_key')
 
        try:
 
            new_ssh_key = SshKeyModel().create(request.authuser.user_id,
 
                                               description, public_key)
 
            Session().commit()
 
            meta.Session().commit()
 
            SshKeyModel().write_authorized_keys()
 
            h.flash(_("SSH key %s successfully added") % new_ssh_key.fingerprint, category='success')
 
        except SshKeyModelException as e:
 
            h.flash(e.args[0], category='error')
 
        raise HTTPFound(location=url('my_account_ssh_keys'))
 

	
 
    @IfSshEnabled
 
    def my_account_ssh_keys_delete(self):
 
        fingerprint = request.POST.get('del_public_key_fingerprint')
 
        try:
 
            SshKeyModel().delete(fingerprint, request.authuser.user_id)
 
            Session().commit()
 
            meta.Session().commit()
 
            SshKeyModel().write_authorized_keys()
 
            h.flash(_("SSH key successfully deleted"), category='success')
 
        except SshKeyModelException as e:
 
            h.flash(e.args[0], category='error')
 
        raise HTTPFound(location=url('my_account_ssh_keys'))
kallithea/controllers/admin/permissions.py
Show inline comments
 
@@ -31,27 +31,27 @@ import traceback
 

	
 
import formencode
 
from formencode import htmlfill
 
from tg import request
 
from tg import tmpl_context as c
 
from tg.i18n import ugettext as _
 
from webob.exc import HTTPFound
 

	
 
from kallithea.lib import helpers as h
 
from kallithea.lib.auth import AuthUser, HasPermissionAnyDecorator, LoginRequired
 
from kallithea.lib.base import BaseController, render
 
from kallithea.lib.webutils import url
 
from kallithea.model import meta
 
from kallithea.model.db import User, UserIpMap
 
from kallithea.model.forms import DefaultPermissionsForm
 
from kallithea.model.meta import Session
 
from kallithea.model.permission import PermissionModel
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class PermissionsController(BaseController):
 

	
 
    @LoginRequired()
 
    @HasPermissionAnyDecorator('hg.admin')
 
    def _before(self, *args, **kwargs):
 
        super(PermissionsController, self)._before(*args, **kwargs)
 
@@ -104,25 +104,25 @@ class PermissionsController(BaseControll
 
                [x[0] for x in c.group_perms_choices],
 
                [x[0] for x in c.user_group_perms_choices],
 
                [x[0] for x in c.repo_create_choices],
 
                [x[0] for x in c.user_group_create_choices],
 
                [x[0] for x in c.fork_choices],
 
                [x[0] for x in c.register_choices],
 
                [x[0] for x in c.extern_activate_choices])()
 

	
 
            try:
 
                form_result = _form.to_python(dict(request.POST))
 
                form_result.update({'perm_user_name': 'default'})
 
                PermissionModel().update(form_result)
 
                Session().commit()
 
                meta.Session().commit()
 
                h.flash(_('Global permissions updated successfully'),
 
                        category='success')
 

	
 
            except formencode.Invalid as errors:
 
                defaults = errors.value
 

	
 
                return htmlfill.render(
 
                    render('admin/permissions/permissions.html'),
 
                    defaults=defaults,
 
                    errors=errors.error_dict or {},
 
                    prefix_error=False,
 
                    encoding="UTF-8",
kallithea/controllers/admin/repo_groups.py
Show inline comments
 
@@ -32,27 +32,27 @@ import formencode
 
from formencode import htmlfill
 
from tg import app_globals, request
 
from tg import tmpl_context as c
 
from tg.i18n import ugettext as _
 
from tg.i18n import ungettext
 
from webob.exc import HTTPForbidden, HTTPFound, HTTPInternalServerError, HTTPNotFound
 

	
 
from kallithea.lib import helpers as h
 
from kallithea.lib.auth import HasPermissionAny, HasRepoGroupPermissionLevel, HasRepoGroupPermissionLevelDecorator, LoginRequired
 
from kallithea.lib.base import BaseController, render
 
from kallithea.lib.utils2 import safe_int
 
from kallithea.lib.webutils import url
 
from kallithea.model import meta
 
from kallithea.model.db import RepoGroup, Repository
 
from kallithea.model.forms import RepoGroupForm, RepoGroupPermsForm
 
from kallithea.model.meta import Session
 
from kallithea.model.repo import RepoModel
 
from kallithea.model.repo_group import RepoGroupModel
 
from kallithea.model.scm import AvailableRepoGroupChoices, RepoGroupList
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class RepoGroupsController(BaseController):
 

	
 
    @LoginRequired(allow_default_user=True)
 
    def _before(self, *args, **kwargs):
 
@@ -141,25 +141,25 @@ class RepoGroupsController(BaseControlle
 
        # here in the Form
 
        repo_group_form = RepoGroupForm(repo_groups=c.repo_groups)
 
        form_result = None
 
        try:
 
            form_result = repo_group_form.to_python(dict(request.POST))
 
            gr = RepoGroupModel().create(
 
                group_name=form_result['group_name'],
 
                group_description=form_result['group_description'],
 
                parent=form_result['parent_group_id'],
 
                owner=request.authuser.user_id, # TODO: make editable
 
                copy_permissions=form_result['group_copy_permissions']
 
            )
 
            Session().commit()
 
            meta.Session().commit()
 
            # TODO: in future action_logger(, '', '', '')
 
        except formencode.Invalid as errors:
 
            return htmlfill.render(
 
                render('admin/repo_groups/repo_group_add.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(_('Error occurred during creation of repository group %s')
 
@@ -206,25 +206,25 @@ class RepoGroupsController(BaseControlle
 
        else:
 
            allow_empty_group = False
 
        repo_group_form = RepoGroupForm(
 
            edit=True,
 
            old_data=c.repo_group.get_dict(),
 
            repo_groups=c.repo_groups,
 
            can_create_in_root=allow_empty_group,
 
        )()
 
        try:
 
            form_result = repo_group_form.to_python(dict(request.POST))
 

	
 
            new_gr = RepoGroupModel().update(group_name, form_result)
 
            Session().commit()
 
            meta.Session().commit()
 
            h.flash(_('Updated repository group %s')
 
                    % form_result['group_name'], category='success')
 
            # we now have new name !
 
            group_name = new_gr.group_name
 
            # TODO: in future action_logger(, '', '', '')
 
        except formencode.Invalid as errors:
 
            c.active = 'settings'
 
            return htmlfill.render(
 
                render('admin/repo_groups/repo_group_edit.html'),
 
                defaults=errors.value,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
@@ -245,25 +245,25 @@ class RepoGroupsController(BaseControlle
 
            h.flash(_('This group contains %s repositories and cannot be '
 
                      'deleted') % len(repos), category='warning')
 
            raise HTTPFound(location=url('repos_groups'))
 

	
 
        children = gr.children.all()
 
        if children:
 
            h.flash(_('This group contains %s subgroups and cannot be deleted'
 
                      % (len(children))), category='warning')
 
            raise HTTPFound(location=url('repos_groups'))
 

	
 
        try:
 
            RepoGroupModel().delete(group_name)
 
            Session().commit()
 
            meta.Session().commit()
 
            h.flash(_('Removed repository group %s') % group_name,
 
                    category='success')
 
            # TODO: in future action_logger(, '', '', '')
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('Error occurred during deletion of repository group %s')
 
                    % group_name, category='error')
 

	
 
        if gr.parent_group:
 
            raise HTTPFound(location=url('repos_group_home', group_name=gr.parent_group.group_name))
 
        raise HTTPFound(location=url('repos_groups'))
 

	
 
@@ -349,25 +349,25 @@ class RepoGroupsController(BaseControlle
 
                raise HTTPFound(location=url('edit_repo_group_perms', group_name=group_name))
 
        recursive = form_result['recursive']
 
        # iterate over all members(if in recursive mode) of this groups and
 
        # set the permissions !
 
        # this can be potentially heavy operation
 
        RepoGroupModel()._update_permissions(c.repo_group,
 
                                             form_result['perms_new'],
 
                                             form_result['perms_updates'],
 
                                             recursive)
 
        # TODO: implement this
 
        #action_logger(request.authuser, 'admin_changed_repo_permissions',
 
        #              repo_name, request.ip_addr)
 
        Session().commit()
 
        meta.Session().commit()
 
        h.flash(_('Repository group permissions updated'), category='success')
 
        raise HTTPFound(location=url('edit_repo_group_perms', group_name=group_name))
 

	
 
    @HasRepoGroupPermissionLevelDecorator('admin')
 
    def delete_perms(self, group_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'))
 
@@ -379,18 +379,18 @@ class RepoGroupsController(BaseControlle
 
                    raise Exception('revoke admin permission on self')
 
            recursive = request.POST.get('recursive', 'none')
 
            if obj_type == 'user':
 
                RepoGroupModel().delete_permission(repo_group=group_name,
 
                                                   obj=obj_id, obj_type='user',
 
                                                   recursive=recursive)
 
            elif obj_type == 'user_group':
 
                RepoGroupModel().delete_permission(repo_group=group_name,
 
                                                   obj=obj_id,
 
                                                   obj_type='user_group',
 
                                                   recursive=recursive)
 

	
 
            Session().commit()
 
            meta.Session().commit()
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during revoking of permission'),
 
                    category='error')
 
            raise HTTPInternalServerError()
kallithea/controllers/admin/repos.py
Show inline comments
 
@@ -36,27 +36,27 @@ from tg import tmpl_context as c
 
from tg.i18n import ugettext as _
 
from webob.exc import HTTPForbidden, HTTPFound, HTTPInternalServerError, HTTPNotFound
 

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

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class ReposController(BaseRepoController):
 

	
 
    @LoginRequired(allow_default_user=True)
 
    def _before(self, *args, **kwargs):
 
        super(ReposController, self)._before(*args, **kwargs)
 
@@ -217,25 +217,25 @@ class ReposController(BaseRepoController
 
                         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(request.authuser, 'admin_updated_repo',
 
                changed_name, request.ip_addr)
 
            Session().commit()
 
            meta.Session().commit()
 
        except formencode.Invalid as errors:
 
            log.info(errors)
 
            defaults = self.__load_data()
 
            defaults.update(errors.value)
 
            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)
 

	
 
@@ -259,25 +259,25 @@ class ReposController(BaseRepoController
 
                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(request.authuser, 'admin_deleted_repo',
 
                repo_name, request.ip_addr)
 
            ScmModel().mark_for_invalidation(repo_name)
 
            h.flash(_('Deleted repository %s') % repo_name, category='success')
 
            Session().commit()
 
            meta.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'))
 
@@ -305,25 +305,25 @@ class ReposController(BaseRepoController
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False)
 

	
 
    @HasRepoPermissionLevelDecorator('admin')
 
    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(request.authuser, 'admin_changed_repo_permissions',
 
        #              repo_name, request.ip_addr)
 
        Session().commit()
 
        meta.Session().commit()
 
        h.flash(_('Repository permissions updated'), category='success')
 
        raise HTTPFound(location=url('edit_repo_perms', repo_name=repo_name))
 

	
 
    @HasRepoPermissionLevelDecorator('admin')
 
    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'))
 
@@ -332,25 +332,25 @@ class ReposController(BaseRepoController
 

	
 
            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
 
                )
 
            else:
 
                assert False
 
            # TODO: implement this
 
            #action_logger(request.authuser, 'admin_revoked_repo_permissions',
 
            #              repo_name, request.ip_addr)
 
            Session().commit()
 
            meta.Session().commit()
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during revoking of permission'),
 
                    category='error')
 
            raise HTTPInternalServerError()
 
        return []
 

	
 
    @HasRepoPermissionLevelDecorator('admin')
 
    def edit_fields(self, repo_name):
 
        c.repo_info = self._load_repo()
 
        c.repo_fields = RepositoryField.query() \
 
            .filter(RepositoryField.repository == c.repo_info).all()
 
@@ -362,39 +362,39 @@ class ReposController(BaseRepoController
 

	
 
    @HasRepoPermissionLevelDecorator('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()
 
            meta.Session().add(new_field)
 
            meta.Session().commit()
 
        except formencode.Invalid as e:
 
            h.flash(_('Field validation error: %s') % e.msg, category='error')
 
        except Exception as e:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during creation of field: %r') % e, category='error')
 
        raise HTTPFound(location=url('edit_repo_fields', repo_name=repo_name))
 

	
 
    @HasRepoPermissionLevelDecorator('admin')
 
    def delete_repo_field(self, repo_name, field_id):
 
        field = RepositoryField.get_or_404(field_id)
 
        try:
 
            Session().delete(field)
 
            Session().commit()
 
            meta.Session().delete(field)
 
            meta.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))
 

	
 
    @HasRepoPermissionLevelDecorator('admin')
 
    def edit_advanced(self, repo_name):
 
        c.repo_info = self._load_repo()
 
        c.default_user_id = kallithea.DEFAULT_USER_ID
 
        c.in_public_journal = UserFollowing.query() \
 
            .filter(UserFollowing.user_id == c.default_user_id) \
 
@@ -427,44 +427,44 @@ class ReposController(BaseRepoController
 
        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 = kallithea.DEFAULT_USER_ID
 
            self.scm_model.toggle_following_repo(repo_id, user_id)
 
            h.flash(_('Updated repository visibility in public journal'),
 
                    category='success')
 
            Session().commit()
 
            meta.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))
 

	
 
    @HasRepoPermissionLevelDecorator('admin')
 
    def edit_advanced_fork(self, repo_name):
 
        """
 
        Mark given repository as a fork of another
 

	
 
        :param repo_name:
 
        """
 
        try:
 
            fork_id = request.POST.get('id_fork_of')
 
            repo = ScmModel().mark_as_fork(repo_name, fork_id,
 
                                           request.authuser.username)
 
            fork = repo.fork.repo_name if repo.fork else _('Nothing')
 
            Session().commit()
 
            meta.Session().commit()
 
            h.flash(_('Marked repository %s as fork of %s') % (repo_name, fork),
 
                    category='success')
 
        except RepositoryError as e:
 
            log.error(traceback.format_exc())
 
            h.flash(e, category='error')
 
        except Exception as e:
 
            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))
 

	
 
@@ -497,20 +497,20 @@ class ReposController(BaseRepoController
 

	
 
        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()
 
                meta.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/admin/settings.py
Show inline comments
 
@@ -34,27 +34,27 @@ from tg import config, request
 
from tg import tmpl_context as c
 
from tg.i18n import ugettext as _
 
from webob.exc import HTTPFound
 

	
 
from kallithea.lib import helpers as h
 
from kallithea.lib.auth import HasPermissionAnyDecorator, LoginRequired
 
from kallithea.lib.base import BaseController, render
 
from kallithea.lib.celerylib import tasks
 
from kallithea.lib.utils import repo2db_mapper, set_app_settings
 
from kallithea.lib.utils2 import safe_str
 
from kallithea.lib.vcs import VCSError
 
from kallithea.lib.webutils import url
 
from kallithea.model import meta
 
from kallithea.model.db import Repository, Setting, Ui
 
from kallithea.model.forms import ApplicationSettingsForm, ApplicationUiSettingsForm, ApplicationVisualisationForm
 
from kallithea.model.meta import Session
 
from kallithea.model.notification import EmailNotificationModel
 
from kallithea.model.scm import ScmModel
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class SettingsController(BaseController):
 

	
 
    @LoginRequired(allow_default_user=True)
 
    def _before(self, *args, **kwargs):
 
        super(SettingsController, self)._before(*args, **kwargs)
 
@@ -103,25 +103,25 @@ class SettingsController(BaseController)
 
                sett.ui_active = form_result['hooks_changegroup_update']
 

	
 
                sett = Ui.get_by_key('hooks', Ui.HOOK_REPO_SIZE)
 
                sett.ui_active = form_result['hooks_changegroup_repo_size']
 

	
 
                ## EXTENSIONS
 
                sett = Ui.get_or_create('extensions', 'largefiles')
 
                sett.ui_active = form_result['extensions_largefiles']
 

	
 
#                sett = Ui.get_or_create('extensions', 'hggit')
 
#                sett.ui_active = form_result['extensions_hggit']
 

	
 
                Session().commit()
 
                meta.Session().commit()
 

	
 
                h.flash(_('Updated VCS settings'), category='success')
 

	
 
            except Exception:
 
                log.error(traceback.format_exc())
 
                h.flash(_('Error occurred while updating '
 
                          'application settings'), category='error')
 

	
 
        defaults = Setting.get_app_settings()
 
        defaults.update(self._get_hg_ui_settings())
 

	
 
        return htmlfill.render(
 
@@ -195,25 +195,25 @@ class SettingsController(BaseController)
 
                    force_defaults=False)
 

	
 
            try:
 
                for setting in (
 
                    'title',
 
                    'realm',
 
                    'ga_code',
 
                    'captcha_public_key',
 
                    'captcha_private_key',
 
                ):
 
                    Setting.create_or_update(setting, form_result[setting])
 

	
 
                Session().commit()
 
                meta.Session().commit()
 
                set_app_settings(config)
 
                h.flash(_('Updated application settings'), category='success')
 

	
 
            except Exception:
 
                log.error(traceback.format_exc())
 
                h.flash(_('Error occurred while updating '
 
                          'application settings'),
 
                          category='error')
 

	
 
            raise HTTPFound(location=url('admin_settings_global'))
 

	
 
        defaults = Setting.get_app_settings()
 
@@ -249,25 +249,25 @@ class SettingsController(BaseController)
 
                    ('repository_fields', 'repository_fields', 'bool'),
 
                    ('dashboard_items', 'dashboard_items', 'int'),
 
                    ('admin_grid_items', 'admin_grid_items', 'int'),
 
                    ('show_version', 'show_version', 'bool'),
 
                    ('use_gravatar', 'use_gravatar', 'bool'),
 
                    ('gravatar_url', 'gravatar_url', 'unicode'),
 
                    ('clone_uri_tmpl', 'clone_uri_tmpl', 'unicode'),
 
                    ('clone_ssh_tmpl', 'clone_ssh_tmpl', 'unicode'),
 
                ]
 
                for setting, form_key, type_ in settings:
 
                    Setting.create_or_update(setting, form_result[form_key], type_)
 

	
 
                Session().commit()
 
                meta.Session().commit()
 
                set_app_settings(config)
 
                h.flash(_('Updated visualisation settings'),
 
                        category='success')
 

	
 
            except Exception:
 
                log.error(traceback.format_exc())
 
                h.flash(_('Error occurred during updating '
 
                          'visualisation settings'),
 
                        category='error')
 

	
 
            raise HTTPFound(location=url('admin_settings_visual'))
 

	
 
@@ -331,39 +331,39 @@ class SettingsController(BaseController)
 

	
 
                try:
 
                    ui_key = ui_key and ui_key.strip()
 
                    if ui_key in (x.ui_key for x in Ui.get_custom_hooks()):
 
                        h.flash(_('Hook already exists'), category='error')
 
                    elif ui_key in (x.ui_key for x in Ui.get_builtin_hooks()):
 
                        h.flash(_('Builtin hooks are read-only. Please use another hook name.'), category='error')
 
                    elif ui_value and ui_key:
 
                        Ui.create_or_update_hook(ui_key, ui_value)
 
                        h.flash(_('Added new hook'), category='success')
 
                    elif hook_id:
 
                        Ui.delete(hook_id)
 
                        Session().commit()
 
                        meta.Session().commit()
 

	
 
                    # check for edits
 
                    update = False
 
                    _d = request.POST.dict_of_lists()
 
                    for k, v, ov in zip(_d.get('hook_ui_key', []),
 
                                        _d.get('hook_ui_value_new', []),
 
                                        _d.get('hook_ui_value', [])):
 
                        if v != ov:
 
                            Ui.create_or_update_hook(k, v)
 
                            update = True
 

	
 
                    if update:
 
                        h.flash(_('Updated hooks'), category='success')
 
                    Session().commit()
 
                    meta.Session().commit()
 
                except Exception:
 
                    log.error(traceback.format_exc())
 
                    h.flash(_('Error occurred during hook creation'),
 
                            category='error')
 

	
 
                raise HTTPFound(location=url('admin_settings_hooks'))
 

	
 
        defaults = Setting.get_app_settings()
 
        defaults.update(self._get_hg_ui_settings())
 

	
 
        c.hooks = Ui.get_builtin_hooks()
 
        c.custom_hooks = Ui.get_custom_hooks()
kallithea/controllers/admin/user_groups.py
Show inline comments
 
@@ -35,27 +35,27 @@ from sqlalchemy.sql.expression import fu
 
from tg import app_globals, request
 
from tg import tmpl_context as c
 
from tg.i18n import ugettext as _
 
from webob.exc import HTTPFound, HTTPInternalServerError
 

	
 
from kallithea.lib import helpers as h
 
from kallithea.lib.auth import HasPermissionAnyDecorator, HasUserGroupPermissionLevelDecorator, LoginRequired
 
from kallithea.lib.base import BaseController, render
 
from kallithea.lib.exceptions import RepoGroupAssignmentError, UserGroupsAssignedException
 
from kallithea.lib.utils import action_logger
 
from kallithea.lib.utils2 import safe_int, safe_str
 
from kallithea.lib.webutils import url
 
from kallithea.model import meta
 
from kallithea.model.db import User, UserGroup, UserGroupRepoGroupToPerm, UserGroupRepoToPerm, UserGroupToPerm
 
from kallithea.model.forms import CustomDefaultPermissionsForm, UserGroupForm, UserGroupPermsForm
 
from kallithea.model.meta import Session
 
from kallithea.model.scm import UserGroupList
 
from kallithea.model.user_group import UserGroupModel
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class UserGroupsController(BaseController):
 

	
 
    @LoginRequired(allow_default_user=True)
 
    def _before(self, *args, **kwargs):
 
        super(UserGroupsController, self)._before(*args, **kwargs)
 
@@ -123,25 +123,25 @@ class UserGroupsController(BaseControlle
 
            form_result = users_group_form.to_python(dict(request.POST))
 
            ug = UserGroupModel().create(name=form_result['users_group_name'],
 
                                         description=form_result['user_group_description'],
 
                                         owner=request.authuser.user_id,
 
                                         active=form_result['users_group_active'])
 

	
 
            gr = form_result['users_group_name']
 
            action_logger(request.authuser,
 
                          'admin_created_users_group:%s' % gr,
 
                          None, request.ip_addr)
 
            h.flash(h.HTML(_('Created user group %s')) % h.link_to(gr, url('edit_users_group', id=ug.users_group_id)),
 
                category='success')
 
            Session().commit()
 
            meta.Session().commit()
 
        except formencode.Invalid as errors:
 
            return htmlfill.render(
 
                render('admin/user_groups/user_group_add.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(_('Error occurred during creation of user group %s')
 
                    % request.POST.get('users_group_name'), category='error')
 
@@ -163,25 +163,25 @@ class UserGroupsController(BaseControlle
 
        users_group_form = UserGroupForm(edit=True,
 
                                         old_data=c.user_group.get_dict(),
 
                                         available_members=available_members)()
 

	
 
        try:
 
            form_result = users_group_form.to_python(request.POST)
 
            UserGroupModel().update(c.user_group, form_result)
 
            gr = form_result['users_group_name']
 
            action_logger(request.authuser,
 
                          'admin_updated_users_group:%s' % gr,
 
                          None, request.ip_addr)
 
            h.flash(_('Updated user group %s') % gr, category='success')
 
            Session().commit()
 
            meta.Session().commit()
 
        except formencode.Invalid as errors:
 
            ug_model = UserGroupModel()
 
            defaults = errors.value
 
            e = errors.error_dict or {}
 
            defaults.update({
 
                'create_repo_perm': ug_model.has_perm(id,
 
                                                      'hg.create.repository'),
 
                'fork_repo_perm': ug_model.has_perm(id,
 
                                                    'hg.fork.repository'),
 
            })
 

	
 
            return htmlfill.render(
 
@@ -194,25 +194,25 @@ class UserGroupsController(BaseControlle
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('Error occurred during update of user group %s')
 
                    % request.POST.get('users_group_name'), category='error')
 

	
 
        raise HTTPFound(location=url('edit_users_group', id=id))
 

	
 
    @HasUserGroupPermissionLevelDecorator('admin')
 
    def delete(self, id):
 
        usr_gr = UserGroup.get_or_404(id)
 
        try:
 
            UserGroupModel().delete(usr_gr)
 
            Session().commit()
 
            meta.Session().commit()
 
            h.flash(_('Successfully deleted user group'), category='success')
 
        except UserGroupsAssignedException as e:
 
            h.flash(e, category='error')
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during deletion of user group'),
 
                    category='error')
 
        raise HTTPFound(location=url('users_groups'))
 

	
 
    @HasUserGroupPermissionLevelDecorator('admin')
 
    def edit(self, id, format='html'):
 
        c.user_group = UserGroup.get_or_404(id)
 
@@ -261,50 +261,50 @@ class UserGroupsController(BaseControlle
 
        form = UserGroupPermsForm()().to_python(request.POST)
 

	
 
        # set the permissions !
 
        try:
 
            UserGroupModel()._update_permissions(user_group, form['perms_new'],
 
                                                 form['perms_updates'])
 
        except RepoGroupAssignmentError:
 
            h.flash(_('Target group cannot be the same'), category='error')
 
            raise HTTPFound(location=url('edit_user_group_perms', id=id))
 
        # TODO: implement this
 
        #action_logger(request.authuser, 'admin_changed_repo_permissions',
 
        #              repo_name, request.ip_addr)
 
        Session().commit()
 
        meta.Session().commit()
 
        h.flash(_('User group permissions updated'), category='success')
 
        raise HTTPFound(location=url('edit_user_group_perms', id=id))
 

	
 
    @HasUserGroupPermissionLevelDecorator('admin')
 
    def delete_perms(self, id):
 
        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 not request.authuser.is_admin:
 
                if obj_type == 'user' and request.authuser.user_id == obj_id:
 
                    msg = _('Cannot revoke permission for yourself as admin')
 
                    h.flash(msg, category='warning')
 
                    raise Exception('revoke admin permission on self')
 
            if obj_type == 'user':
 
                UserGroupModel().revoke_user_permission(user_group=id,
 
                                                        user=obj_id)
 
            elif obj_type == 'user_group':
 
                UserGroupModel().revoke_user_group_permission(target_user_group=id,
 
                                                              user_group=obj_id)
 
            Session().commit()
 
            meta.Session().commit()
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during revoking of permission'),
 
                    category='error')
 
            raise HTTPInternalServerError()
 

	
 
    @HasUserGroupPermissionLevelDecorator('admin')
 
    def edit_default_perms(self, id):
 
        c.user_group = UserGroup.get_or_404(id)
 
        c.active = 'default_perms'
 

	
 
        permissions = {
 
@@ -356,41 +356,41 @@ class UserGroupsController(BaseControlle
 
        user_group = UserGroup.get_or_404(id)
 

	
 
        try:
 
            form = CustomDefaultPermissionsForm()()
 
            form_result = form.to_python(request.POST)
 

	
 
            usergroup_model = UserGroupModel()
 

	
 
            defs = UserGroupToPerm.query() \
 
                .filter(UserGroupToPerm.users_group == user_group) \
 
                .all()
 
            for ug in defs:
 
                Session().delete(ug)
 
                meta.Session().delete(ug)
 

	
 
            if form_result['create_repo_perm']:
 
                usergroup_model.grant_perm(id, 'hg.create.repository')
 
            else:
 
                usergroup_model.grant_perm(id, 'hg.create.none')
 
            if form_result['create_user_group_perm']:
 
                usergroup_model.grant_perm(id, 'hg.usergroup.create.true')
 
            else:
 
                usergroup_model.grant_perm(id, 'hg.usergroup.create.false')
 
            if form_result['fork_repo_perm']:
 
                usergroup_model.grant_perm(id, 'hg.fork.repository')
 
            else:
 
                usergroup_model.grant_perm(id, 'hg.fork.none')
 

	
 
            h.flash(_("Updated permissions"), category='success')
 
            Session().commit()
 
            meta.Session().commit()
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during permissions saving'),
 
                    category='error')
 

	
 
        raise HTTPFound(location=url('edit_user_group_default_perms', id=id))
 

	
 
    @HasUserGroupPermissionLevelDecorator('admin')
 
    def edit_advanced(self, id):
 
        c.user_group = UserGroup.get_or_404(id)
 
        c.active = 'advanced'
 
        c.group_members_obj = sorted((x.user for x in c.user_group.members),
kallithea/controllers/admin/users.py
Show inline comments
 
@@ -36,28 +36,28 @@ from tg import tmpl_context as c
 
from tg.i18n import ugettext as _
 
from webob.exc import HTTPFound, HTTPNotFound
 

	
 
import kallithea
 
from kallithea.lib import auth_modules
 
from kallithea.lib import helpers as h
 
from kallithea.lib.auth import AuthUser, HasPermissionAnyDecorator, LoginRequired
 
from kallithea.lib.base import BaseController, IfSshEnabled, render
 
from kallithea.lib.exceptions import DefaultUserException, UserCreationError, UserOwnsReposException
 
from kallithea.lib.utils import action_logger
 
from kallithea.lib.utils2 import datetime_to_time, generate_api_key, safe_int
 
from kallithea.lib.webutils import url
 
from kallithea.model import meta
 
from kallithea.model.api_key import ApiKeyModel
 
from kallithea.model.db import User, UserEmailMap, UserIpMap, UserToPerm
 
from kallithea.model.forms import CustomDefaultPermissionsForm, UserForm
 
from kallithea.model.meta import Session
 
from kallithea.model.ssh_key import SshKeyModel, SshKeyModelException
 
from kallithea.model.user import UserModel
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class UsersController(BaseController):
 

	
 
    @LoginRequired()
 
    @HasPermissionAnyDecorator('hg.admin')
 
    def _before(self, *args, **kwargs):
 
@@ -110,25 +110,25 @@ class UsersController(BaseController):
 
    def create(self):
 
        c.default_extern_type = User.DEFAULT_AUTH_TYPE
 
        c.default_extern_name = ''
 
        user_model = UserModel()
 
        user_form = UserForm()()
 
        try:
 
            form_result = user_form.to_python(dict(request.POST))
 
            user = user_model.create(form_result)
 
            action_logger(request.authuser, 'admin_created_user:%s' % user.username,
 
                          None, request.ip_addr)
 
            h.flash(_('Created user %s') % user.username,
 
                    category='success')
 
            Session().commit()
 
            meta.Session().commit()
 
        except formencode.Invalid as errors:
 
            return htmlfill.render(
 
                render('admin/users/user_add.html'),
 
                defaults=errors.value,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8",
 
                force_defaults=False)
 
        except UserCreationError as e:
 
            h.flash(e, 'error')
 
        except Exception:
 
            log.error(traceback.format_exc())
 
@@ -148,25 +148,25 @@ class UsersController(BaseController):
 
                                              'email': user.email})()
 
        form_result = {}
 
        try:
 
            form_result = _form.to_python(dict(request.POST))
 
            skip_attrs = ['extern_type', 'extern_name',
 
                         ] + auth_modules.get_managed_fields(user)
 

	
 
            user_model.update(id, form_result, skip_attrs=skip_attrs)
 
            usr = form_result['username']
 
            action_logger(request.authuser, 'admin_updated_user:%s' % usr,
 
                          None, request.ip_addr)
 
            h.flash(_('User updated successfully'), category='success')
 
            Session().commit()
 
            meta.Session().commit()
 
        except formencode.Invalid as errors:
 
            defaults = errors.value
 
            e = errors.error_dict or {}
 
            defaults.update({
 
                'create_repo_perm': user_model.has_perm(id,
 
                                                        'hg.create.repository'),
 
                'fork_repo_perm': user_model.has_perm(id, 'hg.fork.repository'),
 
            })
 
            return htmlfill.render(
 
                self._render_edit_profile(user),
 
                defaults=defaults,
 
                errors=e,
 
@@ -175,25 +175,25 @@ class UsersController(BaseController):
 
                force_defaults=False)
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('Error occurred during update of user %s')
 
                    % form_result.get('username'), category='error')
 
        raise HTTPFound(location=url('edit_user', id=id))
 

	
 
    def delete(self, id):
 
        usr = User.get_or_404(id)
 
        has_ssh_keys = bool(usr.ssh_keys)
 
        try:
 
            UserModel().delete(usr)
 
            Session().commit()
 
            meta.Session().commit()
 
            h.flash(_('Successfully deleted user'), category='success')
 
        except (UserOwnsReposException, DefaultUserException) as e:
 
            h.flash(e, category='warning')
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during deletion of user'),
 
                    category='error')
 
        else:
 
            if has_ssh_keys:
 
                SshKeyModel().write_authorized_keys()
 
        raise HTTPFound(location=url('users'))
 

	
 
@@ -259,39 +259,39 @@ class UsersController(BaseController):
 
        return htmlfill.render(
 
            render('admin/users/user_edit.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False)
 

	
 
    def add_api_key(self, id):
 
        c.user = self._get_user_or_raise_if_default(id)
 

	
 
        lifetime = safe_int(request.POST.get('lifetime'), -1)
 
        description = request.POST.get('description')
 
        ApiKeyModel().create(c.user.user_id, description, lifetime)
 
        Session().commit()
 
        meta.Session().commit()
 
        h.flash(_("API key successfully created"), category='success')
 
        raise HTTPFound(location=url('edit_user_api_keys', id=c.user.user_id))
 

	
 
    def delete_api_key(self, id):
 
        c.user = self._get_user_or_raise_if_default(id)
 

	
 
        api_key = request.POST.get('del_api_key')
 
        if request.POST.get('del_api_key_builtin'):
 
            c.user.api_key = generate_api_key()
 
            Session().commit()
 
            meta.Session().commit()
 
            h.flash(_("API key successfully reset"), category='success')
 
        elif api_key:
 
            ApiKeyModel().delete(api_key, c.user.user_id)
 
            Session().commit()
 
            meta.Session().commit()
 
            h.flash(_("API key successfully deleted"), category='success')
 

	
 
        raise HTTPFound(location=url('edit_user_api_keys', id=c.user.user_id))
 

	
 
    def update_account(self, id):
 
        pass
 

	
 
    def edit_perms(self, id):
 
        c.user = self._get_user_or_raise_if_default(id)
 
        c.active = 'perms'
 
        c.perm_user = AuthUser(dbuser=c.user)
 

	
 
@@ -313,40 +313,40 @@ class UsersController(BaseController):
 
        user = self._get_user_or_raise_if_default(id)
 

	
 
        try:
 
            form = CustomDefaultPermissionsForm()()
 
            form_result = form.to_python(request.POST)
 

	
 
            user_model = UserModel()
 

	
 
            defs = UserToPerm.query() \
 
                .filter(UserToPerm.user == user) \
 
                .all()
 
            for ug in defs:
 
                Session().delete(ug)
 
                meta.Session().delete(ug)
 

	
 
            if form_result['create_repo_perm']:
 
                user_model.grant_perm(id, 'hg.create.repository')
 
            else:
 
                user_model.grant_perm(id, 'hg.create.none')
 
            if form_result['create_user_group_perm']:
 
                user_model.grant_perm(id, 'hg.usergroup.create.true')
 
            else:
 
                user_model.grant_perm(id, 'hg.usergroup.create.false')
 
            if form_result['fork_repo_perm']:
 
                user_model.grant_perm(id, 'hg.fork.repository')
 
            else:
 
                user_model.grant_perm(id, 'hg.fork.none')
 
            h.flash(_("Updated permissions"), category='success')
 
            Session().commit()
 
            meta.Session().commit()
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during permissions saving'),
 
                    category='error')
 
        raise HTTPFound(location=url('edit_user_perms', id=id))
 

	
 
    def edit_emails(self, id):
 
        c.user = self._get_user_or_raise_if_default(id)
 
        c.active = 'emails'
 
        c.user_email_map = UserEmailMap.query() \
 
            .filter(UserEmailMap.user == c.user).all()
 

	
 
@@ -355,41 +355,41 @@ class UsersController(BaseController):
 
            render('admin/users/user_edit.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False)
 

	
 
    def add_email(self, id):
 
        user = self._get_user_or_raise_if_default(id)
 
        email = request.POST.get('new_email')
 
        user_model = UserModel()
 

	
 
        try:
 
            user_model.add_extra_email(id, email)
 
            Session().commit()
 
            meta.Session().commit()
 
            h.flash(_("Added email %s to user") % email, category='success')
 
        except formencode.Invalid as error:
 
            msg = error.error_dict['email']
 
            h.flash(msg, category='error')
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during email saving'),
 
                    category='error')
 
        raise HTTPFound(location=url('edit_user_emails', id=id))
 

	
 
    def delete_email(self, id):
 
        user = self._get_user_or_raise_if_default(id)
 
        email_id = request.POST.get('del_email_id')
 
        user_model = UserModel()
 
        user_model.delete_extra_email(id, email_id)
 
        Session().commit()
 
        meta.Session().commit()
 
        h.flash(_("Removed email from user"), category='success')
 
        raise HTTPFound(location=url('edit_user_emails', id=id))
 

	
 
    def edit_ips(self, id):
 
        c.user = self._get_user_or_raise_if_default(id)
 
        c.active = 'ips'
 
        c.user_ip_map = UserIpMap.query() \
 
            .filter(UserIpMap.user == c.user).all()
 

	
 
        c.default_user_ip_map = UserIpMap.query() \
 
            .filter(UserIpMap.user_id == kallithea.DEFAULT_USER_ID).all()
 

	
 
@@ -397,43 +397,43 @@ class UsersController(BaseController):
 
        return htmlfill.render(
 
            render('admin/users/user_edit.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False)
 

	
 
    def add_ip(self, id):
 
        ip = request.POST.get('new_ip')
 
        user_model = UserModel()
 

	
 
        try:
 
            user_model.add_extra_ip(id, ip)
 
            Session().commit()
 
            meta.Session().commit()
 
            h.flash(_("Added IP address %s to user whitelist") % ip, category='success')
 
        except formencode.Invalid as error:
 
            msg = error.error_dict['ip']
 
            h.flash(msg, category='error')
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred while adding IP address'),
 
                    category='error')
 

	
 
        if 'default_user' in request.POST:
 
            raise HTTPFound(location=url('admin_permissions_ips'))
 
        raise HTTPFound(location=url('edit_user_ips', id=id))
 

	
 
    def delete_ip(self, id):
 
        ip_id = request.POST.get('del_ip_id')
 
        user_model = UserModel()
 
        user_model.delete_extra_ip(id, ip_id)
 
        Session().commit()
 
        meta.Session().commit()
 
        h.flash(_("Removed IP address from user whitelist"), category='success')
 

	
 
        if 'default_user' in request.POST:
 
            raise HTTPFound(location=url('admin_permissions_ips'))
 
        raise HTTPFound(location=url('edit_user_ips', id=id))
 

	
 
    @IfSshEnabled
 
    def edit_ssh_keys(self, id):
 
        c.user = self._get_user_or_raise_if_default(id)
 
        c.active = 'ssh_keys'
 
        c.user_ssh_keys = SshKeyModel().get_ssh_keys(c.user.user_id)
 
        defaults = c.user.get_dict()
 
@@ -443,32 +443,32 @@ class UsersController(BaseController):
 
            encoding="UTF-8",
 
            force_defaults=False)
 

	
 
    @IfSshEnabled
 
    def ssh_keys_add(self, id):
 
        c.user = self._get_user_or_raise_if_default(id)
 

	
 
        description = request.POST.get('description')
 
        public_key = request.POST.get('public_key')
 
        try:
 
            new_ssh_key = SshKeyModel().create(c.user.user_id,
 
                                               description, public_key)
 
            Session().commit()
 
            meta.Session().commit()
 
            SshKeyModel().write_authorized_keys()
 
            h.flash(_("SSH key %s successfully added") % new_ssh_key.fingerprint, category='success')
 
        except SshKeyModelException as e:
 
            h.flash(e.args[0], category='error')
 
        raise HTTPFound(location=url('edit_user_ssh_keys', id=c.user.user_id))
 

	
 
    @IfSshEnabled
 
    def ssh_keys_delete(self, id):
 
        c.user = self._get_user_or_raise_if_default(id)
 

	
 
        fingerprint = request.POST.get('del_public_key_fingerprint')
 
        try:
 
            SshKeyModel().delete(fingerprint, c.user.user_id)
 
            Session().commit()
 
            meta.Session().commit()
 
            SshKeyModel().write_authorized_keys()
 
            h.flash(_("SSH key successfully deleted"), category='success')
 
        except SshKeyModelException as e:
 
            h.flash(e.args[0], category='error')
 
        raise HTTPFound(location=url('edit_user_ssh_keys', id=c.user.user_id))
kallithea/controllers/api/api.py
Show inline comments
 
@@ -29,29 +29,29 @@ import logging
 
import traceback
 
from datetime import datetime
 

	
 
from tg import request
 

	
 
from kallithea.controllers.api import JSONRPCController, JSONRPCError
 
from kallithea.lib.auth import (AuthUser, HasPermissionAny, HasPermissionAnyDecorator, HasRepoGroupPermissionLevel, HasRepoPermissionLevel,
 
                                HasUserGroupPermissionLevel)
 
from kallithea.lib.exceptions import DefaultUserException, UserGroupsAssignedException
 
from kallithea.lib.utils import action_logger, repo2db_mapper
 
from kallithea.lib.vcs.backends.base import EmptyChangeset
 
from kallithea.lib.vcs.exceptions import EmptyRepositoryError
 
from kallithea.model import meta
 
from kallithea.model.changeset_status import ChangesetStatusModel
 
from kallithea.model.comment import ChangesetCommentsModel
 
from kallithea.model.db import ChangesetStatus, Gist, Permission, PullRequest, RepoGroup, Repository, Setting, User, UserGroup, UserIpMap
 
from kallithea.model.gist import GistModel
 
from kallithea.model.meta import Session
 
from kallithea.model.pull_request import PullRequestModel
 
from kallithea.model.repo import RepoModel
 
from kallithea.model.repo_group import RepoGroupModel
 
from kallithea.model.scm import ScmModel, UserGroupList
 
from kallithea.model.user import UserModel
 
from kallithea.model.user_group import UserGroupModel
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
def store_update(updates, attr, name):
 
@@ -492,25 +492,25 @@ class ApiController(JSONRPCController):
 
        try:
 
            user = UserModel().create_or_update(
 
                username=username,
 
                password=password,
 
                email=email,
 
                firstname=firstname,
 
                lastname=lastname,
 
                active=active,
 
                admin=admin,
 
                extern_type=extern_type,
 
                extern_name=extern_name
 
            )
 
            Session().commit()
 
            meta.Session().commit()
 
            return dict(
 
                msg='created new user `%s`' % username,
 
                user=user.get_api_data()
 
            )
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError('failed to create user `%s`' % (username,))
 

	
 
    @HasPermissionAnyDecorator('hg.admin')
 
    def update_user(self, userid, username=None,
 
                    email=None, password=None,
 
                    firstname=None, lastname=None,
 
@@ -570,25 +570,25 @@ class ApiController(JSONRPCController):
 

	
 
            store_update(updates, username, 'username')
 
            store_update(updates, password, 'password')
 
            store_update(updates, email, 'email')
 
            store_update(updates, firstname, 'name')
 
            store_update(updates, lastname, 'lastname')
 
            store_update(updates, active, 'active')
 
            store_update(updates, admin, 'admin')
 
            store_update(updates, extern_name, 'extern_name')
 
            store_update(updates, extern_type, 'extern_type')
 

	
 
            user = UserModel().update_user(user, **updates)
 
            Session().commit()
 
            meta.Session().commit()
 
            return dict(
 
                msg='updated user ID:%s %s' % (user.user_id, user.username),
 
                user=user.get_api_data()
 
            )
 
        except DefaultUserException:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError('editing default user is forbidden')
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError('failed to update user `%s`' % (userid,))
 

	
 
    @HasPermissionAnyDecorator('hg.admin')
 
@@ -613,25 +613,25 @@ class ApiController(JSONRPCController):
 

	
 
          id : <id_given_in_input>
 
          result : null
 
          error :  {
 
            "failed to delete user ID:<userid> <username>"
 
          }
 

	
 
        """
 
        user = get_user_or_error(userid)
 

	
 
        try:
 
            UserModel().delete(userid)
 
            Session().commit()
 
            meta.Session().commit()
 
            return dict(
 
                msg='deleted user ID:%s %s' % (user.user_id, user.username),
 
                user=None
 
            )
 
        except Exception:
 

	
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError('failed to delete user ID:%s %s'
 
                               % (user.user_id, user.username))
 

	
 
    # permission check inside
 
    def get_user_group(self, usergroupid):
 
@@ -723,25 +723,25 @@ class ApiController(JSONRPCController):
 
        """
 

	
 
        if UserGroupModel().get_by_name(group_name):
 
            raise JSONRPCError("user group `%s` already exist" % (group_name,))
 

	
 
        try:
 
            if owner is None:
 
                owner = request.authuser.user_id
 

	
 
            owner = get_user_or_error(owner)
 
            ug = UserGroupModel().create(name=group_name, description=description,
 
                                         owner=owner, active=active)
 
            Session().commit()
 
            meta.Session().commit()
 
            return dict(
 
                msg='created new user group `%s`' % group_name,
 
                user_group=ug.get_api_data()
 
            )
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError('failed to create group `%s`' % (group_name,))
 

	
 
    # permission check inside
 
    def update_user_group(self, usergroupid, group_name=None,
 
                          description=None, owner=None,
 
                          active=None):
 
@@ -784,25 +784,25 @@ class ApiController(JSONRPCController):
 
                raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
 

	
 
        if owner is not None:
 
            owner = get_user_or_error(owner)
 

	
 
        updates = {}
 
        store_update(updates, group_name, 'users_group_name')
 
        store_update(updates, description, 'user_group_description')
 
        store_update(updates, owner, 'owner')
 
        store_update(updates, active, 'users_group_active')
 
        try:
 
            UserGroupModel().update(user_group, updates)
 
            Session().commit()
 
            meta.Session().commit()
 
            return dict(
 
                msg='updated user group ID:%s %s' % (user_group.users_group_id,
 
                                                     user_group.users_group_name),
 
                user_group=user_group.get_api_data()
 
            )
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError('failed to update user group `%s`' % (usergroupid,))
 

	
 
    # permission check inside
 
    def delete_user_group(self, usergroupid):
 
        """
 
@@ -830,25 +830,25 @@ class ApiController(JSONRPCController):
 
            or
 
            "RepoGroup assigned to <repo_groups_list>"
 
          }
 

	
 
        """
 
        user_group = get_user_group_or_error(usergroupid)
 
        if not HasPermissionAny('hg.admin')():
 
            if not HasUserGroupPermissionLevel('admin')(user_group.users_group_name):
 
                raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
 

	
 
        try:
 
            UserGroupModel().delete(user_group)
 
            Session().commit()
 
            meta.Session().commit()
 
            return dict(
 
                msg='deleted user group ID:%s %s' %
 
                    (user_group.users_group_id, user_group.users_group_name),
 
                user_group=None
 
            )
 
        except UserGroupsAssignedException as e:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError(str(e))
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError('failed to delete user group ID:%s %s' %
 
                               (user_group.users_group_id,
 
@@ -891,25 +891,25 @@ class ApiController(JSONRPCController):
 
        user_group = get_user_group_or_error(usergroupid)
 
        if not HasPermissionAny('hg.admin')():
 
            if not HasUserGroupPermissionLevel('admin')(user_group.users_group_name):
 
                raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
 

	
 
        try:
 
            ugm = UserGroupModel().add_user_to_group(user_group, user)
 
            success = True if ugm is not True else False
 
            msg = 'added member `%s` to user group `%s`' % (
 
                user.username, user_group.users_group_name
 
            )
 
            msg = msg if success else 'User is already in that group'
 
            Session().commit()
 
            meta.Session().commit()
 

	
 
            return dict(
 
                success=success,
 
                msg=msg
 
            )
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError(
 
                'failed to add member to user group `%s`' % (
 
                    user_group.users_group_name,
 
                )
 
            )
 
@@ -939,25 +939,25 @@ class ApiController(JSONRPCController):
 
        user = get_user_or_error(userid)
 
        user_group = get_user_group_or_error(usergroupid)
 
        if not HasPermissionAny('hg.admin')():
 
            if not HasUserGroupPermissionLevel('admin')(user_group.users_group_name):
 
                raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
 

	
 
        try:
 
            success = UserGroupModel().remove_user_from_group(user_group, user)
 
            msg = 'removed member `%s` from user group `%s`' % (
 
                user.username, user_group.users_group_name
 
            )
 
            msg = msg if success else "User wasn't in group"
 
            Session().commit()
 
            meta.Session().commit()
 
            return dict(success=success, msg=msg)
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError(
 
                'failed to remove member from user group `%s`' % (
 
                    user_group.users_group_name,
 
                )
 
            )
 

	
 
    # permission check inside
 
    def get_repo(self, repoid,
 
                 with_revision_names=False,
 
@@ -1330,25 +1330,25 @@ class ApiController(JSONRPCController):
 
        try:
 
            store_update(updates, name, 'repo_name')
 
            store_update(updates, repo_group, 'repo_group')
 
            store_update(updates, owner, 'owner')
 
            store_update(updates, description, 'repo_description')
 
            store_update(updates, private, 'repo_private')
 
            store_update(updates, clone_uri, 'clone_uri')
 
            store_update(updates, landing_rev, 'repo_landing_rev')
 
            store_update(updates, enable_statistics, 'repo_enable_statistics')
 
            store_update(updates, enable_downloads, 'repo_enable_downloads')
 

	
 
            RepoModel().update(repo, **updates)
 
            Session().commit()
 
            meta.Session().commit()
 
            return dict(
 
                msg='updated repo ID:%s %s' % (repo.repo_id, repo.repo_name),
 
                repository=repo.get_api_data()
 
            )
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError('failed to update repo `%s`' % repoid)
 

	
 
    @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
 
    def fork_repo(self, repoid, fork_name,
 
                  owner=None,
 
                  description='', copy_permissions=False,
 
@@ -1494,25 +1494,25 @@ class ApiController(JSONRPCController):
 
            _forks = [f for f in repo.forks]
 
            if handle_forks == 'detach':
 
                _forks_msg = ' ' + 'Detached %s forks' % len(_forks)
 
            elif handle_forks == 'delete':
 
                _forks_msg = ' ' + 'Deleted %s forks' % len(_forks)
 
            elif _forks:
 
                raise JSONRPCError(
 
                    'Cannot delete `%s` it still contains attached forks' %
 
                    (repo.repo_name,)
 
                )
 

	
 
            RepoModel().delete(repo, forks=forks)
 
            Session().commit()
 
            meta.Session().commit()
 
            return dict(
 
                msg='Deleted repository `%s`%s' % (repo.repo_name, _forks_msg),
 
                success=True
 
            )
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError(
 
                'failed to delete repository `%s`' % (repo.repo_name,)
 
            )
 

	
 
    @HasPermissionAnyDecorator('hg.admin')
 
    def grant_user_permission(self, repoid, userid, perm):
 
@@ -1535,25 +1535,25 @@ class ApiController(JSONRPCController):
 
                      "success": true
 
                    }
 
            error:  null
 
        """
 
        repo = get_repo_or_error(repoid)
 
        user = get_user_or_error(userid)
 
        perm = get_perm_or_error(perm)
 

	
 
        try:
 

	
 
            RepoModel().grant_user_permission(repo=repo, user=user, perm=perm)
 

	
 
            Session().commit()
 
            meta.Session().commit()
 
            return dict(
 
                msg='Granted perm: `%s` for user: `%s` in repo: `%s`' % (
 
                    perm.permission_name, user.username, repo.repo_name
 
                ),
 
                success=True
 
            )
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError(
 
                'failed to edit permission for user: `%s` in repo: `%s`' % (
 
                    userid, repoid
 
                )
 
@@ -1575,25 +1575,25 @@ class ApiController(JSONRPCController):
 
            result: {
 
                      "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
 
                      "success": true
 
                    }
 
            error:  null
 

	
 
        """
 

	
 
        repo = get_repo_or_error(repoid)
 
        user = get_user_or_error(userid)
 
        try:
 
            RepoModel().revoke_user_permission(repo=repo, user=user)
 
            Session().commit()
 
            meta.Session().commit()
 
            return dict(
 
                msg='Revoked perm for user: `%s` in repo: `%s`' % (
 
                    user.username, repo.repo_name
 
                ),
 
                success=True
 
            )
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError(
 
                'failed to edit permission for user: `%s` in repo: `%s`' % (
 
                    userid, repoid
 
                )
 
@@ -1637,25 +1637,25 @@ class ApiController(JSONRPCController):
 
        user_group = get_user_group_or_error(usergroupid)
 
        if not HasPermissionAny('hg.admin')():
 
            if not HasRepoPermissionLevel('admin')(repo.repo_name):
 
                raise JSONRPCError('repository `%s` does not exist' % (repoid,))
 

	
 
            if not HasUserGroupPermissionLevel('read')(user_group.users_group_name):
 
                raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
 

	
 
        try:
 
            RepoModel().grant_user_group_permission(
 
                repo=repo, group_name=user_group, perm=perm)
 

	
 
            Session().commit()
 
            meta.Session().commit()
 
            return dict(
 
                msg='Granted perm: `%s` for user group: `%s` in '
 
                    'repo: `%s`' % (
 
                        perm.permission_name, user_group.users_group_name,
 
                        repo.repo_name
 
                    ),
 
                success=True
 
            )
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError(
 
                'failed to edit permission for user group: `%s` in '
 
@@ -1687,25 +1687,25 @@ class ApiController(JSONRPCController):
 
        user_group = get_user_group_or_error(usergroupid)
 
        if not HasPermissionAny('hg.admin')():
 
            if not HasRepoPermissionLevel('admin')(repo.repo_name):
 
                raise JSONRPCError('repository `%s` does not exist' % (repoid,))
 

	
 
            if not HasUserGroupPermissionLevel('read')(user_group.users_group_name):
 
                raise JSONRPCError('user group `%s` does not exist' % (usergroupid,))
 

	
 
        try:
 
            RepoModel().revoke_user_group_permission(
 
                repo=repo, group_name=user_group)
 

	
 
            Session().commit()
 
            meta.Session().commit()
 
            return dict(
 
                msg='Revoked perm for user group: `%s` in repo: `%s`' % (
 
                    user_group.users_group_name, repo.repo_name
 
                ),
 
                success=True
 
            )
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError(
 
                'failed to edit permission for user group: `%s` in '
 
                'repo: `%s`' % (
 
                    user_group.users_group_name, repo.repo_name
 
@@ -1806,49 +1806,49 @@ class ApiController(JSONRPCController):
 
        parent_group = None
 
        if parent is not None:
 
            parent_group = get_repo_group_or_error(parent)
 

	
 
        try:
 
            repo_group = RepoGroupModel().create(
 
                group_name=group_name,
 
                group_description=group_description,
 
                owner=owner,
 
                parent=parent_group,
 
                copy_permissions=copy_permissions
 
            )
 
            Session().commit()
 
            meta.Session().commit()
 
            return dict(
 
                msg='created new repo group `%s`' % group_name,
 
                repo_group=repo_group.get_api_data()
 
            )
 
        except Exception:
 

	
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError('failed to create repo group `%s`' % (group_name,))
 

	
 
    @HasPermissionAnyDecorator('hg.admin')
 
    def update_repo_group(self, repogroupid, group_name=None,
 
                          description=None,
 
                          owner=None,
 
                          parent=None):
 
        repo_group = get_repo_group_or_error(repogroupid)
 

	
 
        updates = {}
 
        try:
 
            store_update(updates, group_name, 'group_name')
 
            store_update(updates, description, 'group_description')
 
            store_update(updates, owner, 'owner')
 
            store_update(updates, parent, 'parent_group')
 
            repo_group = RepoGroupModel().update(repo_group, updates)
 
            Session().commit()
 
            meta.Session().commit()
 
            return dict(
 
                msg='updated repository group ID:%s %s' % (repo_group.group_id,
 
                                                           repo_group.group_name),
 
                repo_group=repo_group.get_api_data()
 
            )
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError('failed to update repository group `%s`'
 
                               % (repogroupid,))
 

	
 
    @HasPermissionAnyDecorator('hg.admin')
 
    def delete_repo_group(self, repogroupid):
 
@@ -1870,25 +1870,25 @@ class ApiController(JSONRPCController):
 

	
 
          id : <id_given_in_input>
 
          result : null
 
          error :  {
 
            "failed to delete repo group ID:<repogroupid> <repogroupname>"
 
          }
 

	
 
        """
 
        repo_group = get_repo_group_or_error(repogroupid)
 

	
 
        try:
 
            RepoGroupModel().delete(repo_group)
 
            Session().commit()
 
            meta.Session().commit()
 
            return dict(
 
                msg='deleted repo group ID:%s %s' %
 
                    (repo_group.group_id, repo_group.group_name),
 
                repo_group=None
 
            )
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError('failed to delete repo group ID:%s %s' %
 
                               (repo_group.group_id, repo_group.group_name)
 
                               )
 

	
 
    # permission check inside
 
@@ -1933,25 +1933,25 @@ class ApiController(JSONRPCController):
 
            if not HasRepoGroupPermissionLevel('admin')(repo_group.group_name):
 
                raise JSONRPCError('repository group `%s` does not exist' % (repogroupid,))
 

	
 
        user = get_user_or_error(userid)
 
        perm = get_perm_or_error(perm, prefix='group.')
 

	
 
        try:
 
            RepoGroupModel().add_permission(repo_group=repo_group,
 
                                            obj=user,
 
                                            obj_type="user",
 
                                            perm=perm,
 
                                            recursive=apply_to_children)
 
            Session().commit()
 
            meta.Session().commit()
 
            return dict(
 
                msg='Granted perm: `%s` (recursive:%s) for user: `%s` in repo group: `%s`' % (
 
                    perm.permission_name, apply_to_children, user.username, repo_group.name
 
                ),
 
                success=True
 
            )
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError(
 
                'failed to edit permission for user: `%s` in repo group: `%s`' % (
 
                    userid, repo_group.name))
 

	
 
@@ -1994,25 +1994,25 @@ class ApiController(JSONRPCController):
 
        if not HasPermissionAny('hg.admin')():
 
            if not HasRepoGroupPermissionLevel('admin')(repo_group.group_name):
 
                raise JSONRPCError('repository group `%s` does not exist' % (repogroupid,))
 

	
 
        user = get_user_or_error(userid)
 

	
 
        try:
 
            RepoGroupModel().delete_permission(repo_group=repo_group,
 
                                               obj=user,
 
                                               obj_type="user",
 
                                               recursive=apply_to_children)
 

	
 
            Session().commit()
 
            meta.Session().commit()
 
            return dict(
 
                msg='Revoked perm (recursive:%s) for user: `%s` in repo group: `%s`' % (
 
                    apply_to_children, user.username, repo_group.name
 
                ),
 
                success=True
 
            )
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError(
 
                'failed to edit permission for user: `%s` in repo group: `%s`' % (
 
                    userid, repo_group.name))
 

	
 
@@ -2063,25 +2063,25 @@ class ApiController(JSONRPCController):
 
                    'repository group `%s` does not exist' % (repogroupid,))
 

	
 
            if not HasUserGroupPermissionLevel('read')(user_group.users_group_name):
 
                raise JSONRPCError(
 
                    'user group `%s` does not exist' % (usergroupid,))
 

	
 
        try:
 
            RepoGroupModel().add_permission(repo_group=repo_group,
 
                                            obj=user_group,
 
                                            obj_type="user_group",
 
                                            perm=perm,
 
                                            recursive=apply_to_children)
 
            Session().commit()
 
            meta.Session().commit()
 
            return dict(
 
                msg='Granted perm: `%s` (recursive:%s) for user group: `%s` in repo group: `%s`' % (
 
                    perm.permission_name, apply_to_children,
 
                    user_group.users_group_name, repo_group.name
 
                ),
 
                success=True
 
            )
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError(
 
                'failed to edit permission for user group: `%s` in '
 
                'repo group: `%s`' % (
 
@@ -2130,25 +2130,25 @@ class ApiController(JSONRPCController):
 
                raise JSONRPCError(
 
                    'repository group `%s` does not exist' % (repogroupid,))
 

	
 
            if not HasUserGroupPermissionLevel('read')(user_group.users_group_name):
 
                raise JSONRPCError(
 
                    'user group `%s` does not exist' % (usergroupid,))
 

	
 
        try:
 
            RepoGroupModel().delete_permission(repo_group=repo_group,
 
                                               obj=user_group,
 
                                               obj_type="user_group",
 
                                               recursive=apply_to_children)
 
            Session().commit()
 
            meta.Session().commit()
 
            return dict(
 
                msg='Revoked perm (recursive:%s) for user group: `%s` in repo group: `%s`' % (
 
                    apply_to_children, user_group.users_group_name, repo_group.name
 
                ),
 
                success=True
 
            )
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError(
 
                'failed to edit permission for user group: `%s` in repo group: `%s`' % (
 
                    user_group.users_group_name, repo_group.name
 
                )
 
@@ -2237,25 +2237,25 @@ class ApiController(JSONRPCController):
 
        try:
 
            if owner is None:
 
                owner = request.authuser.user_id
 

	
 
            owner = get_user_or_error(owner)
 

	
 
            gist = GistModel().create(description=description,
 
                                      owner=owner,
 
                                      ip_addr=request.ip_addr,
 
                                      gist_mapping=files,
 
                                      gist_type=gist_type,
 
                                      lifetime=lifetime)
 
            Session().commit()
 
            meta.Session().commit()
 
            return dict(
 
                msg='created new gist',
 
                gist=gist.get_api_data()
 
            )
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError('failed to create gist')
 

	
 
    # permission check inside
 
    def delete_gist(self, gistid):
 
        """
 
        Deletes existing gist
 
@@ -2279,25 +2279,25 @@ class ApiController(JSONRPCController):
 
          error :  {
 
            "failed to delete gist ID:<gist_id>"
 
          }
 

	
 
        """
 
        gist = get_gist_or_error(gistid)
 
        if not HasPermissionAny('hg.admin')():
 
            if gist.owner_id != request.authuser.user_id:
 
                raise JSONRPCError('gist `%s` does not exist' % (gistid,))
 

	
 
        try:
 
            GistModel().delete(gist)
 
            Session().commit()
 
            meta.Session().commit()
 
            return dict(
 
                msg='deleted gist ID:%s' % (gist.gist_access_id,),
 
                gist=None
 
            )
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError('failed to delete gist ID:%s'
 
                               % (gist.gist_access_id,))
 

	
 
    # permission check inside
 
    def get_changesets(self, repoid, start=None, end=None, start_date=None,
 
                       end_date=None, branch_name=None, reverse=False, with_file_list=False, max_revisions=None):
 
@@ -2385,25 +2385,25 @@ class ApiController(JSONRPCController):
 
            ChangesetStatusModel().set_status(
 
                pull_request.org_repo_id,
 
                status,
 
                apiuser.user_id,
 
                comment,
 
                pull_request=pull_request_id
 
            )
 
        if close_pr:
 
            PullRequestModel().close_pull_request(pull_request_id)
 
            action_logger(apiuser,
 
                          'user_closed_pull_request:%s' % pull_request_id,
 
                          pull_request.org_repo, request.ip_addr)
 
        Session().commit()
 
        meta.Session().commit()
 
        return True
 

	
 
    # permission check inside
 
    def edit_reviewers(self, pull_request_id, add=None, remove=None):
 
        """
 
        Add and/or remove one or more reviewers to a pull request, by username
 
        or user ID. Reviewers are specified either as a single-user string or
 
        as a JSON list of one or more strings.
 
        """
 
        if add is None and remove is None:
 
            raise JSONRPCError('''Invalid request. Neither 'add' nor 'remove' is specified.''')
 

	
 
@@ -2425,20 +2425,20 @@ class ApiController(JSONRPCController):
 
            remove = [remove]
 

	
 
        # look up actual user objects from given name or id. Bail out if unknown.
 
        add_objs = set(get_user_or_error(user) for user in add if user is not None)
 
        remove_objs = set(get_user_or_error(user) for user in remove if user is not None)
 

	
 
        new_reviewers = redundant_reviewers = set()
 
        if add_objs:
 
            new_reviewers, redundant_reviewers = PullRequestModel().add_reviewers(apiuser, pull_request, add_objs)
 
        if remove_objs:
 
            PullRequestModel().remove_reviewers(apiuser, pull_request, remove_objs)
 

	
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        return {
 
            'added': [x.username for x in new_reviewers],
 
            'already_present': [x.username for x in redundant_reviewers],
 
            # NOTE: no explicit check that removed reviewers were actually present.
 
            'removed': [x.username for x in remove_objs],
 
        }
kallithea/controllers/changeset.py
Show inline comments
 
@@ -35,28 +35,28 @@ from tg import tmpl_context as c
 
from tg.i18n import ugettext as _
 
from webob.exc import HTTPBadRequest, HTTPForbidden, HTTPNotFound
 

	
 
import kallithea.lib.helpers as h
 
from kallithea.lib import diffs
 
from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired
 
from kallithea.lib.base import BaseRepoController, jsonify, render
 
from kallithea.lib.graphmod import graph_data
 
from kallithea.lib.utils import action_logger
 
from kallithea.lib.utils2 import ascii_str, safe_str
 
from kallithea.lib.vcs.backends.base import EmptyChangeset
 
from kallithea.lib.vcs.exceptions import ChangesetDoesNotExistError, EmptyRepositoryError, RepositoryError
 
from kallithea.model import meta
 
from kallithea.model.changeset_status import ChangesetStatusModel
 
from kallithea.model.comment import ChangesetCommentsModel
 
from kallithea.model.db import ChangesetComment, ChangesetStatus
 
from kallithea.model.meta import Session
 
from kallithea.model.pull_request import PullRequestModel
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
def create_cs_pr_comment(repo_name, revision=None, pull_request=None, allowed_to_change_status=True):
 
    """
 
    Add a comment to the specified changeset or pull request, using POST values
 
    from the request.
 

	
 
    Comments can be inline (when a file path and line number is specified in
 
@@ -88,25 +88,25 @@ def create_cs_pr_comment(repo_name, revi
 
    if not allowed_to_change_status:
 
        if status or close_pr:
 
            h.flash(_('No permission to change status'), 'error')
 
            raise HTTPForbidden()
 

	
 
    if pull_request and delete == "delete":
 
        if (pull_request.owner_id == request.authuser.user_id or
 
            h.HasPermissionAny('hg.admin')() or
 
            h.HasRepoPermissionLevel('admin')(pull_request.org_repo.repo_name) or
 
            h.HasRepoPermissionLevel('admin')(pull_request.other_repo.repo_name)
 
        ) and not pull_request.is_closed():
 
            PullRequestModel().delete(pull_request)
 
            Session().commit()
 
            meta.Session().commit()
 
            h.flash(_('Successfully deleted pull request %s') % pull_request_id,
 
                    category='success')
 
            return {
 
               'location': h.url('my_pullrequests'), # or repo pr list?
 
            }
 
        raise HTTPForbidden()
 

	
 
    text = request.POST.get('text', '').strip()
 

	
 
    comment = ChangesetCommentsModel().create(
 
        text=text,
 
        repo=c.db_repo.repo_id,
 
@@ -132,25 +132,25 @@ def create_cs_pr_comment(repo_name, revi
 
    if pull_request:
 
        action = 'user_commented_pull_request:%s' % pull_request_id
 
    else:
 
        action = 'user_commented_revision:%s' % revision
 
    action_logger(request.authuser, action, c.db_repo, request.ip_addr)
 

	
 
    if pull_request and close_pr:
 
        PullRequestModel().close_pull_request(pull_request_id)
 
        action_logger(request.authuser,
 
                      'user_closed_pull_request:%s' % pull_request_id,
 
                      c.db_repo, request.ip_addr)
 

	
 
    Session().commit()
 
    meta.Session().commit()
 

	
 
    data = {
 
       'target_id': h.safeid(request.POST.get('f_path')),
 
    }
 
    if comment is not None:
 
        c.comment = comment
 
        data.update(comment.get_dict())
 
        data.update({'rendered_text':
 
                     render('changeset/changeset_comment_block.html')})
 

	
 
    return data
 

	
 
@@ -158,25 +158,25 @@ def delete_cs_pr_comment(repo_name, comm
 
    """Delete a comment from a changeset or pull request"""
 
    co = ChangesetComment.get_or_404(comment_id)
 
    if co.repo.repo_name != repo_name:
 
        raise HTTPNotFound()
 
    if co.pull_request and co.pull_request.is_closed():
 
        # don't allow deleting comments on closed pull request
 
        raise HTTPForbidden()
 

	
 
    owner = co.author_id == request.authuser.user_id
 
    repo_admin = h.HasRepoPermissionLevel('admin')(repo_name)
 
    if h.HasPermissionAny('hg.admin')() or repo_admin or owner:
 
        ChangesetCommentsModel().delete(comment=co)
 
        Session().commit()
 
        meta.Session().commit()
 
        return True
 
    else:
 
        raise HTTPForbidden()
 

	
 
class ChangesetController(BaseRepoController):
 

	
 
    def _before(self, *args, **kwargs):
 
        super(ChangesetController, self)._before(*args, **kwargs)
 
        c.affected_files_cut_off = 60
 

	
 
    def _index(self, revision, method):
 
        c.pull_request = None
kallithea/controllers/journal.py
Show inline comments
 
@@ -34,26 +34,26 @@ from sqlalchemy.orm import joinedload
 
from tg import request, response
 
from tg import tmpl_context as c
 
from tg.i18n import ugettext as _
 
from webob.exc import HTTPBadRequest
 

	
 
import kallithea.lib.helpers as h
 
from kallithea.controllers.admin.admin import _journal_filter
 
from kallithea.lib import feeds
 
from kallithea.lib.auth import LoginRequired
 
from kallithea.lib.base import BaseController, render
 
from kallithea.lib.page import Page
 
from kallithea.lib.utils2 import AttributeDict, safe_int
 
from kallithea.model import meta
 
from kallithea.model.db import Repository, User, UserFollowing, UserLog
 
from kallithea.model.meta import Session
 
from kallithea.model.repo import RepoModel
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
language = 'en-us'
 
ttl = "5"
 
feed_nr = 20
 

	
 

	
 
class JournalController(BaseController):
 
@@ -206,36 +206,36 @@ class JournalController(BaseController):
 
            .filter(UserFollowing.user_id == request.authuser.user_id) \
 
            .options(joinedload(UserFollowing.follows_repository)) \
 
            .all()
 
        return self._rss_feed(following, public=False)
 

	
 
    @LoginRequired()
 
    def toggle_following(self):
 
        user_id = request.POST.get('follows_user_id')
 
        if user_id:
 
            try:
 
                self.scm_model.toggle_following_user(user_id,
 
                                            request.authuser.user_id)
 
                Session().commit()
 
                meta.Session().commit()
 
                return 'ok'
 
            except Exception:
 
                log.error(traceback.format_exc())
 
                raise HTTPBadRequest()
 

	
 
        repo_id = request.POST.get('follows_repository_id')
 
        if repo_id:
 
            try:
 
                self.scm_model.toggle_following_repo(repo_id,
 
                                            request.authuser.user_id)
 
                Session().commit()
 
                meta.Session().commit()
 
                return 'ok'
 
            except Exception:
 
                log.error(traceback.format_exc())
 
                raise HTTPBadRequest()
 

	
 
        raise HTTPBadRequest()
 

	
 
    @LoginRequired(allow_default_user=True)
 
    def public_journal(self):
 
        # Return a rendered template
 
        p = safe_int(request.GET.get('page'), 1)
 

	
kallithea/controllers/login.py
Show inline comments
 
@@ -32,27 +32,27 @@ import re
 
import formencode
 
from formencode import htmlfill
 
from tg import request, session
 
from tg import tmpl_context as c
 
from tg.i18n import ugettext as _
 
from webob.exc import HTTPBadRequest, HTTPFound
 

	
 
import kallithea.lib.helpers as h
 
from kallithea.lib.auth import AuthUser, HasPermissionAnyDecorator
 
from kallithea.lib.base import BaseController, log_in_user, render
 
from kallithea.lib.exceptions import UserCreationError
 
from kallithea.lib.webutils import url
 
from kallithea.model import meta
 
from kallithea.model.db import Setting, User
 
from kallithea.model.forms import LoginForm, PasswordResetConfirmationForm, PasswordResetRequestForm, RegisterForm
 
from kallithea.model.meta import Session
 
from kallithea.model.user import UserModel
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class LoginController(BaseController):
 

	
 
    def _validate_came_from(self, came_from,
 
            _re=re.compile(r"/(?!/)[-!#$%&'()*+,./:;=?@_~0-9A-Za-z]*$")):
 
        """Return True if came_from is valid and can and should be used.
 

	
 
@@ -138,25 +138,25 @@ class LoginController(BaseController):
 
                                      private_key=captcha_private_key,
 
                                      remoteip=request.ip_addr)
 
                    if not response.is_valid:
 
                        _value = form_result
 
                        _msg = _('Bad captcha')
 
                        error_dict = {'recaptcha_field': _msg}
 
                        raise formencode.Invalid(_msg, _value, None,
 
                                                 error_dict=error_dict)
 

	
 
                UserModel().create_registration(form_result)
 
                h.flash(_('You have successfully registered with %s') % (c.site_name or 'Kallithea'),
 
                        category='success')
 
                Session().commit()
 
                meta.Session().commit()
 
                raise HTTPFound(location=url('login_home'))
 

	
 
            except formencode.Invalid as errors:
 
                return htmlfill.render(
 
                    render('/register.html'),
 
                    defaults=errors.value,
 
                    errors=errors.error_dict or {},
 
                    prefix_error=False,
 
                    encoding="UTF-8",
 
                    force_defaults=False)
 
            except UserCreationError as e:
 
                # container auth or other auth functions that create users on
kallithea/controllers/pullrequests.py
Show inline comments
 
@@ -36,29 +36,29 @@ from tg.i18n import ugettext as _
 
from webob.exc import HTTPBadRequest, HTTPForbidden, HTTPFound, HTTPNotFound
 

	
 
from kallithea.controllers.changeset import create_cs_pr_comment, delete_cs_pr_comment
 
from kallithea.lib import diffs
 
from kallithea.lib import helpers as h
 
from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired
 
from kallithea.lib.base import BaseRepoController, jsonify, render
 
from kallithea.lib.graphmod import graph_data
 
from kallithea.lib.page import Page
 
from kallithea.lib.utils2 import ascii_bytes, safe_bytes, safe_int
 
from kallithea.lib.vcs.exceptions import ChangesetDoesNotExistError, EmptyRepositoryError
 
from kallithea.lib.webutils import url
 
from kallithea.model import meta
 
from kallithea.model.changeset_status import ChangesetStatusModel
 
from kallithea.model.comment import ChangesetCommentsModel
 
from kallithea.model.db import ChangesetStatus, PullRequest, PullRequestReviewer, Repository, User
 
from kallithea.model.forms import PullRequestForm, PullRequestPostForm
 
from kallithea.model.meta import Session
 
from kallithea.model.pull_request import CreatePullRequestAction, CreatePullRequestIterationAction, PullRequestModel
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
def _get_reviewer(user_id):
 
    """Look up user by ID and validate it as a potential reviewer."""
 
    try:
 
        user = User.get(int(user_id))
 
    except ValueError:
 
        user = None
 
@@ -330,48 +330,48 @@ class PullrequestsController(BaseRepoCon
 
        title = _form['pullrequest_title']
 
        description = _form['pullrequest_desc'].strip()
 
        owner = User.get(request.authuser.user_id)
 

	
 
        try:
 
            cmd = CreatePullRequestAction(org_repo, other_repo, org_ref, other_ref, title, description, owner, reviewers)
 
        except CreatePullRequestAction.ValidationError as e:
 
            h.flash(e, category='error', logf=log.error)
 
            raise HTTPNotFound
 

	
 
        try:
 
            pull_request = cmd.execute()
 
            Session().commit()
 
            meta.Session().commit()
 
        except Exception:
 
            h.flash(_('Error occurred while creating pull request'),
 
                    category='error')
 
            log.error(traceback.format_exc())
 
            raise HTTPFound(location=url('pullrequest_home', repo_name=repo_name))
 

	
 
        h.flash(_('Successfully opened new pull request'),
 
                category='success')
 
        raise HTTPFound(location=pull_request.url())
 

	
 
    def create_new_iteration(self, old_pull_request, new_rev, title, description, reviewers):
 
        owner = User.get(request.authuser.user_id)
 
        new_org_rev = self._get_ref_rev(old_pull_request.org_repo, 'rev', new_rev)
 
        new_other_rev = self._get_ref_rev(old_pull_request.other_repo, old_pull_request.other_ref_parts[0], old_pull_request.other_ref_parts[1])
 
        try:
 
            cmd = CreatePullRequestIterationAction(old_pull_request, new_org_rev, new_other_rev, title, description, owner, reviewers)
 
        except CreatePullRequestAction.ValidationError as e:
 
            h.flash(e, category='error', logf=log.error)
 
            raise HTTPNotFound
 

	
 
        try:
 
            pull_request = cmd.execute()
 
            Session().commit()
 
            meta.Session().commit()
 
        except Exception:
 
            h.flash(_('Error occurred while creating pull request'),
 
                    category='error')
 
            log.error(traceback.format_exc())
 
            raise HTTPFound(location=old_pull_request.url())
 

	
 
        h.flash(_('New pull request iteration created'),
 
                category='success')
 
        raise HTTPFound(location=pull_request.url())
 

	
 
    # pullrequest_post for PR editing
 
    @LoginRequired()
 
@@ -416,38 +416,38 @@ class PullrequestsController(BaseRepoCon
 
        removed_reviewers = (old_reviewers - new_reviewers) & cur_reviewers
 

	
 
        old_description = pull_request.description
 
        pull_request.title = _form['pullrequest_title']
 
        pull_request.description = _form['pullrequest_desc'].strip() or _('No description')
 
        pull_request.owner = User.get_by_username(_form['owner'])
 
        user = User.get(request.authuser.user_id)
 

	
 
        PullRequestModel().mention_from_description(user, pull_request, old_description)
 
        PullRequestModel().add_reviewers(user, pull_request, added_reviewers)
 
        PullRequestModel().remove_reviewers(user, pull_request, removed_reviewers)
 

	
 
        Session().commit()
 
        meta.Session().commit()
 
        h.flash(_('Pull request updated'), category='success')
 

	
 
        raise HTTPFound(location=pull_request.url())
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionLevelDecorator('read')
 
    @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.owner_id == request.authuser.user_id:
 
            PullRequestModel().delete(pull_request)
 
            Session().commit()
 
            meta.Session().commit()
 
            h.flash(_('Successfully deleted pull request'),
 
                    category='success')
 
            raise HTTPFound(location=url('my_pullrequests'))
 
        raise HTTPForbidden()
 

	
 
    @LoginRequired(allow_default_user=True)
 
    @HasRepoPermissionLevelDecorator('read')
 
    def show(self, repo_name, pull_request_id, extra=None):
 
        c.pull_request = PullRequest.get_or_404(pull_request_id)
 
        c.allowed_to_change_status = self._is_allowed_to_change_status(c.pull_request)
 
        cc_model = ChangesetCommentsModel()
 
        cs_model = ChangesetStatusModel()
kallithea/lib/auth.py
Show inline comments
 
@@ -35,27 +35,27 @@ import ipaddr
 
from decorator import decorator
 
from sqlalchemy.orm import joinedload
 
from sqlalchemy.orm.exc import ObjectDeletedError
 
from tg import request
 
from tg.i18n import ugettext as _
 
from webob.exc import HTTPForbidden, HTTPFound
 

	
 
import kallithea
 
from kallithea.lib.utils import get_repo_group_slug, get_repo_slug, get_user_group_slug
 
from kallithea.lib.utils2 import ascii_bytes, ascii_str, safe_bytes
 
from kallithea.lib.vcs.utils.lazy import LazyProperty
 
from kallithea.lib.webutils import url
 
from kallithea.model import meta
 
from kallithea.model.db import (Permission, UserApiKeys, UserGroup, UserGroupMember, UserGroupRepoGroupToPerm, UserGroupRepoToPerm, UserGroupToPerm,
 
                                UserGroupUserGroupToPerm, UserIpMap, UserToPerm)
 
from kallithea.model.meta import Session
 
from kallithea.model.user import UserModel
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class PasswordGenerator(object):
 
    """
 
    This is a simple class for generating password from different sets of
 
    characters
 
    usage::
 

	
 
@@ -223,45 +223,45 @@ class AuthUser(object):
 
            return set(['hg.admin'])
 

	
 
        global_permissions = set()
 

	
 
        # default global permissions from the default user
 
        default_global_perms = UserToPerm.query() \
 
            .filter(UserToPerm.user_id == kallithea.DEFAULT_USER_ID) \
 
            .options(joinedload(UserToPerm.permission))
 
        for perm in default_global_perms:
 
            global_permissions.add(perm.permission.permission_name)
 

	
 
        # user group global permissions
 
        user_perms_from_users_groups = Session().query(UserGroupToPerm) \
 
        user_perms_from_users_groups = meta.Session().query(UserGroupToPerm) \
 
            .options(joinedload(UserGroupToPerm.permission)) \
 
            .join((UserGroupMember, UserGroupToPerm.users_group_id ==
 
                   UserGroupMember.users_group_id)) \
 
            .filter(UserGroupMember.user_id == self.user_id) \
 
            .join((UserGroup, UserGroupMember.users_group_id ==
 
                   UserGroup.users_group_id)) \
 
            .filter(UserGroup.users_group_active == True) \
 
            .order_by(UserGroupToPerm.users_group_id) \
 
            .all()
 
        # need to group here by groups since user can be in more than
 
        # one group
 
        _grouped = [[x, list(y)] for x, y in
 
                    itertools.groupby(user_perms_from_users_groups,
 
                                      lambda x:x.users_group)]
 
        for gr, perms in _grouped:
 
            for perm in perms:
 
                global_permissions.add(perm.permission.permission_name)
 

	
 
        # user specific global permissions
 
        user_perms = Session().query(UserToPerm) \
 
        user_perms = meta.Session().query(UserToPerm) \
 
                .options(joinedload(UserToPerm.permission)) \
 
                .filter(UserToPerm.user_id == self.user_id).all()
 
        for perm in user_perms:
 
            global_permissions.add(perm.permission.permission_name)
 

	
 
        # for each kind of global permissions, only keep the one with heighest weight
 
        kind_max_perm = {}
 
        for perm in sorted(global_permissions, key=lambda n: PERM_WEIGHTS.get(n, -1)):
 
            kind = perm.rsplit('.', 1)[0]
 
            kind_max_perm[kind] = perm
 
        return set(kind_max_perm.values())
 

	
 
@@ -282,25 +282,25 @@ class AuthUser(object):
 
            for perm in default_repo_perms:
 
                r_k = perm.repository.repo_name
 
                if perm.repository.owner_id == self.user_id:
 
                    p = 'repository.admin'
 
                elif perm.repository.private:
 
                    p = 'repository.none'
 
                else:
 
                    p = perm.permission.permission_name
 
                repository_permissions[r_k] = p
 

	
 
            # user group repository permissions
 
            user_repo_perms_from_users_groups = \
 
             Session().query(UserGroupRepoToPerm) \
 
             meta.Session().query(UserGroupRepoToPerm) \
 
                .join((UserGroup, UserGroupRepoToPerm.users_group_id ==
 
                       UserGroup.users_group_id)) \
 
                .filter(UserGroup.users_group_active == True) \
 
                .join((UserGroupMember, UserGroupRepoToPerm.users_group_id ==
 
                       UserGroupMember.users_group_id)) \
 
                .filter(UserGroupMember.user_id == self.user_id) \
 
                .options(joinedload(UserGroupRepoToPerm.repository)) \
 
                .options(joinedload(UserGroupRepoToPerm.permission)) \
 
                .all()
 
            for perm in user_repo_perms_from_users_groups:
 
                bump_permission(repository_permissions,
 
                    perm.repository.repo_name,
 
@@ -328,25 +328,25 @@ class AuthUser(object):
 
                repository_group_permissions[rg_k] = p
 

	
 
        else:
 
            # defaults for repository groups taken from default user permission
 
            # on given group
 
            for perm in default_repo_groups_perms:
 
                rg_k = perm.group.group_name
 
                p = perm.permission.permission_name
 
                repository_group_permissions[rg_k] = p
 

	
 
            # user group for repo groups permissions
 
            user_repo_group_perms_from_users_groups = \
 
                Session().query(UserGroupRepoGroupToPerm) \
 
                meta.Session().query(UserGroupRepoGroupToPerm) \
 
                .join((UserGroup, UserGroupRepoGroupToPerm.users_group_id ==
 
                       UserGroup.users_group_id)) \
 
                .filter(UserGroup.users_group_active == True) \
 
                .join((UserGroupMember, UserGroupRepoGroupToPerm.users_group_id
 
                       == UserGroupMember.users_group_id)) \
 
                .filter(UserGroupMember.user_id == self.user_id) \
 
                .options(joinedload(UserGroupRepoGroupToPerm.permission)) \
 
                .all()
 
            for perm in user_repo_group_perms_from_users_groups:
 
                bump_permission(repository_group_permissions,
 
                    perm.group.group_name,
 
                    perm.permission.permission_name)
 
@@ -373,25 +373,25 @@ class AuthUser(object):
 
                user_group_permissions[u_k] = p
 

	
 
        else:
 
            # defaults for user groups taken from default user permission
 
            # on given user group
 
            for perm in default_user_group_perms:
 
                u_k = perm.user_group.users_group_name
 
                p = perm.permission.permission_name
 
                user_group_permissions[u_k] = p
 

	
 
            # user group for user group permissions
 
            user_group_user_groups_perms = \
 
                Session().query(UserGroupUserGroupToPerm) \
 
                meta.Session().query(UserGroupUserGroupToPerm) \
 
                .join((UserGroup, UserGroupUserGroupToPerm.target_user_group_id
 
                       == UserGroup.users_group_id)) \
 
                .join((UserGroupMember, UserGroupUserGroupToPerm.user_group_id
 
                       == UserGroupMember.users_group_id)) \
 
                .filter(UserGroupMember.user_id == self.user_id) \
 
                .join((UserGroup, UserGroupMember.users_group_id ==
 
                       UserGroup.users_group_id), aliased=True, from_joinpoint=True) \
 
                .filter(UserGroup.users_group_active == True) \
 
                .options(joinedload(UserGroupUserGroupToPerm.permission)) \
 
                .all()
 
            for perm in user_group_user_groups_perms:
 
                bump_permission(user_group_permissions,
kallithea/lib/auth_modules/__init__.py
Show inline comments
 
@@ -14,27 +14,26 @@
 
"""
 
Authentication modules
 
"""
 

	
 
import importlib
 
import logging
 
import traceback
 
from inspect import isfunction
 

	
 
from kallithea.lib.auth import AuthUser, PasswordGenerator
 
from kallithea.lib.compat import hybrid_property
 
from kallithea.lib.utils2 import asbool
 
from kallithea.model import validators
 
from kallithea.model import meta, validators
 
from kallithea.model.db import Setting, User
 
from kallithea.model.meta import Session
 
from kallithea.model.user import UserModel
 
from kallithea.model.user_group import UserGroupModel
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class LazyFormencode(object):
 
    def __init__(self, formencode_obj, *args, **kwargs):
 
        self.formencode_obj = formencode_obj
 
        self.args = args
 
        self.kwargs = kwargs
 
@@ -258,25 +257,25 @@ class KallitheaExternalAuthPlugin(Kallit
 
                email=user_data["email"],
 
                firstname=user_data["firstname"],
 
                lastname=user_data["lastname"],
 
                active=active,
 
                admin=user_data["admin"],
 
                extern_name=user_data["extern_name"],
 
                extern_type=self.name,
 
            )
 
            # enforce user is just in given groups, all of them has to be ones
 
            # created from plugins. We store this info in _group_data JSON field
 
            groups = user_data['groups'] or []
 
            UserGroupModel().enforce_groups(user, groups, self.name)
 
            Session().commit()
 
            meta.Session().commit()
 
        return user_data
 

	
 

	
 
def loadplugin(plugin):
 
    """
 
    Imports, instantiates, and returns the authentication plugin in the module named by plugin
 
    (e.g., plugin='kallithea.lib.auth_modules.auth_internal'). Returns an instance of the
 
    KallitheaAuthPluginBase subclass on success, raises exceptions on failure.
 

	
 
    raises:
 
        AttributeError -- no KallitheaAuthPlugin class in the module
 
        TypeError -- if the KallitheaAuthPlugin is not a subclass of ours KallitheaAuthPluginBase
kallithea/lib/db_manage.py
Show inline comments
 
@@ -29,27 +29,27 @@ Original author and date, and relevant c
 
import getpass
 
import logging
 
import os
 
import sys
 
import uuid
 

	
 
import alembic.command
 
import alembic.config
 
import sqlalchemy
 
from sqlalchemy.engine import create_engine
 

	
 
from kallithea.lib.utils2 import ask_ok
 
from kallithea.model import meta
 
from kallithea.model.base import init_model
 
from kallithea.model.db import Repository, Setting, Ui, User
 
from kallithea.model.meta import Base, Session
 
from kallithea.model.permission import PermissionModel
 
from kallithea.model.user import UserModel
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class DbManage(object):
 
    def __init__(self, dbconf, root, SESSION=None, cli_args=None):
 
        self.dbname = dbconf.split('/')[-1]
 
        self.root = root
 
        self.dburi = dbconf
 
@@ -61,67 +61,67 @@ class DbManage(object):
 
        force_ask = self.cli_args.get('force_ask')
 
        if force_ask is not None:
 
            return force_ask
 
        return ask_ok(msg)
 

	
 
    def init_db(self, SESSION=None):
 
        if SESSION:
 
            self.sa = SESSION
 
        else:
 
            # init new sessions
 
            engine = create_engine(self.dburi)
 
            init_model(engine)
 
            self.sa = Session()
 
            self.sa = meta.Session()
 

	
 
    def create_tables(self, reuse_database=False):
 
        """
 
        Create database (optional) and tables.
 
        If reuse_database is false, the database will be dropped (if it exists)
 
        and a new one created. If true, the existing database will be reused
 
        and cleaned for content.
 
        """
 
        url = sqlalchemy.engine.url.make_url(self.dburi)
 
        database = url.database
 
        if reuse_database:
 
            log.info("The content of the database %r will be destroyed and new tables created." % database)
 
        else:
 
            log.info("The existing database %r will be destroyed and a new one created." % database)
 

	
 
        if not self._ask_ok('Are you sure to destroy old database? [y/n]'):
 
            print('Nothing done.')
 
            sys.exit(0)
 

	
 
        if reuse_database:
 
            Base.metadata.drop_all()
 
            meta.Base.metadata.drop_all()
 
        else:
 
            if url.drivername == 'mysql':
 
                url.database = None  # don't connect to the database (it might not exist)
 
                engine = sqlalchemy.create_engine(url)
 
                with engine.connect() as conn:
 
                    conn.execute('DROP DATABASE IF EXISTS `%s`' % database)
 
                    conn.execute('CREATE DATABASE `%s` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci' % database)
 
            elif url.drivername == 'postgresql':
 
                from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT
 
                url.database = 'postgres'  # connect to the system database (as the real one might not exist)
 
                engine = sqlalchemy.create_engine(url)
 
                with engine.connect() as conn:
 
                    conn.connection.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)
 
                    conn.execute('DROP DATABASE IF EXISTS "%s"' % database)
 
                    conn.execute('CREATE DATABASE "%s"' % database)
 
            else:
 
                # Some databases enforce foreign key constraints and Base.metadata.drop_all() doesn't work, but this is
 
                # known to work on SQLite - possibly not on other databases with strong referential integrity
 
                Base.metadata.drop_all()
 
                meta.Base.metadata.drop_all()
 

	
 
        Base.metadata.create_all(checkfirst=False)
 
        meta.Base.metadata.create_all(checkfirst=False)
 

	
 
        # Create an Alembic configuration and generate the version table,
 
        # "stamping" it with the most recent Alembic migration revision, to
 
        # tell Alembic that all the schema upgrades are already in effect.
 
        alembic_cfg = alembic.config.Config()
 
        alembic_cfg.set_main_option('script_location', 'kallithea:alembic')
 
        alembic_cfg.set_main_option('sqlalchemy.url', self.dburi)
 
        # This command will give an error in an Alembic multi-head scenario,
 
        # but in practice, such a scenario should not come up during database
 
        # creation, even during development.
 
        alembic.command.stamp(alembic_cfg, 'head')
 

	
 
@@ -294,25 +294,25 @@ class DbManage(object):
 
        log.info('creating default user')
 
        # create default user for handling default permissions.
 
        user = UserModel().create_or_update(username=User.DEFAULT_USER_NAME,
 
                                            password=str(uuid.uuid1())[:20],
 
                                            email='anonymous@kallithea-scm.org',
 
                                            firstname='Anonymous',
 
                                            lastname='User')
 
        # based on configuration options activate/deactivate this user which
 
        # controls anonymous access
 
        if self.cli_args.get('public_access') is False:
 
            log.info('Public access disabled')
 
            user.active = False
 
            Session().commit()
 
            meta.Session().commit()
 

	
 
    def create_permissions(self):
 
        """
 
        Creates all permissions defined in the system
 
        """
 
        # module.(access|create|change|delete)_[name]
 
        # module.(none|read|write|admin)
 
        log.info('creating permissions')
 
        PermissionModel().create_permissions()
 

	
 
    def populate_default_permissions(self):
 
        """
kallithea/lib/vcs/backends/ssh.py
Show inline comments
 
@@ -16,26 +16,26 @@
 
vcs.backends.ssh
 
~~~~~~~~~~~~~~~~~
 

	
 
SSH backend for all available SCMs
 
"""
 

	
 
import datetime
 
import logging
 
import sys
 

	
 
from kallithea.lib.auth import AuthUser, HasPermissionAnyMiddleware
 
from kallithea.lib.utils2 import set_hook_environment
 
from kallithea.model import meta
 
from kallithea.model.db import Repository, User, UserSshKeys
 
from kallithea.model.meta import Session
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class BaseSshHandler(object):
 
    # Protocol for setting properties:
 
    # Set by sub class:
 
    #   vcs_type: 'hg' or 'git'
 
    # Set by make() / __init__():
 
    #   repo_name: requested repo name - only validated by serve()
 
    # Set by serve() - must not be accessed before:
 
@@ -65,25 +65,25 @@ class BaseSshHandler(object):
 
        dbuser = User.get(user_id)
 
        if dbuser is None:
 
            self.exit('User %r not found' % user_id)
 
        self.authuser = AuthUser.make(dbuser=dbuser, ip_addr=client_ip)
 
        log.info('Authorized user %s from SSH %s trusting user id %s and key id %s for %r', dbuser, client_ip, user_id, key_id, self.repo_name)
 
        if self.authuser is None: # not ok ... but already kind of authenticated by SSH ... but not really not authorized ...
 
            self.exit('User %s from %s cannot be authorized' % (dbuser.username, client_ip))
 

	
 
        ssh_key = UserSshKeys.get(key_id)
 
        if ssh_key is None:
 
            self.exit('SSH key %r not found' % key_id)
 
        ssh_key.last_seen = datetime.datetime.now()
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        if HasPermissionAnyMiddleware('repository.write',
 
                                      'repository.admin')(self.authuser, self.repo_name):
 
            self.allow_push = True
 
        elif HasPermissionAnyMiddleware('repository.read')(self.authuser, self.repo_name):
 
            self.allow_push = False
 
        else:
 
            self.exit('Access to %r denied' % self.repo_name)
 

	
 
        self.db_repo = Repository.get_by_repo_name(self.repo_name)
 
        if self.db_repo is None:
 
            self.exit("Repository '%s' not found" % self.repo_name)
kallithea/model/api_key.py
Show inline comments
 
@@ -20,59 +20,59 @@ API key model 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: Sep 8, 2013
 
:author: marcink
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 

	
 
import logging
 
import time
 

	
 
from kallithea.lib.utils2 import generate_api_key
 
from kallithea.model import meta
 
from kallithea.model.db import User, UserApiKeys
 
from kallithea.model.meta import Session
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class ApiKeyModel(object):
 

	
 
    def create(self, user, description, lifetime=-1):
 
        """
 
        :param user: user or user_id
 
        :param description: description of ApiKey
 
        :param lifetime: expiration time in seconds
 
        """
 
        user = User.guess_instance(user)
 

	
 
        new_api_key = UserApiKeys()
 
        new_api_key.api_key = generate_api_key()
 
        new_api_key.user_id = user.user_id
 
        new_api_key.description = description
 
        new_api_key.expires = time.time() + (lifetime * 60) if lifetime != -1 else -1
 
        Session().add(new_api_key)
 
        meta.Session().add(new_api_key)
 

	
 
        return new_api_key
 

	
 
    def delete(self, api_key, user=None):
 
        """
 
        Deletes given api_key, if user is set it also filters the object for
 
        deletion by given user.
 
        """
 
        api_key = UserApiKeys.query().filter(UserApiKeys.api_key == api_key)
 

	
 
        if user is not None:
 
            user = User.guess_instance(user)
 
            api_key = api_key.filter(UserApiKeys.user_id == user.user_id)
 

	
 
        api_key = api_key.scalar()
 
        Session().delete(api_key)
 
        meta.Session().delete(api_key)
 

	
 
    def get_api_keys(self, user, show_expired=True):
 
        user = User.guess_instance(user)
 
        user_api_keys = UserApiKeys.query() \
 
            .filter(UserApiKeys.user_id == user.user_id)
 
        if not show_expired:
 
            user_api_keys = user_api_keys.filter_by(is_expired=False)
 
        return user_api_keys
kallithea/model/comment.py
Show inline comments
 
@@ -23,40 +23,40 @@ Original author and date, and relevant c
 
:author: marcink
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 

	
 
import logging
 
from collections import defaultdict
 

	
 
from tg.i18n import ugettext as _
 

	
 
from kallithea.lib import helpers as h
 
from kallithea.lib.utils import extract_mentioned_users
 
from kallithea.model import meta
 
from kallithea.model.db import ChangesetComment, PullRequest, Repository, User
 
from kallithea.model.meta import Session
 
from kallithea.model.notification import NotificationModel
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
def _list_changeset_commenters(revision):
 
    return (Session().query(User)
 
    return (meta.Session().query(User)
 
        .join(ChangesetComment.author)
 
        .filter(ChangesetComment.revision == revision)
 
        .all())
 

	
 
def _list_pull_request_commenters(pull_request):
 
    return (Session().query(User)
 
    return (meta.Session().query(User)
 
        .join(ChangesetComment.author)
 
        .filter(ChangesetComment.pull_request_id == pull_request.pull_request_id)
 
        .all())
 

	
 

	
 
class ChangesetCommentsModel(object):
 

	
 
    def _get_notification_data(self, repo, comment, author, comment_text,
 
                               line_no=None, revision=None, pull_request=None,
 
                               status_change=None, closing_pr=False):
 
        """
 
        :returns: tuple (subj,body,recipients,notification_type,email_kwargs)
 
@@ -184,26 +184,26 @@ class ChangesetCommentsModel(object):
 
        comment.text = text
 
        comment.f_path = f_path
 
        comment.line_no = line_no
 

	
 
        if revision is not None:
 
            comment.revision = revision
 
        elif pull_request is not None:
 
            pull_request = PullRequest.guess_instance(pull_request)
 
            comment.pull_request = pull_request
 
        else:
 
            raise Exception('Please specify revision or pull_request_id')
 

	
 
        Session().add(comment)
 
        Session().flush()
 
        meta.Session().add(comment)
 
        meta.Session().flush()
 

	
 
        if send_email:
 
            (subj, body, recipients, notification_type,
 
             email_kwargs) = self._get_notification_data(
 
                                repo, comment, author,
 
                                comment_text=text,
 
                                line_no=line_no,
 
                                revision=revision,
 
                                pull_request=pull_request,
 
                                status_change=status_change,
 
                                closing_pr=closing_pr)
 
            email_kwargs['is_mention'] = False
 
@@ -221,25 +221,25 @@ class ChangesetCommentsModel(object):
 
                # FIXME: this subject is wrong and unused!
 
                NotificationModel().create(
 
                    created_by=author, subject=subj, body=body,
 
                    recipients=mention_recipients,
 
                    type_=notification_type,
 
                    email_kwargs=email_kwargs
 
                )
 

	
 
        return comment
 

	
 
    def delete(self, comment):
 
        comment = ChangesetComment.guess_instance(comment)
 
        Session().delete(comment)
 
        meta.Session().delete(comment)
 

	
 
        return comment
 

	
 
    def get_comments(self, repo_id, revision=None, pull_request=None):
 
        """
 
        Gets general comments for either revision or pull_request.
 

	
 
        Returns a list, ordered by creation date.
 
        """
 
        return self._get_comments(repo_id, revision=revision, pull_request=pull_request,
 
                                  inline=False)
 

	
 
@@ -261,25 +261,25 @@ class ChangesetCommentsModel(object):
 
    def _get_comments(self, repo_id, revision=None, pull_request=None,
 
                inline=False, f_path=None, line_no=None):
 
        """
 
        Gets comments for either revision or pull_request_id, either inline or general.
 
        If a file path and optionally line number are given, return only the matching inline comments.
 
        """
 
        if f_path is None and line_no is not None:
 
            raise Exception("line_no only makes sense if f_path is given.")
 

	
 
        if inline is None and f_path is not None:
 
            raise Exception("f_path only makes sense for inline comments.")
 

	
 
        q = Session().query(ChangesetComment)
 
        q = meta.Session().query(ChangesetComment)
 

	
 
        if inline:
 
            if f_path is not None:
 
                # inline comments for a given file...
 
                q = q.filter(ChangesetComment.f_path == f_path)
 
                if line_no is None:
 
                    # ... on any line
 
                    q = q.filter(ChangesetComment.line_no != None)
 
                else:
 
                    # ... on specific line
 
                    q = q.filter(ChangesetComment.line_no == line_no)
 
            else:
kallithea/model/db.py
Show inline comments
 
@@ -41,25 +41,25 @@ from sqlalchemy import Boolean, Column, 
 
from sqlalchemy.ext.hybrid import hybrid_property
 
from sqlalchemy.orm import class_mapper, joinedload, relationship, validates
 
from tg.i18n import lazy_ugettext as _
 
from webob.exc import HTTPNotFound
 

	
 
import kallithea
 
from kallithea.lib import ext_json, ssh
 
from kallithea.lib.exceptions import DefaultUserException
 
from kallithea.lib.utils2 import asbool, ascii_bytes, aslist, get_changeset_safe, get_clone_url, remove_prefix, safe_bytes, safe_int, safe_str, urlreadable
 
from kallithea.lib.vcs import get_backend
 
from kallithea.lib.vcs.backends.base import EmptyChangeset
 
from kallithea.lib.vcs.utils.helpers import get_scm
 
from kallithea.model.meta import Base, Session
 
from kallithea.model import meta
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 
#==============================================================================
 
# BASE CLASSES
 
#==============================================================================
 

	
 
class BaseDbModel(object):
 
    """
 
    Base Model for all classes
 
    """
 
@@ -98,25 +98,25 @@ class BaseDbModel(object):
 
            for k in self._get_keys()
 
        ]
 

	
 
    def populate_obj(self, populate_dict):
 
        """populate model with data from given populate_dict"""
 

	
 
        for k in self._get_keys():
 
            if k in populate_dict:
 
                setattr(self, k, populate_dict[k])
 

	
 
    @classmethod
 
    def query(cls):
 
        return Session().query(cls)
 
        return meta.Session().query(cls)
 

	
 
    @classmethod
 
    def get(cls, id_):
 
        if id_:
 
            return cls.query().get(id_)
 

	
 
    @classmethod
 
    def guess_instance(cls, value, callback=None):
 
        """Haphazardly attempt to convert `value` to a `cls` instance.
 

	
 
        If `value` is None or already a `cls` instance, return it. If `value`
 
        is a number (or looks like one if you squint just right), assume it's
 
@@ -148,36 +148,36 @@ class BaseDbModel(object):
 
            id_ = int(id_)
 
        except (TypeError, ValueError):
 
            raise HTTPNotFound
 

	
 
        res = cls.query().get(id_)
 
        if res is None:
 
            raise HTTPNotFound
 
        return res
 

	
 
    @classmethod
 
    def delete(cls, id_):
 
        obj = cls.query().get(id_)
 
        Session().delete(obj)
 
        meta.Session().delete(obj)
 

	
 
    def __repr__(self):
 
        return '<DB:%s>' % (self.__class__.__name__)
 

	
 

	
 
_table_args_default_dict = {'extend_existing': True,
 
                            'mysql_engine': 'InnoDB',
 
                            'sqlite_autoincrement': True,
 
                           }
 

	
 
class Setting(Base, BaseDbModel):
 
class Setting(meta.Base, BaseDbModel):
 
    __tablename__ = 'settings'
 
    __table_args__ = (
 
        _table_args_default_dict,
 
    )
 

	
 
    SETTINGS_TYPES = {
 
        'str': safe_bytes,
 
        'int': safe_int,
 
        'unicode': safe_str,
 
        'bool': asbool,
 
        'list': functools.partial(aslist, sep=',')
 
    }
 
@@ -248,25 +248,25 @@ class Setting(Base, BaseDbModel):
 

	
 
        :param key:
 
        :param val:
 
        :param type:
 
        :return:
 
        """
 
        res = cls.get_by_name(key)
 
        if res is None:
 
            # new setting
 
            val = val if val is not None else ''
 
            type = type if type is not None else 'unicode'
 
            res = cls(key, val, type)
 
            Session().add(res)
 
            meta.Session().add(res)
 
        else:
 
            if val is not None:
 
                # update if set
 
                res.app_settings_value = val
 
            if type is not None:
 
                # update if set
 
                res.app_settings_type = type
 
        return res
 

	
 
    @classmethod
 
    def get_app_settings(cls):
 

	
 
@@ -312,25 +312,25 @@ class Setting(Base, BaseDbModel):
 
        mods = [(p.project_name, p.version) for p in pkg_resources.working_set]
 
        info = {
 
            'modules': sorted(mods, key=lambda k: k[0].lower()),
 
            'py_version': platform.python_version(),
 
            'platform': platform.platform(),
 
            'kallithea_version': kallithea.__version__,
 
            'git_version': str(check_git_version()),
 
            'git_path': kallithea.CONFIG.get('git_path')
 
        }
 
        return info
 

	
 

	
 
class Ui(Base, BaseDbModel):
 
class Ui(meta.Base, BaseDbModel):
 
    __tablename__ = 'ui'
 
    __table_args__ = (
 
        Index('ui_ui_section_ui_key_idx', 'ui_section', 'ui_key'),
 
        UniqueConstraint('ui_section', 'ui_key'),
 
        _table_args_default_dict,
 
    )
 

	
 
    HOOK_UPDATE = 'changegroup.update'
 
    HOOK_REPO_SIZE = 'changegroup.repo_size'
 

	
 
    ui_id = Column(Integer(), primary_key=True)
 
    ui_section = Column(String(255), nullable=False)
 
@@ -340,25 +340,25 @@ class Ui(Base, BaseDbModel):
 

	
 
    @classmethod
 
    def get_by_key(cls, section, key):
 
        """ Return specified Ui object, or None if not found. """
 
        return cls.query().filter_by(ui_section=section, ui_key=key).scalar()
 

	
 
    @classmethod
 
    def get_or_create(cls, section, key):
 
        """ Return specified Ui object, creating it if necessary. """
 
        setting = cls.get_by_key(section, key)
 
        if setting is None:
 
            setting = cls(ui_section=section, ui_key=key)
 
            Session().add(setting)
 
            meta.Session().add(setting)
 
        return setting
 

	
 
    @classmethod
 
    def get_builtin_hooks(cls):
 
        q = cls.query()
 
        q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE]))
 
        q = q.filter(cls.ui_section == 'hooks')
 
        q = q.order_by(cls.ui_section, cls.ui_key)
 
        return q.all()
 

	
 
    @classmethod
 
    def get_custom_hooks(cls):
 
@@ -375,25 +375,25 @@ class Ui(Base, BaseDbModel):
 
    @classmethod
 
    def create_or_update_hook(cls, key, val):
 
        new_ui = cls.get_or_create('hooks', key)
 
        new_ui.ui_active = True
 
        new_ui.ui_value = val
 

	
 
    def __repr__(self):
 
        return '<%s %s.%s=%r>' % (
 
            self.__class__.__name__,
 
            self.ui_section, self.ui_key, self.ui_value)
 

	
 

	
 
class User(Base, BaseDbModel):
 
class User(meta.Base, BaseDbModel):
 
    __tablename__ = 'users'
 
    __table_args__ = (
 
        Index('u_username_idx', 'username'),
 
        Index('u_email_idx', 'email'),
 
        _table_args_default_dict,
 
    )
 

	
 
    DEFAULT_USER_NAME = 'default'
 
    DEFAULT_GRAVATAR_URL = 'https://secure.gravatar.com/avatar/{md5email}?d=identicon&s={size}'
 
    # The name of the default auth type in extern_type, 'internal' lives in auth_internal.py
 
    DEFAULT_AUTH_TYPE = 'internal'
 

	
 
@@ -655,76 +655,76 @@ class User(Base, BaseDbModel):
 

	
 
    def __json__(self):
 
        data = dict(
 
            full_name=self.full_name,
 
            full_name_or_username=self.full_name_or_username,
 
            short_contact=self.short_contact,
 
            full_contact=self.full_contact
 
        )
 
        data.update(self.get_api_data())
 
        return data
 

	
 

	
 
class UserApiKeys(Base, BaseDbModel):
 
class UserApiKeys(meta.Base, BaseDbModel):
 
    __tablename__ = 'user_api_keys'
 
    __table_args__ = (
 
        Index('uak_api_key_idx', 'api_key'),
 
        Index('uak_api_key_expires_idx', 'api_key', 'expires'),
 
        _table_args_default_dict,
 
    )
 

	
 
    user_api_key_id = Column(Integer(), primary_key=True)
 
    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
 
    api_key = Column(String(255), nullable=False, unique=True)
 
    description = Column(UnicodeText(), nullable=False)
 
    expires = Column(Float(53), nullable=False)
 
    created_on = Column(DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
 

	
 
    user = relationship('User')
 

	
 
    @hybrid_property
 
    def is_expired(self):
 
        return (self.expires != -1) & (time.time() > self.expires)
 

	
 

	
 
class UserEmailMap(Base, BaseDbModel):
 
class UserEmailMap(meta.Base, BaseDbModel):
 
    __tablename__ = 'user_email_map'
 
    __table_args__ = (
 
        Index('uem_email_idx', 'email'),
 
        _table_args_default_dict,
 
    )
 

	
 
    email_id = Column(Integer(), primary_key=True)
 
    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
 
    _email = Column("email", String(255), nullable=False, unique=True)
 
    user = relationship('User')
 

	
 
    @validates('_email')
 
    def validate_email(self, key, email):
 
        # check if this email is not main one
 
        main_email = Session().query(User).filter(User.email == email).scalar()
 
        main_email = meta.Session().query(User).filter(User.email == email).scalar()
 
        if main_email is not None:
 
            raise AttributeError('email %s is present is user table' % email)
 
        return email
 

	
 
    @hybrid_property
 
    def email(self):
 
        return self._email
 

	
 
    @email.setter
 
    def email(self, val):
 
        self._email = val.lower() if val else None
 

	
 

	
 
class UserIpMap(Base, BaseDbModel):
 
class UserIpMap(meta.Base, BaseDbModel):
 
    __tablename__ = 'user_ip_map'
 
    __table_args__ = (
 
        UniqueConstraint('user_id', 'ip_addr'),
 
        _table_args_default_dict,
 
    )
 

	
 
    ip_id = Column(Integer(), primary_key=True)
 
    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
 
    ip_addr = Column(String(255), nullable=False)
 
    active = Column(Boolean(), nullable=False, default=True)
 
    user = relationship('User')
 

	
 
@@ -734,25 +734,25 @@ class UserIpMap(Base, BaseDbModel):
 
        return [str(net.network), str(net.broadcast)]
 

	
 
    def __json__(self):
 
        return dict(
 
          ip_addr=self.ip_addr,
 
          ip_range=self._get_ip_range(self.ip_addr)
 
        )
 

	
 
    def __repr__(self):
 
        return "<%s %s: %s>" % (self.__class__.__name__, self.user_id, self.ip_addr)
 

	
 

	
 
class UserLog(Base, BaseDbModel):
 
class UserLog(meta.Base, BaseDbModel):
 
    __tablename__ = 'user_logs'
 
    __table_args__ = (
 
        _table_args_default_dict,
 
    )
 

	
 
    user_log_id = Column(Integer(), primary_key=True)
 
    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=True)
 
    username = Column(String(255), nullable=False)
 
    repository_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=True)
 
    repository_name = Column(Unicode(255), nullable=False)
 
    user_ip = Column(String(255), nullable=True)
 
    action = Column(UnicodeText(), nullable=False)
 
@@ -762,25 +762,25 @@ class UserLog(Base, BaseDbModel):
 
        return "<%s %r: %r>" % (self.__class__.__name__,
 
                                  self.repository_name,
 
                                  self.action)
 

	
 
    @property
 
    def action_as_day(self):
 
        return datetime.date(*self.action_date.timetuple()[:3])
 

	
 
    user = relationship('User')
 
    repository = relationship('Repository', cascade='')
 

	
 

	
 
class UserGroup(Base, BaseDbModel):
 
class UserGroup(meta.Base, BaseDbModel):
 
    __tablename__ = 'users_groups'
 
    __table_args__ = (
 
        _table_args_default_dict,
 
    )
 

	
 
    users_group_id = Column(Integer(), primary_key=True)
 
    users_group_name = Column(Unicode(255), nullable=False, unique=True)
 
    user_group_description = Column(Unicode(10000), nullable=True) # FIXME: not nullable?
 
    users_group_active = Column(Boolean(), nullable=False)
 
    owner_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
 
    created_on = Column(DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
 
    _group_data = Column("group_data", LargeBinary(), nullable=True)  # JSON data # FIXME: not nullable?
 
@@ -843,43 +843,43 @@ class UserGroup(Base, BaseDbModel):
 
            active=user_group.users_group_active,
 
            owner=user_group.owner.username,
 
        )
 
        if with_members:
 
            data['members'] = [
 
                ugm.user.get_api_data()
 
                for ugm in user_group.members
 
            ]
 

	
 
        return data
 

	
 

	
 
class UserGroupMember(Base, BaseDbModel):
 
class UserGroupMember(meta.Base, BaseDbModel):
 
    __tablename__ = 'users_groups_members'
 
    __table_args__ = (
 
        _table_args_default_dict,
 
    )
 

	
 
    users_group_member_id = Column(Integer(), primary_key=True)
 
    users_group_id = Column(Integer(), ForeignKey('users_groups.users_group_id'), nullable=False)
 
    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
 

	
 
    user = relationship('User')
 
    users_group = relationship('UserGroup')
 

	
 
    def __init__(self, gr_id='', u_id=''):
 
        self.users_group_id = gr_id
 
        self.user_id = u_id
 

	
 

	
 
class RepositoryField(Base, BaseDbModel):
 
class RepositoryField(meta.Base, BaseDbModel):
 
    __tablename__ = 'repositories_fields'
 
    __table_args__ = (
 
        UniqueConstraint('repository_id', 'field_key'),  # no-multi field
 
        _table_args_default_dict,
 
    )
 

	
 
    PREFIX = 'ex_'  # prefix used in form to not conflict with already existing fields
 

	
 
    repo_field_id = Column(Integer(), primary_key=True)
 
    repository_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=False)
 
    field_key = Column(String(250), nullable=False)
 
    field_label = Column(String(1024), nullable=False)
 
@@ -899,25 +899,25 @@ class RepositoryField(Base, BaseDbModel)
 
        if key.startswith(cls.PREFIX):
 
            return key[len(cls.PREFIX):]
 
        return key
 

	
 
    @classmethod
 
    def get_by_key_name(cls, key, repo):
 
        row = cls.query() \
 
                .filter(cls.repository == repo) \
 
                .filter(cls.field_key == key).scalar()
 
        return row
 

	
 

	
 
class Repository(Base, BaseDbModel):
 
class Repository(meta.Base, BaseDbModel):
 
    __tablename__ = 'repositories'
 
    __table_args__ = (
 
        Index('r_repo_name_idx', 'repo_name'),
 
        _table_args_default_dict,
 
    )
 

	
 
    DEFAULT_CLONE_URI = '{scheme}://{user}@{netloc}/{repo}'
 
    DEFAULT_CLONE_SSH = 'ssh://{system_user}@{hostname}/{repo}'
 

	
 
    STATE_CREATED = 'repo_state_created'
 
    STATE_PENDING = 'repo_state_pending'
 
    STATE_ERROR = 'repo_state_error'
 
@@ -1026,27 +1026,27 @@ class Repository(Base, BaseDbModel):
 
        """
 
        return kallithea.URL_SEP.join(repo_name.split(os.sep))
 

	
 
    @classmethod
 
    def guess_instance(cls, value):
 
        return super(Repository, cls).guess_instance(value, Repository.get_by_repo_name)
 

	
 
    @classmethod
 
    def get_by_repo_name(cls, repo_name, case_insensitive=False):
 
        """Get the repo, defaulting to database case sensitivity.
 
        case_insensitive will be slower and should only be specified if necessary."""
 
        if case_insensitive:
 
            q = Session().query(cls).filter(sqlalchemy.func.lower(cls.repo_name) == sqlalchemy.func.lower(repo_name))
 
            q = meta.Session().query(cls).filter(sqlalchemy.func.lower(cls.repo_name) == sqlalchemy.func.lower(repo_name))
 
        else:
 
            q = Session().query(cls).filter(cls.repo_name == repo_name)
 
            q = meta.Session().query(cls).filter(cls.repo_name == repo_name)
 
        q = q.options(joinedload(Repository.fork)) \
 
                .options(joinedload(Repository.owner)) \
 
                .options(joinedload(Repository.group))
 
        return q.scalar()
 

	
 
    @classmethod
 
    def get_by_full_path(cls, repo_full_path):
 
        base_full_path = os.path.realpath(kallithea.CONFIG['base_path'])
 
        repo_full_path = os.path.realpath(repo_full_path)
 
        assert repo_full_path.startswith(base_full_path + os.path.sep)
 
        repo_name = repo_full_path[len(base_full_path) + 1:]
 
        repo_name = cls.normalize_repo_name(repo_name)
 
@@ -1239,25 +1239,25 @@ class Repository(Base, BaseDbModel):
 
                cs_cache = scm_repo.get_changeset()
 

	
 
        if isinstance(cs_cache, BaseChangeset):
 
            cs_cache = cs_cache.__json__()
 

	
 
        if (not self.changeset_cache or cs_cache['raw_id'] != self.changeset_cache['raw_id']):
 
            _default = datetime.datetime.fromtimestamp(0)
 
            last_change = cs_cache.get('date') or _default
 
            log.debug('updated repo %s with new cs cache %s',
 
                      self.repo_name, cs_cache)
 
            self.updated_on = last_change
 
            self.changeset_cache = cs_cache
 
            Session().commit()
 
            meta.Session().commit()
 
        else:
 
            log.debug('changeset_cache for %s already up to date with %s',
 
                      self.repo_name, cs_cache['raw_id'])
 

	
 
    @property
 
    def tip(self):
 
        return self.get_changeset('tip')
 

	
 
    @property
 
    def author(self):
 
        return self.tip.author
 

	
 
@@ -1348,25 +1348,25 @@ class Repository(Base, BaseDbModel):
 
            self._scm_instance = backend(repo_full_path, create=False)
 

	
 
        return self._scm_instance
 

	
 
    def __json__(self):
 
        return dict(
 
            repo_id=self.repo_id,
 
            repo_name=self.repo_name,
 
            landing_rev=self.landing_rev,
 
        )
 

	
 

	
 
class RepoGroup(Base, BaseDbModel):
 
class RepoGroup(meta.Base, BaseDbModel):
 
    __tablename__ = 'groups'
 
    __table_args__ = (
 
        _table_args_default_dict,
 
    )
 

	
 
    SEP = ' &raquo; '
 

	
 
    group_id = Column(Integer(), primary_key=True)
 
    group_name = Column(Unicode(255), nullable=False, unique=True) # full path
 
    parent_group_id = Column('group_parent_id', Integer(), ForeignKey('groups.group_id'), nullable=True)
 
    group_description = Column(Unicode(10000), nullable=False)
 
    owner_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
 
@@ -1517,25 +1517,25 @@ class RepoGroup(Base, BaseDbModel):
 
        group = self
 
        data = dict(
 
            group_id=group.group_id,
 
            group_name=group.group_name,
 
            group_description=group.group_description,
 
            parent_group=group.parent_group.group_name if group.parent_group else None,
 
            repositories=[x.repo_name for x in group.repositories],
 
            owner=group.owner.username
 
        )
 
        return data
 

	
 

	
 
class Permission(Base, BaseDbModel):
 
class Permission(meta.Base, BaseDbModel):
 
    __tablename__ = 'permissions'
 
    __table_args__ = (
 
        Index('p_perm_name_idx', 'permission_name'),
 
        _table_args_default_dict,
 
    )
 

	
 
    PERMS = (
 
        ('hg.admin', _('Kallithea Administrator')),
 

	
 
        ('repository.none', _('Default user has no access to new repositories')),
 
        ('repository.read', _('Default user has read access to new repositories')),
 
        ('repository.write', _('Default user has write access to new repositories')),
 
@@ -1624,297 +1624,297 @@ class Permission(Base, BaseDbModel):
 
        )
 

	
 
    @classmethod
 
    def guess_instance(cls, value):
 
        return super(Permission, cls).guess_instance(value, Permission.get_by_key)
 

	
 
    @classmethod
 
    def get_by_key(cls, key):
 
        return cls.query().filter(cls.permission_name == key).scalar()
 

	
 
    @classmethod
 
    def get_default_perms(cls, default_user_id):
 
        q = Session().query(UserRepoToPerm) \
 
        q = meta.Session().query(UserRepoToPerm) \
 
         .options(joinedload(UserRepoToPerm.repository)) \
 
         .options(joinedload(UserRepoToPerm.permission)) \
 
         .filter(UserRepoToPerm.user_id == default_user_id)
 

	
 
        return q.all()
 

	
 
    @classmethod
 
    def get_default_group_perms(cls, default_user_id):
 
        q = Session().query(UserRepoGroupToPerm) \
 
        q = meta.Session().query(UserRepoGroupToPerm) \
 
         .options(joinedload(UserRepoGroupToPerm.group)) \
 
         .options(joinedload(UserRepoGroupToPerm.permission)) \
 
         .filter(UserRepoGroupToPerm.user_id == default_user_id)
 

	
 
        return q.all()
 

	
 
    @classmethod
 
    def get_default_user_group_perms(cls, default_user_id):
 
        q = Session().query(UserUserGroupToPerm) \
 
        q = meta.Session().query(UserUserGroupToPerm) \
 
         .options(joinedload(UserUserGroupToPerm.user_group)) \
 
         .options(joinedload(UserUserGroupToPerm.permission)) \
 
         .filter(UserUserGroupToPerm.user_id == default_user_id)
 

	
 
        return q.all()
 

	
 

	
 
class UserRepoToPerm(Base, BaseDbModel):
 
class UserRepoToPerm(meta.Base, BaseDbModel):
 
    __tablename__ = 'repo_to_perm'
 
    __table_args__ = (
 
        UniqueConstraint('user_id', 'repository_id', 'permission_id'),
 
        _table_args_default_dict,
 
    )
 

	
 
    repo_to_perm_id = Column(Integer(), primary_key=True)
 
    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
 
    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False)
 
    repository_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=False)
 

	
 
    user = relationship('User')
 
    repository = relationship('Repository')
 
    permission = relationship('Permission')
 

	
 
    @classmethod
 
    def create(cls, user, repository, permission):
 
        n = cls()
 
        n.user = user
 
        n.repository = repository
 
        n.permission = permission
 
        Session().add(n)
 
        meta.Session().add(n)
 
        return n
 

	
 
    def __repr__(self):
 
        return '<%s %s at %s: %s>' % (
 
            self.__class__.__name__, self.user, self.repository, self.permission)
 

	
 

	
 
class UserUserGroupToPerm(Base, BaseDbModel):
 
class UserUserGroupToPerm(meta.Base, BaseDbModel):
 
    __tablename__ = 'user_user_group_to_perm'
 
    __table_args__ = (
 
        UniqueConstraint('user_id', 'user_group_id', 'permission_id'),
 
        _table_args_default_dict,
 
    )
 

	
 
    user_user_group_to_perm_id = Column(Integer(), primary_key=True)
 
    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
 
    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False)
 
    user_group_id = Column(Integer(), ForeignKey('users_groups.users_group_id'), nullable=False)
 

	
 
    user = relationship('User')
 
    user_group = relationship('UserGroup')
 
    permission = relationship('Permission')
 

	
 
    @classmethod
 
    def create(cls, user, user_group, permission):
 
        n = cls()
 
        n.user = user
 
        n.user_group = user_group
 
        n.permission = permission
 
        Session().add(n)
 
        meta.Session().add(n)
 
        return n
 

	
 
    def __repr__(self):
 
        return '<%s %s at %s: %s>' % (
 
            self.__class__.__name__, self.user, self.user_group, self.permission)
 

	
 

	
 
class UserToPerm(Base, BaseDbModel):
 
class UserToPerm(meta.Base, BaseDbModel):
 
    __tablename__ = 'user_to_perm'
 
    __table_args__ = (
 
        UniqueConstraint('user_id', 'permission_id'),
 
        _table_args_default_dict,
 
    )
 

	
 
    user_to_perm_id = Column(Integer(), primary_key=True)
 
    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
 
    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False)
 

	
 
    user = relationship('User')
 
    permission = relationship('Permission')
 

	
 
    def __repr__(self):
 
        return '<%s %s: %s>' % (
 
            self.__class__.__name__, self.user, self.permission)
 

	
 

	
 
class UserGroupRepoToPerm(Base, BaseDbModel):
 
class UserGroupRepoToPerm(meta.Base, BaseDbModel):
 
    __tablename__ = 'users_group_repo_to_perm'
 
    __table_args__ = (
 
        UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
 
        _table_args_default_dict,
 
    )
 

	
 
    users_group_to_perm_id = Column(Integer(), primary_key=True)
 
    users_group_id = Column(Integer(), ForeignKey('users_groups.users_group_id'), nullable=False)
 
    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False)
 
    repository_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=False)
 

	
 
    users_group = relationship('UserGroup')
 
    permission = relationship('Permission')
 
    repository = relationship('Repository')
 

	
 
    @classmethod
 
    def create(cls, users_group, repository, permission):
 
        n = cls()
 
        n.users_group = users_group
 
        n.repository = repository
 
        n.permission = permission
 
        Session().add(n)
 
        meta.Session().add(n)
 
        return n
 

	
 
    def __repr__(self):
 
        return '<%s %s at %s: %s>' % (
 
            self.__class__.__name__, self.users_group, self.repository, self.permission)
 

	
 

	
 
class UserGroupUserGroupToPerm(Base, BaseDbModel):
 
class UserGroupUserGroupToPerm(meta.Base, BaseDbModel):
 
    __tablename__ = 'user_group_user_group_to_perm'
 
    __table_args__ = (
 
        UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'),
 
        _table_args_default_dict,
 
    )
 

	
 
    user_group_user_group_to_perm_id = Column(Integer(), primary_key=True)
 
    target_user_group_id = Column(Integer(), ForeignKey('users_groups.users_group_id'), nullable=False)
 
    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False)
 
    user_group_id = Column(Integer(), ForeignKey('users_groups.users_group_id'), nullable=False)
 

	
 
    target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id')
 
    user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id')
 
    permission = relationship('Permission')
 

	
 
    @classmethod
 
    def create(cls, target_user_group, user_group, permission):
 
        n = cls()
 
        n.target_user_group = target_user_group
 
        n.user_group = user_group
 
        n.permission = permission
 
        Session().add(n)
 
        meta.Session().add(n)
 
        return n
 

	
 
    def __repr__(self):
 
        return '<%s %s at %s: %s>' % (
 
            self.__class__.__name__, self.user_group, self.target_user_group, self.permission)
 

	
 

	
 
class UserGroupToPerm(Base, BaseDbModel):
 
class UserGroupToPerm(meta.Base, BaseDbModel):
 
    __tablename__ = 'users_group_to_perm'
 
    __table_args__ = (
 
        UniqueConstraint('users_group_id', 'permission_id',),
 
        _table_args_default_dict,
 
    )
 

	
 
    users_group_to_perm_id = Column(Integer(), primary_key=True)
 
    users_group_id = Column(Integer(), ForeignKey('users_groups.users_group_id'), nullable=False)
 
    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False)
 

	
 
    users_group = relationship('UserGroup')
 
    permission = relationship('Permission')
 

	
 

	
 
class UserRepoGroupToPerm(Base, BaseDbModel):
 
class UserRepoGroupToPerm(meta.Base, BaseDbModel):
 
    __tablename__ = 'user_repo_group_to_perm'
 
    __table_args__ = (
 
        UniqueConstraint('user_id', 'group_id', 'permission_id'),
 
        _table_args_default_dict,
 
    )
 

	
 
    group_to_perm_id = Column(Integer(), primary_key=True)
 
    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
 
    group_id = Column(Integer(), ForeignKey('groups.group_id'), nullable=False)
 
    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False)
 

	
 
    user = relationship('User')
 
    group = relationship('RepoGroup')
 
    permission = relationship('Permission')
 

	
 
    @classmethod
 
    def create(cls, user, repository_group, permission):
 
        n = cls()
 
        n.user = user
 
        n.group = repository_group
 
        n.permission = permission
 
        Session().add(n)
 
        meta.Session().add(n)
 
        return n
 

	
 

	
 
class UserGroupRepoGroupToPerm(Base, BaseDbModel):
 
class UserGroupRepoGroupToPerm(meta.Base, BaseDbModel):
 
    __tablename__ = 'users_group_repo_group_to_perm'
 
    __table_args__ = (
 
        UniqueConstraint('users_group_id', 'group_id'),
 
        _table_args_default_dict,
 
    )
 

	
 
    users_group_repo_group_to_perm_id = Column(Integer(), primary_key=True)
 
    users_group_id = Column(Integer(), ForeignKey('users_groups.users_group_id'), nullable=False)
 
    group_id = Column(Integer(), ForeignKey('groups.group_id'), nullable=False)
 
    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False)
 

	
 
    users_group = relationship('UserGroup')
 
    permission = relationship('Permission')
 
    group = relationship('RepoGroup')
 

	
 
    @classmethod
 
    def create(cls, user_group, repository_group, permission):
 
        n = cls()
 
        n.users_group = user_group
 
        n.group = repository_group
 
        n.permission = permission
 
        Session().add(n)
 
        meta.Session().add(n)
 
        return n
 

	
 

	
 
class Statistics(Base, BaseDbModel):
 
class Statistics(meta.Base, BaseDbModel):
 
    __tablename__ = 'statistics'
 
    __table_args__ = (
 
         _table_args_default_dict,
 
    )
 

	
 
    stat_id = Column(Integer(), primary_key=True)
 
    repository_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True)
 
    stat_on_revision = Column(Integer(), nullable=False)
 
    commit_activity = Column(LargeBinary(1000000), nullable=False) # JSON data
 
    commit_activity_combined = Column(LargeBinary(), nullable=False) # JSON data
 
    languages = Column(LargeBinary(1000000), nullable=False) # JSON data
 

	
 
    repository = relationship('Repository', single_parent=True)
 

	
 

	
 
class UserFollowing(Base, BaseDbModel):
 
class UserFollowing(meta.Base, BaseDbModel):
 
    __tablename__ = 'user_followings'
 
    __table_args__ = (
 
        UniqueConstraint('user_id', 'follows_repository_id', name='uq_user_followings_user_repo'),
 
        UniqueConstraint('user_id', 'follows_user_id', name='uq_user_followings_user_user'),
 
        _table_args_default_dict,
 
    )
 

	
 
    user_following_id = Column(Integer(), primary_key=True)
 
    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
 
    follows_repository_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=True)
 
    follows_user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=True)
 
    follows_from = Column(DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
 

	
 
    user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
 

	
 
    follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
 
    follows_repository = relationship('Repository', order_by=lambda: sqlalchemy.func.lower(Repository.repo_name))
 

	
 
    @classmethod
 
    def get_repo_followers(cls, repo_id):
 
        return cls.query().filter(cls.follows_repository_id == repo_id)
 

	
 

	
 
class ChangesetComment(Base, BaseDbModel):
 
class ChangesetComment(meta.Base, BaseDbModel):
 
    __tablename__ = 'changeset_comments'
 
    __table_args__ = (
 
        Index('cc_revision_idx', 'revision'),
 
        Index('cc_pull_request_id_idx', 'pull_request_id'),
 
        _table_args_default_dict,
 
    )
 

	
 
    comment_id = Column(Integer(), primary_key=True)
 
    repo_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=False)
 
    revision = Column(String(40), nullable=True)
 
    pull_request_id = Column(Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
 
    line_no = Column(Unicode(10), nullable=True)
 
@@ -1943,25 +1943,25 @@ class ChangesetComment(Base, BaseDbModel
 

	
 
    def __json__(self):
 
        return dict(
 
            comment_id=self.comment_id,
 
            username=self.author.username,
 
            text=self.text,
 
        )
 

	
 
    def deletable(self):
 
        return self.created_on > datetime.datetime.now() - datetime.timedelta(minutes=5)
 

	
 

	
 
class ChangesetStatus(Base, BaseDbModel):
 
class ChangesetStatus(meta.Base, BaseDbModel):
 
    __tablename__ = 'changeset_statuses'
 
    __table_args__ = (
 
        Index('cs_revision_idx', 'revision'),
 
        Index('cs_version_idx', 'version'),
 
        Index('cs_pull_request_id_idx', 'pull_request_id'),
 
        Index('cs_changeset_comment_id_idx', 'changeset_comment_id'),
 
        Index('cs_pull_request_id_user_id_version_idx', 'pull_request_id', 'user_id', 'version'),
 
        Index('cs_repo_id_pull_request_id_idx', 'repo_id', 'pull_request_id'),
 
        UniqueConstraint('repo_id', 'revision', 'version'),
 
        _table_args_default_dict,
 
    )
 

	
 
@@ -2006,25 +2006,25 @@ class ChangesetStatus(Base, BaseDbModel)
 
    @property
 
    def status_lbl(self):
 
        return ChangesetStatus.get_status_lbl(self.status)
 

	
 
    def __json__(self):
 
        return dict(
 
            status=self.status,
 
            modified_at=self.modified_at.replace(microsecond=0),
 
            reviewer=self.author.username,
 
            )
 

	
 

	
 
class PullRequest(Base, BaseDbModel):
 
class PullRequest(meta.Base, BaseDbModel):
 
    __tablename__ = 'pull_requests'
 
    __table_args__ = (
 
        Index('pr_org_repo_id_idx', 'org_repo_id'),
 
        Index('pr_other_repo_id_idx', 'other_repo_id'),
 
        _table_args_default_dict,
 
    )
 

	
 
    # values for .status
 
    STATUS_NEW = 'new'
 
    STATUS_CLOSED = 'closed'
 

	
 
    pull_request_id = Column(Integer(), primary_key=True)
 
@@ -2148,25 +2148,25 @@ class PullRequest(Base, BaseDbModel):
 
        if b != self.other_ref_parts[1]:
 
            s = '/_/' + b
 
        else:
 
            s = '/_/' + self.title
 
        kwargs['extra'] = urlreadable(s)
 
        if canonical:
 
            return h.canonical_url('pullrequest_show', repo_name=self.other_repo.repo_name,
 
                                   pull_request_id=self.pull_request_id, **kwargs)
 
        return h.url('pullrequest_show', repo_name=self.other_repo.repo_name,
 
                     pull_request_id=self.pull_request_id, **kwargs)
 

	
 

	
 
class PullRequestReviewer(Base, BaseDbModel):
 
class PullRequestReviewer(meta.Base, BaseDbModel):
 
    __tablename__ = 'pull_request_reviewers'
 
    __table_args__ = (
 
        Index('pull_request_reviewers_user_id_idx', 'user_id'),
 
        UniqueConstraint('pull_request_id', 'user_id'),
 
        _table_args_default_dict,
 
    )
 

	
 
    def __init__(self, user=None, pull_request=None):
 
        self.user = user
 
        self.pull_request = pull_request
 

	
 
    pull_request_reviewers_id = Column('pull_requests_reviewers_id', Integer(), primary_key=True)
 
@@ -2180,25 +2180,25 @@ class PullRequestReviewer(Base, BaseDbMo
 
        return dict(
 
            username=self.user.username if self.user else None,
 
        )
 

	
 

	
 
class Notification(object):
 
    __tablename__ = 'notifications'
 

	
 
class UserNotification(object):
 
    __tablename__ = 'user_to_notification'
 

	
 

	
 
class Gist(Base, BaseDbModel):
 
class Gist(meta.Base, BaseDbModel):
 
    __tablename__ = 'gists'
 
    __table_args__ = (
 
        Index('g_gist_access_id_idx', 'gist_access_id'),
 
        Index('g_created_on_idx', 'created_on'),
 
        _table_args_default_dict,
 
    )
 

	
 
    GIST_PUBLIC = 'public'
 
    GIST_PRIVATE = 'private'
 
    DEFAULT_FILENAME = 'gistfile1.txt'
 

	
 
    gist_id = Column(Integer(), primary_key=True)
 
@@ -2267,25 +2267,25 @@ class Gist(Base, BaseDbModel):
 
        return data
 

	
 
    ## SCM functions
 

	
 
    @property
 
    def scm_instance(self):
 
        from kallithea.lib.vcs import get_repo
 
        from kallithea.model.gist import GIST_STORE_LOC
 
        gist_base_path = os.path.join(kallithea.CONFIG['base_path'], GIST_STORE_LOC)
 
        return get_repo(os.path.join(gist_base_path, self.gist_access_id))
 

	
 

	
 
class UserSshKeys(Base, BaseDbModel):
 
class UserSshKeys(meta.Base, BaseDbModel):
 
    __tablename__ = 'user_ssh_keys'
 
    __table_args__ = (
 
        Index('usk_fingerprint_idx', 'fingerprint'),
 
        _table_args_default_dict
 
    )
 
    __mapper_args__ = {}
 

	
 
    user_ssh_key_id = Column(Integer(), primary_key=True)
 
    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
 
    _public_key = Column('public_key', UnicodeText(), nullable=False)
 
    description = Column(UnicodeText(), nullable=False)
 
    fingerprint = Column(String(255), nullable=False, unique=True)
kallithea/model/pull_request.py
Show inline comments
 
@@ -27,26 +27,26 @@ Original author and date, and relevant c
 

	
 
import datetime
 
import logging
 
import re
 

	
 
from tg import request
 
from tg.i18n import ugettext as _
 

	
 
from kallithea.lib import helpers as h
 
from kallithea.lib.hooks import log_create_pullrequest
 
from kallithea.lib.utils import extract_mentioned_users
 
from kallithea.lib.utils2 import ascii_bytes
 
from kallithea.model import meta
 
from kallithea.model.db import ChangesetStatus, PullRequest, PullRequestReviewer, User
 
from kallithea.model.meta import Session
 
from kallithea.model.notification import NotificationModel
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
def _assert_valid_reviewers(seq):
 
    """Sanity check: elements are actual User objects, and not the default user."""
 
    assert not any(user.is_default_user for user in seq)
 

	
 

	
 
class PullRequestModel(object):
 
@@ -65,25 +65,25 @@ class PullRequestModel(object):
 
            .filter(PullRequestReviewer.pull_request == pr) \
 
            .filter(PullRequestReviewer.user_id.in_(r.user_id for r in reviewers))
 
            .all())
 

	
 
        if redundant_reviewers:
 
            log.debug('Following reviewers were already part of pull request %s: %s', pr.pull_request_id, redundant_reviewers)
 

	
 
            reviewers -= redundant_reviewers
 

	
 
        log.debug('Adding reviewers to pull request %s: %s', pr.pull_request_id, reviewers)
 
        for reviewer in reviewers:
 
            prr = PullRequestReviewer(reviewer, pr)
 
            Session().add(prr)
 
            meta.Session().add(prr)
 

	
 
        # notification to reviewers
 
        pr_url = pr.url(canonical=True)
 
        threading = ['%s-pr-%s@%s' % (pr.other_repo.repo_name,
 
                                      pr.pull_request_id,
 
                                      h.canonical_hostname())]
 
        subject = h.link_to(
 
            _('%(user)s wants you to review pull request %(pr_nice_id)s: %(pr_title)s') %
 
                {'user': user.username,
 
                 'pr_title': pr.title,
 
                 'pr_nice_id': pr.nice_id()},
 
            pr_url)
 
@@ -141,25 +141,25 @@ class PullRequestModel(object):
 
    def remove_reviewers(self, user, pull_request, reviewers):
 
        """Remove specified users from being reviewers of the PR."""
 
        if not reviewers:
 
            return # avoid SQLAlchemy warning about empty sequence for IN-predicate
 

	
 
        PullRequestReviewer.query() \
 
            .filter_by(pull_request=pull_request) \
 
            .filter(PullRequestReviewer.user_id.in_(r.user_id for r in reviewers)) \
 
            .delete(synchronize_session='fetch') # the default of 'evaluate' is not available
 

	
 
    def delete(self, pull_request):
 
        pull_request = PullRequest.guess_instance(pull_request)
 
        Session().delete(pull_request)
 
        meta.Session().delete(pull_request)
 
        if pull_request.org_repo.scm_instance.alias == 'git':
 
            # remove a ref under refs/pull/ so that commits can be garbage-collected
 
            try:
 
                del pull_request.org_repo.scm_instance._repo[b"refs/pull/%d/head" % pull_request.pull_request_id]
 
            except KeyError:
 
                pass
 

	
 
    def close_pull_request(self, pull_request):
 
        pull_request = PullRequest.guess_instance(pull_request)
 
        pull_request.status = PullRequest.STATUS_CLOSED
 
        pull_request.updated_on = datetime.datetime.now()
 

	
 
@@ -256,26 +256,26 @@ class CreatePullRequestAction(object):
 
    def execute(self):
 
        created_by = User.get(request.authuser.user_id)
 

	
 
        pr = PullRequest()
 
        pr.org_repo = self.org_repo
 
        pr.org_ref = self.org_ref
 
        pr.other_repo = self.other_repo
 
        pr.other_ref = self.other_ref
 
        pr.revisions = self.revisions
 
        pr.title = self.title
 
        pr.description = self.description
 
        pr.owner = self.owner
 
        Session().add(pr)
 
        Session().flush() # make database assign pull_request_id
 
        meta.Session().add(pr)
 
        meta.Session().flush() # make database assign pull_request_id
 

	
 
        if self.org_repo.scm_instance.alias == 'git':
 
            # create a ref under refs/pull/ so that commits don't get garbage-collected
 
            self.org_repo.scm_instance._repo[b"refs/pull/%d/head" % pr.pull_request_id] = ascii_bytes(self.org_rev)
 

	
 
        # reset state to under-review
 
        from kallithea.model.changeset_status import ChangesetStatusModel
 
        from kallithea.model.comment import ChangesetCommentsModel
 
        comment = ChangesetCommentsModel().create(
 
            text='',
 
            repo=self.org_repo,
 
            author=created_by,
kallithea/model/ssh_key.py
Show inline comments
 
@@ -22,26 +22,26 @@ SSH key model for Kallithea
 
import errno
 
import logging
 
import os
 
import stat
 
import tempfile
 

	
 
from tg import config
 
from tg.i18n import ugettext as _
 

	
 
from kallithea.lib import ssh
 
from kallithea.lib.utils2 import asbool
 
from kallithea.lib.vcs.exceptions import RepositoryError
 
from kallithea.model import meta
 
from kallithea.model.db import User, UserSshKeys
 
from kallithea.model.meta import Session
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class SshKeyModelException(RepositoryError):
 
    """Exception raised by SshKeyModel methods to report errors"""
 

	
 

	
 
class SshKeyModel(object):
 

	
 
    def create(self, user, description, public_key):
 
@@ -60,42 +60,42 @@ class SshKeyModel(object):
 

	
 
        user = User.guess_instance(user)
 

	
 
        new_ssh_key = UserSshKeys()
 
        new_ssh_key.user_id = user.user_id
 
        new_ssh_key.description = description
 
        new_ssh_key.public_key = public_key
 

	
 
        for ssh_key in UserSshKeys.query().filter(UserSshKeys.fingerprint == new_ssh_key.fingerprint).all():
 
            raise SshKeyModelException(_('SSH key %s is already used by %s') %
 
                                       (new_ssh_key.fingerprint, ssh_key.user.username))
 

	
 
        Session().add(new_ssh_key)
 
        meta.Session().add(new_ssh_key)
 

	
 
        return new_ssh_key
 

	
 
    def delete(self, fingerprint, user):
 
        """
 
        Deletes ssh key with given fingerprint for the given user.
 
        Will raise SshKeyModelException on errors
 
        """
 
        ssh_key = UserSshKeys.query().filter(UserSshKeys.fingerprint == fingerprint)
 

	
 
        user = User.guess_instance(user)
 
        ssh_key = ssh_key.filter(UserSshKeys.user_id == user.user_id)
 

	
 
        ssh_key = ssh_key.scalar()
 
        if ssh_key is None:
 
            raise SshKeyModelException(_('SSH key with fingerprint %r found') % fingerprint)
 
        Session().delete(ssh_key)
 
        meta.Session().delete(ssh_key)
 

	
 
    def get_ssh_keys(self, user):
 
        user = User.guess_instance(user)
 
        user_ssh_keys = UserSshKeys.query() \
 
            .filter(UserSshKeys.user_id == user.user_id).all()
 
        return user_ssh_keys
 

	
 
    def write_authorized_keys(self):
 
        if not asbool(config.get('ssh_enabled', False)):
 
            log.error("Will not write SSH authorized_keys file - ssh_enabled is not configured")
 
            return
 
        authorized_keys = config.get('ssh_authorized_keys')
kallithea/model/user.py
Show inline comments
 
@@ -29,26 +29,26 @@ Original author and date, and relevant c
 
import hashlib
 
import hmac
 
import logging
 
import time
 
import traceback
 

	
 
from sqlalchemy.exc import DatabaseError
 
from tg import config
 
from tg.i18n import ugettext as _
 

	
 
from kallithea.lib.exceptions import DefaultUserException, UserOwnsReposException
 
from kallithea.lib.utils2 import generate_api_key, get_current_authuser
 
from kallithea.model import meta
 
from kallithea.model.db import Permission, User, UserEmailMap, UserIpMap, UserToPerm
 
from kallithea.model.meta import Session
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class UserModel(object):
 
    password_reset_token_lifetime = 86400 # 24 hours
 

	
 
    def get(self, user_id):
 
        user = User.query()
 
        return user.get(user_id)
 

	
 
@@ -74,26 +74,26 @@ class UserModel(object):
 
        check_allowed_create_user(user_data, cur_user)
 
        from kallithea.lib.auth import get_crypt_password
 

	
 
        new_user = User()
 
        for k, v in form_data.items():
 
            if k == 'password':
 
                v = get_crypt_password(v)
 
            if k == 'firstname':
 
                k = 'name'
 
            setattr(new_user, k, v)
 

	
 
        new_user.api_key = generate_api_key()
 
        Session().add(new_user)
 
        Session().flush() # make database assign new_user.user_id
 
        meta.Session().add(new_user)
 
        meta.Session().flush() # make database assign new_user.user_id
 

	
 
        log_create_user(new_user.get_dict(), cur_user)
 
        return new_user
 

	
 
    def create_or_update(self, username, password, email, firstname='',
 
                         lastname='', active=True, admin=False,
 
                         extern_type=None, extern_name=None, cur_user=None):
 
        """
 
        Creates a new instance if not found, or updates current one
 

	
 
        :param username:
 
        :param password:
 
@@ -145,26 +145,26 @@ class UserModel(object):
 
                new_user.api_key = generate_api_key()
 

	
 
            # set password only if creating an user or password is changed
 
            password_change = new_user.password and \
 
                not check_password(password, new_user.password)
 
            if not edit or password_change:
 
                reason = 'new password' if edit else 'new user'
 
                log.debug('Updating password reason=>%s', reason)
 
                new_user.password = get_crypt_password(password) \
 
                    if password else ''
 

	
 
            if user is None:
 
                Session().add(new_user)
 
                Session().flush() # make database assign new_user.user_id
 
                meta.Session().add(new_user)
 
                meta.Session().flush() # make database assign new_user.user_id
 

	
 
            if not edit:
 
                log_create_user(new_user.get_dict(), cur_user)
 

	
 
            return new_user
 
        except (DatabaseError,):
 
            log.error(traceback.format_exc())
 
            raise
 

	
 
    def create_registration(self, form_data):
 
        import kallithea.lib.helpers as h
 
        from kallithea.model.notification import NotificationModel
 
@@ -250,25 +250,25 @@ class UserModel(object):
 
        if user.repo_groups:
 
            repogroups = [x.group_name for x in user.repo_groups]
 
            raise UserOwnsReposException(_(
 
                'User "%s" still owns %s repository groups and cannot be '
 
                'removed. Switch owners or remove those repository groups: %s')
 
                % (user.username, len(repogroups), ', '.join(repogroups)))
 
        if user.user_groups:
 
            usergroups = [x.users_group_name for x in user.user_groups]
 
            raise UserOwnsReposException(
 
                _('User "%s" still owns %s user groups and cannot be '
 
                  'removed. Switch owners or remove those user groups: %s')
 
                % (user.username, len(usergroups), ', '.join(usergroups)))
 
        Session().delete(user)
 
        meta.Session().delete(user)
 

	
 
        from kallithea.lib.hooks import log_delete_user
 
        log_delete_user(user.get_dict(), cur_user)
 

	
 
    def can_change_password(self, user):
 
        from kallithea.lib import auth_modules
 
        managed_fields = auth_modules.get_managed_fields(user)
 
        return 'password' not in managed_fields
 

	
 
    def get_reset_password_token(self, user, timestamp, session_id):
 
        """
 
        The token is a 40-digit hexstring, calculated as a HMAC-SHA1.
 
@@ -382,25 +382,25 @@ class UserModel(object):
 
        log.debug('computed password reset token: %s', expected_token)
 
        log.debug('received password reset token: %s', token)
 
        return expected_token == token
 

	
 
    def reset_password(self, user_email, new_passwd):
 
        from kallithea.lib import auth
 
        from kallithea.lib.celerylib import tasks
 
        user = User.get_by_email(user_email)
 
        if user is not None:
 
            if not self.can_change_password(user):
 
                raise Exception('trying to change password for external user')
 
            user.password = auth.get_crypt_password(new_passwd)
 
            Session().commit()
 
            meta.Session().commit()
 
            log.info('change password for %s', user_email)
 
        if new_passwd is None:
 
            raise Exception('unable to set new password')
 

	
 
        tasks.send_email([user_email],
 
                 _('Password reset notification'),
 
                 _('The password to your account %s has been changed using password reset form.') % (user.username,))
 
        log.info('send password reset mail to %s', user_email)
 

	
 
        return True
 

	
 
    def has_perm(self, user, perm):
 
@@ -420,25 +420,25 @@ class UserModel(object):
 
        user = User.guess_instance(user)
 
        perm = Permission.guess_instance(perm)
 
        # if this permission is already granted skip it
 
        _perm = UserToPerm.query() \
 
            .filter(UserToPerm.user == user) \
 
            .filter(UserToPerm.permission == perm) \
 
            .scalar()
 
        if _perm:
 
            return
 
        new = UserToPerm()
 
        new.user = user
 
        new.permission = perm
 
        Session().add(new)
 
        meta.Session().add(new)
 
        return new
 

	
 
    def revoke_perm(self, user, perm):
 
        """
 
        Revoke users global permissions
 

	
 
        :param user:
 
        :param perm:
 
        """
 
        user = User.guess_instance(user)
 
        perm = Permission.guess_instance(perm)
 

	
 
@@ -453,56 +453,56 @@ class UserModel(object):
 

	
 
        :param user:
 
        :param email:
 
        """
 
        from kallithea.model import forms
 
        form = forms.UserExtraEmailForm()()
 
        data = form.to_python(dict(email=email))
 
        user = User.guess_instance(user)
 

	
 
        obj = UserEmailMap()
 
        obj.user = user
 
        obj.email = data['email']
 
        Session().add(obj)
 
        meta.Session().add(obj)
 
        return obj
 

	
 
    def delete_extra_email(self, user, email_id):
 
        """
 
        Removes email address from UserEmailMap
 

	
 
        :param user:
 
        :param email_id:
 
        """
 
        user = User.guess_instance(user)
 
        obj = UserEmailMap.query().get(email_id)
 
        if obj is not None:
 
            Session().delete(obj)
 
            meta.Session().delete(obj)
 

	
 
    def add_extra_ip(self, user, ip):
 
        """
 
        Adds IP address to UserIpMap
 

	
 
        :param user:
 
        :param ip:
 
        """
 
        from kallithea.model import forms
 
        form = forms.UserExtraIpForm()()
 
        data = form.to_python(dict(ip=ip))
 
        user = User.guess_instance(user)
 

	
 
        obj = UserIpMap()
 
        obj.user = user
 
        obj.ip_addr = data['ip']
 
        Session().add(obj)
 
        meta.Session().add(obj)
 
        return obj
 

	
 
    def delete_extra_ip(self, user, ip_id):
 
        """
 
        Removes IP address from UserIpMap
 

	
 
        :param user:
 
        :param ip_id:
 
        """
 
        user = User.guess_instance(user)
 
        obj = UserIpMap.query().get(ip_id)
 
        if obj:
 
            Session().delete(obj)
 
            meta.Session().delete(obj)
kallithea/tests/api/api_base.py
Show inline comments
 
@@ -17,28 +17,28 @@ Tests for the JSON-RPC web api.
 
"""
 

	
 
import os
 
import random
 
import re
 

	
 
import mock
 
import pytest
 

	
 
from kallithea.lib import ext_json
 
from kallithea.lib.auth import AuthUser
 
from kallithea.lib.utils2 import ascii_bytes
 
from kallithea.model import meta
 
from kallithea.model.changeset_status import ChangesetStatusModel
 
from kallithea.model.db import ChangesetStatus, PullRequest, PullRequestReviewer, RepoGroup, Repository, Setting, Ui, User
 
from kallithea.model.gist import GistModel
 
from kallithea.model.meta import Session
 
from kallithea.model.pull_request import PullRequestModel
 
from kallithea.model.repo import RepoModel
 
from kallithea.model.repo_group import RepoGroupModel
 
from kallithea.model.scm import ScmModel
 
from kallithea.model.user import UserModel
 
from kallithea.model.user_group import UserGroupModel
 
from kallithea.tests import base
 
from kallithea.tests.fixture import Fixture, raise_exception
 

	
 

	
 
API_URL = '/_admin/api'
 
TEST_USER_GROUP = 'test_user_group'
 
@@ -66,50 +66,50 @@ jsonify = lambda obj: ext_json.loads(ext
 

	
 
def api_call(test_obj, params):
 
    response = test_obj.app.post(API_URL, content_type='application/json',
 
                                 params=params)
 
    return response
 

	
 

	
 
## helpers
 
def make_user_group(name=TEST_USER_GROUP):
 
    gr = fixture.create_user_group(name, cur_user=base.TEST_USER_ADMIN_LOGIN)
 
    UserGroupModel().add_user_to_group(user_group=gr,
 
                                       user=base.TEST_USER_ADMIN_LOGIN)
 
    Session().commit()
 
    meta.Session().commit()
 
    return gr
 

	
 

	
 
def make_repo_group(name=TEST_REPO_GROUP):
 
    gr = fixture.create_repo_group(name, cur_user=base.TEST_USER_ADMIN_LOGIN)
 
    Session().commit()
 
    meta.Session().commit()
 
    return gr
 

	
 

	
 
class _BaseTestApi(object):
 
    REPO = None
 
    REPO_TYPE = None
 

	
 
    @classmethod
 
    def setup_class(cls):
 
        cls.usr = User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
 
        cls.apikey = cls.usr.api_key
 
        cls.test_user = UserModel().create_or_update(
 
            username='test-api',
 
            password='test',
 
            email='test@example.com',
 
            firstname='first',
 
            lastname='last'
 
        )
 
        Session().commit()
 
        meta.Session().commit()
 
        cls.TEST_USER_LOGIN = cls.test_user.username
 
        cls.apikey_regular = cls.test_user.api_key
 

	
 
    @classmethod
 
    def teardown_class(cls):
 
        pass
 

	
 
    def setup_method(self, method):
 
        make_user_group()
 
        make_repo_group()
 

	
 
    def teardown_method(self, method):
 
@@ -250,25 +250,25 @@ class _BaseTestApi(object):
 

	
 
        expected = 'userid is not the same as your user'
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    def test_api_pull_remote(self):
 
        # Note: pulling from local repos is a mis-feature - it will bypass access control
 
        # ... but ok, if the path already has been set in the database
 
        repo_name = 'test_pull'
 
        r = fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
 
        # hack around that clone_uri can't be set to to a local path
 
        # (as shown by test_api_create_repo_clone_uri_local)
 
        r.clone_uri = os.path.join(Ui.get_by_key('paths', '/').ui_value, self.REPO)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        pre_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in Repository.query().filter(Repository.repo_name == repo_name)]
 

	
 
        id_, params = _build_data(self.apikey, 'pull',
 
                                  repoid=repo_name,)
 
        response = api_call(self, params)
 

	
 
        expected = {'msg': 'Pulled from `%s`' % repo_name,
 
                    'repository': repo_name}
 
        self._compare_ok(id_, expected, given=response.body)
 

	
 
        post_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in Repository.query().filter(Repository.repo_name == repo_name)]
 
@@ -423,46 +423,46 @@ class _BaseTestApi(object):
 
                                  username=username,
 
                                  email=email,
 
                                  password='trololo')
 
        response = api_call(self, params)
 
        expected = 'failed to create user `%s`' % username
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    def test_api_delete_user(self):
 
        usr = UserModel().create_or_update(username='test_user',
 
                                           password='qweqwe',
 
                                           email='u232@example.com',
 
                                           firstname='u1', lastname='u1')
 
        Session().commit()
 
        meta.Session().commit()
 
        username = usr.username
 
        email = usr.email
 
        usr_id = usr.user_id
 
        ## DELETE THIS USER NOW
 

	
 
        id_, params = _build_data(self.apikey, 'delete_user',
 
                                  userid=username, )
 
        response = api_call(self, params)
 

	
 
        ret = {'msg': 'deleted user ID:%s %s' % (usr_id, username),
 
               'user': None}
 
        expected = ret
 
        self._compare_ok(id_, expected, given=response.body)
 

	
 
    @mock.patch.object(UserModel, 'delete', raise_exception)
 
    def test_api_delete_user_when_exception_happened(self):
 
        usr = UserModel().create_or_update(username='test_user',
 
                                           password='qweqwe',
 
                                           email='u232@example.com',
 
                                           firstname='u1', lastname='u1')
 
        Session().commit()
 
        meta.Session().commit()
 
        username = usr.username
 

	
 
        id_, params = _build_data(self.apikey, 'delete_user',
 
                                  userid=username, )
 
        response = api_call(self, params)
 
        ret = 'failed to delete user ID:%s %s' % (usr.user_id,
 
                                                  usr.username)
 
        expected = ret
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    @base.parametrize('name,expected', [
 
        ('firstname', 'new_username'),
 
@@ -545,25 +545,25 @@ class _BaseTestApi(object):
 
        response = api_call(self, params)
 
        ret = 'failed to update user `%s`' % usr.user_id
 

	
 
        expected = ret
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    def test_api_get_repo(self):
 
        new_group = 'some_new_group'
 
        make_user_group(new_group)
 
        RepoModel().grant_user_group_permission(repo=self.REPO,
 
                                                group_name=new_group,
 
                                                perm='repository.read')
 
        Session().commit()
 
        meta.Session().commit()
 
        id_, params = _build_data(self.apikey, 'get_repo',
 
                                  repoid=self.REPO)
 
        response = api_call(self, params)
 
        assert "tags" not in response.json['result']
 
        assert 'pull_requests' not in response.json['result']
 

	
 
        repo = RepoModel().get_by_repo_name(self.REPO)
 
        ret = repo.get_api_data()
 

	
 
        members = []
 
        followers = []
 
        for user in repo.repo_to_perm:
 
@@ -597,25 +597,25 @@ class _BaseTestApi(object):
 
        assert "v0.2.0" in response.json['result']['tags']
 
        assert 'pull_requests' in response.json['result']
 

	
 
    @base.parametrize('grant_perm', [
 
        ('repository.admin'),
 
        ('repository.write'),
 
        ('repository.read'),
 
    ])
 
    def test_api_get_repo_by_non_admin(self, grant_perm):
 
        RepoModel().grant_user_permission(repo=self.REPO,
 
                                          user=self.TEST_USER_LOGIN,
 
                                          perm=grant_perm)
 
        Session().commit()
 
        meta.Session().commit()
 
        id_, params = _build_data(self.apikey_regular, 'get_repo',
 
                                  repoid=self.REPO)
 
        response = api_call(self, params)
 

	
 
        repo = RepoModel().get_by_repo_name(self.REPO)
 
        assert len(repo.repo_to_perm) >= 2  # make sure we actually are testing something - probably the default 2 permissions, possibly more
 

	
 
        expected = repo.get_api_data()
 

	
 
        members = []
 
        for user in repo.repo_to_perm:
 
            perm = user.permission.permission_name
 
@@ -749,25 +749,25 @@ class _BaseTestApi(object):
 
                    % (','.join(sorted(['files', 'dirs', 'all']))))
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    @base.parametrize('name,ret_type,grant_perm', [
 
        ('all', 'all', 'repository.write'),
 
        ('dirs', 'dirs', 'repository.admin'),
 
        ('files', 'files', 'repository.read'),
 
    ])
 
    def test_api_get_repo_nodes_by_regular_user(self, name, ret_type, grant_perm):
 
        RepoModel().grant_user_permission(repo=self.REPO,
 
                                          user=self.TEST_USER_LOGIN,
 
                                          perm=grant_perm)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        rev = 'tip'
 
        path = '/'
 
        id_, params = _build_data(self.apikey_regular, 'get_repo_nodes',
 
                                  repoid=self.REPO, revision=rev,
 
                                  root_path=path,
 
                                  ret_type=ret_type)
 
        response = api_call(self, params)
 

	
 
        # we don't the actual return types here since it's tested somewhere
 
        # else
 
        expected = response.json['result']
 
@@ -842,25 +842,25 @@ class _BaseTestApi(object):
 
        # repo creation can no longer also create repo group
 
        id_, params = _build_data(self.apikey, 'create_repo',
 
                                  repo_name=repo_name,
 
                                  owner=base.TEST_USER_ADMIN_LOGIN,
 
                                  repo_type=self.REPO_TYPE,)
 
        response = api_call(self, params)
 
        expected = 'repo group `%s` not found' % repo_group_name
 
        self._compare_error(id_, expected, given=response.body)
 
        assert RepoModel().get_by_repo_name(repo_name) is None
 

	
 
        # create group before creating repo
 
        rg = fixture.create_repo_group(repo_group_name)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        id_, params = _build_data(self.apikey, 'create_repo',
 
                                  repo_name=repo_name,
 
                                  owner=base.TEST_USER_ADMIN_LOGIN,
 
                                  repo_type=self.REPO_TYPE,)
 
        response = api_call(self, params)
 
        expected = {
 
            'msg': 'Created new repository `%s`' % repo_name,
 
            'success': True,
 
            'task': None,
 
        }
 
        self._compare_ok(id_, expected, given=response.body)
 
@@ -869,29 +869,29 @@ class _BaseTestApi(object):
 

	
 
        fixture.destroy_repo(repo_name)
 
        fixture.destroy_repo_group(repo_group_name)
 

	
 
    def test_api_create_repo_in_repo_group_without_permission(self):
 
        repo_group_basename = 'api-repo-repo'
 
        repo_group_name = '%s/%s' % (TEST_REPO_GROUP, repo_group_basename)
 
        repo_name = '%s/api-repo' % repo_group_name
 

	
 
        top_group = RepoGroup.get_by_group_name(TEST_REPO_GROUP)
 
        assert top_group
 
        rg = fixture.create_repo_group(repo_group_basename, parent_group_id=top_group)
 
        Session().commit()
 
        meta.Session().commit()
 
        RepoGroupModel().grant_user_permission(repo_group_name,
 
                                               self.TEST_USER_LOGIN,
 
                                               'group.none')
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        id_, params = _build_data(self.apikey_regular, 'create_repo',
 
                                  repo_name=repo_name,
 
                                  repo_type=self.REPO_TYPE,
 
        )
 
        response = api_call(self, params)
 

	
 
        # Current result when API access control is different from Web:
 
        ret = {
 
            'msg': 'Created new repository `%s`' % repo_name,
 
            'success': True,
 
            'task': None,
 
@@ -1542,45 +1542,45 @@ class _BaseTestApi(object):
 
                                      usergroupid=gr_name,
 
                                      userid=base.TEST_USER_ADMIN_LOGIN)
 
            response = api_call(self, params)
 
            expected = 'failed to add member to user group `%s`' % gr_name
 
            self._compare_error(id_, expected, given=response.body)
 
        finally:
 
            fixture.destroy_user_group(gr_name)
 

	
 
    def test_api_remove_user_from_user_group(self):
 
        gr_name = 'test_group_3'
 
        gr = fixture.create_user_group(gr_name)
 
        UserGroupModel().add_user_to_group(gr, user=base.TEST_USER_ADMIN_LOGIN)
 
        Session().commit()
 
        meta.Session().commit()
 
        try:
 
            id_, params = _build_data(self.apikey, 'remove_user_from_user_group',
 
                                      usergroupid=gr_name,
 
                                      userid=base.TEST_USER_ADMIN_LOGIN)
 
            response = api_call(self, params)
 
            expected = {
 
                'msg': 'removed member `%s` from user group `%s`' % (
 
                    base.TEST_USER_ADMIN_LOGIN, gr_name
 
                ),
 
                'success': True}
 
            self._compare_ok(id_, expected, given=response.body)
 
        finally:
 
            fixture.destroy_user_group(gr_name)
 

	
 
    @mock.patch.object(UserGroupModel, 'remove_user_from_group', raise_exception)
 
    def test_api_remove_user_from_user_group_exception_occurred(self):
 
        gr_name = 'test_group_3'
 
        gr = fixture.create_user_group(gr_name)
 
        UserGroupModel().add_user_to_group(gr, user=base.TEST_USER_ADMIN_LOGIN)
 
        Session().commit()
 
        meta.Session().commit()
 
        try:
 
            id_, params = _build_data(self.apikey, 'remove_user_from_user_group',
 
                                      usergroupid=gr_name,
 
                                      userid=base.TEST_USER_ADMIN_LOGIN)
 
            response = api_call(self, params)
 
            expected = 'failed to remove member from user group `%s`' % gr_name
 
            self._compare_error(id_, expected, given=response.body)
 
        finally:
 
            fixture.destroy_user_group(gr_name)
 

	
 
    def test_api_delete_user_group(self):
 
        gr_name = 'test_group'
 
@@ -1755,25 +1755,25 @@ class _BaseTestApi(object):
 
                                  perm=perm)
 
        response = api_call(self, params)
 

	
 
        expected = 'failed to edit permission for user group: `%s` in repo: `%s`' % (
 
            TEST_USER_GROUP, self.REPO
 
        )
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    def test_api_revoke_user_group_permission(self):
 
        RepoModel().grant_user_group_permission(repo=self.REPO,
 
                                                group_name=TEST_USER_GROUP,
 
                                                perm='repository.read')
 
        Session().commit()
 
        meta.Session().commit()
 
        id_, params = _build_data(self.apikey,
 
                                  'revoke_user_group_permission',
 
                                  repoid=self.REPO,
 
                                  usergroupid=TEST_USER_GROUP, )
 
        response = api_call(self, params)
 

	
 
        expected = {
 
            'msg': 'Revoked perm for user group: `%s` in repo: `%s`' % (
 
                TEST_USER_GROUP, self.REPO
 
            ),
 
            'success': True
 
        }
 
@@ -1839,25 +1839,25 @@ class _BaseTestApi(object):
 
        # with granted perms
 
        ('none_ok', 'group.none', 'none', True, True),
 
        ('read_ok', 'group.read', 'none', True, True),
 
        ('write_ok', 'group.write', 'none', True, True),
 
        ('admin_ok', 'group.admin', 'none', True, True),
 
    ])
 
    def test_api_grant_user_permission_to_repo_group_by_regular_user(
 
            self, name, perm, apply_to_children, grant_admin, access_ok):
 
        if grant_admin:
 
            RepoGroupModel().grant_user_permission(TEST_REPO_GROUP,
 
                                                   self.TEST_USER_LOGIN,
 
                                                   'group.admin')
 
            Session().commit()
 
            meta.Session().commit()
 

	
 
        id_, params = _build_data(self.apikey_regular,
 
                                  'grant_user_permission_to_repo_group',
 
                                  repogroupid=TEST_REPO_GROUP,
 
                                  userid=base.TEST_USER_ADMIN_LOGIN,
 
                                  perm=perm, apply_to_children=apply_to_children)
 
        response = api_call(self, params)
 
        if access_ok:
 
            ret = {
 
                'msg': 'Granted perm: `%s` (recursive:%s) for user: `%s` in repo group: `%s`' % (
 
                    perm, apply_to_children, base.TEST_USER_ADMIN_LOGIN, TEST_REPO_GROUP
 
                ),
 
@@ -1897,25 +1897,25 @@ class _BaseTestApi(object):
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    @base.parametrize('name,apply_to_children', [
 
        ('none', 'none'),
 
        ('all', 'all'),
 
        ('repos', 'repos'),
 
        ('groups', 'groups'),
 
    ])
 
    def test_api_revoke_user_permission_from_repo_group(self, name, apply_to_children):
 
        RepoGroupModel().grant_user_permission(repo_group=TEST_REPO_GROUP,
 
                                               user=base.TEST_USER_ADMIN_LOGIN,
 
                                               perm='group.read',)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        id_, params = _build_data(self.apikey,
 
                                  'revoke_user_permission_from_repo_group',
 
                                  repogroupid=TEST_REPO_GROUP,
 
                                  userid=base.TEST_USER_ADMIN_LOGIN,
 
                                  apply_to_children=apply_to_children,)
 
        response = api_call(self, params)
 

	
 
        expected = {
 
            'msg': 'Revoked perm (recursive:%s) for user: `%s` in repo group: `%s`' % (
 
                apply_to_children, base.TEST_USER_ADMIN_LOGIN, TEST_REPO_GROUP
 
            ),
 
@@ -1931,31 +1931,31 @@ class _BaseTestApi(object):
 

	
 
        # after granting admin rights
 
        ('none', 'none', False, False),
 
        ('all', 'all', False, False),
 
        ('repos', 'repos', False, False),
 
        ('groups', 'groups', False, False),
 
    ])
 
    def test_api_revoke_user_permission_from_repo_group_by_regular_user(
 
            self, name, apply_to_children, grant_admin, access_ok):
 
        RepoGroupModel().grant_user_permission(repo_group=TEST_REPO_GROUP,
 
                                               user=base.TEST_USER_ADMIN_LOGIN,
 
                                               perm='group.read',)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        if grant_admin:
 
            RepoGroupModel().grant_user_permission(TEST_REPO_GROUP,
 
                                                   self.TEST_USER_LOGIN,
 
                                                   'group.admin')
 
            Session().commit()
 
            meta.Session().commit()
 

	
 
        id_, params = _build_data(self.apikey_regular,
 
                                  'revoke_user_permission_from_repo_group',
 
                                  repogroupid=TEST_REPO_GROUP,
 
                                  userid=base.TEST_USER_ADMIN_LOGIN,
 
                                  apply_to_children=apply_to_children,)
 
        response = api_call(self, params)
 
        if access_ok:
 
            expected = {
 
                'msg': 'Revoked perm (recursive:%s) for user: `%s` in repo group: `%s`' % (
 
                    apply_to_children, base.TEST_USER_ADMIN_LOGIN, TEST_REPO_GROUP
 
                ),
 
@@ -2027,25 +2027,25 @@ class _BaseTestApi(object):
 
        # with granted perms
 
        ('none_ok', 'group.none', 'none', True, True),
 
        ('read_ok', 'group.read', 'none', True, True),
 
        ('write_ok', 'group.write', 'none', True, True),
 
        ('admin_ok', 'group.admin', 'none', True, True),
 
    ])
 
    def test_api_grant_user_group_permission_to_repo_group_by_regular_user(
 
            self, name, perm, apply_to_children, grant_admin, access_ok):
 
        if grant_admin:
 
            RepoGroupModel().grant_user_permission(TEST_REPO_GROUP,
 
                                                   self.TEST_USER_LOGIN,
 
                                                   'group.admin')
 
            Session().commit()
 
            meta.Session().commit()
 

	
 
        id_, params = _build_data(self.apikey_regular,
 
                                  'grant_user_group_permission_to_repo_group',
 
                                  repogroupid=TEST_REPO_GROUP,
 
                                  usergroupid=TEST_USER_GROUP,
 
                                  perm=perm,
 
                                  apply_to_children=apply_to_children,)
 
        response = api_call(self, params)
 
        if access_ok:
 
            ret = {
 
                'msg': 'Granted perm: `%s` (recursive:%s) for user group: `%s` in repo group: `%s`' % (
 
                    perm, apply_to_children, TEST_USER_GROUP, TEST_REPO_GROUP
 
@@ -2086,25 +2086,25 @@ class _BaseTestApi(object):
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    @base.parametrize('name,apply_to_children', [
 
        ('none', 'none'),
 
        ('all', 'all'),
 
        ('repos', 'repos'),
 
        ('groups', 'groups'),
 
    ])
 
    def test_api_revoke_user_group_permission_from_repo_group(self, name, apply_to_children):
 
        RepoGroupModel().grant_user_group_permission(repo_group=TEST_REPO_GROUP,
 
                                                     group_name=TEST_USER_GROUP,
 
                                                     perm='group.read',)
 
        Session().commit()
 
        meta.Session().commit()
 
        id_, params = _build_data(self.apikey,
 
                                  'revoke_user_group_permission_from_repo_group',
 
                                  repogroupid=TEST_REPO_GROUP,
 
                                  usergroupid=TEST_USER_GROUP,
 
                                  apply_to_children=apply_to_children,)
 
        response = api_call(self, params)
 

	
 
        expected = {
 
            'msg': 'Revoked perm (recursive:%s) for user group: `%s` in repo group: `%s`' % (
 
                apply_to_children, TEST_USER_GROUP, TEST_REPO_GROUP
 
            ),
 
            'success': True
 
@@ -2119,31 +2119,31 @@ class _BaseTestApi(object):
 

	
 
        # after granting admin rights
 
        ('none', 'none', False, False),
 
        ('all', 'all', False, False),
 
        ('repos', 'repos', False, False),
 
        ('groups', 'groups', False, False),
 
    ])
 
    def test_api_revoke_user_group_permission_from_repo_group_by_regular_user(
 
            self, name, apply_to_children, grant_admin, access_ok):
 
        RepoGroupModel().grant_user_permission(repo_group=TEST_REPO_GROUP,
 
                                               user=base.TEST_USER_ADMIN_LOGIN,
 
                                               perm='group.read',)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        if grant_admin:
 
            RepoGroupModel().grant_user_permission(TEST_REPO_GROUP,
 
                                                   self.TEST_USER_LOGIN,
 
                                                   'group.admin')
 
            Session().commit()
 
            meta.Session().commit()
 

	
 
        id_, params = _build_data(self.apikey_regular,
 
                                  'revoke_user_group_permission_from_repo_group',
 
                                  repogroupid=TEST_REPO_GROUP,
 
                                  usergroupid=TEST_USER_GROUP,
 
                                  apply_to_children=apply_to_children,)
 
        response = api_call(self, params)
 
        if access_ok:
 
            expected = {
 
                'msg': 'Revoked perm (recursive:%s) for user group: `%s` in repo group: `%s`' % (
 
                    apply_to_children, base.TEST_USER_ADMIN_LOGIN, TEST_REPO_GROUP
 
                ),
 
@@ -2676,26 +2676,26 @@ class _BaseTestApi(object):
 
        expected = { 'added': [],
 
                     'already_present': [],
 
                     'removed': [base.TEST_USER_REGULAR2_LOGIN],
 
                   }
 
        self._compare_ok(random_id, expected, given=response.body)
 
        assert User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
 
        assert User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) not in pullrequest.get_reviewer_users()
 

	
 
    def test_api_edit_reviewers_remove_multiple(self):
 
        pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
 
        pullrequest = PullRequest().get(pull_request_id)
 
        prr = PullRequestReviewer(User.get_by_username(base.TEST_USER_REGULAR2_LOGIN), pullrequest)
 
        Session().add(prr)
 
        Session().commit()
 
        meta.Session().add(prr)
 
        meta.Session().commit()
 

	
 
        assert User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
 
        assert User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
 

	
 
        pullrequest.owner = self.test_user
 
        random_id = random.randrange(1, 9999)
 
        params = ascii_bytes(ext_json.dumps({
 
            "id": random_id,
 
            "api_key": self.apikey_regular,
 
            "method": "edit_reviewers",
 
            "args": {"pull_request_id": pull_request_id, "remove": [ base.TEST_USER_REGULAR_LOGIN, base.TEST_USER_REGULAR2_LOGIN ] },
 
        }))
 
@@ -2767,26 +2767,26 @@ class _BaseTestApi(object):
 
        expected = { 'added': [base.TEST_USER_REGULAR2_LOGIN],
 
                     'already_present': [],
 
                     'removed': [base.TEST_USER_REGULAR_LOGIN],
 
                   }
 
        self._compare_ok(random_id, expected, given=response.body)
 
        assert User.get_by_username(base.TEST_USER_REGULAR_LOGIN) not in pullrequest.get_reviewer_users()
 
        assert User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
 

	
 
    def test_api_edit_reviewers_add_remove_multiple(self):
 
        pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
 
        pullrequest = PullRequest().get(pull_request_id)
 
        prr = PullRequestReviewer(User.get_by_username(base.TEST_USER_ADMIN_LOGIN), pullrequest)
 
        Session().add(prr)
 
        Session().commit()
 
        meta.Session().add(prr)
 
        meta.Session().commit()
 
        assert User.get_by_username(base.TEST_USER_ADMIN_LOGIN) in pullrequest.get_reviewer_users()
 
        assert User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
 
        assert User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) not in pullrequest.get_reviewer_users()
 

	
 
        pullrequest.owner = self.test_user
 
        random_id = random.randrange(1, 9999)
 
        params = ascii_bytes(ext_json.dumps({
 
            "id": random_id,
 
            "api_key": self.apikey_regular,
 
            "method": "edit_reviewers",
 
            "args": {"pull_request_id": pull_request_id,
 
                     "add": [ base.TEST_USER_REGULAR2_LOGIN ],
kallithea/tests/conftest.py
Show inline comments
 
@@ -6,26 +6,26 @@ import time
 
import formencode
 
import pkg_resources
 
import pytest
 
from paste.deploy import loadwsgi
 
from pytest_localserver.http import WSGIServer
 
from routes.util import URLGenerator
 
from tg.util.webtest import test_context
 

	
 
import kallithea.tests.base  # FIXME: needed for setting testapp instance!!!
 
from kallithea.controllers.root import RootController
 
from kallithea.lib import inifile
 
from kallithea.lib.utils import repo2db_mapper
 
from kallithea.model import meta
 
from kallithea.model.db import Setting, User, UserIpMap
 
from kallithea.model.meta import Session
 
from kallithea.model.scm import ScmModel
 
from kallithea.model.user import UserModel
 
from kallithea.tests.base import TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS, TEST_USER_REGULAR_LOGIN, TESTS_TMP_PATH, invalidate_all_caches
 

	
 

	
 
def pytest_configure():
 
    os.environ['TZ'] = 'UTC'
 
    if not kallithea.is_windows:
 
        time.tzset() # only available on Unix
 

	
 
    path = os.getcwd()
 
    sys.path.insert(0, path)
 
@@ -95,48 +95,48 @@ def pytest_configure():
 
@pytest.fixture
 
def create_test_user():
 
    """Provide users that automatically disappear after test is over."""
 
    test_user_ids = []
 

	
 
    def _create_test_user(user_form):
 
        user = UserModel().create(user_form)
 
        test_user_ids.append(user.user_id)
 
        return user
 
    yield _create_test_user
 
    for user_id in test_user_ids:
 
        UserModel().delete(user_id)
 
    Session().commit()
 
    meta.Session().commit()
 

	
 

	
 
def _set_settings(*kvtseq):
 
    session = Session()
 
    session = meta.Session()
 
    for kvt in kvtseq:
 
        assert len(kvt) in (2, 3)
 
        k = kvt[0]
 
        v = kvt[1]
 
        t = kvt[2] if len(kvt) == 3 else 'unicode'
 
        Setting.create_or_update(k, v, t)
 
    session.commit()
 

	
 

	
 
@pytest.fixture
 
def set_test_settings():
 
    """Restore settings after test is over."""
 
    # Save settings.
 
    settings_snapshot = [
 
        (s.app_settings_name, s.app_settings_value, s.app_settings_type)
 
        for s in Setting.query().all()]
 
    yield _set_settings
 
    # Restore settings.
 
    session = Session()
 
    session = meta.Session()
 
    keys = frozenset(k for (k, v, t) in settings_snapshot)
 
    for s in Setting.query().all():
 
        if s.app_settings_name not in keys:
 
            session.delete(s)
 
    for k, v, t in settings_snapshot:
 
        if t == 'list' and hasattr(v, '__iter__'):
 
            v = ','.join(v) # Quirk: must format list value manually.
 
        Setting.create_or_update(k, v, t)
 
    session.commit()
 

	
 

	
 
@pytest.fixture
 
@@ -149,25 +149,25 @@ def auto_clear_ip_permissions():
 
    user_model = UserModel()
 

	
 
    user_ids = []
 
    user_ids.append(kallithea.DEFAULT_USER_ID)
 
    user_ids.append(User.get_by_username(TEST_USER_REGULAR_LOGIN).user_id)
 

	
 
    for user_id in user_ids:
 
        for ip in UserIpMap.query().filter(UserIpMap.user_id == user_id):
 
            user_model.delete_extra_ip(user_id, ip.ip_id)
 

	
 
    # IP permissions are cached, need to invalidate this cache explicitly
 
    invalidate_all_caches()
 
    session = Session()
 
    session = meta.Session()
 
    session.commit()
 

	
 

	
 
@pytest.fixture
 
def test_context_fixture(app_fixture):
 
    """
 
    Encompass the entire test using this fixture in a test_context,
 
    making sure that certain functionality still works even if no call to
 
    self.app.get/post has been made.
 
    The typical error message indicating you need a test_context is:
 
        TypeError: No object (name: context) has been registered for this thread
 

	
kallithea/tests/fixture.py
Show inline comments
 
@@ -21,29 +21,29 @@ import os
 
import shutil
 
import tarfile
 
from os.path import dirname
 

	
 
import mock
 
from tg import request
 
from tg.util.webtest import test_context
 

	
 
from kallithea.lib import helpers
 
from kallithea.lib.auth import AuthUser
 
from kallithea.lib.db_manage import DbManage
 
from kallithea.lib.vcs.backends.base import EmptyChangeset
 
from kallithea.model import meta
 
from kallithea.model.changeset_status import ChangesetStatusModel
 
from kallithea.model.comment import ChangesetCommentsModel
 
from kallithea.model.db import ChangesetStatus, Gist, RepoGroup, Repository, User, UserGroup
 
from kallithea.model.gist import GistModel
 
from kallithea.model.meta import Session
 
from kallithea.model.pull_request import CreatePullRequestAction  # , CreatePullRequestIterationAction, PullRequestModel
 
from kallithea.model.repo import RepoModel
 
from kallithea.model.repo_group import RepoGroupModel
 
from kallithea.model.scm import ScmModel
 
from kallithea.model.user import UserModel
 
from kallithea.model.user_group import UserGroupModel
 
from kallithea.tests.base import (GIT_REPO, HG_REPO, IP_ADDR, TEST_USER_ADMIN_EMAIL, TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS, TEST_USER_REGULAR2_EMAIL,
 
                                  TEST_USER_REGULAR2_LOGIN, TEST_USER_REGULAR2_PASS, TEST_USER_REGULAR_EMAIL, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS,
 
                                  TESTS_TMP_PATH, invalidate_all_caches)
 

	
 

	
 
log = logging.getLogger(__name__)
 
@@ -68,31 +68,31 @@ class Fixture(object):
 
        Usage:
 

	
 
        fixture = Fixture()
 
        with fixture.anon_access(False):
 
            stuff
 
        """
 

	
 
        class context(object):
 
            def __enter__(self):
 
                anon = User.get_default_user()
 
                self._before = anon.active
 
                anon.active = status
 
                Session().commit()
 
                meta.Session().commit()
 
                invalidate_all_caches()
 

	
 
            def __exit__(self, exc_type, exc_val, exc_tb):
 
                anon = User.get_default_user()
 
                anon.active = self._before
 
                Session().commit()
 
                meta.Session().commit()
 

	
 
        return context()
 

	
 
    def _get_repo_create_params(self, **custom):
 
        """Return form values to be validated through RepoForm"""
 
        defs = dict(
 
            repo_name=None,
 
            repo_type='hg',
 
            clone_uri='',
 
            repo_group='-1',
 
            repo_description='DESC',
 
            repo_private=False,
 
@@ -156,137 +156,137 @@ class Fixture(object):
 
            del kwargs['skip_if_exists']
 
            r = Repository.get_by_repo_name(name)
 
            if r:
 
                return r
 

	
 
        if isinstance(repo_group, RepoGroup):
 
            repo_group = repo_group.group_id
 

	
 
        form_data = self._get_repo_create_params(repo_name=name, **kwargs)
 
        form_data['repo_group'] = repo_group # patch form dict so it can be used directly by model
 
        cur_user = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN)
 
        RepoModel().create(form_data, cur_user)
 
        Session().commit()
 
        meta.Session().commit()
 
        ScmModel().mark_for_invalidation(name)
 
        return Repository.get_by_repo_name(name)
 

	
 
    def create_fork(self, repo_to_fork, fork_name, **kwargs):
 
        repo_to_fork = Repository.get_by_repo_name(repo_to_fork)
 

	
 
        form_data = self._get_repo_create_params(repo_name=fork_name,
 
                                            fork_parent_id=repo_to_fork,
 
                                            repo_type=repo_to_fork.repo_type,
 
                                            **kwargs)
 
        # patch form dict so it can be used directly by model
 
        form_data['description'] = form_data['repo_description']
 
        form_data['private'] = form_data['repo_private']
 
        form_data['landing_rev'] = form_data['repo_landing_rev']
 

	
 
        owner = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN)
 
        RepoModel().create_fork(form_data, cur_user=owner)
 
        Session().commit()
 
        meta.Session().commit()
 
        ScmModel().mark_for_invalidation(fork_name)
 
        r = Repository.get_by_repo_name(fork_name)
 
        assert r
 
        return r
 

	
 
    def destroy_repo(self, repo_name, **kwargs):
 
        RepoModel().delete(repo_name, **kwargs)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    def create_repo_group(self, name, parent_group_id=None, **kwargs):
 
        assert '/' not in name, (name, kwargs) # use group_parent_id to make nested groups
 
        if 'skip_if_exists' in kwargs:
 
            del kwargs['skip_if_exists']
 
            gr = RepoGroup.get_by_group_name(group_name=name)
 
            if gr:
 
                return gr
 
        form_data = self._get_repo_group_create_params(group_name=name, **kwargs)
 
        gr = RepoGroupModel().create(
 
            group_name=form_data['group_name'],
 
            group_description=form_data['group_name'],
 
            parent=parent_group_id,
 
            owner=kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN),
 
            )
 
        Session().commit()
 
        meta.Session().commit()
 
        gr = RepoGroup.get_by_group_name(gr.group_name)
 
        return gr
 

	
 
    def destroy_repo_group(self, repogroupid):
 
        RepoGroupModel().delete(repogroupid)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    def create_user(self, name, **kwargs):
 
        if 'skip_if_exists' in kwargs:
 
            del kwargs['skip_if_exists']
 
            user = User.get_by_username(name)
 
            if user:
 
                return user
 
        form_data = self._get_user_create_params(name, **kwargs)
 
        user = UserModel().create(form_data)
 
        Session().commit()
 
        meta.Session().commit()
 
        user = User.get_by_username(user.username)
 
        return user
 

	
 
    def destroy_user(self, userid):
 
        UserModel().delete(userid)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    def create_user_group(self, name, **kwargs):
 
        if 'skip_if_exists' in kwargs:
 
            del kwargs['skip_if_exists']
 
            gr = UserGroup.get_by_group_name(group_name=name)
 
            if gr:
 
                return gr
 
        form_data = self._get_user_group_create_params(name, **kwargs)
 
        owner = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN)
 
        user_group = UserGroupModel().create(
 
            name=form_data['users_group_name'],
 
            description=form_data['user_group_description'],
 
            owner=owner, active=form_data['users_group_active'],
 
            group_data=form_data['user_group_data'])
 
        Session().commit()
 
        meta.Session().commit()
 
        user_group = UserGroup.get_by_group_name(user_group.users_group_name)
 
        return user_group
 

	
 
    def destroy_user_group(self, usergroupid):
 
        UserGroupModel().delete(user_group=usergroupid, force=True)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    def create_gist(self, **kwargs):
 
        form_data = {
 
            'description': 'new-gist',
 
            'owner': TEST_USER_ADMIN_LOGIN,
 
            'gist_type': Gist.GIST_PUBLIC,
 
            'lifetime': -1,
 
            'gist_mapping': {'filename1.txt': {'content': 'hello world'}}
 
        }
 
        form_data.update(kwargs)
 
        gist = GistModel().create(
 
            description=form_data['description'], owner=form_data['owner'], ip_addr=IP_ADDR,
 
            gist_mapping=form_data['gist_mapping'], gist_type=form_data['gist_type'],
 
            lifetime=form_data['lifetime']
 
        )
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        return gist
 

	
 
    def destroy_gists(self, gistid=None):
 
        for g in Gist.query():
 
            if gistid:
 
                if gistid == g.gist_access_id:
 
                    GistModel().delete(g)
 
            else:
 
                GistModel().delete(g)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    def load_resource(self, resource_name, strip=True):
 
        with open(os.path.join(FIXTURES, resource_name), 'rb') as f:
 
            source = f.read()
 
            if strip:
 
                source = source.strip()
 

	
 
        return source
 

	
 
    def commit_change(self, repo, filename, content, message, vcs_type,
 
                      parent=None, newfile=False, author=None):
 
        repo = Repository.get_by_repo_name(repo)
 
@@ -318,40 +318,40 @@ class Fixture(object):
 
                user=TEST_USER_ADMIN_LOGIN,
 
                ip_addr=IP_ADDR,
 
                author=author,
 
                message=message,
 
                content=content,
 
                f_path=filename
 
            )
 
        return cs
 

	
 
    def review_changeset(self, repo, revision, status, author=TEST_USER_ADMIN_LOGIN):
 
        comment = ChangesetCommentsModel().create("review comment", repo, author, revision=revision, send_email=False)
 
        csm = ChangesetStatusModel().set_status(repo, ChangesetStatus.STATUS_APPROVED, author, comment, revision=revision)
 
        Session().commit()
 
        meta.Session().commit()
 
        return csm
 

	
 
    def create_pullrequest(self, testcontroller, repo_name, pr_src_rev, pr_dst_rev, title='title'):
 
        org_ref = 'branch:stable:%s' % pr_src_rev
 
        other_ref = 'branch:default:%s' % pr_dst_rev
 
        with test_context(testcontroller.app): # needed to be able to mock request user
 
            org_repo = other_repo = Repository.get_by_repo_name(repo_name)
 
            owner_user = User.get_by_username(TEST_USER_ADMIN_LOGIN)
 
            reviewers = [User.get_by_username(TEST_USER_REGULAR_LOGIN)]
 
            request.authuser = AuthUser(dbuser=owner_user)
 
            # creating a PR sends a message with an absolute URL - without routing that requires mocking
 
            with mock.patch.object(helpers, 'url', (lambda arg, qualified=False, **kwargs: ('https://localhost' if qualified else '') + '/fake/' + arg)):
 
                cmd = CreatePullRequestAction(org_repo, other_repo, org_ref, other_ref, title, 'No description', owner_user, reviewers)
 
                pull_request = cmd.execute()
 
            Session().commit()
 
            meta.Session().commit()
 
        return pull_request.pull_request_id
 

	
 

	
 
#==============================================================================
 
# Global test environment setup
 
#==============================================================================
 

	
 
def create_test_env(repos_test_path, config, reuse_database):
 
    """
 
    Makes a fresh database and
 
    install test repository into tmp dir
 
    """
 
@@ -372,25 +372,25 @@ def create_test_env(repos_test_path, con
 
                            'password': TEST_USER_ADMIN_PASS,
 
                            'email': TEST_USER_ADMIN_EMAIL,
 
                        })
 
    dbmanage.create_tables(reuse_database=reuse_database)
 
    # for tests dynamically set new root paths based on generated content
 
    dbmanage.create_settings(dbmanage.prompt_repo_root_path(repos_test_path))
 
    dbmanage.create_default_user()
 
    dbmanage.create_admin_user()
 
    dbmanage.create_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS, TEST_USER_REGULAR_EMAIL, False)
 
    dbmanage.create_user(TEST_USER_REGULAR2_LOGIN, TEST_USER_REGULAR2_PASS, TEST_USER_REGULAR2_EMAIL, False)
 
    dbmanage.create_permissions()
 
    dbmanage.populate_default_permissions()
 
    Session().commit()
 
    meta.Session().commit()
 
    # PART TWO make test repo
 
    log.debug('making test vcs repositories')
 

	
 
    idx_path = config['index_dir']
 
    data_path = config['cache_dir']
 

	
 
    # clean index and data
 
    if idx_path and os.path.exists(idx_path):
 
        log.debug('remove %s', idx_path)
 
        shutil.rmtree(idx_path)
 

	
 
    if data_path and os.path.exists(data_path):
kallithea/tests/functional/test_admin.py
Show inline comments
 
import csv
 
import datetime
 
import os
 
from os.path import dirname
 

	
 
from kallithea.model import meta
 
from kallithea.model.db import UserLog
 
from kallithea.model.meta import Session
 
from kallithea.tests import base
 

	
 

	
 
FIXTURES = os.path.join(dirname(dirname(os.path.abspath(__file__))), 'fixtures')
 

	
 

	
 
class TestAdminController(base.TestController):
 

	
 
    @classmethod
 
    def setup_class(cls):
 
        UserLog.query().delete()
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        def strptime(val):
 
            fmt = '%Y-%m-%d %H:%M:%S'
 
            if '.' not in val:
 
                return datetime.datetime.strptime(val, fmt)
 

	
 
            nofrag, frag = val.split(".")
 
            date = datetime.datetime.strptime(nofrag, fmt)
 

	
 
            frag = frag[:6]  # truncate to microseconds
 
            frag += (6 - len(frag)) * '0'  # add 0s
 
            return date.replace(microsecond=int(frag))
 

	
 
        with open(os.path.join(FIXTURES, 'journal_dump.csv')) as f:
 
            for row in csv.DictReader(f):
 
                ul = UserLog()
 
                for k, v in row.items():
 
                    if k == 'action_date':
 
                        v = strptime(v)
 
                    if k in ['user_id', 'repository_id']:
 
                        # nullable due to FK problems
 
                        v = None
 
                    setattr(ul, k, v)
 
                Session().add(ul)
 
            Session().commit()
 
                meta.Session().add(ul)
 
            meta.Session().commit()
 

	
 
    @classmethod
 
    def teardown_class(cls):
 
        UserLog.query().delete()
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    def test_index(self):
 
        self.log_user()
 
        response = self.app.get(base.url(controller='admin/admin', action='index'))
 
        response.mustcontain('Admin Journal')
 

	
 
    def test_filter_all_entries(self):
 
        self.log_user()
 
        response = self.app.get(base.url(controller='admin/admin', action='index',))
 
        response.mustcontain(' 2036 Entries')
 

	
 
    def test_filter_journal_filter_exact_match_on_repository(self):
kallithea/tests/functional/test_admin_gists.py
Show inline comments
 
from kallithea.model import meta
 
from kallithea.model.db import Gist, User
 
from kallithea.model.gist import GistModel
 
from kallithea.model.meta import Session
 
from kallithea.tests import base
 

	
 

	
 
def _create_gist(f_name, content='some gist', lifetime=-1,
 
                 description='gist-desc', gist_type='public',
 
                 owner=base.TEST_USER_ADMIN_LOGIN):
 
    gist_mapping = {
 
        f_name: {'content': content}
 
    }
 
    owner = User.get_by_username(owner)
 
    gist = GistModel().create(description, owner=owner, ip_addr=base.IP_ADDR,
 
                       gist_mapping=gist_mapping, gist_type=gist_type,
 
                       lifetime=lifetime)
 
    Session().commit()
 
    meta.Session().commit()
 
    return gist
 

	
 

	
 
class TestGistsController(base.TestController):
 

	
 
    def teardown_method(self, method):
 
        for g in Gist.query():
 
            GistModel().delete(g)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    def test_index(self):
 
        self.log_user()
 
        response = self.app.get(base.url('gists'))
 
        # Test response...
 
        response.mustcontain('There are no gists yet')
 

	
 
        g1 = _create_gist('gist1').gist_access_id
 
        g2 = _create_gist('gist2', lifetime=1400).gist_access_id
 
        g3 = _create_gist('gist3', description='gist3-desc').gist_access_id
 
        g4 = _create_gist('gist4', gist_type='private').gist_access_id
 
        response = self.app.get(base.url('gists'))
 
@@ -81,25 +81,25 @@ class TestGistsController(base.TestContr
 
                                 params={'lifetime': -1,
 
                                         'content': 'gist test',
 
                                         'filename': '/home/foo',
 
                                         'public': 'public',
 
                                         '_session_csrf_secret_token': self.session_csrf_secret_token()},
 
                                 status=200)
 
        response.mustcontain('Filename cannot be inside a directory')
 

	
 
    def test_access_expired_gist(self):
 
        self.log_user()
 
        gist = _create_gist('never-see-me')
 
        gist.gist_expires = 0  # 1970
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        response = self.app.get(base.url('gist', gist_id=gist.gist_access_id), status=404)
 

	
 
    def test_create_private(self):
 
        self.log_user()
 
        response = self.app.post(base.url('gists'),
 
                                 params={'lifetime': -1,
 
                                         'content': 'private gist test',
 
                                         'filename': 'private-foo',
 
                                         'private': 'private',
 
                                         '_session_csrf_secret_token': self.session_csrf_secret_token()},
 
                                 status=302)
kallithea/tests/functional/test_admin_repo_groups.py
Show inline comments
 
from kallithea.model.meta import Session
 
from kallithea.model import meta
 
from kallithea.model.repo_group import RepoGroupModel
 
from kallithea.tests.base import TestController, url
 
from kallithea.tests.fixture import Fixture
 

	
 

	
 
fixture = Fixture()
 

	
 

	
 
class TestRepoGroupsController(TestController):
 

	
 
    def test_case_insensitivity(self):
 
        self.log_user()
 
        group_name = 'newgroup'
 
        response = self.app.post(url('repos_groups'),
 
                                 fixture._get_repo_group_create_params(group_name=group_name,
 
                                                                 _session_csrf_secret_token=self.session_csrf_secret_token()))
 
        # try to create repo group with swapped case
 
        swapped_group_name = group_name.swapcase()
 
        response = self.app.post(url('repos_groups'),
 
                                 fixture._get_repo_group_create_params(group_name=swapped_group_name,
 
                                                                 _session_csrf_secret_token=self.session_csrf_secret_token()))
 
        response.mustcontain('already exists')
 

	
 
        RepoGroupModel().delete(group_name)
 
        Session().commit()
 
        meta.Session().commit()
kallithea/tests/functional/test_admin_repos.py
Show inline comments
 
# -*- coding: utf-8 -*-
 

	
 
import os
 
import urllib.parse
 

	
 
import mock
 
import pytest
 

	
 
import kallithea
 
from kallithea.lib import vcs
 
from kallithea.model import meta
 
from kallithea.model.db import Permission, Repository, Ui, User, UserRepoToPerm
 
from kallithea.model.meta import Session
 
from kallithea.model.repo import RepoModel
 
from kallithea.model.repo_group import RepoGroupModel
 
from kallithea.model.user import UserModel
 
from kallithea.tests import base
 
from kallithea.tests.fixture import Fixture, raise_exception
 

	
 

	
 
fixture = Fixture()
 

	
 

	
 
def _get_permission_for_user(user, repo):
 
    perm = UserRepoToPerm.query() \
 
@@ -52,153 +52,153 @@ class _BaseTestCase(base.TestController)
 
                                                repo_name=repo_name,
 
                                                repo_type=self.REPO_TYPE,
 
                                                repo_description=description,
 
                                                _session_csrf_secret_token=self.session_csrf_secret_token()))
 
        ## run the check page that triggers the flash message
 
        response = self.app.get(base.url('repo_check_home', repo_name=repo_name))
 
        assert response.json == {'result': True}
 
        self.checkSessionFlash(response,
 
                               'Created repository <a href="/%s">%s</a>'
 
                               % (repo_name, repo_name))
 

	
 
        # test if the repo was created in the database
 
        new_repo = Session().query(Repository) \
 
        new_repo = meta.Session().query(Repository) \
 
            .filter(Repository.repo_name == repo_name).one()
 

	
 
        assert new_repo.repo_name == repo_name
 
        assert new_repo.description == description
 

	
 
        # test if the repository is visible in the list ?
 
        response = self.app.get(base.url('summary_home', repo_name=repo_name))
 
        response.mustcontain(repo_name)
 
        response.mustcontain(self.REPO_TYPE)
 

	
 
        # test if the repository was created on filesystem
 
        try:
 
            vcs.get_repo(os.path.join(Ui.get_by_key('paths', '/').ui_value, repo_name))
 
        except vcs.exceptions.VCSError:
 
            pytest.fail('no repo %s in filesystem' % repo_name)
 

	
 
        RepoModel().delete(repo_name)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    def test_case_insensitivity(self):
 
        self.log_user()
 
        repo_name = self.NEW_REPO
 
        description = 'description for newly created repo'
 
        response = self.app.post(base.url('repos'),
 
                                 fixture._get_repo_create_params(repo_private=False,
 
                                                                 repo_name=repo_name,
 
                                                                 repo_type=self.REPO_TYPE,
 
                                                                 repo_description=description,
 
                                                                 _session_csrf_secret_token=self.session_csrf_secret_token()))
 
        # try to create repo with swapped case
 
        swapped_repo_name = repo_name.swapcase()
 
        response = self.app.post(base.url('repos'),
 
                                 fixture._get_repo_create_params(repo_private=False,
 
                                                                 repo_name=swapped_repo_name,
 
                                                                 repo_type=self.REPO_TYPE,
 
                                                                 repo_description=description,
 
                                                                 _session_csrf_secret_token=self.session_csrf_secret_token()))
 
        response.mustcontain('already exists')
 

	
 
        RepoModel().delete(repo_name)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    def test_create_in_group(self):
 
        self.log_user()
 

	
 
        ## create GROUP
 
        group_name = 'sometest_%s' % self.REPO_TYPE
 
        gr = RepoGroupModel().create(group_name=group_name,
 
                                     group_description='test',
 
                                     owner=base.TEST_USER_ADMIN_LOGIN)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        repo_name = 'ingroup'
 
        repo_name_full = kallithea.URL_SEP.join([group_name, repo_name])
 
        description = 'description for newly created repo'
 
        response = self.app.post(base.url('repos'),
 
                        fixture._get_repo_create_params(repo_private=False,
 
                                                repo_name=repo_name,
 
                                                repo_type=self.REPO_TYPE,
 
                                                repo_description=description,
 
                                                repo_group=gr.group_id,
 
                                                _session_csrf_secret_token=self.session_csrf_secret_token()))
 
        ## run the check page that triggers the flash message
 
        response = self.app.get(base.url('repo_check_home', repo_name=repo_name_full))
 
        assert response.json == {'result': True}
 
        self.checkSessionFlash(response,
 
                               'Created repository <a href="/%s">%s</a>'
 
                               % (repo_name_full, repo_name_full))
 
        # test if the repo was created in the database
 
        new_repo = Session().query(Repository) \
 
        new_repo = meta.Session().query(Repository) \
 
            .filter(Repository.repo_name == repo_name_full).one()
 
        new_repo_id = new_repo.repo_id
 

	
 
        assert new_repo.repo_name == repo_name_full
 
        assert new_repo.description == description
 

	
 
        # test if the repository is visible in the list ?
 
        response = self.app.get(base.url('summary_home', repo_name=repo_name_full))
 
        response.mustcontain(repo_name_full)
 
        response.mustcontain(self.REPO_TYPE)
 

	
 
        inherited_perms = UserRepoToPerm.query() \
 
            .filter(UserRepoToPerm.repository_id == new_repo_id).all()
 
        assert len(inherited_perms) == 1
 

	
 
        # test if the repository was created on filesystem
 
        try:
 
            vcs.get_repo(os.path.join(Ui.get_by_key('paths', '/').ui_value, repo_name_full))
 
        except vcs.exceptions.VCSError:
 
            RepoGroupModel().delete(group_name)
 
            Session().commit()
 
            meta.Session().commit()
 
            pytest.fail('no repo %s in filesystem' % repo_name)
 

	
 
        RepoModel().delete(repo_name_full)
 
        RepoGroupModel().delete(group_name)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    def test_create_in_group_without_needed_permissions(self):
 
        usr = self.log_user(base.TEST_USER_REGULAR_LOGIN, base.TEST_USER_REGULAR_PASS)
 
        # avoid spurious RepoGroup DetachedInstanceError ...
 
        session_csrf_secret_token = self.session_csrf_secret_token()
 
        # revoke
 
        user_model = UserModel()
 
        # disable fork and create on default user
 
        user_model.revoke_perm(User.DEFAULT_USER_NAME, 'hg.create.repository')
 
        user_model.grant_perm(User.DEFAULT_USER_NAME, 'hg.create.none')
 
        user_model.revoke_perm(User.DEFAULT_USER_NAME, 'hg.fork.repository')
 
        user_model.grant_perm(User.DEFAULT_USER_NAME, 'hg.fork.none')
 

	
 
        # disable on regular user
 
        user_model.revoke_perm(base.TEST_USER_REGULAR_LOGIN, 'hg.create.repository')
 
        user_model.grant_perm(base.TEST_USER_REGULAR_LOGIN, 'hg.create.none')
 
        user_model.revoke_perm(base.TEST_USER_REGULAR_LOGIN, 'hg.fork.repository')
 
        user_model.grant_perm(base.TEST_USER_REGULAR_LOGIN, 'hg.fork.none')
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        ## create GROUP
 
        group_name = 'reg_sometest_%s' % self.REPO_TYPE
 
        gr = RepoGroupModel().create(group_name=group_name,
 
                                     group_description='test',
 
                                     owner=base.TEST_USER_ADMIN_LOGIN)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        group_name_allowed = 'reg_sometest_allowed_%s' % self.REPO_TYPE
 
        gr_allowed = RepoGroupModel().create(group_name=group_name_allowed,
 
                                     group_description='test',
 
                                     owner=base.TEST_USER_REGULAR_LOGIN)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        repo_name = 'ingroup'
 
        repo_name_full = kallithea.URL_SEP.join([group_name, repo_name])
 
        description = 'description for newly created repo'
 
        response = self.app.post(base.url('repos'),
 
                        fixture._get_repo_create_params(repo_private=False,
 
                                                repo_name=repo_name,
 
                                                repo_type=self.REPO_TYPE,
 
                                                repo_description=description,
 
                                                repo_group=gr.group_id,
 
                                                _session_csrf_secret_token=session_csrf_secret_token))
 

	
 
@@ -214,118 +214,118 @@ class _BaseTestCase(base.TestController)
 
                                                repo_type=self.REPO_TYPE,
 
                                                repo_description=description,
 
                                                repo_group=gr_allowed.group_id,
 
                                                _session_csrf_secret_token=session_csrf_secret_token))
 

	
 
        ## run the check page that triggers the flash message
 
        response = self.app.get(base.url('repo_check_home', repo_name=repo_name_full))
 
        assert response.json == {'result': True}
 
        self.checkSessionFlash(response,
 
                               'Created repository <a href="/%s">%s</a>'
 
                               % (repo_name_full, repo_name_full))
 
        # test if the repo was created in the database
 
        new_repo = Session().query(Repository) \
 
        new_repo = meta.Session().query(Repository) \
 
            .filter(Repository.repo_name == repo_name_full).one()
 
        new_repo_id = new_repo.repo_id
 

	
 
        assert new_repo.repo_name == repo_name_full
 
        assert new_repo.description == description
 

	
 
        # test if the repository is visible in the list ?
 
        response = self.app.get(base.url('summary_home', repo_name=repo_name_full))
 
        response.mustcontain(repo_name_full)
 
        response.mustcontain(self.REPO_TYPE)
 

	
 
        inherited_perms = UserRepoToPerm.query() \
 
            .filter(UserRepoToPerm.repository_id == new_repo_id).all()
 
        assert len(inherited_perms) == 1
 

	
 
        # test if the repository was created on filesystem
 
        try:
 
            vcs.get_repo(os.path.join(Ui.get_by_key('paths', '/').ui_value, repo_name_full))
 
        except vcs.exceptions.VCSError:
 
            RepoGroupModel().delete(group_name)
 
            Session().commit()
 
            meta.Session().commit()
 
            pytest.fail('no repo %s in filesystem' % repo_name)
 

	
 
        RepoModel().delete(repo_name_full)
 
        RepoGroupModel().delete(group_name)
 
        RepoGroupModel().delete(group_name_allowed)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    def test_create_in_group_inherit_permissions(self):
 
        self.log_user()
 

	
 
        ## create GROUP
 
        group_name = 'sometest_%s' % self.REPO_TYPE
 
        gr = RepoGroupModel().create(group_name=group_name,
 
                                     group_description='test',
 
                                     owner=base.TEST_USER_ADMIN_LOGIN)
 
        perm = Permission.get_by_key('repository.write')
 
        RepoGroupModel().grant_user_permission(gr, base.TEST_USER_REGULAR_LOGIN, perm)
 

	
 
        ## add repo permissions
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        repo_name = 'ingroup_inherited_%s' % self.REPO_TYPE
 
        repo_name_full = kallithea.URL_SEP.join([group_name, repo_name])
 
        description = 'description for newly created repo'
 
        response = self.app.post(base.url('repos'),
 
                        fixture._get_repo_create_params(repo_private=False,
 
                                                repo_name=repo_name,
 
                                                repo_type=self.REPO_TYPE,
 
                                                repo_description=description,
 
                                                repo_group=gr.group_id,
 
                                                repo_copy_permissions=True,
 
                                                _session_csrf_secret_token=self.session_csrf_secret_token()))
 

	
 
        ## run the check page that triggers the flash message
 
        response = self.app.get(base.url('repo_check_home', repo_name=repo_name_full))
 
        self.checkSessionFlash(response,
 
                               'Created repository <a href="/%s">%s</a>'
 
                               % (repo_name_full, repo_name_full))
 
        # test if the repo was created in the database
 
        new_repo = Session().query(Repository) \
 
        new_repo = meta.Session().query(Repository) \
 
            .filter(Repository.repo_name == repo_name_full).one()
 
        new_repo_id = new_repo.repo_id
 

	
 
        assert new_repo.repo_name == repo_name_full
 
        assert new_repo.description == description
 

	
 
        # test if the repository is visible in the list ?
 
        response = self.app.get(base.url('summary_home', repo_name=repo_name_full))
 
        response.mustcontain(repo_name_full)
 
        response.mustcontain(self.REPO_TYPE)
 

	
 
        # test if the repository was created on filesystem
 
        try:
 
            vcs.get_repo(os.path.join(Ui.get_by_key('paths', '/').ui_value, repo_name_full))
 
        except vcs.exceptions.VCSError:
 
            RepoGroupModel().delete(group_name)
 
            Session().commit()
 
            meta.Session().commit()
 
            pytest.fail('no repo %s in filesystem' % repo_name)
 

	
 
        # check if inherited permissiona are applied
 
        inherited_perms = UserRepoToPerm.query() \
 
            .filter(UserRepoToPerm.repository_id == new_repo_id).all()
 
        assert len(inherited_perms) == 2
 

	
 
        assert base.TEST_USER_REGULAR_LOGIN in [x.user.username
 
                                                    for x in inherited_perms]
 
        assert 'repository.write' in [x.permission.permission_name
 
                                               for x in inherited_perms]
 

	
 
        RepoModel().delete(repo_name_full)
 
        RepoGroupModel().delete(group_name)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    def test_create_remote_repo_wrong_clone_uri(self):
 
        self.log_user()
 
        repo_name = self.NEW_REPO
 
        description = 'description for newly created repo'
 
        response = self.app.post(base.url('repos'),
 
                        fixture._get_repo_create_params(repo_private=False,
 
                                                repo_name=repo_name,
 
                                                repo_type=self.REPO_TYPE,
 
                                                repo_description=description,
 
                                                clone_uri='http://127.0.0.1/repo',
 
                                                _session_csrf_secret_token=self.session_csrf_secret_token()))
 
@@ -364,98 +364,98 @@ class _BaseTestCase(base.TestController)
 
        response = self.app.post(base.url('repos'),
 
                        fixture._get_repo_create_params(repo_private=False,
 
                                                repo_type=self.REPO_TYPE,
 
                                                repo_name=repo_name,
 
                                                repo_description=description,
 
                                                _session_csrf_secret_token=self.session_csrf_secret_token()))
 
        ## run the check page that triggers the flash message
 
        response = self.app.get(base.url('repo_check_home', repo_name=repo_name))
 
        self.checkSessionFlash(response,
 
                               'Created repository <a href="/%s">%s</a>'
 
                               % (repo_name, repo_name))
 
        # test if the repo was created in the database
 
        new_repo = Session().query(Repository) \
 
        new_repo = meta.Session().query(Repository) \
 
            .filter(Repository.repo_name == repo_name).one()
 

	
 
        assert new_repo.repo_name == repo_name
 
        assert new_repo.description == description
 

	
 
        # test if the repository is visible in the list ?
 
        response = self.app.get(base.url('summary_home', repo_name=repo_name))
 
        response.mustcontain(repo_name)
 
        response.mustcontain(self.REPO_TYPE)
 

	
 
        # test if the repository was created on filesystem
 
        try:
 
            vcs.get_repo(os.path.join(Ui.get_by_key('paths', '/').ui_value, repo_name))
 
        except vcs.exceptions.VCSError:
 
            pytest.fail('no repo %s in filesystem' % repo_name)
 

	
 
        response = self.app.post(base.url('delete_repo', repo_name=repo_name),
 
            params={'_session_csrf_secret_token': self.session_csrf_secret_token()})
 

	
 
        self.checkSessionFlash(response, 'Deleted repository %s' % (repo_name))
 

	
 
        response.follow()
 

	
 
        # check if repo was deleted from db
 
        deleted_repo = Session().query(Repository) \
 
        deleted_repo = meta.Session().query(Repository) \
 
            .filter(Repository.repo_name == repo_name).scalar()
 

	
 
        assert deleted_repo is None
 

	
 
        assert os.path.isdir(os.path.join(Ui.get_by_key('paths', '/').ui_value, repo_name)) == False
 

	
 
    def test_delete_non_ascii(self):
 
        self.log_user()
 
        non_ascii = "ąęł"
 
        repo_name = "%s%s" % (self.NEW_REPO, non_ascii)
 
        description = 'description for newly created repo' + non_ascii
 
        response = self.app.post(base.url('repos'),
 
                        fixture._get_repo_create_params(repo_private=False,
 
                                                repo_name=repo_name,
 
                                                repo_type=self.REPO_TYPE,
 
                                                repo_description=description,
 
                                                _session_csrf_secret_token=self.session_csrf_secret_token()))
 
        ## run the check page that triggers the flash message
 
        response = self.app.get(base.url('repo_check_home', repo_name=repo_name))
 
        assert response.json == {'result': True}
 
        self.checkSessionFlash(response,
 
                               'Created repository <a href="/%s">%s</a>'
 
                               % (urllib.parse.quote(repo_name), repo_name))
 
        # test if the repo was created in the database
 
        new_repo = Session().query(Repository) \
 
        new_repo = meta.Session().query(Repository) \
 
            .filter(Repository.repo_name == repo_name).one()
 

	
 
        assert new_repo.repo_name == repo_name
 
        assert new_repo.description == description
 

	
 
        # test if the repository is visible in the list ?
 
        response = self.app.get(base.url('summary_home', repo_name=repo_name))
 
        response.mustcontain(repo_name)
 
        response.mustcontain(self.REPO_TYPE)
 

	
 
        # test if the repository was created on filesystem
 
        try:
 
            vcs.get_repo(os.path.join(Ui.get_by_key('paths', '/').ui_value, repo_name))
 
        except vcs.exceptions.VCSError:
 
            pytest.fail('no repo %s in filesystem' % repo_name)
 

	
 
        response = self.app.post(base.url('delete_repo', repo_name=repo_name),
 
            params={'_session_csrf_secret_token': self.session_csrf_secret_token()})
 
        self.checkSessionFlash(response, 'Deleted repository %s' % (repo_name))
 
        response.follow()
 

	
 
        # check if repo was deleted from db
 
        deleted_repo = Session().query(Repository) \
 
        deleted_repo = meta.Session().query(Repository) \
 
            .filter(Repository.repo_name == repo_name).scalar()
 

	
 
        assert deleted_repo is None
 

	
 
        assert os.path.isdir(os.path.join(Ui.get_by_key('paths', '/').ui_value, repo_name)) == False
 

	
 
    def test_delete_repo_with_group(self):
 
        # TODO:
 
        pass
 

	
 
    def test_delete_browser_fakeout(self):
 
        response = self.app.post(base.url('delete_repo', repo_name=self.REPO),
 
@@ -499,25 +499,25 @@ class _BaseTestCase(base.TestController)
 
                                                _session_csrf_secret_token=self.session_csrf_secret_token()))
 
        self.checkSessionFlash(response,
 
                               msg='Repository %s updated successfully' % (self.REPO))
 
        assert Repository.get_by_repo_name(self.REPO).private == False
 

	
 
        # we turn off private now the repo default permission should stay None
 
        perm = _get_permission_for_user(user='default', repo=self.REPO)
 
        assert len(perm), 1
 
        assert perm[0].permission.permission_name == 'repository.none'
 

	
 
        # update this permission back
 
        perm[0].permission = Permission.get_by_key('repository.read')
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    def test_set_repo_fork_has_no_self_id(self):
 
        self.log_user()
 
        repo = Repository.get_by_repo_name(self.REPO)
 
        response = self.app.get(base.url('edit_repo_advanced', repo_name=self.REPO))
 
        opt = """<option value="%s">%s</option>""" % (repo.repo_id, self.REPO)
 
        response.mustcontain(no=[opt])
 

	
 
    def test_set_fork_of_other_repo(self):
 
        self.log_user()
 
        other_repo = 'other_%s' % self.REPO_TYPE
 
        fixture.create_repo(other_repo, repo_type=self.REPO_TYPE)
 
@@ -577,42 +577,42 @@ class _BaseTestCase(base.TestController)
 
        user_model = UserModel()
 
        # disable fork and create on default user
 
        user_model.revoke_perm(User.DEFAULT_USER_NAME, 'hg.create.repository')
 
        user_model.grant_perm(User.DEFAULT_USER_NAME, 'hg.create.none')
 
        user_model.revoke_perm(User.DEFAULT_USER_NAME, 'hg.fork.repository')
 
        user_model.grant_perm(User.DEFAULT_USER_NAME, 'hg.fork.none')
 

	
 
        # disable on regular user
 
        user_model.revoke_perm(base.TEST_USER_REGULAR_LOGIN, 'hg.create.repository')
 
        user_model.grant_perm(base.TEST_USER_REGULAR_LOGIN, 'hg.create.none')
 
        user_model.revoke_perm(base.TEST_USER_REGULAR_LOGIN, 'hg.fork.repository')
 
        user_model.grant_perm(base.TEST_USER_REGULAR_LOGIN, 'hg.fork.none')
 
        Session().commit()
 
        meta.Session().commit()
 

	
 

	
 
        user = User.get(usr['user_id'])
 

	
 
        repo_name = self.NEW_REPO + 'no_perms'
 
        description = 'description for newly created repo'
 
        response = self.app.post(base.url('repos'),
 
                        fixture._get_repo_create_params(repo_private=False,
 
                                                repo_name=repo_name,
 
                                                repo_type=self.REPO_TYPE,
 
                                                repo_description=description,
 
                                                _session_csrf_secret_token=self.session_csrf_secret_token()))
 

	
 
        response.mustcontain('<span class="error-message">Invalid value</span>')
 

	
 
        RepoModel().delete(repo_name)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    @mock.patch.object(RepoModel, '_create_filesystem_repo', raise_exception)
 
    def test_create_repo_when_filesystem_op_fails(self):
 
        self.log_user()
 
        repo_name = self.NEW_REPO
 
        description = 'description for newly created repo'
 

	
 
        response = self.app.post(base.url('repos'),
 
                        fixture._get_repo_create_params(repo_private=False,
 
                                                repo_name=repo_name,
 
                                                repo_type=self.REPO_TYPE,
 
                                                repo_description=description,
kallithea/tests/functional/test_admin_user_groups.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
from kallithea.model import meta
 
from kallithea.model.db import Permission, UserGroup, UserGroupToPerm
 
from kallithea.model.meta import Session
 
from kallithea.tests import base
 

	
 

	
 
TEST_USER_GROUP = 'admins_test'
 

	
 

	
 
class TestAdminUsersGroupsController(base.TestController):
 

	
 
    def test_index(self):
 
        self.log_user()
 
        response = self.app.get(base.url('users_groups'))
 
        # Test response...
 
@@ -43,31 +43,31 @@ class TestAdminUsersGroupsController(bas
 
        self.log_user()
 
        users_group_name = TEST_USER_GROUP + 'another'
 
        response = self.app.post(base.url('users_groups'),
 
                                 {'users_group_name': users_group_name,
 
                                  'user_group_description': 'DESC',
 
                                  'active': True,
 
                                  '_session_csrf_secret_token': self.session_csrf_secret_token()})
 
        response.follow()
 

	
 
        self.checkSessionFlash(response,
 
                               'Created user group ')
 

	
 
        gr = Session().query(UserGroup) \
 
        gr = meta.Session().query(UserGroup) \
 
            .filter(UserGroup.users_group_name == users_group_name).one()
 

	
 
        response = self.app.post(base.url('delete_users_group', id=gr.users_group_id),
 
            params={'_session_csrf_secret_token': self.session_csrf_secret_token()})
 

	
 
        gr = Session().query(UserGroup) \
 
        gr = meta.Session().query(UserGroup) \
 
            .filter(UserGroup.users_group_name == users_group_name).scalar()
 

	
 
        assert gr is None
 

	
 
    def test_default_perms_enable_repository_read_on_group(self):
 
        self.log_user()
 
        users_group_name = TEST_USER_GROUP + 'another2'
 
        response = self.app.post(base.url('users_groups'),
 
                                 {'users_group_name': users_group_name,
 
                                  'user_group_description': 'DESC',
 
                                  'active': True,
 
                                  '_session_csrf_secret_token': self.session_csrf_secret_token()})
 
@@ -112,25 +112,25 @@ class TestAdminUsersGroupsController(bas
 
            .filter(UserGroupToPerm.users_group == ug).all()
 

	
 
        assert sorted([[x.users_group_id, x.permission_id, ] for x in perms]) == sorted([[ug.users_group_id, p.permission_id],
 
                    [ug.users_group_id, p2.permission_id],
 
                    [ug.users_group_id, p3.permission_id]])
 

	
 
        # DELETE !
 
        ug = UserGroup.get_by_group_name(users_group_name)
 
        ugid = ug.users_group_id
 
        response = self.app.post(base.url('delete_users_group', id=ug.users_group_id),
 
            params={'_session_csrf_secret_token': self.session_csrf_secret_token()})
 
        response = response.follow()
 
        gr = Session().query(UserGroup) \
 
        gr = meta.Session().query(UserGroup) \
 
            .filter(UserGroup.users_group_name == users_group_name).scalar()
 

	
 
        assert gr is None
 
        p = Permission.get_by_key('hg.create.repository')
 
        perms = UserGroupToPerm.query() \
 
            .filter(UserGroupToPerm.users_group_id == ugid).all()
 
        perms = [[x.users_group_id,
 
                  x.permission_id, ] for x in perms]
 
        assert perms == []
 

	
 
    def test_default_perms_enable_repository_fork_on_group(self):
 
        self.log_user()
 
@@ -179,25 +179,25 @@ class TestAdminUsersGroupsController(bas
 
            .filter(UserGroupToPerm.users_group == ug).all()
 

	
 
        assert sorted([[x.users_group_id, x.permission_id, ] for x in perms]) == sorted([[ug.users_group_id, p.permission_id],
 
                    [ug.users_group_id, p2.permission_id],
 
                    [ug.users_group_id, p3.permission_id]])
 

	
 
        # DELETE !
 
        ug = UserGroup.get_by_group_name(users_group_name)
 
        ugid = ug.users_group_id
 
        response = self.app.post(base.url('delete_users_group', id=ug.users_group_id),
 
            params={'_session_csrf_secret_token': self.session_csrf_secret_token()})
 
        response = response.follow()
 
        gr = Session().query(UserGroup) \
 
        gr = meta.Session().query(UserGroup) \
 
                           .filter(UserGroup.users_group_name ==
 
                                   users_group_name).scalar()
 

	
 
        assert gr is None
 
        p = Permission.get_by_key('hg.fork.repository')
 
        perms = UserGroupToPerm.query() \
 
            .filter(UserGroupToPerm.users_group_id == ugid).all()
 
        perms = [[x.users_group_id,
 
                  x.permission_id, ] for x in perms]
 
        assert perms == []
 

	
 
    def test_delete_browser_fakeout(self):
kallithea/tests/functional/test_admin_users.py
Show inline comments
 
@@ -12,27 +12,26 @@
 
# 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 pytest
 
from sqlalchemy.orm.exc import NoResultFound
 
from tg.util.webtest import test_context
 
from webob.exc import HTTPNotFound
 

	
 
import kallithea
 
from kallithea.controllers.admin.users import UsersController
 
from kallithea.lib import helpers as h
 
from kallithea.lib.auth import check_password
 
from kallithea.model import validators
 
from kallithea.model import meta, validators
 
from kallithea.model.db import Permission, RepoGroup, User, UserApiKeys, UserSshKeys
 
from kallithea.model.meta import Session
 
from kallithea.model.user import UserModel
 
from kallithea.tests import base
 
from kallithea.tests.fixture import Fixture
 

	
 

	
 
fixture = Fixture()
 

	
 

	
 
@pytest.fixture
 
def user_and_repo_group_fail():
 
    username = 'repogrouperr'
 
    groupname = 'repogroup_fail'
 
@@ -42,25 +41,25 @@ def user_and_repo_group_fail():
 
    # cleanup
 
    if RepoGroup.get_by_group_name(groupname):
 
        fixture.destroy_repo_group(repo_group)
 

	
 

	
 
class TestAdminUsersController(base.TestController):
 
    test_user_1 = 'testme'
 

	
 
    @classmethod
 
    def teardown_class(cls):
 
        if User.get_by_username(cls.test_user_1):
 
            UserModel().delete(cls.test_user_1)
 
            Session().commit()
 
            meta.Session().commit()
 

	
 
    def test_index(self):
 
        self.log_user()
 
        response = self.app.get(base.url('users'))
 
        # TODO: Test response...
 

	
 
    def test_create(self):
 
        self.log_user()
 
        username = 'newtestuser'
 
        password = 'test12'
 
        password_confirmation = password
 
        name = 'name'
 
@@ -77,25 +76,25 @@ class TestAdminUsersController(base.Test
 
             'extern_name': 'internal',
 
             'extern_type': 'internal',
 
             'email': email,
 
             '_session_csrf_secret_token': self.session_csrf_secret_token()})
 
        # 302 Found
 
        # The resource was found at http://localhost/_admin/users/5/edit; you should be redirected automatically.
 

	
 
        self.checkSessionFlash(response, '''Created user %s''' % username)
 

	
 
        response = response.follow()
 
        response.mustcontain("""%s user settings""" % username) # in <title>
 

	
 
        new_user = Session().query(User). \
 
        new_user = meta.Session().query(User). \
 
            filter(User.username == username).one()
 

	
 
        assert new_user.username == username
 
        assert check_password(password, new_user.password) == True
 
        assert new_user.name == name
 
        assert new_user.lastname == lastname
 
        assert new_user.email == email
 

	
 
    def test_create_err(self):
 
        self.log_user()
 
        username = 'new_user'
 
        password = ''
 
@@ -111,25 +110,25 @@ class TestAdminUsersController(base.Test
 
             'lastname': lastname,
 
             'email': email,
 
             '_session_csrf_secret_token': self.session_csrf_secret_token()})
 

	
 
        with test_context(self.app):
 
            msg = validators.ValidUsername(False, {})._messages['system_invalid_username']
 
        msg = h.html_escape(msg % {'username': 'new_user'})
 
        response.mustcontain("""<span class="error-message">%s</span>""" % msg)
 
        response.mustcontain("""<span class="error-message">Please enter a value</span>""")
 
        response.mustcontain("""<span class="error-message">An email address must contain a single @</span>""")
 

	
 
        def get_user():
 
            Session().query(User).filter(User.username == username).one()
 
            meta.Session().query(User).filter(User.username == username).one()
 

	
 
        with pytest.raises(NoResultFound):
 
            get_user(), 'found user in database'
 

	
 
    def test_new(self):
 
        self.log_user()
 
        response = self.app.get(base.url('new_user'))
 

	
 
    @base.parametrize('name,attrs',
 
        [('firstname', {'firstname': 'new_username'}),
 
         ('lastname', {'lastname': 'new_username'}),
 
         ('admin', {'admin': True}),
 
@@ -142,25 +141,25 @@ class TestAdminUsersController(base.Test
 
         ('active', {'active': True}),
 
         ('email', {'email': 'someemail@example.com'}),
 
        # ('new_password', {'new_password': 'foobar123',
 
        #                   'password_confirmation': 'foobar123'})
 
        ])
 
    def test_update(self, name, attrs):
 
        self.log_user()
 
        usr = fixture.create_user(self.test_user_1, password='qweqwe',
 
                                  email='testme@example.com',
 
                                  extern_type='internal',
 
                                  extern_name=self.test_user_1,
 
                                  skip_if_exists=True)
 
        Session().commit()
 
        meta.Session().commit()
 
        params = usr.get_api_data(True)
 
        params.update({'password_confirmation': ''})
 
        params.update({'new_password': ''})
 
        params.update(attrs)
 
        if name == 'email':
 
            params['emails'] = [attrs['email']]
 
        if name == 'extern_type':
 
            # cannot update this via form, expected value is original one
 
            params['extern_type'] = "internal"
 
        if name == 'extern_name':
 
            # cannot update this via form, expected value is original one
 
            params['extern_name'] = self.test_user_1
 
@@ -176,40 +175,40 @@ class TestAdminUsersController(base.Test
 
        updated_params = updated_user.get_api_data(True)
 
        updated_params.update({'password_confirmation': ''})
 
        updated_params.update({'new_password': ''})
 

	
 
        assert params == updated_params
 

	
 
    def test_delete(self):
 
        self.log_user()
 
        username = 'newtestuserdeleteme'
 

	
 
        fixture.create_user(name=username)
 

	
 
        new_user = Session().query(User) \
 
        new_user = meta.Session().query(User) \
 
            .filter(User.username == username).one()
 
        response = self.app.post(base.url('delete_user', id=new_user.user_id),
 
            params={'_session_csrf_secret_token': self.session_csrf_secret_token()})
 

	
 
        self.checkSessionFlash(response, 'Successfully deleted user')
 

	
 
    def test_delete_repo_err(self):
 
        self.log_user()
 
        username = 'repoerr'
 
        reponame = 'repoerr_fail'
 

	
 
        fixture.create_user(name=username)
 
        fixture.create_repo(name=reponame, cur_user=username)
 

	
 
        new_user = Session().query(User) \
 
        new_user = meta.Session().query(User) \
 
            .filter(User.username == username).one()
 
        response = self.app.post(base.url('delete_user', id=new_user.user_id),
 
            params={'_session_csrf_secret_token': self.session_csrf_secret_token()})
 
        self.checkSessionFlash(response, 'User &quot;%s&quot; still '
 
                               'owns 1 repositories and cannot be removed. '
 
                               'Switch owners or remove those repositories: '
 
                               '%s' % (username, reponame))
 

	
 
        response = self.app.post(base.url('delete_repo', repo_name=reponame),
 
            params={'_session_csrf_secret_token': self.session_csrf_secret_token()})
 
        self.checkSessionFlash(response, 'Deleted repository %s' % reponame)
 

	
 
@@ -242,25 +241,25 @@ class TestAdminUsersController(base.Test
 
        response = self.app.post(base.url('delete_user', id=new_user.user_id),
 
            params={'_session_csrf_secret_token': self.session_csrf_secret_token()})
 
        self.checkSessionFlash(response, 'Successfully deleted user')
 

	
 
    def test_delete_user_group_err(self):
 
        self.log_user()
 
        username = 'usergrouperr'
 
        groupname = 'usergroup_fail'
 

	
 
        fixture.create_user(name=username)
 
        ug = fixture.create_user_group(name=groupname, cur_user=username)
 

	
 
        new_user = Session().query(User) \
 
        new_user = meta.Session().query(User) \
 
            .filter(User.username == username).one()
 
        response = self.app.post(base.url('delete_user', id=new_user.user_id),
 
            params={'_session_csrf_secret_token': self.session_csrf_secret_token()})
 
        self.checkSessionFlash(response, 'User &quot;%s&quot; still '
 
                               'owns 1 user groups and cannot be removed. '
 
                               'Switch owners or remove those user groups: '
 
                               '%s' % (username, groupname))
 

	
 
        # TODO: why do this fail?
 
        #response = self.app.delete(base.url('delete_users_group', id=groupname))
 
        #self.checkSessionFlash(response, 'Removed user group %s' % groupname)
 

	
 
@@ -274,133 +273,133 @@ class TestAdminUsersController(base.Test
 
        self.log_user()
 
        user = User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
 
        response = self.app.get(base.url('edit_user', id=user.user_id))
 

	
 
    def test_add_perm_create_repo(self):
 
        self.log_user()
 
        perm_none = Permission.get_by_key('hg.create.none')
 
        perm_create = Permission.get_by_key('hg.create.repository')
 

	
 
        user = UserModel().create_or_update(username='dummy', password='qwe',
 
                                            email='dummy', firstname='a',
 
                                            lastname='b')
 
        Session().commit()
 
        meta.Session().commit()
 
        uid = user.user_id
 

	
 
        try:
 
            # User should have None permission on creation repository
 
            assert UserModel().has_perm(user, perm_none) == False
 
            assert UserModel().has_perm(user, perm_create) == False
 

	
 
            response = self.app.post(base.url('edit_user_perms_update', id=uid),
 
                                     params=dict(create_repo_perm=True,
 
                                                 _session_csrf_secret_token=self.session_csrf_secret_token()))
 

	
 
            perm_none = Permission.get_by_key('hg.create.none')
 
            perm_create = Permission.get_by_key('hg.create.repository')
 

	
 
            # User should have None permission on creation repository
 
            assert UserModel().has_perm(uid, perm_none) == False
 
            assert UserModel().has_perm(uid, perm_create) == True
 
        finally:
 
            UserModel().delete(uid)
 
            Session().commit()
 
            meta.Session().commit()
 

	
 
    def test_revoke_perm_create_repo(self):
 
        self.log_user()
 
        perm_none = Permission.get_by_key('hg.create.none')
 
        perm_create = Permission.get_by_key('hg.create.repository')
 

	
 
        user = UserModel().create_or_update(username='dummy', password='qwe',
 
                                            email='dummy', firstname='a',
 
                                            lastname='b')
 
        Session().commit()
 
        meta.Session().commit()
 
        uid = user.user_id
 

	
 
        try:
 
            # User should have None permission on creation repository
 
            assert UserModel().has_perm(user, perm_none) == False
 
            assert UserModel().has_perm(user, perm_create) == False
 

	
 
            response = self.app.post(base.url('edit_user_perms_update', id=uid),
 
                                     params=dict(_session_csrf_secret_token=self.session_csrf_secret_token()))
 

	
 
            perm_none = Permission.get_by_key('hg.create.none')
 
            perm_create = Permission.get_by_key('hg.create.repository')
 

	
 
            # User should have None permission on creation repository
 
            assert UserModel().has_perm(uid, perm_none) == True
 
            assert UserModel().has_perm(uid, perm_create) == False
 
        finally:
 
            UserModel().delete(uid)
 
            Session().commit()
 
            meta.Session().commit()
 

	
 
    def test_add_perm_fork_repo(self):
 
        self.log_user()
 
        perm_none = Permission.get_by_key('hg.fork.none')
 
        perm_fork = Permission.get_by_key('hg.fork.repository')
 

	
 
        user = UserModel().create_or_update(username='dummy', password='qwe',
 
                                            email='dummy', firstname='a',
 
                                            lastname='b')
 
        Session().commit()
 
        meta.Session().commit()
 
        uid = user.user_id
 

	
 
        try:
 
            # User should have None permission on creation repository
 
            assert UserModel().has_perm(user, perm_none) == False
 
            assert UserModel().has_perm(user, perm_fork) == False
 

	
 
            response = self.app.post(base.url('edit_user_perms_update', id=uid),
 
                                     params=dict(create_repo_perm=True,
 
                                                 _session_csrf_secret_token=self.session_csrf_secret_token()))
 

	
 
            perm_none = Permission.get_by_key('hg.create.none')
 
            perm_create = Permission.get_by_key('hg.create.repository')
 

	
 
            # User should have None permission on creation repository
 
            assert UserModel().has_perm(uid, perm_none) == False
 
            assert UserModel().has_perm(uid, perm_create) == True
 
        finally:
 
            UserModel().delete(uid)
 
            Session().commit()
 
            meta.Session().commit()
 

	
 
    def test_revoke_perm_fork_repo(self):
 
        self.log_user()
 
        perm_none = Permission.get_by_key('hg.fork.none')
 
        perm_fork = Permission.get_by_key('hg.fork.repository')
 

	
 
        user = UserModel().create_or_update(username='dummy', password='qwe',
 
                                            email='dummy', firstname='a',
 
                                            lastname='b')
 
        Session().commit()
 
        meta.Session().commit()
 
        uid = user.user_id
 

	
 
        try:
 
            # User should have None permission on creation repository
 
            assert UserModel().has_perm(user, perm_none) == False
 
            assert UserModel().has_perm(user, perm_fork) == False
 

	
 
            response = self.app.post(base.url('edit_user_perms_update', id=uid),
 
                                     params=dict(_session_csrf_secret_token=self.session_csrf_secret_token()))
 

	
 
            perm_none = Permission.get_by_key('hg.create.none')
 
            perm_create = Permission.get_by_key('hg.create.repository')
 

	
 
            # User should have None permission on creation repository
 
            assert UserModel().has_perm(uid, perm_none) == True
 
            assert UserModel().has_perm(uid, perm_create) == False
 
        finally:
 
            UserModel().delete(uid)
 
            Session().commit()
 
            meta.Session().commit()
 

	
 
    def test_ips(self):
 
        self.log_user()
 
        user = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
 
        response = self.app.get(base.url('edit_user_ips', id=user.user_id))
 
        response.mustcontain('All IP addresses are allowed')
 

	
 
    @base.parametrize('test_name,ip,ip_range,failure', [
 
        ('127/24', '127.0.0.1/24', '127.0.0.0 - 127.0.0.255', False),
 
        ('10/32', '10.0.0.10/32', '10.0.0.10 - 10.0.0.10', False),
 
        ('0/16', '0.0.0.0/16', '0.0.0.0 - 0.0.255.255', False),
 
        ('0/8', '0.0.0.0/8', '0.0.0.0 - 0.255.255.255', False),
 
@@ -425,25 +424,25 @@ class TestAdminUsersController(base.Test
 
            response = self.app.get(base.url('edit_user_ips', id=user_id))
 
            response.mustcontain(ip)
 
            response.mustcontain(ip_range)
 

	
 
    def test_delete_ip(self, auto_clear_ip_permissions):
 
        self.log_user()
 
        user = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
 
        user_id = user.user_id
 
        ip = '127.0.0.1/32'
 
        ip_range = '127.0.0.1 - 127.0.0.1'
 
        with test_context(self.app):
 
            new_ip = UserModel().add_extra_ip(user_id, ip)
 
            Session().commit()
 
            meta.Session().commit()
 
        new_ip_id = new_ip.ip_id
 

	
 
        response = self.app.get(base.url('edit_user_ips', id=user_id))
 
        response.mustcontain(ip)
 
        response.mustcontain(ip_range)
 

	
 
        self.app.post(base.url('edit_user_ips_delete', id=user_id),
 
                      params=dict(del_ip_id=new_ip_id, _session_csrf_secret_token=self.session_csrf_secret_token()))
 

	
 
        response = self.app.get(base.url('edit_user_ips', id=user_id))
 
        response.mustcontain('All IP addresses are allowed')
 
        response.mustcontain(no=[ip])
 
@@ -468,26 +467,26 @@ class TestAdminUsersController(base.Test
 
        user_id = user.user_id
 

	
 
        response = self.app.post(base.url('edit_user_api_keys_update', id=user_id),
 
                 {'description': desc, 'lifetime': lifetime, '_session_csrf_secret_token': self.session_csrf_secret_token()})
 
        self.checkSessionFlash(response, 'API key successfully created')
 
        try:
 
            response = response.follow()
 
            user = User.get(user_id)
 
            for api_key in user.api_keys:
 
                response.mustcontain(api_key)
 
        finally:
 
            for api_key in UserApiKeys.query().filter(UserApiKeys.user_id == user_id).all():
 
                Session().delete(api_key)
 
                Session().commit()
 
                meta.Session().delete(api_key)
 
                meta.Session().commit()
 

	
 
    def test_remove_api_key(self):
 
        self.log_user()
 
        user = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
 
        user_id = user.user_id
 

	
 
        response = self.app.post(base.url('edit_user_api_keys_update', id=user_id),
 
                {'description': 'desc', 'lifetime': -1, '_session_csrf_secret_token': self.session_csrf_secret_token()})
 
        self.checkSessionFlash(response, 'API key successfully created')
 
        response = response.follow()
 

	
 
        # now delete our key
 
@@ -526,26 +525,26 @@ class TestAdminUsersController(base.Test
 

	
 
        response = self.app.post(base.url('edit_user_ssh_keys', id=user_id),
 
                                 {'description': description,
 
                                  'public_key': public_key,
 
                                  '_session_csrf_secret_token': self.session_csrf_secret_token()})
 
        self.checkSessionFlash(response, 'SSH key %s successfully added' % fingerprint)
 

	
 
        response = response.follow()
 
        response.mustcontain(fingerprint)
 
        ssh_key = UserSshKeys.query().filter(UserSshKeys.user_id == user_id).one()
 
        assert ssh_key.fingerprint == fingerprint
 
        assert ssh_key.description == description
 
        Session().delete(ssh_key)
 
        Session().commit()
 
        meta.Session().delete(ssh_key)
 
        meta.Session().commit()
 

	
 
    def test_remove_ssh_key(self):
 
        description = ''
 
        public_key = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC6Ycnc2oUZHQnQwuqgZqTTdMDZD7ataf3JM7oG2Fw8JR6cdmz4QZLe5mfDwaFwG2pWHLRpVqzfrD/Pn3rIO++bgCJH5ydczrl1WScfryV1hYMJ/4EzLGM657J1/q5EI+b9SntKjf4ax+KP322L0TNQGbZUHLbfG2MwHMrYBQpHUQ== me@localhost'
 
        fingerprint = 'Ke3oUCNJM87P0jJTb3D+e3shjceP2CqMpQKVd75E9I8'
 

	
 
        self.log_user()
 
        user = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
 
        user_id = user.user_id
 

	
 
        response = self.app.post(base.url('edit_user_ssh_keys', id=user_id),
 
                                 {'description': description,
kallithea/tests/functional/test_changeset_pullrequests_comments.py
Show inline comments
 
import re
 

	
 
from kallithea.model import meta
 
from kallithea.model.changeset_status import ChangesetStatusModel
 
from kallithea.model.db import ChangesetComment, PullRequest
 
from kallithea.model.meta import Session
 
from kallithea.tests import base
 

	
 

	
 
class TestChangeSetCommentsController(base.TestController):
 

	
 
    def setup_method(self, method):
 
        for x in ChangesetComment.query().all():
 
            Session().delete(x)
 
        Session().commit()
 
            meta.Session().delete(x)
 
        meta.Session().commit()
 

	
 
    def test_create(self):
 
        self.log_user()
 
        rev = '27cd5cce30c96924232dffcd24178a07ffeb5dfc'
 
        text = 'general comment on changeset'
 

	
 
        params = {'text': text, '_session_csrf_secret_token': self.session_csrf_secret_token()}
 
        response = self.app.post(base.url(controller='changeset', action='comment',
 
                                     repo_name=base.HG_REPO, revision=rev),
 
                                     params=params, extra_environ={'HTTP_X_PARTIAL_XHR': '1'})
 
        # Test response...
 
        assert response.status == '200 OK'
 
@@ -144,26 +144,26 @@ class TestChangeSetCommentsController(ba
 
                                repo_name=base.HG_REPO, revision=rev))
 
        response.mustcontain(
 
            '''<div class="comments-number">'''
 
            ''' 0 comments (0 inline, 0 general)'''
 
        )
 
        response.mustcontain(no=text)
 

	
 

	
 
class TestPullrequestsCommentsController(base.TestController):
 

	
 
    def setup_method(self, method):
 
        for x in ChangesetComment.query().all():
 
            Session().delete(x)
 
        Session().commit()
 
            meta.Session().delete(x)
 
        meta.Session().commit()
 

	
 
    def _create_pr(self):
 
        response = self.app.post(base.url(controller='pullrequests', action='create',
 
                                     repo_name=base.HG_REPO),
 
                                 {'org_repo': base.HG_REPO,
 
                                  'org_ref': 'branch:stable:4f7e2131323e0749a740c0a56ab68ae9269c562a',
 
                                  'other_repo': base.HG_REPO,
 
                                  'other_ref': 'branch:default:96507bd11ecc815ebc6270fdf6db110928c09c1e',
 
                                  'pullrequest_title': 'title',
 
                                  'pullrequest_desc': 'description',
 
                                  '_session_csrf_secret_token': self.session_csrf_secret_token(),
 
                                 },
kallithea/tests/functional/test_compare.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
from kallithea.model.meta import Session
 
from kallithea.model import meta
 
from kallithea.model.repo import RepoModel
 
from kallithea.tests import base
 
from kallithea.tests.fixture import Fixture
 

	
 

	
 
fixture = Fixture()
 

	
 

	
 
def _commit_ref(repo_name, sha, msg):
 
    return '''<div class="message-firstline"><a class="message-link" href="/%s/changeset/%s">%s</a></div>''' % (repo_name, sha, msg)
 

	
 

	
 
class TestCompareController(base.TestController):
 

	
 
    def setup_method(self, method):
 
        self.r1_id = None
 
        self.r2_id = None
 

	
 
    def teardown_method(self, method):
 
        if self.r2_id:
 
            RepoModel().delete(self.r2_id)
 
        if self.r1_id:
 
            RepoModel().delete(self.r1_id)
 
        Session().commit()
 
        Session.remove()
 
        meta.Session().commit()
 
        meta.Session.remove()
 

	
 
    def test_compare_forks_on_branch_extra_commits_hg(self):
 
        self.log_user()
 
        repo1 = fixture.create_repo('one', repo_type='hg',
 
                                    repo_description='diff-test',
 
                                    cur_user=base.TEST_USER_ADMIN_LOGIN)
 
        self.r1_id = repo1.repo_id
 
        # commit something !
 
        cs0 = fixture.commit_change(repo1.repo_name, filename='file1',
 
                content='line1\n', message='commit1', vcs_type='hg',
 
                parent=None, newfile=True)
 

	
 
@@ -448,30 +448,30 @@ class TestCompareController(base.TestCon
 
    def test_org_repo_new_commits_after_forking_simple_diff_hg(self):
 
        self.log_user()
 

	
 
        repo1 = fixture.create_repo('one', repo_type='hg',
 
                                    repo_description='diff-test',
 
                                    cur_user=base.TEST_USER_ADMIN_LOGIN)
 

	
 
        self.r1_id = repo1.repo_id
 
        r1_name = repo1.repo_name
 

	
 
        cs0 = fixture.commit_change(repo=r1_name, filename='file1',
 
                content='line1', message='commit1', vcs_type='hg', newfile=True)
 
        Session().commit()
 
        meta.Session().commit()
 
        assert repo1.scm_instance.revisions == [cs0.raw_id]
 
        # fork the repo1
 
        repo2 = fixture.create_fork(r1_name, 'one-fork',
 
                                    cur_user=base.TEST_USER_ADMIN_LOGIN)
 
        Session().commit()
 
        meta.Session().commit()
 
        assert repo2.scm_instance.revisions == [cs0.raw_id]
 
        self.r2_id = repo2.repo_id
 
        r2_name = repo2.repo_name
 

	
 
        cs1 = fixture.commit_change(repo=r2_name, filename='file1-fork',
 
                content='file1-line1-from-fork', message='commit1-fork',
 
                vcs_type='hg', parent=repo2.scm_instance[-1], newfile=True)
 

	
 
        cs2 = fixture.commit_change(repo=r2_name, filename='file2-fork',
 
                content='file2-line1-from-fork', message='commit2-fork',
 
                vcs_type='hg', parent=cs1, newfile=True)
 

	
 
@@ -521,30 +521,30 @@ class TestCompareController(base.TestCon
 
        self.log_user()
 

	
 
        repo1 = fixture.create_repo('one-git', repo_type='git',
 
                                    repo_description='diff-test',
 
                                    cur_user=base.TEST_USER_ADMIN_LOGIN)
 

	
 
        self.r1_id = repo1.repo_id
 
        r1_name = repo1.repo_name
 

	
 
        cs0 = fixture.commit_change(repo=r1_name, filename='file1',
 
                content='line1', message='commit1', vcs_type='git',
 
                newfile=True)
 
        Session().commit()
 
        meta.Session().commit()
 
        assert repo1.scm_instance.revisions == [cs0.raw_id]
 
        # fork the repo1
 
        repo2 = fixture.create_fork(r1_name, 'one-git-fork',
 
                                    cur_user=base.TEST_USER_ADMIN_LOGIN)
 
        Session().commit()
 
        meta.Session().commit()
 
        assert repo2.scm_instance.revisions == [cs0.raw_id]
 
        self.r2_id = repo2.repo_id
 
        r2_name = repo2.repo_name
 

	
 

	
 
        cs1 = fixture.commit_change(repo=r2_name, filename='file1-fork',
 
                content='file1-line1-from-fork', message='commit1-fork',
 
                vcs_type='git', parent=repo2.scm_instance[-1], newfile=True)
 

	
 
        cs2 = fixture.commit_change(repo=r2_name, filename='file2-fork',
 
                content='file2-line1-from-fork', message='commit2-fork',
 
                vcs_type='git', parent=cs1, newfile=True)
kallithea/tests/functional/test_files.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
import json
 
import mimetypes
 
import posixpath
 

	
 
from kallithea.model import meta
 
from kallithea.model.db import Repository
 
from kallithea.model.meta import Session
 
from kallithea.tests import base
 
from kallithea.tests.fixture import Fixture
 

	
 

	
 
fixture = Fixture()
 

	
 
ARCHIVE_SPECS = {
 
    '.tar.bz2': ('application/x-bzip2', 'tbz2', ''),
 
    '.tar.gz': ('application/x-gzip', 'tgz', ''),
 
    '.zip': ('application/zip', 'zip', ''),
 
}
 

	
 
HG_NODE_HISTORY = fixture.load_resource('hg_node_history_response.json')
 
GIT_NODE_HISTORY = fixture.load_resource('git_node_history_response.json')
 

	
 

	
 
def _set_downloads(repo_name, set_to):
 
    repo = Repository.get_by_repo_name(repo_name)
 
    repo.enable_downloads = set_to
 
    Session().commit()
 
    meta.Session().commit()
 

	
 

	
 
class TestFilesController(base.TestController):
 

	
 
    def test_index(self):
 
        self.log_user()
 
        response = self.app.get(base.url(controller='files', action='index',
 
                                    repo_name=base.HG_REPO,
 
                                    revision='tip',
 
                                    f_path='/'))
 
        # Test response...
 
        response.mustcontain('<a class="browser-dir ypjax-link" href="/%s/files/96507bd11ecc815ebc6270fdf6db110928c09c1e/docs"><i class="icon-folder-open"></i><span>docs</span></a>' % base.HG_REPO)
kallithea/tests/functional/test_forks.py
Show inline comments
 
# -*- coding: utf-8 -*-
 

	
 
import urllib.parse
 

	
 
from kallithea.model import meta
 
from kallithea.model.db import Repository, User
 
from kallithea.model.meta import Session
 
from kallithea.model.repo import RepoModel
 
from kallithea.model.user import UserModel
 
from kallithea.tests import base
 
from kallithea.tests.fixture import Fixture
 

	
 

	
 
fixture = Fixture()
 

	
 

	
 
class _BaseTestCase(base.TestController):
 
    """
 
    Write all tests here
 
    """
 
    REPO = None
 
    REPO_TYPE = None
 
    NEW_REPO = None
 
    REPO_FORK = None
 

	
 
    def setup_method(self, method):
 
        self.username = 'forkuser'
 
        self.password = 'qweqwe'
 
        u1 = fixture.create_user(self.username, password=self.password, email='fork_king@example.com')
 
        self.u1_id = u1.user_id
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    def teardown_method(self, method):
 
        fixture.destroy_user(self.u1_id)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    def test_index(self):
 
        self.log_user()
 
        repo_name = self.REPO
 
        response = self.app.get(base.url(controller='forks', action='forks',
 
                                    repo_name=repo_name))
 

	
 
        response.mustcontain("""There are no forks yet""")
 

	
 
    def test_no_permissions_to_fork(self):
 
        self.log_user(base.TEST_USER_REGULAR_LOGIN, base.TEST_USER_REGULAR_PASS)['user_id']
 
        try:
 
            user_model = UserModel()
 
            usr = User.get_default_user()
 
            user_model.revoke_perm(usr, 'hg.fork.repository')
 
            user_model.grant_perm(usr, 'hg.fork.none')
 
            Session().commit()
 
            meta.Session().commit()
 
            # try create a fork
 
            repo_name = self.REPO
 
            self.app.post(base.url(controller='forks', action='fork_create',
 
                              repo_name=repo_name), {'_session_csrf_secret_token': self.session_csrf_secret_token()}, status=403)
 
        finally:
 
            usr = User.get_default_user()
 
            user_model.revoke_perm(usr, 'hg.fork.none')
 
            user_model.grant_perm(usr, 'hg.fork.repository')
 
            Session().commit()
 
            meta.Session().commit()
 

	
 
    def test_index_with_fork(self):
 
        self.log_user()
 

	
 
        # create a fork
 
        fork_name = self.REPO_FORK
 
        description = 'fork of vcs test'
 
        repo_name = self.REPO
 
        org_repo = Repository.get_by_repo_name(repo_name)
 
        creation_args = {
 
            'repo_name': fork_name,
 
            'repo_group': '-1',
 
@@ -113,25 +113,25 @@ class _BaseTestCase(base.TestController)
 
                          repo_name=repo_name), creation_args)
 
        repo = Repository.get_by_repo_name(fork_name_full)
 
        assert repo.fork.repo_name == self.REPO
 

	
 
        ## run the check page that triggers the flash message
 
        response = self.app.get(base.url('repo_check_home', repo_name=fork_name_full))
 
        # test if we have a message that fork is ok
 
        self.checkSessionFlash(response,
 
                'Forked repository %s as <a href="/%s">%s</a>'
 
                % (repo_name, fork_name_full, fork_name_full))
 

	
 
        # test if the fork was created in the database
 
        fork_repo = Session().query(Repository) \
 
        fork_repo = meta.Session().query(Repository) \
 
            .filter(Repository.repo_name == fork_name_full).one()
 

	
 
        assert fork_repo.repo_name == fork_name_full
 
        assert fork_repo.fork.repo_name == repo_name
 

	
 
        # test if the repository is visible in the list ?
 
        response = self.app.get(base.url('summary_home', repo_name=fork_name_full))
 
        response.mustcontain(fork_name_full)
 
        response.mustcontain(self.REPO_TYPE)
 
        response.mustcontain('Fork of "<a href="/%s">%s</a>"' % (repo_name, repo_name))
 

	
 
        fixture.destroy_repo(fork_name_full)
 
@@ -207,62 +207,62 @@ class _BaseTestCase(base.TestController)
 
                          repo_name=repo_name), creation_args)
 
        repo = Repository.get_by_repo_name(self.REPO_FORK)
 
        assert repo.fork.repo_name == self.REPO
 

	
 
        ## run the check page that triggers the flash message
 
        response = self.app.get(base.url('repo_check_home', repo_name=fork_name))
 
        # test if we have a message that fork is ok
 
        self.checkSessionFlash(response,
 
                'Forked repository %s as <a href="/%s">%s</a>'
 
                % (repo_name, fork_name, fork_name))
 

	
 
        # test if the fork was created in the database
 
        fork_repo = Session().query(Repository) \
 
        fork_repo = meta.Session().query(Repository) \
 
            .filter(Repository.repo_name == fork_name).one()
 

	
 
        assert fork_repo.repo_name == fork_name
 
        assert fork_repo.fork.repo_name == repo_name
 

	
 
        # test if the repository is visible in the list ?
 
        response = self.app.get(base.url('summary_home', repo_name=fork_name))
 
        response.mustcontain(fork_name)
 
        response.mustcontain(self.REPO_TYPE)
 
        response.mustcontain('Fork of "<a href="/%s">%s</a>"' % (repo_name, repo_name))
 

	
 
        usr = self.log_user(self.username, self.password)['user_id']
 

	
 
        forks = Repository.query() \
 
            .filter(Repository.repo_type == self.REPO_TYPE) \
 
            .filter(Repository.fork_id != None).all()
 
        assert 1 == len(forks)
 

	
 
        # set read permissions for this
 
        RepoModel().grant_user_permission(repo=forks[0],
 
                                          user=usr,
 
                                          perm='repository.read')
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        response = self.app.get(base.url(controller='forks', action='forks',
 
                                    repo_name=repo_name))
 

	
 
        response.mustcontain('<div>fork of vcs test</div>')
 

	
 
        # remove permissions
 
        default_user = User.get_default_user()
 
        try:
 
            RepoModel().grant_user_permission(repo=forks[0],
 
                                              user=usr, perm='repository.none')
 
            RepoModel().grant_user_permission(repo=forks[0],
 
                                              user=default_user, perm='repository.none')
 
            Session().commit()
 
            meta.Session().commit()
 

	
 
            # fork shouldn't be visible
 
            response = self.app.get(base.url(controller='forks', action='forks',
 
                                        repo_name=repo_name))
 
            response.mustcontain('There are no forks yet')
 

	
 
        finally:
 
            RepoModel().grant_user_permission(repo=forks[0],
 
                                              user=usr, perm='repository.read')
 
            RepoModel().grant_user_permission(repo=forks[0],
 
                                              user=default_user, perm='repository.read')
 
            RepoModel().delete(repo=forks[0])
kallithea/tests/functional/test_home.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
import json
 

	
 
from kallithea.model.meta import Session
 
from kallithea.model import meta
 
from kallithea.model.repo import RepoModel
 
from kallithea.model.repo_group import RepoGroupModel
 
from kallithea.tests import base
 
from kallithea.tests.fixture import Fixture
 

	
 

	
 
fixture = Fixture()
 

	
 

	
 
class TestHomeController(base.TestController):
 

	
 
    def test_index(self):
 
@@ -53,25 +53,25 @@ class TestHomeController(base.TestContro
 

	
 
    def test_index_page_on_groups(self):
 
        self.log_user()
 
        gr = fixture.create_repo_group('gr1')
 
        fixture.create_repo(name='gr1/repo_in_group', repo_group=gr)
 
        response = self.app.get(base.url('repos_group_home', group_name='gr1'))
 

	
 
        try:
 
            response.mustcontain("gr1/repo_in_group")
 
        finally:
 
            RepoModel().delete('gr1/repo_in_group')
 
            RepoGroupModel().delete(repo_group='gr1', force_delete=True)
 
            Session().commit()
 
            meta.Session().commit()
 

	
 
    def test_users_and_groups_data(self):
 
        fixture.create_user('evil', firstname='D\'o\'ct"o"r', lastname='Évíl')
 
        fixture.create_user_group('grrrr', user_group_description="Groüp")
 
        response = self.app.get(base.url('users_and_groups_data', query='evi'))
 
        assert response.status_code == 302
 
        assert base.url('login_home') in response.location
 
        self.log_user(base.TEST_USER_REGULAR_LOGIN, base.TEST_USER_REGULAR_PASS)
 
        response = self.app.get(base.url('users_and_groups_data', query='evi'))
 
        result = json.loads(response.body)['results']
 
        assert result[0].get('fname') == 'D\'o\'ct"o"r'
 
        assert result[0].get('lname') == 'Évíl'
kallithea/tests/functional/test_login.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
import re
 
import time
 
import urllib.parse
 

	
 
import mock
 
from tg.util.webtest import test_context
 

	
 
import kallithea.lib.celerylib.tasks
 
from kallithea.lib import helpers as h
 
from kallithea.lib.auth import check_password
 
from kallithea.lib.utils2 import generate_api_key
 
from kallithea.model import validators
 
from kallithea.model import meta, validators
 
from kallithea.model.api_key import ApiKeyModel
 
from kallithea.model.db import User
 
from kallithea.model.meta import Session
 
from kallithea.model.user import UserModel
 
from kallithea.tests import base
 
from kallithea.tests.fixture import Fixture
 

	
 

	
 
fixture = Fixture()
 

	
 

	
 
class TestLoginController(base.TestController):
 

	
 
    def test_index(self):
 
        response = self.app.get(base.url(controller='login', action='index'))
 
@@ -353,25 +352,25 @@ class TestLoginController(base.TestContr
 
        response = self.app.post(base.url(controller='login', action='register'),
 
                                            {'username': username,
 
                                             'password': password,
 
                                             'password_confirmation': password,
 
                                             'email': email,
 
                                             'firstname': name,
 
                                             'lastname': lastname,
 
                                             'admin': True,
 
                                             '_session_csrf_secret_token': self.session_csrf_secret_token()})  # This should be overridden
 
        assert response.status == '302 Found'
 
        self.checkSessionFlash(response, 'You have successfully registered with Kallithea')
 

	
 
        ret = Session().query(User).filter(User.username == 'test_regular4').one()
 
        ret = meta.Session().query(User).filter(User.username == 'test_regular4').one()
 
        assert ret.username == username
 
        assert check_password(password, ret.password) == True
 
        assert ret.email == email
 
        assert ret.name == name
 
        assert ret.lastname == lastname
 
        assert ret.api_key is not None
 
        assert ret.admin == False
 

	
 
    #==========================================================================
 
    # PASSWORD RESET
 
    #==========================================================================
 

	
 
@@ -394,26 +393,26 @@ class TestLoginController(base.TestContr
 
        email = 'username@example.com'
 
        name = 'passwd'
 
        lastname = 'reset'
 
        timestamp = int(time.time())
 

	
 
        new = User()
 
        new.username = username
 
        new.password = password
 
        new.email = email
 
        new.name = name
 
        new.lastname = lastname
 
        new.api_key = generate_api_key()
 
        Session().add(new)
 
        Session().commit()
 
        meta.Session().add(new)
 
        meta.Session().commit()
 

	
 
        token = UserModel().get_reset_password_token(
 
            User.get_by_username(username), timestamp, self.session_csrf_secret_token())
 

	
 
        collected = []
 
        def mock_send_email(recipients, subject, body='', html_body='', headers=None, from_name=None):
 
            collected.append((recipients, subject, body, html_body))
 

	
 
        with mock.patch.object(kallithea.lib.celerylib.tasks, 'send_email', mock_send_email), \
 
                mock.patch.object(time, 'time', lambda: timestamp):
 
            response = self.app.post(base.url(controller='login',
 
                                         action='password_reset'),
 
@@ -513,22 +512,22 @@ class TestLoginController(base.TestContr
 
        ('none', None, 302),
 
        ('empty_string', '', 403),
 
        ('fake_number', '123456', 403),
 
        ('fake_not_alnum', 'a-z', 403),
 
        ('fake_api_key', '0123456789abcdef0123456789ABCDEF01234567', 403),
 
        ('proper_api_key', True, 200)
 
    ])
 
    def test_access_page_via_api_key(self, test_name, api_key, code):
 
        self._api_key_test(api_key, code)
 

	
 
    def test_access_page_via_extra_api_key(self):
 
        new_api_key = ApiKeyModel().create(base.TEST_USER_ADMIN_LOGIN, 'test')
 
        Session().commit()
 
        meta.Session().commit()
 
        self._api_key_test(new_api_key.api_key, status=200)
 

	
 
    def test_access_page_via_expired_api_key(self):
 
        new_api_key = ApiKeyModel().create(base.TEST_USER_ADMIN_LOGIN, 'test')
 
        Session().commit()
 
        meta.Session().commit()
 
        # patch the API key and make it expired
 
        new_api_key.expires = 0
 
        Session().commit()
 
        meta.Session().commit()
 
        self._api_key_test(new_api_key.api_key, status=403)
kallithea/tests/functional/test_my_account.py
Show inline comments
 
# -*- coding: utf-8 -*-
 

	
 
from tg.util.webtest import test_context
 

	
 
from kallithea.lib import helpers as h
 
from kallithea.model import meta
 
from kallithea.model.db import Repository, User, UserApiKeys, UserFollowing, UserSshKeys
 
from kallithea.model.meta import Session
 
from kallithea.model.user import UserModel
 
from kallithea.tests import base
 
from kallithea.tests.fixture import Fixture
 

	
 

	
 
fixture = Fixture()
 

	
 

	
 
class TestMyAccountController(base.TestController):
 
    test_user_1 = 'testme'
 

	
 
    @classmethod
 
    def teardown_class(cls):
 
        if User.get_by_username(cls.test_user_1):
 
            UserModel().delete(cls.test_user_1)
 
            Session().commit()
 
            meta.Session().commit()
 

	
 
    def test_my_account(self):
 
        self.log_user()
 
        response = self.app.get(base.url('my_account'))
 

	
 
        response.mustcontain('value="%s' % base.TEST_USER_ADMIN_LOGIN)
 

	
 
    def test_my_account_my_repos(self):
 
        self.log_user()
 
        response = self.app.get(base.url('my_account_repos'))
 
        cnt = Repository.query().filter(Repository.owner ==
 
                           User.get_by_username(base.TEST_USER_ADMIN_LOGIN)).count()
 
@@ -207,26 +207,26 @@ class TestMyAccountController(base.TestC
 
        usr = self.log_user(base.TEST_USER_REGULAR2_LOGIN, base.TEST_USER_REGULAR2_PASS)
 
        user = User.get(usr['user_id'])
 
        response = self.app.post(base.url('my_account_api_keys'),
 
                                 {'description': desc, 'lifetime': lifetime, '_session_csrf_secret_token': self.session_csrf_secret_token()})
 
        self.checkSessionFlash(response, 'API key successfully created')
 
        try:
 
            response = response.follow()
 
            user = User.get(usr['user_id'])
 
            for api_key in user.api_keys:
 
                response.mustcontain(api_key)
 
        finally:
 
            for api_key in UserApiKeys.query().all():
 
                Session().delete(api_key)
 
                Session().commit()
 
                meta.Session().delete(api_key)
 
                meta.Session().commit()
 

	
 
    def test_my_account_remove_api_key(self):
 
        usr = self.log_user(base.TEST_USER_REGULAR2_LOGIN, base.TEST_USER_REGULAR2_PASS)
 
        user = User.get(usr['user_id'])
 
        response = self.app.post(base.url('my_account_api_keys'),
 
                                 {'description': 'desc', 'lifetime': -1, '_session_csrf_secret_token': self.session_csrf_secret_token()})
 
        self.checkSessionFlash(response, 'API key successfully created')
 
        response = response.follow()
 

	
 
        # now delete our key
 
        keys = UserApiKeys.query().all()
 
        assert 1 == len(keys)
 
@@ -260,26 +260,26 @@ class TestMyAccountController(base.TestC
 
        response = self.app.post(base.url('my_account_ssh_keys'),
 
                                 {'description': description,
 
                                  'public_key': public_key,
 
                                  '_session_csrf_secret_token': self.session_csrf_secret_token()})
 
        self.checkSessionFlash(response, 'SSH key %s successfully added' % fingerprint)
 

	
 
        response = response.follow()
 
        response.mustcontain(fingerprint)
 
        user_id = response.session['authuser']['user_id']
 
        ssh_key = UserSshKeys.query().filter(UserSshKeys.user_id == user_id).one()
 
        assert ssh_key.fingerprint == fingerprint
 
        assert ssh_key.description == description
 
        Session().delete(ssh_key)
 
        Session().commit()
 
        meta.Session().delete(ssh_key)
 
        meta.Session().commit()
 

	
 
    def test_my_account_remove_ssh_key(self):
 
        description = ''
 
        public_key = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC6Ycnc2oUZHQnQwuqgZqTTdMDZD7ataf3JM7oG2Fw8JR6cdmz4QZLe5mfDwaFwG2pWHLRpVqzfrD/Pn3rIO++bgCJH5ydczrl1WScfryV1hYMJ/4EzLGM657J1/q5EI+b9SntKjf4ax+KP322L0TNQGbZUHLbfG2MwHMrYBQpHUQ== me@localhost'
 
        fingerprint = 'Ke3oUCNJM87P0jJTb3D+e3shjceP2CqMpQKVd75E9I8'
 

	
 
        self.log_user(base.TEST_USER_REGULAR2_LOGIN, base.TEST_USER_REGULAR2_PASS)
 
        response = self.app.post(base.url('my_account_ssh_keys'),
 
                                 {'description': description,
 
                                  'public_key': public_key,
 
                                  '_session_csrf_secret_token': self.session_csrf_secret_token()})
 
        self.checkSessionFlash(response, 'SSH key %s successfully added' % fingerprint)
kallithea/tests/functional/test_pullrequests.py
Show inline comments
 
import re
 

	
 
import pytest
 

	
 
from kallithea.controllers.pullrequests import PullrequestsController
 
from kallithea.model import meta
 
from kallithea.model.db import PullRequest, User
 
from kallithea.model.meta import Session
 
from kallithea.tests import base
 
from kallithea.tests.fixture import Fixture
 

	
 

	
 
fixture = Fixture()
 

	
 

	
 
class TestPullrequestsController(base.TestController):
 

	
 
    def test_index(self):
 
        self.log_user()
 
        response = self.app.get(base.url(controller='pullrequests', action='index',
 
@@ -247,47 +247,47 @@ class TestPullrequestsController(base.Te
 
                'other_ref': 'branch:default:3d1091ee5a533b1f4577ec7d8a226bb315fb1336',
 
                'pullrequest_title': 'title',
 
                'pullrequest_desc': 'description',
 
                '_session_csrf_secret_token': self.session_csrf_secret_token(),
 
            },
 
            status=302)
 
        pr1_id = int(re.search(r'/pull-request/(\d+)/', response.location).group(1))
 
        pr1 = PullRequest.get(pr1_id)
 

	
 
        assert pr1.org_ref == 'branch:webvcs:9e6119747791ff886a5abe1193a730b6bf874e1c'
 
        assert pr1.other_ref == 'branch:default:948da46b29c125838a717f6a8496eb409717078d'
 

	
 
        Session().rollback() # invalidate loaded PR objects before issuing next request.
 
        meta.Session().rollback() # invalidate loaded PR objects before issuing next request.
 

	
 
        # create PR 2 (new iteration with same ancestor)
 
        response = self.app.post(
 
            base.url(controller='pullrequests', action='post', repo_name=base.HG_REPO, pull_request_id=pr1_id),
 
            {
 
                'updaterev': '5ec21f21aafe95220f1fc4843a4a57c378498b71',
 
                'pullrequest_title': 'title',
 
                'pullrequest_desc': 'description',
 
                'owner': base.TEST_USER_REGULAR_LOGIN,
 
                '_session_csrf_secret_token': self.session_csrf_secret_token(),
 
             },
 
             status=302)
 
        pr2_id = int(re.search(r'/pull-request/(\d+)/', response.location).group(1))
 
        pr1 = PullRequest.get(pr1_id)
 
        pr2 = PullRequest.get(pr2_id)
 

	
 
        assert pr2_id != pr1_id
 
        assert pr1.status == PullRequest.STATUS_CLOSED
 
        assert pr2.org_ref == 'branch:webvcs:5ec21f21aafe95220f1fc4843a4a57c378498b71'
 
        assert pr2.other_ref == pr1.other_ref
 

	
 
        Session().rollback() # invalidate loaded PR objects before issuing next request.
 
        meta.Session().rollback() # invalidate loaded PR objects before issuing next request.
 

	
 
        # create PR 3 (new iteration with new ancestor)
 
        response = self.app.post(
 
            base.url(controller='pullrequests', action='post', repo_name=base.HG_REPO, pull_request_id=pr2_id),
 
            {
 
                'updaterev': 'fb95b340e0d03fa51f33c56c991c08077c99303e',
 
                'pullrequest_title': 'title',
 
                'pullrequest_desc': 'description',
 
                'owner': base.TEST_USER_REGULAR_LOGIN,
 
                '_session_csrf_secret_token': self.session_csrf_secret_token(),
 
             },
 
             status=302)
 
@@ -299,31 +299,31 @@ class TestPullrequestsController(base.Te
 
        assert pr2.status == PullRequest.STATUS_CLOSED
 
        assert pr3.org_ref == 'branch:webvcs:fb95b340e0d03fa51f33c56c991c08077c99303e'
 
        assert pr3.other_ref == 'branch:default:41d2568309a05f422cffb8008e599d385f8af439'
 

	
 

	
 
@pytest.mark.usefixtures("test_context_fixture") # apply fixture for all test methods
 
class TestPullrequestsGetRepoRefs(base.TestController):
 

	
 
    def setup_method(self, method):
 
        self.repo_name = 'main'
 
        repo = fixture.create_repo(self.repo_name, repo_type='hg')
 
        self.repo_scm_instance = repo.scm_instance
 
        Session().commit()
 
        meta.Session().commit()
 
        self.c = PullrequestsController()
 

	
 
    def teardown_method(self, method):
 
        fixture.destroy_repo('main')
 
        Session().commit()
 
        Session.remove()
 
        meta.Session().commit()
 
        meta.Session.remove()
 

	
 
    def test_repo_refs_empty_repo(self):
 
        # empty repo with no commits, no branches, no bookmarks, just one tag
 
        refs, default = self.c._get_repo_refs(self.repo_scm_instance)
 
        assert default == 'tag:null:0000000000000000000000000000000000000000'
 

	
 
    def test_repo_refs_one_commit_no_hints(self):
 
        cs0 = fixture.commit_change(self.repo_name, filename='file1',
 
                content='line1\n', message='commit1', vcs_type='hg',
 
                parent=None, newfile=True)
 

	
 
        refs, default = self.c._get_repo_refs(self.repo_scm_instance)
kallithea/tests/functional/test_pullrequests_git.py
Show inline comments
 
import re
 

	
 
import pytest
 

	
 
from kallithea.controllers.pullrequests import PullrequestsController
 
from kallithea.model.meta import Session
 
from kallithea.model import meta
 
from kallithea.tests import base
 
from kallithea.tests.fixture import Fixture
 

	
 

	
 
fixture = Fixture()
 

	
 

	
 
class TestPullrequestsController(base.TestController):
 

	
 
    def test_index(self):
 
        self.log_user()
 
        response = self.app.get(base.url(controller='pullrequests', action='index',
 
@@ -83,31 +83,31 @@ class TestPullrequestsController(base.Te
 
                                  'review_members': [str(invalid_user_id)],
 
                                 },
 
                                 status=400)
 
        response.mustcontain('Invalid reviewer &quot;%s&quot; specified' % invalid_user_id)
 

	
 
@pytest.mark.usefixtures("test_context_fixture") # apply fixture for all test methods
 
class TestPullrequestsGetRepoRefs(base.TestController):
 

	
 
    def setup_method(self, method):
 
        self.repo_name = 'main'
 
        repo = fixture.create_repo(self.repo_name, repo_type='git')
 
        self.repo_scm_instance = repo.scm_instance
 
        Session().commit()
 
        meta.Session().commit()
 
        self.c = PullrequestsController()
 

	
 
    def teardown_method(self, method):
 
        fixture.destroy_repo('main')
 
        Session().commit()
 
        Session.remove()
 
        meta.Session().commit()
 
        meta.Session.remove()
 

	
 
    def test_repo_refs_empty_repo(self):
 
        # empty repo with no commits, no branches, no bookmarks, just one tag
 
        refs, default = self.c._get_repo_refs(self.repo_scm_instance)
 
        assert default == ''  # doesn't make sense, but better than nothing
 

	
 
    def test_repo_refs_one_commit_no_hints(self):
 
        cs0 = fixture.commit_change(self.repo_name, filename='file1',
 
                content='line1\n', message='commit1', vcs_type='git',
 
                parent=None, newfile=True)
 

	
 
        refs, default = self.c._get_repo_refs(self.repo_scm_instance)
kallithea/tests/functional/test_search_indexing.py
Show inline comments
 
import mock
 

	
 
import kallithea
 
from kallithea.lib.conf import INDEX_FILENAMES
 
from kallithea.model.meta import Session
 
from kallithea.model import meta
 
from kallithea.model.repo import RepoModel
 
from kallithea.model.repo_group import RepoGroupModel
 
from kallithea.tests import base
 
from kallithea.tests.fixture import Fixture, create_test_index
 

	
 

	
 
fixture = Fixture()
 

	
 

	
 
def init_indexing_test(repo):
 
    prev = fixture.commit_change(repo.repo_name,
 
                                 filename='this_should_be_unique_filename.txt',
 
@@ -94,26 +94,26 @@ class TestSearchControllerIndexing(base.
 

	
 
    @classmethod
 
    def teardown_class(cls):
 
        # delete in reversed order, to delete fork destination at first
 
        for reponame, init_or_fork, groupname in reversed(repos):
 
            RepoModel().delete(repoids[reponame])
 

	
 
        for reponame, init_or_fork, groupname in reversed(repos):
 
            if groupname in groupids:
 
                RepoGroupModel().delete(groupids.pop(groupname),
 
                                        force_delete=True)
 

	
 
        Session().commit()
 
        Session.remove()
 
        meta.Session().commit()
 
        meta.Session.remove()
 

	
 
        rebuild_index(full_index=True) # rebuild fully for subsequent tests
 

	
 
    @base.parametrize('reponame', [
 
        ('indexing_test'),
 
        ('indexing_test-fork'),
 
        ('group/indexing_test'),
 
        ('this-is-it'),
 
        ('*-fork'),
 
        ('group/*'),
 
    ])
 
    @base.parametrize('searchtype,query,hit', [
kallithea/tests/functional/test_summary.py
Show inline comments
 
@@ -5,26 +5,26 @@
 
# (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 pytest
 

	
 
from kallithea.model import meta
 
from kallithea.model.db import Repository
 
from kallithea.model.meta import Session
 
from kallithea.model.repo import RepoModel
 
from kallithea.model.scm import ScmModel
 
from kallithea.tests import base
 
from kallithea.tests.fixture import Fixture
 

	
 

	
 
fixture = Fixture()
 

	
 
@pytest.fixture
 
def custom_settings(set_test_settings):
 
    # overwrite DEFAULT_CLONE_SSH = 'ssh://{system_user}@{hostname}/{repo}'
 
    set_test_settings(
 
@@ -111,46 +111,46 @@ class TestSummaryController(base.TestCon
 

	
 
    def test_index_by_repo_having_id_path_in_name_hg(self):
 
        self.log_user()
 
        fixture.create_repo(name='repo_1')
 
        response = self.app.get(base.url(controller='summary',
 
                                    action='index',
 
                                    repo_name='repo_1'))
 

	
 
        try:
 
            response.mustcontain("repo_1")
 
        finally:
 
            RepoModel().delete(Repository.get_by_repo_name('repo_1'))
 
            Session().commit()
 
            meta.Session().commit()
 

	
 
    def test_index_by_id_git(self):
 
        self.log_user()
 
        ID = Repository.get_by_repo_name(base.GIT_REPO).repo_id
 
        response = self.app.get(base.url(controller='summary',
 
                                    action='index',
 
                                    repo_name='_%s' % ID))
 

	
 
        # repo type
 
        response.mustcontain(
 
            """<span class="label label-repo" title="Git repository">git"""
 
        )
 
        # public/private
 
        response.mustcontain(
 
            """<i class="icon-globe">"""
 
        )
 

	
 
    def _enable_stats(self, repo):
 
        r = Repository.get_by_repo_name(repo)
 
        r.enable_statistics = True
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    def test_index_trending(self):
 
        self.log_user()
 
        # codes stats
 
        self._enable_stats(base.HG_REPO)
 

	
 
        ScmModel().mark_for_invalidation(base.HG_REPO)
 
        # generate statistics first
 
        response = self.app.get(base.url(controller='summary', action='statistics',
 
                                    repo_name=base.HG_REPO))
 
        response = self.app.get(base.url(controller='summary', action='index',
 
                                    repo_name=base.HG_REPO))
kallithea/tests/models/common.py
Show inline comments
 
from kallithea.lib.auth import AuthUser
 
from kallithea.model import meta
 
from kallithea.model.db import RepoGroup, Repository, User
 
from kallithea.model.meta import Session
 
from kallithea.model.repo import RepoModel
 
from kallithea.model.repo_group import RepoGroupModel
 
from kallithea.model.user import UserModel
 
from kallithea.tests.fixture import Fixture
 

	
 

	
 
fixture = Fixture()
 

	
 

	
 
def _destroy_project_tree(test_u1_id):
 
    Session.remove()
 
    meta.Session.remove()
 
    repo_group = RepoGroup.get_by_group_name(group_name='g0')
 
    for el in reversed(repo_group.recursive_groups_and_repos()):
 
        if isinstance(el, Repository):
 
            RepoModel().delete(el)
 
        elif isinstance(el, RepoGroup):
 
            RepoGroupModel().delete(el, force_delete=True)
 

	
 
    u = User.get(test_u1_id)
 
    Session().delete(u)
 
    Session().commit()
 
    meta.Session().delete(u)
 
    meta.Session().commit()
 

	
 

	
 
def _create_project_tree():
 
    """
 
    Creates a tree of groups and repositories to test permissions
 

	
 
    structure
 
     [g0] - group `g0` with 3 subgroups
 
     |
 
     |__[g0_1] group g0_1 with 2 groups 0 repos
 
     |  |
 
     |  |__[g0_1_1] group g0_1_1 with 1 group 2 repos
kallithea/tests/models/test_notifications.py
Show inline comments
 
import os
 
import re
 

	
 
import mock
 
from tg.util.webtest import test_context
 

	
 
import kallithea.lib.celerylib
 
import kallithea.lib.celerylib.tasks
 
from kallithea.lib import helpers as h
 
from kallithea.model import meta
 
from kallithea.model.db import User
 
from kallithea.model.meta import Session
 
from kallithea.model.notification import EmailNotificationModel, NotificationModel
 
from kallithea.model.user import UserModel
 
from kallithea.tests import base
 

	
 

	
 
class TestNotifications(base.TestController):
 

	
 
    def setup_method(self, method):
 
        Session.remove()
 
        meta.Session.remove()
 
        u1 = UserModel().create_or_update(username='u1',
 
                                        password='qweqwe',
 
                                        email='u1@example.com',
 
                                        firstname='u1', lastname='u1')
 
        Session().commit()
 
        meta.Session().commit()
 
        self.u1 = u1.user_id
 

	
 
        u2 = UserModel().create_or_update(username='u2',
 
                                        password='qweqwe',
 
                                        email='u2@example.com',
 
                                        firstname='u2', lastname='u3')
 
        Session().commit()
 
        meta.Session().commit()
 
        self.u2 = u2.user_id
 

	
 
        u3 = UserModel().create_or_update(username='u3',
 
                                        password='qweqwe',
 
                                        email='u3@example.com',
 
                                        firstname='u3', lastname='u3')
 
        Session().commit()
 
        meta.Session().commit()
 
        self.u3 = u3.user_id
 

	
 
    def test_create_notification(self):
 
        with test_context(self.app):
 
            usrs = [self.u1, self.u2]
 

	
 
            def send_email(recipients, subject, body='', html_body='', headers=None, from_name=None):
 
                assert recipients == ['u2@example.com']
 
                assert subject == 'Test Message'
 
                assert body == "hi there"
 
                assert '>hi there<' in html_body
 
                assert from_name == 'u1 u1'
kallithea/tests/models/test_permissions.py
Show inline comments
 
import kallithea
 
from kallithea.lib.auth import AuthUser
 
from kallithea.model import meta
 
from kallithea.model.db import Permission, User, UserGroupRepoGroupToPerm, UserToPerm
 
from kallithea.model.meta import Session
 
from kallithea.model.permission import PermissionModel
 
from kallithea.model.repo import RepoModel
 
from kallithea.model.repo_group import RepoGroupModel
 
from kallithea.model.user import UserModel
 
from kallithea.model.user_group import UserGroupModel
 
from kallithea.tests import base
 
from kallithea.tests.fixture import Fixture
 

	
 

	
 
fixture = Fixture()
 

	
 

	
 
class TestPermissions(base.TestController):
 

	
 
    @classmethod
 
    def setup_class(cls):
 
        # recreate default user to get a clean start
 
        PermissionModel().create_default_permissions(user=User.DEFAULT_USER_NAME,
 
                                                     force=True)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    def setup_method(self, method):
 
        self.u1 = UserModel().create_or_update(
 
            username='u1', password='qweqwe',
 
            email='u1@example.com', firstname='u1', lastname='u1'
 
        )
 
        self.u2 = UserModel().create_or_update(
 
            username='u2', password='qweqwe',
 
            email='u2@example.com', firstname='u2', lastname='u2'
 
        )
 
        self.u3 = UserModel().create_or_update(
 
            username='u3', password='qweqwe',
 
            email='u3@example.com', firstname='u3', lastname='u3'
 
        )
 
        self.anon = User.get_default_user()
 
        self.a1 = UserModel().create_or_update(
 
            username='a1', password='qweqwe',
 
            email='a1@example.com', firstname='a1', lastname='a1', admin=True
 
        )
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    def teardown_method(self, method):
 
        if hasattr(self, 'test_repo'):
 
            RepoModel().delete(repo=self.test_repo)
 

	
 
        UserModel().delete(self.u1)
 
        UserModel().delete(self.u2)
 
        UserModel().delete(self.u3)
 
        UserModel().delete(self.a1)
 

	
 
        Session().commit() # commit early to avoid SQLAlchemy warning from double cascade delete to users_groups_members
 
        meta.Session().commit() # commit early to avoid SQLAlchemy warning from double cascade delete to users_groups_members
 

	
 
        if hasattr(self, 'g1'):
 
            RepoGroupModel().delete(self.g1.group_id)
 
        if hasattr(self, 'g2'):
 
            RepoGroupModel().delete(self.g2.group_id)
 

	
 
        if hasattr(self, 'ug2'):
 
            UserGroupModel().delete(self.ug2, force=True)
 
        if hasattr(self, 'ug1'):
 
            UserGroupModel().delete(self.ug1, force=True)
 

	
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    def test_default_perms_set(self):
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        assert u1_auth.repository_permissions[base.HG_REPO] == 'repository.read'
 
        new_perm = 'repository.write'
 
        RepoModel().grant_user_permission(repo=base.HG_REPO, user=self.u1,
 
                                          perm=new_perm)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        assert u1_auth.repository_permissions[base.HG_REPO] == new_perm
 

	
 
    def test_default_admin_perms_set(self):
 
        a1_auth = AuthUser(user_id=self.a1.user_id)
 
        assert a1_auth.repository_permissions[base.HG_REPO] == 'repository.admin'
 
        new_perm = 'repository.write'
 
        RepoModel().grant_user_permission(repo=base.HG_REPO, user=self.a1,
 
                                          perm=new_perm)
 
        Session().commit()
 
        meta.Session().commit()
 
        # cannot really downgrade admins permissions !? they still gets set as
 
        # admin !
 
        u1_auth = AuthUser(user_id=self.a1.user_id)
 
        assert u1_auth.repository_permissions[base.HG_REPO] == 'repository.admin'
 

	
 
    def test_default_group_perms(self):
 
        self.g1 = fixture.create_repo_group('test1', skip_if_exists=True)
 
        self.g2 = fixture.create_repo_group('test2', skip_if_exists=True)
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        assert u1_auth.repository_permissions[base.HG_REPO] == 'repository.read'
 
        assert u1_auth.repository_group_permissions.get('test1') == 'group.read'
 
        assert u1_auth.repository_group_permissions.get('test2') == 'group.read'
 
@@ -104,25 +104,25 @@ class TestPermissions(base.TestControlle
 
        a1_auth = AuthUser(user_id=self.a1.user_id)
 
        assert a1_auth.repository_permissions[base.HG_REPO] == 'repository.admin'
 
        assert a1_auth.repository_group_permissions.get('test1') == 'group.admin'
 
        assert a1_auth.repository_group_permissions.get('test2') == 'group.admin'
 

	
 
    def test_propagated_permission_from_users_group_by_explicit_perms_exist(self):
 
        # make group
 
        self.ug1 = fixture.create_user_group('G1')
 
        UserGroupModel().add_user_to_group(self.ug1, self.u1)
 

	
 
        # set user permission none
 
        RepoModel().grant_user_permission(repo=base.HG_REPO, user=self.u1, perm='repository.none')
 
        Session().commit()
 
        meta.Session().commit()
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        assert u1_auth.repository_permissions[base.HG_REPO] == 'repository.read' # inherit from default user
 

	
 
        # grant perm for group this should override permission from user
 
        RepoModel().grant_user_group_permission(repo=base.HG_REPO,
 
                                                 group_name=self.ug1,
 
                                                 perm='repository.write')
 

	
 
        # verify that user group permissions win
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        assert u1_auth.repository_permissions[base.HG_REPO] == 'repository.write'
 

	
 
@@ -141,25 +141,25 @@ class TestPermissions(base.TestControlle
 
        assert u3_auth.repository_permissions[base.HG_REPO] == new_perm_gr
 

	
 
    def test_propagated_permission_from_users_group_lower_weight(self):
 
        # make group
 
        self.ug1 = fixture.create_user_group('G1')
 
        # add user to group
 
        UserGroupModel().add_user_to_group(self.ug1, self.u1)
 

	
 
        # set permission to lower
 
        new_perm_h = 'repository.write'
 
        RepoModel().grant_user_permission(repo=base.HG_REPO, user=self.u1,
 
                                          perm=new_perm_h)
 
        Session().commit()
 
        meta.Session().commit()
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        assert u1_auth.repository_permissions[base.HG_REPO] == new_perm_h
 

	
 
        # grant perm for group this should NOT override permission from user
 
        # since it's lower than granted
 
        new_perm_l = 'repository.read'
 
        RepoModel().grant_user_group_permission(repo=base.HG_REPO,
 
                                                 group_name=self.ug1,
 
                                                 perm=new_perm_l)
 
        # check perms
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        assert u1_auth.repository_permissions[base.HG_REPO] == new_perm_h
 
@@ -203,25 +203,25 @@ class TestPermissions(base.TestControlle
 
        assert u1_auth.repository_group_permissions.get('group1') == 'group.none'
 
        assert u1_auth.repository_group_permissions.get('group2') == 'group.none'
 

	
 
        a1_auth = AuthUser(user_id=self.anon.user_id)
 
        assert a1_auth.repository_group_permissions.get('group1') == 'group.none'
 
        assert a1_auth.repository_group_permissions.get('group2') == 'group.none'
 

	
 
        # grant permission for u2 !
 
        RepoGroupModel().grant_user_permission(repo_group=self.g1, user=self.u2,
 
                                               perm='group.read')
 
        RepoGroupModel().grant_user_permission(repo_group=self.g2, user=self.u2,
 
                                               perm='group.read')
 
        Session().commit()
 
        meta.Session().commit()
 
        assert self.u1 != self.u2
 
        # u1 and anon should have not change perms while u2 should !
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        assert u1_auth.repository_group_permissions.get('group1') == 'group.none'
 
        assert u1_auth.repository_group_permissions.get('group2') == 'group.none'
 

	
 
        u2_auth = AuthUser(user_id=self.u2.user_id)
 
        assert u2_auth.repository_group_permissions.get('group1') == 'group.read'
 
        assert u2_auth.repository_group_permissions.get('group2') == 'group.read'
 

	
 
        a1_auth = AuthUser(user_id=self.anon.user_id)
 
        assert a1_auth.repository_group_permissions.get('group1') == 'group.none'
 
@@ -233,107 +233,107 @@ class TestPermissions(base.TestControlle
 
        a1_auth = AuthUser(user_id=self.anon.user_id)
 

	
 
        assert a1_auth.repository_group_permissions.get('group1') == 'group.read'
 

	
 
        # set default permission to none
 
        RepoGroupModel().grant_user_permission(repo_group=self.g1,
 
                                               user=self.anon,
 
                                               perm='group.none')
 
        # make group
 
        self.ug1 = fixture.create_user_group('G1')
 
        # add user to group
 
        UserGroupModel().add_user_to_group(self.ug1, self.u1)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        # check if user is in the group
 
        members = [x.user_id for x in UserGroupModel().get(self.ug1.users_group_id).members]
 
        assert members == [self.u1.user_id]
 
        # add some user to that group
 

	
 
        # check his permissions
 
        a1_auth = AuthUser(user_id=self.anon.user_id)
 
        assert a1_auth.repository_group_permissions.get('group1') == 'group.none'
 

	
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        assert u1_auth.repository_group_permissions.get('group1') == 'group.none'
 

	
 
        # grant ug1 read permissions for
 
        RepoGroupModel().grant_user_group_permission(repo_group=self.g1,
 
                                                      group_name=self.ug1,
 
                                                      perm='group.read')
 
        Session().commit()
 
        meta.Session().commit()
 
        # check if the
 
        obj = Session().query(UserGroupRepoGroupToPerm) \
 
        obj = meta.Session().query(UserGroupRepoGroupToPerm) \
 
            .filter(UserGroupRepoGroupToPerm.group == self.g1) \
 
            .filter(UserGroupRepoGroupToPerm.users_group == self.ug1) \
 
            .scalar()
 
        assert obj.permission.permission_name == 'group.read'
 

	
 
        a1_auth = AuthUser(user_id=self.anon.user_id)
 

	
 
        assert a1_auth.repository_group_permissions.get('group1') == 'group.none'
 

	
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        assert u1_auth.repository_group_permissions.get('group1') == 'group.read'
 

	
 
    def test_inherit_nice_permissions_from_default_user(self):
 
        user_model = UserModel()
 
        # enable fork and create on default user
 
        usr = 'default'
 
        user_model.revoke_perm(usr, 'hg.create.none')
 
        user_model.grant_perm(usr, 'hg.create.repository')
 
        user_model.revoke_perm(usr, 'hg.fork.none')
 
        user_model.grant_perm(usr, 'hg.fork.repository')
 
        Session().commit()
 
        meta.Session().commit()
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        # this user will have inherited permissions from default user
 
        assert u1_auth.global_permissions == set(['hg.create.repository', 'hg.fork.repository',
 
                              'hg.register.manual_activate',
 
                              'hg.extern_activate.auto',
 
                              'repository.read', 'group.read',
 
                              'usergroup.read'])
 

	
 
    def test_inherit_sad_permissions_from_default_user(self):
 
        user_model = UserModel()
 
        # disable fork and create on default user
 
        usr = 'default'
 
        user_model.revoke_perm(usr, 'hg.create.repository')
 
        user_model.grant_perm(usr, 'hg.create.none')
 
        user_model.revoke_perm(usr, 'hg.fork.repository')
 
        user_model.grant_perm(usr, 'hg.fork.none')
 
        Session().commit()
 
        meta.Session().commit()
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        # this user will have inherited permissions from default user
 
        assert u1_auth.global_permissions == set(['hg.create.none', 'hg.fork.none',
 
                              'hg.register.manual_activate',
 
                              'hg.extern_activate.auto',
 
                              'repository.read', 'group.read',
 
                              'usergroup.read'])
 

	
 
    def test_inherit_more_permissions_from_default_user(self):
 
        user_model = UserModel()
 
        # enable fork and create on default user
 
        usr = 'default'
 
        user_model.revoke_perm(usr, 'hg.create.none')
 
        user_model.grant_perm(usr, 'hg.create.repository')
 
        user_model.revoke_perm(usr, 'hg.fork.none')
 
        user_model.grant_perm(usr, 'hg.fork.repository')
 

	
 
        # disable global perms on specific user
 
        user_model.revoke_perm(self.u1, 'hg.create.repository')
 
        user_model.grant_perm(self.u1, 'hg.create.none')
 
        user_model.revoke_perm(self.u1, 'hg.fork.repository')
 
        user_model.grant_perm(self.u1, 'hg.fork.none')
 

	
 
        Session().commit()
 
        meta.Session().commit()
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        # this user will have inherited more permissions from default user
 
        assert u1_auth.global_permissions == set([
 
                              'hg.create.repository',
 
                              'hg.fork.repository',
 
                              'hg.register.manual_activate',
 
                              'hg.extern_activate.auto',
 
                              'repository.read', 'group.read',
 
                              'usergroup.read'])
 

	
 
    def test_inherit_less_permissions_from_default_user(self):
 
        user_model = UserModel()
 
@@ -341,25 +341,25 @@ class TestPermissions(base.TestControlle
 
        usr = 'default'
 
        user_model.revoke_perm(usr, 'hg.create.repository')
 
        user_model.grant_perm(usr, 'hg.create.none')
 
        user_model.revoke_perm(usr, 'hg.fork.repository')
 
        user_model.grant_perm(usr, 'hg.fork.none')
 

	
 
        # enable global perms on specific user
 
        user_model.revoke_perm(self.u1, 'hg.create.none')
 
        user_model.grant_perm(self.u1, 'hg.create.repository')
 
        user_model.revoke_perm(self.u1, 'hg.fork.none')
 
        user_model.grant_perm(self.u1, 'hg.fork.repository')
 

	
 
        Session().commit()
 
        meta.Session().commit()
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        # this user will have inherited less permissions from default user
 
        assert u1_auth.global_permissions == set([
 
                              'hg.create.repository',
 
                              'hg.fork.repository',
 
                              'hg.register.manual_activate',
 
                              'hg.extern_activate.auto',
 
                              'repository.read', 'group.read',
 
                              'usergroup.read'])
 

	
 
    def test_inactive_user_group_does_not_affect_global_permissions(self):
 
        # Add user to inactive user group, set specific permissions on user
 
@@ -374,25 +374,25 @@ class TestPermissions(base.TestControlle
 
        user_group_model.grant_perm(self.ug1, perm='hg.create.repository')
 
        user_group_model.revoke_perm(self.ug1, perm='hg.fork.none')
 
        user_group_model.grant_perm(self.ug1, perm='hg.fork.repository')
 

	
 
        user_model = UserModel()
 
        # disable fork and create on default user
 
        usr = 'default'
 
        user_model.revoke_perm(usr, 'hg.create.repository')
 
        user_model.grant_perm(usr, 'hg.create.none')
 
        user_model.revoke_perm(usr, 'hg.fork.repository')
 
        user_model.grant_perm(usr, 'hg.fork.none')
 

	
 
        Session().commit()
 
        meta.Session().commit()
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 

	
 
        assert u1_auth.global_permissions == set(['hg.create.none', 'hg.fork.none',
 
                              'hg.register.manual_activate',
 
                              'hg.extern_activate.auto',
 
                              'repository.read', 'group.read',
 
                              'usergroup.read',
 
                              ])
 

	
 
    def test_inactive_user_group_does_not_affect_global_permissions_inverse(self):
 
        # Add user to inactive user group, set specific permissions on user
 
        # group and and verify it really is inactive.
 
@@ -406,25 +406,25 @@ class TestPermissions(base.TestControlle
 
        user_group_model.grant_perm(self.ug1, perm='hg.create.none')
 
        user_group_model.revoke_perm(self.ug1, perm='hg.fork.repository')
 
        user_group_model.grant_perm(self.ug1, perm='hg.fork.none')
 

	
 
        user_model = UserModel()
 
        # enable fork and create on default user
 
        usr = 'default'
 
        user_model.revoke_perm(usr, 'hg.create.none')
 
        user_model.grant_perm(usr, 'hg.create.repository')
 
        user_model.revoke_perm(usr, 'hg.fork.none')
 
        user_model.grant_perm(usr, 'hg.fork.repository')
 

	
 
        Session().commit()
 
        meta.Session().commit()
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 

	
 
        assert u1_auth.global_permissions == set(['hg.create.repository', 'hg.fork.repository',
 
                              'hg.register.manual_activate',
 
                              'hg.extern_activate.auto',
 
                              'repository.read', 'group.read',
 
                              'usergroup.read',
 
                              ])
 

	
 
    def test_inactive_user_group_does_not_affect_repo_permissions(self):
 
        self.ug1 = fixture.create_user_group('G1')
 
        user_group_model = UserGroupModel()
 
@@ -436,189 +436,189 @@ class TestPermissions(base.TestControlle
 
        self.test_repo = fixture.create_repo(name='myownrepo',
 
                                             repo_type='hg',
 
                                             cur_user=self.u2)
 

	
 
        # enable admin access for user group on repo
 
        RepoModel().grant_user_group_permission(self.test_repo,
 
                                                group_name=self.ug1,
 
                                                perm='repository.admin')
 
        # enable only write access for default user on repo
 
        RepoModel().grant_user_permission(self.test_repo,
 
                                          user='default',
 
                                          perm='repository.write')
 
        Session().commit()
 
        meta.Session().commit()
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        assert u1_auth.repository_permissions['myownrepo'] == 'repository.write'
 

	
 
    def test_inactive_user_group_does_not_affect_repo_permissions_inverse(self):
 
        self.ug1 = fixture.create_user_group('G1')
 
        user_group_model = UserGroupModel()
 
        user_group_model.add_user_to_group(self.ug1, self.u1)
 
        user_group_model.update(self.ug1, {'users_group_active': False})
 

	
 
        # note: make u2 repo owner rather than u1, because the owner always has
 
        # admin permissions
 
        self.test_repo = fixture.create_repo(name='myownrepo',
 
                                             repo_type='hg',
 
                                             cur_user=self.u2)
 

	
 
        # enable only write access for user group on repo
 
        RepoModel().grant_user_group_permission(self.test_repo,
 
                                                group_name=self.ug1,
 
                                                perm='repository.write')
 
        # enable admin access for default user on repo
 
        RepoModel().grant_user_permission(self.test_repo,
 
                                          user='default',
 
                                          perm='repository.admin')
 
        Session().commit()
 
        meta.Session().commit()
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        assert u1_auth.repository_permissions['myownrepo'] == 'repository.admin'
 

	
 
    def test_inactive_user_group_does_not_affect_repo_group_permissions(self):
 
        self.ug1 = fixture.create_user_group('G1')
 
        user_group_model = UserGroupModel()
 
        user_group_model.add_user_to_group(self.ug1, self.u1)
 
        user_group_model.update(self.ug1, {'users_group_active': False})
 

	
 
        self.g1 = fixture.create_repo_group('group1', skip_if_exists=True)
 

	
 
        # enable admin access for user group on repo group
 
        RepoGroupModel().grant_user_group_permission(self.g1,
 
                                                     group_name=self.ug1,
 
                                                     perm='group.admin')
 
        # enable only write access for default user on repo group
 
        RepoGroupModel().grant_user_permission(self.g1,
 
                                               user='default',
 
                                               perm='group.write')
 
        Session().commit()
 
        meta.Session().commit()
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        assert u1_auth.repository_group_permissions.get('group1') == 'group.write'
 

	
 
    def test_inactive_user_group_does_not_affect_repo_group_permissions_inverse(self):
 
        self.ug1 = fixture.create_user_group('G1')
 
        user_group_model = UserGroupModel()
 
        user_group_model.add_user_to_group(self.ug1, self.u1)
 
        user_group_model.update(self.ug1, {'users_group_active': False})
 

	
 
        self.g1 = fixture.create_repo_group('group1', skip_if_exists=True)
 

	
 
        # enable only write access for user group on repo group
 
        RepoGroupModel().grant_user_group_permission(self.g1,
 
                                                     group_name=self.ug1,
 
                                                     perm='group.write')
 
        # enable admin access for default user on repo group
 
        RepoGroupModel().grant_user_permission(self.g1,
 
                                               user='default',
 
                                               perm='group.admin')
 
        Session().commit()
 
        meta.Session().commit()
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        assert u1_auth.repository_group_permissions.get('group1') == 'group.admin'
 

	
 
    def test_inactive_user_group_does_not_affect_user_group_permissions(self):
 
        self.ug1 = fixture.create_user_group('G1')
 
        user_group_model = UserGroupModel()
 
        user_group_model.add_user_to_group(self.ug1, self.u1)
 
        user_group_model.update(self.ug1, {'users_group_active': False})
 

	
 
        self.ug2 = fixture.create_user_group('G2')
 

	
 
        # enable admin access for user group on user group
 
        UserGroupModel().grant_user_group_permission(self.ug2,
 
                                                     user_group=self.ug1,
 
                                                     perm='usergroup.admin')
 
        # enable only write access for default user on user group
 
        UserGroupModel().grant_user_permission(self.ug2,
 
                                               user='default',
 
                                               perm='usergroup.write')
 
        Session().commit()
 
        meta.Session().commit()
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        assert u1_auth.user_group_permissions['G1'] == 'usergroup.read'
 
        assert u1_auth.user_group_permissions['G2'] == 'usergroup.write'
 

	
 
    def test_inactive_user_group_does_not_affect_user_group_permissions_inverse(self):
 
        self.ug1 = fixture.create_user_group('G1')
 
        user_group_model = UserGroupModel()
 
        user_group_model.add_user_to_group(self.ug1, self.u1)
 
        user_group_model.update(self.ug1, {'users_group_active': False})
 

	
 
        self.ug2 = fixture.create_user_group('G2')
 

	
 
        # enable only write access for user group on user group
 
        UserGroupModel().grant_user_group_permission(self.ug2,
 
                                                     user_group=self.ug1,
 
                                                     perm='usergroup.write')
 
        # enable admin access for default user on user group
 
        UserGroupModel().grant_user_permission(self.ug2,
 
                                               user='default',
 
                                               perm='usergroup.admin')
 
        Session().commit()
 
        meta.Session().commit()
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        assert u1_auth.user_group_permissions['G1'] == 'usergroup.read'
 
        assert u1_auth.user_group_permissions['G2'] == 'usergroup.admin'
 

	
 
    def test_owner_permissions_doesnot_get_overwritten_by_group(self):
 
        # create repo as USER,
 
        self.test_repo = fixture.create_repo(name='myownrepo',
 
                                             repo_type='hg',
 
                                             cur_user=self.u1)
 

	
 
        # he has permissions of admin as owner
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        assert u1_auth.repository_permissions['myownrepo'] == 'repository.admin'
 
        # set his permission as user group, he should still be admin
 
        self.ug1 = fixture.create_user_group('G1')
 
        UserGroupModel().add_user_to_group(self.ug1, self.u1)
 
        RepoModel().grant_user_group_permission(self.test_repo,
 
                                                 group_name=self.ug1,
 
                                                 perm='repository.none')
 

	
 
        Session().commit()
 
        meta.Session().commit()
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        assert u1_auth.repository_permissions['myownrepo'] == 'repository.admin'
 

	
 
    def test_owner_permissions_doesnot_get_overwritten_by_others(self):
 
        # create repo as USER,
 
        self.test_repo = fixture.create_repo(name='myownrepo',
 
                                             repo_type='hg',
 
                                             cur_user=self.u1)
 

	
 
        # he has permissions of admin as owner
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        assert u1_auth.repository_permissions['myownrepo'] == 'repository.admin'
 
        # set his permission as user, he should still be admin
 
        RepoModel().grant_user_permission(self.test_repo, user=self.u1,
 
                                          perm='repository.none')
 
        Session().commit()
 
        meta.Session().commit()
 
        u1_auth = AuthUser(user_id=self.u1.user_id)
 
        assert u1_auth.repository_permissions['myownrepo'] == 'repository.admin'
 

	
 
    def _test_def_perm_equal(self, user, change_factor=0):
 
        perms = UserToPerm.query() \
 
                .filter(UserToPerm.user == user) \
 
                .all()
 
        assert len(perms) == len(Permission.DEFAULT_USER_PERMISSIONS,)+change_factor, perms
 

	
 
    def test_set_default_permissions(self):
 
        PermissionModel().create_default_permissions(user=self.u1)
 
        self._test_def_perm_equal(user=self.u1)
 

	
 
    def test_set_default_permissions_after_one_is_missing(self):
 
        PermissionModel().create_default_permissions(user=self.u1)
 
        self._test_def_perm_equal(user=self.u1)
 
        # now we delete one, it should be re-created after another call
 
        perms = UserToPerm.query() \
 
                .filter(UserToPerm.user == self.u1) \
 
                .all()
 
        Session().delete(perms[0])
 
        Session().commit()
 
        meta.Session().delete(perms[0])
 
        meta.Session().commit()
 

	
 
        self._test_def_perm_equal(user=self.u1, change_factor=-1)
 

	
 
        # create missing one !
 
        PermissionModel().create_default_permissions(user=self.u1)
 
        self._test_def_perm_equal(user=self.u1)
 

	
 
    @base.parametrize('perm,modify_to', [
 
        ('repository.read', 'repository.none'),
 
        ('group.read', 'group.none'),
 
        ('usergroup.read', 'usergroup.none'),
 
        ('hg.create.repository', 'hg.create.none'),
 
@@ -631,16 +631,16 @@ class TestPermissions(base.TestControlle
 

	
 
        old = Permission.get_by_key(perm)
 
        new = Permission.get_by_key(modify_to)
 
        assert old is not None
 
        assert new is not None
 

	
 
        # now modify permissions
 
        p = UserToPerm.query() \
 
                .filter(UserToPerm.user == self.u1) \
 
                .filter(UserToPerm.permission == old) \
 
                .one()
 
        p.permission = new
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        PermissionModel().create_default_permissions(user=self.u1)
 
        self._test_def_perm_equal(user=self.u1)
kallithea/tests/models/test_repo_groups.py
Show inline comments
 
import os
 

	
 
import pytest
 
from sqlalchemy.exc import IntegrityError
 

	
 
import kallithea
 
from kallithea.model import meta
 
from kallithea.model.db import RepoGroup
 
from kallithea.model.meta import Session
 
from kallithea.model.repo import RepoModel
 
from kallithea.model.repo_group import RepoGroupModel
 
from kallithea.tests import base
 
from kallithea.tests.fixture import Fixture
 

	
 

	
 
fixture = Fixture()
 

	
 

	
 
def _update_repo_group(id_, group_name, desc='desc', parent_id=None):
 
    form_data = dict(
 
        group_name=group_name,
 
@@ -34,48 +34,48 @@ def _update_repo(name, **kwargs):
 
    r = RepoModel().update(name, **kwargs)
 
    return r
 

	
 

	
 
class TestRepoGroups(base.TestController):
 

	
 
    def setup_method(self, method):
 
        self.g1 = fixture.create_repo_group('test1', skip_if_exists=True)
 
        self.g2 = fixture.create_repo_group('test2', skip_if_exists=True)
 
        self.g3 = fixture.create_repo_group('test3', skip_if_exists=True)
 

	
 
    def teardown_method(self, method):
 
        Session.remove()
 
        meta.Session.remove()
 

	
 
    def __check_path(self, *path):
 
        """
 
        Checks the path for existence !
 
        """
 
        path = [base.TESTS_TMP_PATH] + list(path)
 
        path = os.path.join(*path)
 
        return os.path.isdir(path)
 

	
 
    def __delete_group(self, id_):
 
        RepoGroupModel().delete(id_)
 

	
 
    def test_create_group(self):
 
        g = fixture.create_repo_group('newGroup')
 
        Session().commit()
 
        meta.Session().commit()
 
        assert g.full_path == 'newGroup'
 

	
 
        assert self.__check_path('newGroup')
 

	
 
        # test_create_same_name_group
 
        with pytest.raises(IntegrityError):
 
            fixture.create_repo_group('newGroup')
 
        Session().rollback()
 
        meta.Session().rollback()
 

	
 
    def test_same_subgroup(self):
 
        sg1 = fixture.create_repo_group('sub1', parent_group_id=self.g1.group_id)
 
        assert sg1.parent_group == self.g1
 
        assert sg1.full_path == 'test1/sub1'
 
        assert self.__check_path('test1', 'sub1')
 

	
 
        ssg1 = fixture.create_repo_group('subsub1', parent_group_id=sg1.group_id)
 
        assert ssg1.parent_group == sg1
 
        assert ssg1.full_path == 'test1/sub1/subsub1'
 
        assert self.__check_path('test1', 'sub1', 'subsub1')
 

	
 
@@ -117,82 +117,82 @@ class TestRepoGroups(base.TestController
 
        assert RepoGroup.get_by_group_name('hello') == new_sg1
 

	
 
    def test_subgrouping_with_repo(self):
 

	
 
        g1 = fixture.create_repo_group('g1')
 
        g2 = fixture.create_repo_group('g2')
 
        # create new repo
 
        r = fixture.create_repo('john')
 

	
 
        assert r.repo_name == 'john'
 
        # put repo into group
 
        r = _update_repo('john', repo_group=g1.group_id)
 
        Session().commit()
 
        meta.Session().commit()
 
        assert r.repo_name == 'g1/john'
 

	
 
        _update_repo_group(g1.group_id, 'g1', parent_id=g2.group_id)
 
        assert self.__check_path('g2', 'g1')
 

	
 
        # test repo
 
        assert r.repo_name == kallithea.URL_SEP.join(['g2', 'g1', r.just_name])
 

	
 
    def test_move_to_root(self):
 
        g1 = fixture.create_repo_group('t11')
 
        g2 = fixture.create_repo_group('t22', parent_group_id=g1.group_id)
 

	
 
        assert g2.full_path == 't11/t22'
 
        assert self.__check_path('t11', 't22')
 

	
 
        g2 = _update_repo_group(g2.group_id, 'g22', parent_id=None)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        assert g2.group_name == 'g22'
 
        # we moved out group from t1 to '' so it's full path should be 'g2'
 
        assert g2.full_path == 'g22'
 
        assert not self.__check_path('t11', 't22')
 
        assert self.__check_path('g22')
 

	
 
    def test_rename_top_level_group_in_nested_setup(self):
 
        g1 = fixture.create_repo_group('L1')
 
        g2 = fixture.create_repo_group('L2', parent_group_id=g1.group_id)
 
        g3 = fixture.create_repo_group('L3', parent_group_id=g2.group_id)
 

	
 
        r = fixture.create_repo('L1/L2/L3/L3_REPO', repo_group=g3.group_id)
 

	
 
        ## rename L1 all groups should be now changed
 
        _update_repo_group(g1.group_id, 'L1_NEW')
 
        Session().commit()
 
        meta.Session().commit()
 
        assert g1.full_path == 'L1_NEW'
 
        assert g2.full_path == 'L1_NEW/L2'
 
        assert g3.full_path == 'L1_NEW/L2/L3'
 
        assert r.repo_name == 'L1_NEW/L2/L3/L3_REPO'
 

	
 
    def test_change_parent_of_top_level_group_in_nested_setup(self):
 
        g1 = fixture.create_repo_group('R1')
 
        g2 = fixture.create_repo_group('R2', parent_group_id=g1.group_id)
 
        g3 = fixture.create_repo_group('R3', parent_group_id=g2.group_id)
 
        g4 = fixture.create_repo_group('R1_NEW')
 

	
 
        r = fixture.create_repo('R1/R2/R3/R3_REPO', repo_group=g3.group_id)
 
        ## rename L1 all groups should be now changed
 
        _update_repo_group(g1.group_id, 'R1', parent_id=g4.group_id)
 
        Session().commit()
 
        meta.Session().commit()
 
        assert g1.full_path == 'R1_NEW/R1'
 
        assert g2.full_path == 'R1_NEW/R1/R2'
 
        assert g3.full_path == 'R1_NEW/R1/R2/R3'
 
        assert r.repo_name == 'R1_NEW/R1/R2/R3/R3_REPO'
 

	
 
    def test_change_parent_of_top_level_group_in_nested_setup_with_rename(self):
 
        g1 = fixture.create_repo_group('X1')
 
        g2 = fixture.create_repo_group('X2', parent_group_id=g1.group_id)
 
        g3 = fixture.create_repo_group('X3', parent_group_id=g2.group_id)
 
        g4 = fixture.create_repo_group('X1_NEW')
 

	
 
        r = fixture.create_repo('X1/X2/X3/X3_REPO', repo_group=g3.group_id)
 

	
 
        ## rename L1 all groups should be now changed
 
        _update_repo_group(g1.group_id, 'X1_PRIM', parent_id=g4.group_id)
 
        Session().commit()
 
        meta.Session().commit()
 
        assert g1.full_path == 'X1_NEW/X1_PRIM'
 
        assert g2.full_path == 'X1_NEW/X1_PRIM/X2'
 
        assert g3.full_path == 'X1_NEW/X1_PRIM/X2/X3'
 
        assert r.repo_name == 'X1_NEW/X1_PRIM/X2/X3/X3_REPO'
kallithea/tests/models/test_repos.py
Show inline comments
 
import pytest
 

	
 
from kallithea.lib.exceptions import AttachedForksError
 
from kallithea.model import meta
 
from kallithea.model.db import Repository
 
from kallithea.model.meta import Session
 
from kallithea.model.repo import RepoModel
 
from kallithea.tests import base
 
from kallithea.tests.fixture import Fixture
 

	
 

	
 
fixture = Fixture()
 

	
 

	
 
class TestRepos(base.TestController):
 

	
 
    def teardown_method(self, method):
 
        Session.remove()
 
        meta.Session.remove()
 

	
 
    def test_remove_repo(self):
 
        repo = fixture.create_repo(name='test-repo-1')
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        RepoModel().delete(repo=repo)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        assert Repository.get_by_repo_name(repo_name='test-repo-1') is None
 

	
 
    def test_remove_repo_repo_raises_exc_when_attached_forks(self):
 
        repo = fixture.create_repo(name='test-repo-1')
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        fixture.create_fork(repo.repo_name, 'test-repo-fork-1')
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        with pytest.raises(AttachedForksError):
 
            RepoModel().delete(repo=repo)
 
        # cleanup
 
        RepoModel().delete(repo='test-repo-fork-1')
 
        RepoModel().delete(repo='test-repo-1')
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    def test_remove_repo_delete_forks(self):
 
        repo = fixture.create_repo(name='test-repo-1')
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        fork = fixture.create_fork(repo.repo_name, 'test-repo-fork-1')
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        # fork of fork
 
        fixture.create_fork(fork.repo_name, 'test-repo-fork-fork-1')
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        RepoModel().delete(repo=repo, forks='delete')
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        assert Repository.get_by_repo_name(repo_name='test-repo-1') is None
 
        assert Repository.get_by_repo_name(repo_name='test-repo-fork-1') is None
 
        assert Repository.get_by_repo_name(repo_name='test-repo-fork-fork-1') is None
 

	
 
    def test_remove_repo_detach_forks(self):
 
        repo = fixture.create_repo(name='test-repo-1')
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        fork = fixture.create_fork(repo.repo_name, 'test-repo-fork-1')
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        # fork of fork
 
        fixture.create_fork(fork.repo_name, 'test-repo-fork-fork-1')
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        RepoModel().delete(repo=repo, forks='detach')
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        try:
 
            assert Repository.get_by_repo_name(repo_name='test-repo-1') is None
 
            assert Repository.get_by_repo_name(repo_name='test-repo-fork-1') is not None
 
            assert Repository.get_by_repo_name(repo_name='test-repo-fork-fork-1') is not None
 
        finally:
 
            RepoModel().delete(repo='test-repo-fork-fork-1')
 
            RepoModel().delete(repo='test-repo-fork-1')
 
            Session().commit()
 
            meta.Session().commit()
kallithea/tests/models/test_settings.py
Show inline comments
 
from kallithea.model import meta
 
from kallithea.model.db import Setting
 
from kallithea.model.meta import Session
 

	
 

	
 
name = 'spam-setting-name'
 

	
 

	
 
def test_passing_list_setting_value_results_in_string_valued_setting():
 
    assert Setting.get_by_name(name) is None
 
    setting = Setting.create_or_update(name, ['spam', 'eggs'])
 
    Session().flush() # must flush so we can delete it below
 
    meta.Session().flush() # must flush so we can delete it below
 
    try:
 
        assert Setting.get_by_name(name) is not None
 
        # Quirk: list value is stringified.
 
        assert Setting.get_by_name(name).app_settings_value \
 
               == "['spam', 'eggs']"
 
        assert Setting.get_by_name(name).app_settings_type == 'unicode'
 
    finally:
 
        Session().delete(setting)
 
        meta.Session().delete(setting)
 

	
 

	
 
def test_list_valued_setting_creation_requires_manual_value_formatting():
 
    assert Setting.get_by_name(name) is None
 
    # Quirk: need manual formatting of list setting value.
 
    setting = Setting.create_or_update(name, 'spam,eggs', type='list')
 
    Session().flush() # must flush so we can delete it below
 
    meta.Session().flush() # must flush so we can delete it below
 
    try:
 
        assert setting.app_settings_value == ['spam', 'eggs']
 
    finally:
 
        Session().delete(setting)
 
        meta.Session().delete(setting)
 

	
 

	
 
def test_list_valued_setting_update():
 
    assert Setting.get_by_name(name) is None
 
    setting = Setting.create_or_update(name, 'spam', type='list')
 
    Session().flush() # must flush so we can delete it below
 
    meta.Session().flush() # must flush so we can delete it below
 
    try:
 
        assert setting.app_settings_value == ['spam']
 
        # Assign back setting value.
 
        setting.app_settings_value = setting.app_settings_value
 
        # Quirk: value is stringified on write and listified on read.
 
        assert setting.app_settings_value == ["['spam']"]
 
        setting.app_settings_value = setting.app_settings_value
 
        assert setting.app_settings_value == ["[\"['spam']\"]"]
 
    finally:
 
        Session().delete(setting)
 
        meta.Session().delete(setting)
kallithea/tests/models/test_user_group_permissions_on_repo_groups.py
Show inline comments
 
import functools
 

	
 
from kallithea.model import meta
 
from kallithea.model.db import RepoGroup
 
from kallithea.model.meta import Session
 
from kallithea.model.repo_group import RepoGroupModel
 
from kallithea.model.user_group import UserGroupModel
 
from kallithea.tests.fixture import Fixture
 
from kallithea.tests.models.common import _check_expected_count, _create_project_tree, _destroy_project_tree, _get_perms, check_tree_perms, expected_count
 

	
 

	
 
fixture = Fixture()
 

	
 
test_u2_id = None
 
test_u2_gr_id = None
 
_get_repo_perms = None
 
_get_group_perms = None
 
@@ -25,38 +25,38 @@ def permissions_setup_func(group_name='g
 
        raise Exception('Cannot get group %s' % group_name)
 

	
 
    # Start with a baseline that current group can read recursive
 
    perms_updates = [[test_u2_gr_id, 'group.read', 'users_group']]
 
    RepoGroupModel()._update_permissions(repo_group,
 
                                         perms_updates=perms_updates,
 
                                         recursive='all', check_perms=False)
 

	
 
    perms_updates = [[test_u2_gr_id, perm, 'users_group']]
 
    RepoGroupModel()._update_permissions(repo_group,
 
                                         perms_updates=perms_updates,
 
                                         recursive=recursive, check_perms=False)
 
    Session().commit()
 
    meta.Session().commit()
 

	
 

	
 
def setup_module():
 
    global test_u2_id, test_u2_gr_id, _get_repo_perms, _get_group_perms
 
    test_u2 = _create_project_tree()
 
    Session().commit()
 
    meta.Session().commit()
 
    test_u2_id = test_u2.user_id
 

	
 
    gr1 = fixture.create_user_group('perms_group_1')
 
    Session().commit()
 
    meta.Session().commit()
 
    test_u2_gr_id = gr1.users_group_id
 
    UserGroupModel().add_user_to_group(gr1, user=test_u2_id)
 
    Session().commit()
 
    meta.Session().commit()
 

	
 
    _get_repo_perms = functools.partial(_get_perms, key='repositories',
 
                                        test_u1_id=test_u2_id)
 
    _get_group_perms = functools.partial(_get_perms, key='repositories_groups',
 
                                         test_u1_id=test_u2_id)
 

	
 

	
 
def teardown_module():
 
    _destroy_project_tree(test_u2_id)
 
    fixture.destroy_user_group('perms_group_1')
 

	
 

	
kallithea/tests/models/test_user_groups.py
Show inline comments
 
from kallithea.model import meta
 
from kallithea.model.db import User, UserGroup
 
from kallithea.model.meta import Session
 
from kallithea.model.user_group import UserGroupModel
 
from kallithea.tests import base
 
from kallithea.tests.fixture import Fixture
 

	
 

	
 
fixture = Fixture()
 

	
 

	
 
class TestUserGroups(base.TestController):
 

	
 
    def teardown_method(self, method):
 
        # delete all groups
 
        for gr in UserGroup.query():
 
            fixture.destroy_user_group(gr)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    @base.parametrize('pre_existing,regular_should_be,external_should_be,groups,expected', [
 
        ([], [], [], [], []),
 
        ([], ['regular'], [], [], ['regular']),  # no changes of regular
 
        (['some_other'], [], [], ['some_other'], []),   # not added to regular group
 
        ([], ['regular'], ['container'], ['container'], ['regular', 'container']),
 
        ([], ['regular'], [], ['container', 'container2'], ['regular', 'container', 'container2']),
 
        ([], ['regular'], ['other'], [], ['regular']),  # remove not used
 
        (['some_other'], ['regular'], ['other', 'container'], ['container', 'container2'], ['regular', 'container', 'container2']),
 
    ])
 
    def test_enforce_groups(self, pre_existing, regular_should_be,
 
                            external_should_be, groups, expected):
 
        # delete all groups
 
        for gr in UserGroup.query():
 
            fixture.destroy_user_group(gr)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        user = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
 
        for gr in pre_existing:
 
            gr = fixture.create_user_group(gr)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        # make sure use is just in those groups
 
        for gr in regular_should_be:
 
            gr = fixture.create_user_group(gr)
 
            Session().commit()
 
            meta.Session().commit()
 
            UserGroupModel().add_user_to_group(gr, user)
 
            Session().commit()
 
            meta.Session().commit()
 

	
 
        # now special external groups created by auth plugins
 
        for gr in external_should_be:
 
            gr = fixture.create_user_group(gr, user_group_data={'extern_type': 'container'})
 
            Session().commit()
 
            meta.Session().commit()
 
            UserGroupModel().add_user_to_group(gr, user)
 
            Session().commit()
 
            meta.Session().commit()
 

	
 
        UserGroupModel().enforce_groups(user, groups, 'container')
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        user = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
 
        in_groups = user.group_member
 
        assert sorted(expected) == sorted(x.users_group.users_group_name for x in in_groups)
kallithea/tests/models/test_user_permissions_on_repo_groups.py
Show inline comments
 
import functools
 

	
 
import kallithea
 
from kallithea.model import meta
 
from kallithea.model.db import RepoGroup, Repository
 
from kallithea.model.meta import Session
 
from kallithea.model.repo_group import RepoGroupModel
 
from kallithea.tests.models.common import _check_expected_count, _create_project_tree, _destroy_project_tree, _get_perms, check_tree_perms, expected_count
 

	
 

	
 
test_u1_id = None
 
_get_repo_perms = None
 
_get_group_perms = None
 

	
 

	
 
def permissions_setup_func(group_name='g0', perm='group.read', recursive='all',
 
                           user_id=None):
 
    """
 
@@ -27,31 +27,31 @@ def permissions_setup_func(group_name='g
 
        raise Exception('Cannot get group %s' % group_name)
 

	
 
    # Start with a baseline that current group can read recursive
 
    perms_updates = [[user_id, 'group.read', 'user']]
 
    RepoGroupModel()._update_permissions(repo_group,
 
                                         perms_updates=perms_updates,
 
                                         recursive='all', check_perms=False)
 

	
 
    perms_updates = [[user_id, perm, 'user']]
 
    RepoGroupModel()._update_permissions(repo_group,
 
                                         perms_updates=perms_updates,
 
                                         recursive=recursive, check_perms=False)
 
    Session().commit()
 
    meta.Session().commit()
 

	
 

	
 
def setup_module():
 
    global test_u1_id, _get_repo_perms, _get_group_perms
 
    test_u1 = _create_project_tree()
 
    Session().commit()
 
    meta.Session().commit()
 
    test_u1_id = test_u1.user_id
 
    _get_repo_perms = functools.partial(_get_perms, key='repositories',
 
                                        test_u1_id=test_u1_id)
 
    _get_group_perms = functools.partial(_get_perms, key='repositories_groups',
 
                                         test_u1_id=test_u1_id)
 

	
 

	
 
def teardown_module():
 
    _destroy_project_tree(test_u1_id)
 

	
 

	
 
def test_user_permissions_on_group_without_recursive_mode():
kallithea/tests/models/test_users.py
Show inline comments
 
import pytest
 

	
 
from kallithea.model import meta
 
from kallithea.model.db import Permission, User, UserEmailMap, UserGroup, UserGroupMember
 
from kallithea.model.meta import Session
 
from kallithea.model.user import UserModel
 
from kallithea.model.user_group import UserGroupModel
 
from kallithea.tests import base
 
from kallithea.tests.fixture import Fixture
 

	
 

	
 
fixture = Fixture()
 

	
 

	
 
class TestUser(base.TestController):
 

	
 
    @classmethod
 
    def setup_class(cls):
 
        Session.remove()
 
        meta.Session.remove()
 

	
 
    def teardown_method(self, method):
 
        Session.remove()
 
        meta.Session.remove()
 

	
 
    def test_create_and_remove(self):
 
        usr = UserModel().create_or_update(username='test_user',
 
                                           password='qweqwe',
 
                                           email='u232@example.com',
 
                                           firstname='u1', lastname='u1')
 
        Session().commit()
 
        meta.Session().commit()
 
        assert User.get_by_username('test_user') == usr
 
        assert User.get_by_username('test_USER', case_insensitive=True) == usr
 
        # User.get_by_username without explicit request for case insensitivty
 
        # will use database case sensitivity. The following will thus return
 
        # None on for example PostgreSQL but find test_user on MySQL - we are
 
        # fine with leaving that as undefined as long as it doesn't crash.
 
        User.get_by_username('test_USER', case_insensitive=False)
 

	
 
        # make user group
 
        user_group = fixture.create_user_group('some_example_group')
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        UserGroupModel().add_user_to_group(user_group, usr)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        assert UserGroup.get(user_group.users_group_id) == user_group
 
        assert UserGroupMember.query().count() == 1
 
        UserModel().delete(usr.user_id)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        assert UserGroupMember.query().all() == []
 

	
 
    def test_additional_email_as_main(self):
 
        usr = UserModel().create_or_update(username='test_user',
 
                                           password='qweqwe',
 
                                     email='main_email@example.com',
 
                                     firstname='u1', lastname='u1')
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        with pytest.raises(AttributeError):
 
            m = UserEmailMap()
 
            m.email = 'main_email@example.com'
 
            m.user = usr
 
            Session().add(m)
 
            Session().commit()
 
            meta.Session().add(m)
 
            meta.Session().commit()
 

	
 
        UserModel().delete(usr.user_id)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    def test_extra_email_map(self):
 
        usr = UserModel().create_or_update(username='test_user',
 
                                           password='qweqwe',
 
                                     email='main_email@example.com',
 
                                     firstname='u1', lastname='u1')
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        m = UserEmailMap()
 
        m.email = 'main_email2@example.com'
 
        m.user = usr
 
        Session().add(m)
 
        Session().commit()
 
        meta.Session().add(m)
 
        meta.Session().commit()
 

	
 
        u = User.get_by_email(email='MAIN_email@example.com')
 
        assert usr.user_id == u.user_id
 
        assert usr.username == u.username
 

	
 
        u = User.get_by_email(email='main_email@example.com')
 
        assert usr.user_id == u.user_id
 
        assert usr.username == u.username
 

	
 
        u = User.get_by_email(email='main_email2@example.com')
 
        assert usr.user_id == u.user_id
 
        assert usr.username == u.username
 
        u = User.get_by_email(email='main_email3@example.com')
 
        assert u is None
 

	
 
        u = User.get_by_email(email='main_e%ail@example.com')
 
        assert u is None
 
        u = User.get_by_email(email='main_emai_@example.com')
 
        assert u is None
 

	
 
        UserModel().delete(usr.user_id)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 

	
 
class TestUsers(base.TestController):
 

	
 
    def setup_method(self, method):
 
        self.u1 = UserModel().create_or_update(username='u1',
 
                                        password='qweqwe',
 
                                        email='u1@example.com',
 
                                        firstname='u1', lastname='u1')
 

	
 
    def teardown_method(self, method):
 
        perm = Permission.query().all()
 
        for p in perm:
 
            UserModel().revoke_perm(self.u1, p)
 

	
 
        UserModel().delete(self.u1)
 
        Session().commit()
 
        Session.remove()
 
        meta.Session().commit()
 
        meta.Session.remove()
 

	
 
    def test_add_perm(self):
 
        perm = Permission.query().all()[0]
 
        UserModel().grant_perm(self.u1, perm)
 
        Session().commit()
 
        meta.Session().commit()
 
        assert UserModel().has_perm(self.u1, perm) == True
 

	
 
    def test_has_perm(self):
 
        perm = Permission.query().all()
 
        for p in perm:
 
            has_p = UserModel().has_perm(self.u1, p)
 
            assert False == has_p
 

	
 
    def test_revoke_perm(self):
 
        perm = Permission.query().all()[0]
 
        UserModel().grant_perm(self.u1, perm)
 
        Session().commit()
 
        meta.Session().commit()
 
        assert UserModel().has_perm(self.u1, perm) == True
 

	
 
        # revoke
 
        UserModel().revoke_perm(self.u1, perm)
 
        Session().commit()
 
        meta.Session().commit()
 
        assert UserModel().has_perm(self.u1, perm) == False
kallithea/tests/other/test_validators.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
import formencode
 
import pytest
 

	
 
from kallithea.model import meta
 
from kallithea.model import validators as v
 
from kallithea.model.meta import Session
 
from kallithea.model.repo_group import RepoGroupModel
 
from kallithea.model.user_group import UserGroupModel
 
from kallithea.tests import base
 
from kallithea.tests.fixture import Fixture
 

	
 

	
 
fixture = Fixture()
 

	
 

	
 
@pytest.mark.usefixtures("test_context_fixture") # apply fixture for all test methods
 
class TestRepoGroups(base.TestController):
 

	
 
    def teardown_method(self, method):
 
        Session.remove()
 
        meta.Session.remove()
 

	
 
    def test_Message_extractor(self):
 
        validator = v.ValidUsername()
 
        with pytest.raises(formencode.Invalid):
 
            validator.to_python('default')
 

	
 
        class StateObj(object):
 
            pass
 

	
 
        with pytest.raises(formencode.Invalid):
 
            validator.to_python('default', StateObj)
 

	
 
@@ -51,41 +51,41 @@ class TestRepoGroups(base.TestController
 
            validator.to_python('nouser')
 
        assert base.TEST_USER_ADMIN_LOGIN == validator.to_python(base.TEST_USER_ADMIN_LOGIN)
 

	
 
    def test_ValidUserGroup(self):
 
        validator = v.ValidUserGroup()
 
        with pytest.raises(formencode.Invalid):
 
            validator.to_python('default')
 
        with pytest.raises(formencode.Invalid):
 
            validator.to_python('.,')
 

	
 
        gr = fixture.create_user_group('test')
 
        gr2 = fixture.create_user_group('tes2')
 
        Session().commit()
 
        meta.Session().commit()
 
        with pytest.raises(formencode.Invalid):
 
            validator.to_python('test')
 
        assert gr.users_group_id is not None
 
        validator = v.ValidUserGroup(edit=True,
 
                                    old_data={'users_group_id':
 
                                              gr2.users_group_id})
 

	
 
        with pytest.raises(formencode.Invalid):
 
            validator.to_python('test')
 
        with pytest.raises(formencode.Invalid):
 
            validator.to_python('TesT')
 
        with pytest.raises(formencode.Invalid):
 
            validator.to_python('TEST')
 
        UserGroupModel().delete(gr)
 
        UserGroupModel().delete(gr2)
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
    def test_ValidRepoGroup(self):
 
        validator = v.ValidRepoGroup()
 
        model = RepoGroupModel()
 
        with pytest.raises(formencode.Invalid):
 
            validator.to_python({'group_name': base.HG_REPO, })
 
        gr = model.create(group_name='test_gr', group_description='desc',
 
                          parent=None,
 
                          just_db=True,
 
                          owner=base.TEST_USER_ADMIN_LOGIN)
 
        with pytest.raises(formencode.Invalid):
 
            validator.to_python({'group_name': gr.group_name, })
kallithea/tests/other/test_vcs_operations.py
Show inline comments
 
@@ -29,26 +29,26 @@ import json
 
import os
 
import re
 
import tempfile
 
import time
 
import urllib.request
 
from subprocess import PIPE, Popen
 
from tempfile import _RandomNameSequence
 

	
 
import pytest
 

	
 
import kallithea
 
from kallithea.lib.utils2 import ascii_bytes, safe_str
 
from kallithea.model import meta
 
from kallithea.model.db import Repository, Ui, User, UserIpMap, UserLog
 
from kallithea.model.meta import Session
 
from kallithea.model.ssh_key import SshKeyModel
 
from kallithea.model.user import UserModel
 
from kallithea.tests import base
 
from kallithea.tests.fixture import Fixture
 

	
 

	
 
DEBUG = True
 
HOST = '127.0.0.1:4999'  # test host
 

	
 
fixture = Fixture()
 

	
 

	
 
@@ -66,25 +66,25 @@ class SshVcsTest(object):
 
        base.TEST_USER_REGULAR_LOGIN: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC6Ycnc2oUZHQnQwuqgZqTTdMDZD7ataf3JM7oG2Fw8JR6cdmz4QZLe5mfDwaFwG2pWHLRpVqzfrD/Pn3rIO++bgCJH5ydczrl1WScfryV1hYMJ/4EzLGM657J1/q5EI+b9SntKjf4ax+KP322L0TNQGbZUHLbfG2MwHMrYBQpHUQ== kallithea@localhost',
 
        base.TEST_USER_ADMIN_LOGIN: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC6Ycnc2oUZHQnQwuqgZqTTdMDZD7ataf3JM7oG2Fw8JR6cdmz4QZLe5mfDwaFwG2pWHLRpVqzfrD/Pn3rIO++bgCJH5ydczrl1WScfryV1hYMJ/4EzLGM657J1/q5EI+b9SntKjf4ax+KP322L0TNQGbZUHLbfG2MwHMrYBQpHUq== kallithea@localhost',
 
    }
 

	
 
    @classmethod
 
    def repo_url_param(cls, webserver, repo_name, username=base.TEST_USER_ADMIN_LOGIN, password=base.TEST_USER_ADMIN_PASS, client_ip=base.IP_ADDR):
 
        user = User.get_by_username(username)
 
        if user.ssh_keys:
 
            ssh_key = user.ssh_keys[0]
 
        else:
 
            sshkeymodel = SshKeyModel()
 
            ssh_key = sshkeymodel.create(user, 'test key', cls.public_keys[user.username])
 
            Session().commit()
 
            meta.Session().commit()
 

	
 
        return cls._ssh_param(repo_name, user, ssh_key, client_ip)
 

	
 
# Mixins for using Mercurial and Git
 
class HgVcsTest(object):
 
    repo_type = 'hg'
 
    repo_name = base.HG_REPO
 

	
 
class GitVcsTest(object):
 
    repo_type = 'git'
 
    repo_name = base.GIT_REPO
 

	
 
@@ -214,25 +214,25 @@ def _add_files_and_push(webserver, vt, d
 
def _check_outgoing(vcs, cwd, clone_url):
 
    if vcs == 'hg':
 
        # hg removes the password from default URLs, so we have to provide it here via the clone_url
 
        return Command(cwd).execute('hg -q outgoing', clone_url, ignoreReturnCode=True)
 
    elif vcs == 'git':
 
        Command(cwd).execute('git remote update')
 
        return Command(cwd).execute('git log origin/master..master')
 

	
 

	
 
def set_anonymous_access(enable=True):
 
    user = User.get_default_user()
 
    user.active = enable
 
    Session().commit()
 
    meta.Session().commit()
 
    if enable != User.get_default_user().active:
 
        raise Exception('Cannot set anonymous access')
 

	
 

	
 
#==============================================================================
 
# TESTS
 
#==============================================================================
 

	
 

	
 
def _check_proper_git_push(stdout, stderr):
 
    assert 'fatal' not in stderr
 
    assert 'rejected' not in stderr
 
@@ -246,26 +246,26 @@ class TestVCSOperations(base.TestControl
 
    @classmethod
 
    def setup_class(cls):
 
        # DISABLE ANONYMOUS ACCESS
 
        set_anonymous_access(False)
 

	
 
    @pytest.fixture()
 
    def testhook_cleanup(self):
 
        yield
 
        # remove hook
 
        for hook in ['prechangegroup', 'pretxnchangegroup', 'preoutgoing', 'changegroup', 'outgoing', 'incoming']:
 
            entry = Ui.get_by_key('hooks', '%s.testhook' % hook)
 
            if entry:
 
                Session().delete(entry)
 
        Session().commit()
 
                meta.Session().delete(entry)
 
        meta.Session().commit()
 

	
 
    @pytest.fixture(scope="module")
 
    def testfork(self):
 
        # create fork so the repo stays untouched
 
        git_fork_name = '%s_fork%s' % (base.GIT_REPO, next(_RandomNameSequence()))
 
        fixture.create_fork(base.GIT_REPO, git_fork_name)
 
        hg_fork_name = '%s_fork%s' % (base.HG_REPO, next(_RandomNameSequence()))
 
        fixture.create_fork(base.HG_REPO, hg_fork_name)
 
        return {'git': git_fork_name, 'hg': hg_fork_name}
 

	
 
    @parametrize_vcs_test
 
    def test_clone_repo_by_admin(self, webserver, vt):
 
@@ -305,25 +305,25 @@ class TestVCSOperations(base.TestControl
 
    def test_clone_non_existing_path(self, webserver, vt):
 
        clone_url = vt.repo_url_param(webserver, 'trololo')
 
        stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
 
        if vt.repo_type == 'git':
 
            assert 'not found' in stderr or 'abort: Access to %r denied' % 'trololo' in stderr
 
        elif vt.repo_type == 'hg':
 
            assert 'HTTP Error 404: Not Found' in stderr or 'abort: no suitable response from remote hg' in stderr and 'remote: abort: Access to %r denied' % 'trololo' in stdout + stderr
 

	
 
    @parametrize_vcs_test
 
    def test_push_new_repo(self, webserver, vt):
 
        # Clear the log so we know what is added
 
        UserLog.query().delete()
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        # Create an empty server repo using the API
 
        repo_name = 'new_%s_%s' % (vt.repo_type, next(_RandomNameSequence()))
 
        usr = User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
 
        params = {
 
            "id": 7,
 
            "api_key": usr.api_key,
 
            "method": 'create_repo',
 
            "args": dict(repo_name=repo_name,
 
                         owner=base.TEST_USER_ADMIN_LOGIN,
 
                         repo_type=vt.repo_type),
 
        }
 
@@ -349,72 +349,72 @@ class TestVCSOperations(base.TestControl
 
        stdout, stderr = _add_files_and_push(webserver, vt, local_clone_dir, clone_url=clone_url)
 
        if vt.repo_type == 'git':
 
            _check_proper_git_push(stdout, stderr)
 
        elif vt.repo_type == 'hg':
 
            assert 'pushing to ' in stdout
 
            assert 'remote: added ' in stdout
 

	
 
        # Verify that we got the right events in UserLog. Expect something like:
 
        # <UserLog('id:new_git_XXX:started_following_repo')>
 
        # <UserLog('id:new_git_XXX:user_created_repo')>
 
        # <UserLog('id:new_git_XXX:pull')>
 
        # <UserLog('id:new_git_XXX:push:aed9d4c1732a1927da3be42c47eb9afdc200d427,d38b083a07af10a9f44193486959a96a23db78da,4841ff9a2b385bec995f4679ef649adb3f437622')>
 
        Session.close()  # make sure SA fetches all new log entries (apparently only needed for MariaDB/MySQL ...)
 
        meta.Session.close()  # make sure SA fetches all new log entries (apparently only needed for MariaDB/MySQL ...)
 
        action_parts = [ul.action.split(':', 1) for ul in UserLog.query().order_by(UserLog.user_log_id)]
 
        assert [(t[0], (t[1].count(',') + 1) if len(t) == 2 else 0) for t in action_parts] == ([
 
            ('started_following_repo', 0),
 
            ('user_created_repo', 0),
 
            ('pull', 0),
 
            ('push', 3)]
 
            if vt.repo_type == 'git' else [
 
            ('started_following_repo', 0),
 
            ('user_created_repo', 0),
 
            # (u'pull', 0), # Mercurial outgoing hook is not called for empty clones
 
            ('push', 3)])
 

	
 
    @parametrize_vcs_test
 
    def test_push_new_file(self, webserver, testfork, vt):
 
        UserLog.query().delete()
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        dest_dir = _get_tmp_dir()
 
        clone_url = vt.repo_url_param(webserver, vt.repo_name)
 
        stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
 

	
 
        clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type])
 
        stdout, stderr = _add_files_and_push(webserver, vt, dest_dir, clone_url=clone_url)
 

	
 
        if vt.repo_type == 'git':
 
            _check_proper_git_push(stdout, stderr)
 
        elif vt.repo_type == 'hg':
 
            assert 'pushing to' in stdout
 
            assert 'Repository size' in stdout
 
            assert 'Last revision is now' in stdout
 

	
 
        Session.close()  # make sure SA fetches all new log entries (apparently only needed for MariaDB/MySQL ...)
 
        meta.Session.close()  # make sure SA fetches all new log entries (apparently only needed for MariaDB/MySQL ...)
 
        action_parts = [ul.action.split(':', 1) for ul in UserLog.query().order_by(UserLog.user_log_id)]
 
        assert [(t[0], (t[1].count(',') + 1) if len(t) == 2 else 0) for t in action_parts] == \
 
            [('pull', 0), ('push', 3)]
 

	
 
    @parametrize_vcs_test
 
    def test_pull(self, webserver, testfork, vt):
 
        UserLog.query().delete()
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        dest_dir = _get_tmp_dir()
 
        stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'init', dest_dir)
 

	
 
        clone_url = vt.repo_url_param(webserver, vt.repo_name)
 
        stdout, stderr = Command(dest_dir).execute(vt.repo_type, 'pull', clone_url)
 
        Session.close()  # make sure SA fetches all new log entries (apparently only needed for MariaDB/MySQL ...)
 
        meta.Session.close()  # make sure SA fetches all new log entries (apparently only needed for MariaDB/MySQL ...)
 

	
 
        if vt.repo_type == 'git':
 
            assert 'FETCH_HEAD' in stderr
 
        elif vt.repo_type == 'hg':
 
            assert 'new changesets' in stdout
 

	
 
        action_parts = [ul.action for ul in UserLog.query().order_by(UserLog.user_log_id)]
 
        assert action_parts == ['pull']
 

	
 
        # Test handling of URLs with extra '/' around repo_name
 
        stdout, stderr = Command(dest_dir).execute(vt.repo_type, 'pull', clone_url.replace('/' + vt.repo_name, '/./%s/' % vt.repo_name), ignoreReturnCode=True)
 
        if issubclass(vt, HttpVcsTest):
 
@@ -445,60 +445,60 @@ class TestVCSOperations(base.TestControl
 
    def test_push_invalidates_cache(self, webserver, testfork, vt):
 
        pre_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in Repository.query().filter(Repository.repo_name == testfork[vt.repo_type])]
 

	
 
        dest_dir = _get_tmp_dir()
 
        clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type])
 
        stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
 

	
 
        stdout, stderr = _add_files_and_push(webserver, vt, dest_dir, files_no=1, clone_url=clone_url)
 

	
 
        if vt.repo_type == 'git':
 
            _check_proper_git_push(stdout, stderr)
 

	
 
        Session.close()  # expire session to make sure SA fetches new Repository instances after last_changeset has been updated by server side hook in another process
 
        meta.Session.close()  # expire session to make sure SA fetches new Repository instances after last_changeset has been updated by server side hook in another process
 
        post_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in Repository.query().filter(Repository.repo_name == testfork[vt.repo_type])]
 
        assert pre_cached_tip != post_cached_tip
 

	
 
    @parametrize_vcs_test_http
 
    def test_push_wrong_credentials(self, webserver, vt):
 
        dest_dir = _get_tmp_dir()
 
        clone_url = vt.repo_url_param(webserver, vt.repo_name)
 
        stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
 

	
 
        clone_url = webserver.repo_url(vt.repo_name, username='bad', password='name')
 
        stdout, stderr = _add_files_and_push(webserver, vt, dest_dir,
 
                                             clone_url=clone_url, ignoreReturnCode=True)
 

	
 
        if vt.repo_type == 'git':
 
            assert 'fatal: Authentication failed' in stderr
 
        elif vt.repo_type == 'hg':
 
            assert 'abort: authorization failed' in stderr
 

	
 
    @parametrize_vcs_test
 
    def test_push_with_readonly_credentials(self, webserver, vt):
 
        UserLog.query().delete()
 
        Session().commit()
 
        meta.Session().commit()
 

	
 
        dest_dir = _get_tmp_dir()
 
        clone_url = vt.repo_url_param(webserver, vt.repo_name, username=base.TEST_USER_REGULAR_LOGIN, password=base.TEST_USER_REGULAR_PASS)
 
        stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
 

	
 
        stdout, stderr = _add_files_and_push(webserver, vt, dest_dir, ignoreReturnCode=True, clone_url=clone_url)
 

	
 
        if vt.repo_type == 'git':
 
            assert 'The requested URL returned error: 403' in stderr or 'abort: Push access to %r denied' % str(vt.repo_name) in stderr
 
        elif vt.repo_type == 'hg':
 
            assert 'abort: HTTP Error 403: Forbidden' in stderr or 'abort: push failed on remote' in stderr and 'remote: Push access to %r denied' % str(vt.repo_name) in stdout
 

	
 
        Session.close()  # make sure SA fetches all new log entries (apparently only needed for MariaDB/MySQL ...)
 
        meta.Session.close()  # make sure SA fetches all new log entries (apparently only needed for MariaDB/MySQL ...)
 
        action_parts = [ul.action.split(':', 1) for ul in UserLog.query().order_by(UserLog.user_log_id)]
 
        assert [(t[0], (t[1].count(',') + 1) if len(t) == 2 else 0) for t in action_parts] == \
 
            [('pull', 0)]
 

	
 
    @parametrize_vcs_test
 
    def test_push_back_to_wrong_url(self, webserver, vt):
 
        dest_dir = _get_tmp_dir()
 
        clone_url = vt.repo_url_param(webserver, vt.repo_name)
 
        stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
 

	
 
        stdout, stderr = _add_files_and_push(
 
            webserver, vt, dest_dir, clone_url='http://%s:%s/tmp' % (
 
@@ -507,108 +507,108 @@ class TestVCSOperations(base.TestControl
 

	
 
        if vt.repo_type == 'git':
 
            assert 'not found' in stderr
 
        elif vt.repo_type == 'hg':
 
            assert 'HTTP Error 404: Not Found' in stderr
 

	
 
    @parametrize_vcs_test
 
    def test_ip_restriction(self, webserver, vt):
 
        user_model = UserModel()
 
        try:
 
            # Add IP constraint that excludes the test context:
 
            user_model.add_extra_ip(base.TEST_USER_ADMIN_LOGIN, '10.10.10.10/32')
 
            Session().commit()
 
            meta.Session().commit()
 
            # IP permissions are cached, need to wait for the cache in the server process to expire
 
            time.sleep(1.5)
 
            clone_url = vt.repo_url_param(webserver, vt.repo_name)
 
            stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
 
            if vt.repo_type == 'git':
 
                # The message apparently changed in Git 1.8.3, so match it loosely.
 
                assert re.search(r'\b403\b', stderr) or 'abort: User test_admin from 127.0.0.127 cannot be authorized' in stderr
 
            elif vt.repo_type == 'hg':
 
                assert 'abort: HTTP Error 403: Forbidden' in stderr or 'remote: abort: User test_admin from 127.0.0.127 cannot be authorized' in stdout + stderr
 
        finally:
 
            # release IP restrictions
 
            for ip in UserIpMap.query():
 
                UserIpMap.delete(ip.ip_id)
 
            Session().commit()
 
            meta.Session().commit()
 
            # IP permissions are cached, need to wait for the cache in the server process to expire
 
            time.sleep(1.5)
 

	
 
        clone_url = vt.repo_url_param(webserver, vt.repo_name)
 
        stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, _get_tmp_dir())
 

	
 
        if vt.repo_type == 'git':
 
            assert 'Cloning into' in stdout + stderr
 
            assert stderr == '' or stdout == ''
 
        elif vt.repo_type == 'hg':
 
            assert 'requesting all changes' in stdout
 
            assert 'adding changesets' in stdout
 
            assert 'adding manifests' in stdout
 
            assert 'adding file changes' in stdout
 

	
 
            assert stderr == ''
 

	
 
    @parametrize_vcs_test_hg # git hooks doesn't work like hg hooks
 
    def test_custom_hooks_preoutgoing(self, testhook_cleanup, webserver, testfork, vt):
 
        # set prechangegroup to failing hook (returns True)
 
        Ui.create_or_update_hook('preoutgoing.testhook', 'python:kallithea.tests.fixture.failing_test_hook')
 
        Session().commit()
 
        meta.Session().commit()
 
        # clone repo
 
        clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type], username=base.TEST_USER_ADMIN_LOGIN, password=base.TEST_USER_ADMIN_PASS)
 
        dest_dir = _get_tmp_dir()
 
        stdout, stderr = Command(base.TESTS_TMP_PATH) \
 
            .execute(vt.repo_type, 'clone', clone_url, dest_dir, ignoreReturnCode=True)
 
        if vt.repo_type == 'hg':
 
            assert 'preoutgoing.testhook hook failed' in stdout
 
        elif vt.repo_type == 'git':
 
            assert 'error: 406' in stderr
 

	
 
    @parametrize_vcs_test_hg # git hooks doesn't work like hg hooks
 
    def test_custom_hooks_prechangegroup(self, testhook_cleanup, webserver, testfork, vt):
 
        # set prechangegroup to failing hook (returns exit code 1)
 
        Ui.create_or_update_hook('prechangegroup.testhook', 'python:kallithea.tests.fixture.failing_test_hook')
 
        Session().commit()
 
        meta.Session().commit()
 
        # clone repo
 
        clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type], username=base.TEST_USER_ADMIN_LOGIN, password=base.TEST_USER_ADMIN_PASS)
 
        dest_dir = _get_tmp_dir()
 
        stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
 

	
 
        stdout, stderr = _add_files_and_push(webserver, vt, dest_dir, clone_url,
 
                                             ignoreReturnCode=True)
 
        assert 'failing_test_hook failed' in stdout + stderr
 
        assert 'Traceback' not in stdout + stderr
 
        assert 'prechangegroup.testhook hook failed' in stdout + stderr
 
        # there are still outgoing changesets
 
        stdout, stderr = _check_outgoing(vt.repo_type, dest_dir, clone_url)
 
        assert stdout != ''
 

	
 
        # set prechangegroup hook to exception throwing method
 
        Ui.create_or_update_hook('prechangegroup.testhook', 'python:kallithea.tests.fixture.exception_test_hook')
 
        Session().commit()
 
        meta.Session().commit()
 
        # re-try to push
 
        stdout, stderr = Command(dest_dir).execute('%s push' % vt.repo_type, clone_url, ignoreReturnCode=True)
 
        if vt is HgHttpVcsTest:
 
            # like with 'hg serve...' 'HTTP Error 500: INTERNAL SERVER ERROR' should be returned
 
            assert 'HTTP Error 500: INTERNAL SERVER ERROR' in stderr
 
        elif vt is HgSshVcsTest:
 
            assert 'remote: Exception: exception_test_hook threw an exception' in stdout
 
        else: assert False
 
        # there are still outgoing changesets
 
        stdout, stderr = _check_outgoing(vt.repo_type, dest_dir, clone_url)
 
        assert stdout != ''
 

	
 
        # set prechangegroup hook to method that returns False
 
        Ui.create_or_update_hook('prechangegroup.testhook', 'python:kallithea.tests.fixture.passing_test_hook')
 
        Session().commit()
 
        meta.Session().commit()
 
        # re-try to push
 
        stdout, stderr = Command(dest_dir).execute('%s push' % vt.repo_type, clone_url, ignoreReturnCode=True)
 
        assert 'passing_test_hook succeeded' in stdout + stderr
 
        assert 'Traceback' not in stdout + stderr
 
        assert 'prechangegroup.testhook hook failed' not in stdout + stderr
 
        # no more outgoing changesets
 
        stdout, stderr = _check_outgoing(vt.repo_type, dest_dir, clone_url)
 
        assert stdout == ''
 
        assert stderr == ''
 

	
 
    def test_add_submodule_git(self, webserver, testfork):
 
        dest_dir = _get_tmp_dir()
0 comments (0 inline, 0 general)