Changeset - 04027bdb876c
[Not reviewed]
rhodecode/controllers/admin/permissions.py
Show inline comments
 
@@ -51,117 +51,117 @@ class PermissionsController(BaseControll
 
    @LoginRequired()
 
    @HasPermissionAllDecorator('hg.admin')
 
    def __before__(self):
 
        c.admin_user = session.get('admin_user')
 
        c.admin_username = session.get('admin_username')
 
        super(PermissionsController, self).__before__()
 

	
 
        self.perms_choices = [('repository.none', _('None'),),
 
                              ('repository.read', _('Read'),),
 
                              ('repository.write', _('Write'),),
 
                              ('repository.admin', _('Admin'),)]
 
        self.register_choices = [
 
            ('hg.register.none',
 
                _('disabled')),
 
            ('hg.register.manual_activate',
 
                _('allowed with manual account activation')),
 
            ('hg.register.auto_activate',
 
                _('allowed with automatic account activation')), ]
 

	
 
        self.create_choices = [('hg.create.none', _('Disabled')),
 
                               ('hg.create.repository', _('Enabled'))]
 

	
 
    def index(self, format='html'):
 
        """GET /permissions: All items in the collection"""
 
        # url('permissions')
 

	
 
    def create(self):
 
        """POST /permissions: Create a new item"""
 
        # url('permissions')
 

	
 
    def new(self, format='html'):
 
        """GET /permissions/new: Form to create a new item"""
 
        # url('new_permission')
 

	
 
    def update(self, id):
 
        """PUT /permissions/id: Update an existing item"""
 
        # Forms posted to this method should contain a hidden field:
 
        #    <input type="hidden" name="_method" value="PUT" />
 
        # Or using helpers:
 
        #    h.form(url('permission', id=ID),
 
        #           method='put')
 
        # url('permission', id=ID)
 

	
 
        permission_model = PermissionModel()
 

	
 
        _form = DefaultPermissionsForm([x[0] for x in self.perms_choices],
 
                                       [x[0] for x in self.register_choices],
 
                                       [x[0] for x in self.create_choices])()
 

	
 
        try:
 
            form_result = _form.to_python(dict(request.POST))
 
            form_result.update({'perm_user_name': id})
 
            permission_model.update(form_result)
 
            h.flash(_('Default permissions updated successfully'),
 
                    category='success')
 

	
 
        except formencode.Invalid, errors:
 
            c.perms_choices = self.perms_choices
 
            c.register_choices = self.register_choices
 
            c.create_choices = self.create_choices
 
            defaults = errors.value
 

	
 
            return htmlfill.render(
 
                render('admin/permissions/permissions.html'),
 
                defaults=defaults,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8")
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('error occurred during update of permissions'),
 
                    category='error')
 

	
 
        return redirect(url('edit_permission', id=id))
 

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

	
 
    def show(self, id, format='html'):
 
        """GET /permissions/id: Show a specific item"""
 
        # url('permission', id=ID)
 

	
 
    def edit(self, id, format='html'):
 
        """GET /permissions/id/edit: Form to edit an existing item"""
 
        #url('edit_permission', id=ID)
 
        c.perms_choices = self.perms_choices
 
        c.register_choices = self.register_choices
 
        c.create_choices = self.create_choices
 

	
 
        if id == 'default':
 
            default_user = User.by_username('default')
 
            default_user = User.get_by_username('default')
 
            defaults = {'_method': 'put',
 
                        'anonymous': default_user.active}
 

	
 
            for p in default_user.user_perms:
 
                if p.permission.permission_name.startswith('repository.'):
 
                    defaults['default_perm'] = p.permission.permission_name
 

	
 
                if p.permission.permission_name.startswith('hg.register.'):
 
                    defaults['default_register'] = p.permission.permission_name
 

	
 
                if p.permission.permission_name.startswith('hg.create.'):
 
                    defaults['default_create'] = p.permission.permission_name
 

	
 
            return htmlfill.render(
 
                        render('admin/permissions/permissions.html'),
 
                        defaults=defaults,
 
                        encoding="UTF-8",
 
                        force_defaults=True,)
 
        else:
 
            return redirect(url('admin_home'))
rhodecode/controllers/admin/repos.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.admin.repos
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Admin controller for RhodeCode
 

	
 
    :created_on: Apr 7, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
import logging
 
import traceback
 
import formencode
 
from operator import itemgetter
 
from formencode import htmlfill
 

	
 
from paste.httpexceptions import HTTPInternalServerError
 
from pylons import request, response, session, tmpl_context as c, url
 
from pylons.controllers.util import abort, redirect
 
from pylons.i18n.translation import _
 

	
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
 
    HasPermissionAnyDecorator
 
from rhodecode.lib.base import BaseController, render
 
from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
 
from rhodecode.lib.helpers import get_token
 
from rhodecode.model.db import User, Repository, UserFollowing, Group
 
from rhodecode.model.forms import RepoForm
 
from rhodecode.model.scm import ScmModel
 
from rhodecode.model.repo import RepoModel
 
from sqlalchemy.exc import IntegrityError
 

	
 
log = logging.getLogger(__name__)
 

	
 

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

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

	
 
    def __load_defaults(self):
 
        repo_model = RepoModel()
 

	
 
        c.repo_groups = [('', '')]
 
        parents_link = lambda k: h.literal('&raquo;'.join(
 
                                    map(lambda k: k.group_name,
 
                                        k.parents + [k])
 
                                    )
 
                                )
 

	
 
        c.repo_groups.extend([(x.group_id, parents_link(x)) for \
 
                                            x in self.sa.query(Group).all()])
 
        c.repo_groups = sorted(c.repo_groups,
 
                               key=lambda t: t[1].split('&raquo;')[0])
 
        c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
 
        c.users_array = repo_model.get_users_js()
 
        c.users_groups_array = repo_model.get_users_groups_js()
 

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

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

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

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

	
 
            return redirect(url('repos'))
 

	
 
        c.default_user_id = User.by_username('default').user_id
 
        c.default_user_id = User.get_by_username('default').user_id
 
        c.in_public_journal = self.sa.query(UserFollowing)\
 
            .filter(UserFollowing.user_id == c.default_user_id)\
 
            .filter(UserFollowing.follows_repository == c.repo_info).scalar()
 

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

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

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

	
 
        defaults = c.repo_info.get_dict()
 
        group, repo_name = c.repo_info.groups_and_repo
 
        defaults['repo_name'] = repo_name
 
        defaults['repo_group'] = getattr(group[-1] if group else None,
 
                                         'group_id', None)
 

	
 
        #fill owner
 
        if c.repo_info.user:
 
            defaults.update({'user': c.repo_info.user.username})
 
        else:
 
            replacement_user = self.sa.query(User)\
 
            .filter(User.admin == True).first().username
 
            defaults.update({'user': replacement_user})
 

	
 
        #fill repository users
 
        for p in c.repo_info.repo_to_perm:
 
            defaults.update({'u_perm_%s' % p.user.username:
 
                             p.permission.permission_name})
 

	
 
        #fill repository groups
 
        for p in c.repo_info.users_group_to_perm:
 
            defaults.update({'g_perm_%s' % p.users_group.users_group_name:
 
                             p.permission.permission_name})
 

	
 
        return defaults
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def index(self, format='html'):
 
        """GET /repos: All items in the collection"""
 
        # url('repos')
 

	
 
        c.repos_list = ScmModel().get_repos(Repository.query()
 
                                            .order_by(Repository.repo_name)
 
                                            .all(), sort_key='name_sort')
 
        return render('admin/repos/repos.html')
 

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

	
 
            if request.POST.get('user_created'):
 
                #created by regular non admin user
 
                action_logger(self.rhodecode_user, 'user_created_repo',
 
                              form_result['repo_name_full'], '', self.sa)
 
            else:
 
                action_logger(self.rhodecode_user, 'admin_created_repo',
 
                              form_result['repo_name_full'], '', self.sa)
 

	
 
        except formencode.Invalid, errors:
 

	
 
            c.new_repo = errors.value['repo_name']
 

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

	
 
            return htmlfill.render(
 
                r,
 
                defaults=errors.value,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
@@ -288,144 +288,144 @@ class ReposController(BaseController):
 

	
 
        except IntegrityError, e:
 
            if e.message.find('repositories_fork_id_fkey'):
 
                log.error(traceback.format_exc())
 
                h.flash(_('Cannot delete %s it still contains attached '
 
                          'forks') % repo_name,
 
                        category='warning')
 
            else:
 
                log.error(traceback.format_exc())
 
                h.flash(_('An error occurred during '
 
                          'deletion of %s') % repo_name,
 
                        category='error')
 

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

	
 
        return redirect(url('repos'))
 

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

	
 
        :param repo_name:
 
        """
 

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

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def delete_perm_users_group(self, repo_name):
 
        """
 
        DELETE an existing repository permission users group
 

	
 
        :param repo_name:
 
        """
 
        try:
 
            repo_model = RepoModel()
 
            repo_model.delete_perm_users_group(request.POST, repo_name)
 
        except Exception, e:
 
            h.flash(_('An error occurred during deletion of repository'
 
                      ' users groups'),
 
                    category='error')
 
            raise HTTPInternalServerError()
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def repo_stats(self, repo_name):
 
        """
 
        DELETE an existing repository statistics
 

	
 
        :param repo_name:
 
        """
 

	
 
        try:
 
            repo_model = RepoModel()
 
            repo_model.delete_stats(repo_name)
 
        except Exception, e:
 
            h.flash(_('An error occurred during deletion of repository stats'),
 
                    category='error')
 
        return redirect(url('edit_repo', repo_name=repo_name))
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def repo_cache(self, repo_name):
 
        """
 
        INVALIDATE existing repository cache
 

	
 
        :param repo_name:
 
        """
 

	
 
        try:
 
            ScmModel().mark_for_invalidation(repo_name)
 
        except Exception, e:
 
            h.flash(_('An error occurred during cache invalidation'),
 
                    category='error')
 
        return redirect(url('edit_repo', repo_name=repo_name))
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def repo_public_journal(self, repo_name):
 
        """
 
        Set's this repository to be visible in public journal,
 
        in other words assing default user to follow this repo
 

	
 
        :param repo_name:
 
        """
 

	
 
        cur_token = request.POST.get('auth_token')
 
        token = get_token()
 
        if cur_token == token:
 
            try:
 
                repo_id = Repository.by_repo_name(repo_name).repo_id
 
                user_id = User.by_username('default').user_id
 
                repo_id = Repository.get_by_repo_name(repo_name).repo_id
 
                user_id = User.get_by_username('default').user_id
 
                self.scm_model.toggle_following_repo(repo_id, user_id)
 
                h.flash(_('Updated repository visibility in public journal'),
 
                        category='success')
 
            except:
 
                h.flash(_('An error occurred during setting this'
 
                          ' repository in public journal'),
 
                        category='error')
 

	
 
        else:
 
            h.flash(_('Token mismatch'), category='error')
 
        return redirect(url('edit_repo', repo_name=repo_name))
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def repo_pull(self, repo_name):
 
        """
 
        Runs task to update given repository with remote changes,
 
        ie. make pull on remote location
 

	
 
        :param repo_name:
 
        """
 
        try:
 
            ScmModel().pull_changes(repo_name, self.rhodecode_user.username)
 
            h.flash(_('Pulled from remote location'), category='success')
 
        except Exception, e:
 
            h.flash(_('An error occurred during pull from remote location'),
 
                    category='error')
 

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

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

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def edit(self, repo_name, format='html'):
 
        """GET /repos/repo_name/edit: Form to edit an existing item"""
 
        # url('edit_repo', repo_name=ID)
 
        defaults = self.__load_data(repo_name)
 

	
 
        return htmlfill.render(
 
            render('admin/repos/repo_edit.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False
 
        )
rhodecode/controllers/login.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.login
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Login controller for rhodeocode
 

	
 
    :created_on: Apr 22, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
import logging
 
import formencode
 

	
 
from formencode import htmlfill
 

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

	
 
import rhodecode.lib.helpers as h
 
from rhodecode.lib.auth import AuthUser, HasPermissionAnyDecorator
 
from rhodecode.lib.base import BaseController, render
 
from rhodecode.model.db import User
 
from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm
 
from rhodecode.model.user import UserModel
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class LoginController(BaseController):
 

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

	
 
    def index(self):
 
        #redirect if already logged in
 
        c.came_from = request.GET.get('came_from', None)
 

	
 
        if self.rhodecode_user.is_authenticated \
 
                            and self.rhodecode_user.username != 'default':
 

	
 
            return redirect(url('home'))
 

	
 
        if request.POST:
 
            #import Login Form validator class
 
            login_form = LoginForm()
 
            try:
 
                c.form_result = login_form.to_python(dict(request.POST))
 
                #form checks for username/password, now we're authenticated
 
                username = c.form_result['username']
 
                user = User.by_username(username,
 
                                                   case_insensitive=True)
 
                user = User.get_by_username(username, case_insensitive=True)
 
                auth_user = AuthUser(user.user_id)
 
                auth_user.set_authenticated()
 
                session['rhodecode_user'] = auth_user
 
                session.save()
 

	
 
                log.info('user %s is now authenticated and stored in session',
 
                         username)
 
                user.update_lastlogin()
 

	
 
                if c.came_from:
 
                    return redirect(c.came_from)
 
                else:
 
                    return redirect(url('home'))
 

	
 
            except formencode.Invalid, errors:
 
                return htmlfill.render(
 
                    render('/login.html'),
 
                    defaults=errors.value,
 
                    errors=errors.error_dict or {},
 
                    prefix_error=False,
 
                    encoding="UTF-8")
 

	
 
        return render('/login.html')
 

	
 
    @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate',
 
                               'hg.register.manual_activate')
 
    def register(self):
 
        user_model = UserModel()
 
        c.auto_active = False
 
        for perm in user_model.get_by_username('default',
 
                                               cache=False).user_perms:
 
        for perm in User.get_by_username('default').user_perms:
 
            if perm.permission.permission_name == 'hg.register.auto_activate':
 
                c.auto_active = True
 
                break
 

	
 
        if request.POST:
 

	
 
            register_form = RegisterForm()()
 
            try:
 
                form_result = register_form.to_python(dict(request.POST))
 
                form_result['active'] = c.auto_active
 
                user_model.create_registration(form_result)
 
                h.flash(_('You have successfully registered into rhodecode'),
 
                            category='success')
 
                return redirect(url('login_home'))
 

	
 
            except formencode.Invalid, errors:
 
                return htmlfill.render(
 
                    render('/register.html'),
 
                    defaults=errors.value,
 
                    errors=errors.error_dict or {},
 
                    prefix_error=False,
 
                    encoding="UTF-8")
 

	
 
        return render('/register.html')
 

	
 
    def password_reset(self):
 
        user_model = UserModel()
 
        if request.POST:
 

	
 
            password_reset_form = PasswordResetForm()()
 
            try:
 
                form_result = password_reset_form.to_python(dict(request.POST))
 
                user_model.reset_password_link(form_result)
 
                h.flash(_('Your password reset link was sent'),
 
                            category='success')
 
                return redirect(url('login_home'))
 

	
 
            except formencode.Invalid, errors:
 
                return htmlfill.render(
 
                    render('/password_reset.html'),
 
                    defaults=errors.value,
 
                    errors=errors.error_dict or {},
 
                    prefix_error=False,
 
                    encoding="UTF-8")
 

	
 
        return render('/password_reset.html')
 

	
 
    def password_reset_confirmation(self):
 

	
 
        if request.GET and request.GET.get('key'):
 
            try:
 
                user_model = UserModel()
 
                user = User.get_by_api_key(request.GET.get('key'))
 
                data = dict(email=user.email)
 
                user_model.reset_password(data)
 
                h.flash(_('Your password reset was successful, '
 
                          'new password has been sent to your email'),
 
                            category='success')
 
            except Exception, e:
 
                log.error(e)
 
                return redirect(url('reset_password'))
 

	
 
        return redirect(url('login_home'))
 

	
 
    def logout(self):
 
        del session['rhodecode_user']
 
        session.save()
 
        log.info('Logging out and setting user as Empty')
 
        redirect(url('home'))
rhodecode/lib/auth.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.auth
 
    ~~~~~~~~~~~~~~~~~~
 

	
 
    authentication and permission libraries
 

	
 
    :created_on: Apr 4, 2010
 
    :copyright: (c) 2010 by marcink.
 
    :license: LICENSE_NAME, see LICENSE_FILE for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
import random
 
import logging
 
import traceback
 
import hashlib
 

	
 
from tempfile import _RandomNameSequence
 
from decorator import decorator
 

	
 
from pylons import config, session, url, request
 
from pylons.controllers.util import abort, redirect
 
from pylons.i18n.translation import _
 

	
 
from rhodecode import __platform__, PLATFORM_WIN, PLATFORM_OTHERS
 

	
 
if __platform__ in PLATFORM_WIN:
 
    from hashlib import sha256
 
if __platform__ in PLATFORM_OTHERS:
 
    import bcrypt
 

	
 
from rhodecode.lib import str2bool, safe_unicode
 
from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError
 
from rhodecode.lib.utils import get_repo_slug
 
from rhodecode.lib.auth_ldap import AuthLdap
 

	
 
from rhodecode.model import meta
 
from rhodecode.model.user import UserModel
 
from rhodecode.model.db import Permission, RhodeCodeSettings
 
from rhodecode.model.db import Permission, RhodeCodeSettings, User
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class PasswordGenerator(object):
 
    """This is a simple class for generating password from
 
        different sets of characters
 
        usage:
 
        passwd_gen = PasswordGenerator()
 
        #print 8-letter password containing only big and small letters
 
            of alphabet
 
        print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
 
    """
 
    ALPHABETS_NUM = r'''1234567890'''
 
    ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''
 
    ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''
 
    ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?'''
 
    ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \
 
        + ALPHABETS_NUM + ALPHABETS_SPECIAL
 
    ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM
 
    ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
 
    ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM
 
    ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM
 

	
 
    def __init__(self, passwd=''):
 
        self.passwd = passwd
 

	
 
    def gen_password(self, len, type):
 
        self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
 
        return self.passwd
 

	
 

	
 
class RhodeCodeCrypto(object):
 

	
 
    @classmethod
 
    def hash_string(cls, str_):
 
        """
 
        Cryptographic function used for password hashing based on pybcrypt
 
        or pycrypto in windows
 

	
 
        :param password: password to hash
 
        """
 
        if __platform__ in PLATFORM_WIN:
 
            return sha256(str_).hexdigest()
 
        elif __platform__ in PLATFORM_OTHERS:
 
            return bcrypt.hashpw(str_, bcrypt.gensalt(10))
 
        else:
 
            raise Exception('Unknown or unsupported platform %s' \
 
                            % __platform__)
 

	
 
    @classmethod
 
    def hash_check(cls, password, hashed):
 
        """
 
        Checks matching password with it's hashed value, runs different
 
        implementation based on platform it runs on
 

	
 
        :param password: password
 
        :param hashed: password in hashed form
 
        """
 

	
 
        if __platform__ in PLATFORM_WIN:
 
            return sha256(password).hexdigest() == hashed
 
        elif __platform__ in PLATFORM_OTHERS:
 
            return bcrypt.hashpw(password, hashed) == hashed
 
        else:
 
            raise Exception('Unknown or unsupported platform %s' \
 
                            % __platform__)
 

	
 

	
 
def get_crypt_password(password):
 
    return RhodeCodeCrypto.hash_string(password)
 

	
 

	
 
def check_password(password, hashed):
 
    return RhodeCodeCrypto.hash_check(password, hashed)
 

	
 

	
 
def generate_api_key(username, salt=None):
 
    if salt is None:
 
        salt = _RandomNameSequence().next()
 

	
 
    return hashlib.sha1(username + salt).hexdigest()
 

	
 

	
 
def authfunc(environ, username, password):
 
    """Dummy authentication function used in Mercurial/Git/ and access control,
 

	
 
    :param environ: needed only for using in Basic auth
 
    """
 
    return authenticate(username, password)
 

	
 

	
 
def authenticate(username, password):
 
    """Authentication function used for access control,
 
    firstly checks for db authentication then if ldap is enabled for ldap
 
    authentication, also creates ldap user if not in database
 

	
 
    :param username: username
 
    :param password: password
 
    """
 

	
 
    user_model = UserModel()
 
    user = user_model.get_by_username(username, cache=False)
 
    user = User.get_by_username(username)
 

	
 
    log.debug('Authenticating user using RhodeCode account')
 
    if user is not None and not user.ldap_dn:
 
        if user.active:
 
            if user.username == 'default' and user.active:
 
                log.info('user %s authenticated correctly as anonymous user',
 
                         username)
 
                return True
 

	
 
            elif user.username == username and check_password(password,
 
                                                              user.password):
 
                log.info('user %s authenticated correctly', username)
 
                return True
 
        else:
 
            log.warning('user %s is disabled', username)
 

	
 
    else:
 
        log.debug('Regular authentication failed')
 
        user_obj = user_model.get_by_username(username, cache=False,
 
                                            case_insensitive=True)
 
        user_obj = User.get_by_username(username, case_insensitive=True)
 

	
 
        if user_obj is not None and not user_obj.ldap_dn:
 
            log.debug('this user already exists as non ldap')
 
            return False
 

	
 
        ldap_settings = RhodeCodeSettings.get_ldap_settings()
 
        #======================================================================
 
        # FALLBACK TO LDAP AUTH IF ENABLE
 
        #======================================================================
 
        if str2bool(ldap_settings.get('ldap_active')):
 
            log.debug("Authenticating user using ldap")
 
            kwargs = {
 
                  'server': ldap_settings.get('ldap_host', ''),
 
                  'base_dn': ldap_settings.get('ldap_base_dn', ''),
 
                  'port': ldap_settings.get('ldap_port'),
 
                  'bind_dn': ldap_settings.get('ldap_dn_user'),
 
                  'bind_pass': ldap_settings.get('ldap_dn_pass'),
 
                  'tls_kind': ldap_settings.get('ldap_tls_kind'),
 
                  'tls_reqcert': ldap_settings.get('ldap_tls_reqcert'),
 
                  'ldap_filter': ldap_settings.get('ldap_filter'),
 
                  'search_scope': ldap_settings.get('ldap_search_scope'),
 
                  'attr_login': ldap_settings.get('ldap_attr_login'),
 
                  'ldap_version': 3,
 
                  }
 
            log.debug('Checking for ldap authentication')
 
            try:
 
                aldap = AuthLdap(**kwargs)
 
                (user_dn, ldap_attrs) = aldap.authenticate_ldap(username,
 
                                                                password)
 
                log.debug('Got ldap DN response %s', user_dn)
 

	
 
                get_ldap_attr = lambda k: ldap_attrs.get(ldap_settings\
 
                                                           .get(k), [''])[0]
 

	
 
                user_attrs = {
 
                 'name': safe_unicode(get_ldap_attr('ldap_attr_firstname')),
 
                 'lastname': safe_unicode(get_ldap_attr('ldap_attr_lastname')),
 
                 'email': get_ldap_attr('ldap_attr_email'),
 
                }
 

	
 
                if user_model.create_ldap(username, password, user_dn,
 
                                          user_attrs):
 
                    log.info('created new ldap user %s', username)
 

	
 
                return True
 
            except (LdapUsernameError, LdapPasswordError,):
 
                pass
 
            except (Exception,):
 
                log.error(traceback.format_exc())
 
                pass
 
    return False
 

	
 

	
 
class  AuthUser(object):
 
    """
 
    A simple object that handles all attributes of user in RhodeCode
 

	
 
    It does lookup based on API key,given user, or user present in session
 
    Then it fills all required information for such user. It also checks if
 
    anonymous access is enabled and if so, it returns default user as logged
 
    in
 
    """
 

	
 
    def __init__(self, user_id=None, api_key=None):
 

	
 
        self.user_id = user_id
 
        self.api_key = None
 

	
 
        self.username = 'None'
 
        self.name = ''
 
        self.lastname = ''
 
        self.email = ''
 
        self.is_authenticated = False
 
        self.admin = False
 
        self.permissions = {}
 
        self._api_key = api_key
 
        self.propagate_data()
 

	
 
    def propagate_data(self):
 
        user_model = UserModel()
 
        self.anonymous_user = user_model.get_by_username('default', cache=True)
 
        self.anonymous_user = User.get_by_username('default')
 
        if self._api_key and self._api_key != self.anonymous_user.api_key:
 
            #try go get user by api key
 
            log.debug('Auth User lookup by API KEY %s', self._api_key)
 
            user_model.fill_data(self, api_key=self._api_key)
 
        else:
 
            log.debug('Auth User lookup by USER ID %s', self.user_id)
 
            if self.user_id is not None \
 
                and self.user_id != self.anonymous_user.user_id:
 
                user_model.fill_data(self, user_id=self.user_id)
 
            else:
 
                if self.anonymous_user.active is True:
 
                    user_model.fill_data(self,
 
                                         user_id=self.anonymous_user.user_id)
 
                    #then we set this user is logged in
 
                    self.is_authenticated = True
 
                else:
 
                    self.is_authenticated = False
 

	
 
        log.debug('Auth User is now %s', self)
 
        user_model.fill_perms(self)
 

	
 
    @property
 
    def is_admin(self):
 
        return self.admin
 

	
 
    @property
 
    def full_contact(self):
 
        return '%s %s <%s>' % (self.name, self.lastname, self.email)
 

	
 
    def __repr__(self):
 
        return "<AuthUser('id:%s:%s|%s')>" % (self.user_id, self.username,
 
                                              self.is_authenticated)
 

	
 
    def set_authenticated(self, authenticated=True):
 

	
 
        if self.user_id != self.anonymous_user.user_id:
 
            self.is_authenticated = authenticated
 

	
 

	
 
def set_available_permissions(config):
 
    """This function will propagate pylons globals with all available defined
 
    permission given in db. We don't want to check each time from db for new
 
    permissions since adding a new permission also requires application restart
 
    ie. to decorate new views with the newly created permission
 

	
 
    :param config: current pylons config instance
 

	
 
    """
 
    log.info('getting information about all available permissions')
 
    try:
 
        sa = meta.Session()
 
        all_perms = sa.query(Permission).all()
 
    except:
 
        pass
 
    finally:
 
        meta.Session.remove()
 

	
 
    config['available_permissions'] = [x.permission_name for x in all_perms]
 

	
 

	
 
#==============================================================================
 
# CHECK DECORATORS
 
#==============================================================================
 
class LoginRequired(object):
 
    """
 
    Must be logged in to execute this function else
 
    redirect to login page
 

	
 
    :param api_access: if enabled this checks only for valid auth token
 
        and grants access based on valid token
 
    """
 

	
 
    def __init__(self, api_access=False):
 
        self.api_access = api_access
 

	
 
    def __call__(self, func):
 
        return decorator(self.__wrapper, func)
 

	
 
    def __wrapper(self, func, *fargs, **fkwargs):
 
        cls = fargs[0]
 
        user = cls.rhodecode_user
 

	
 
        api_access_ok = False
 
        if self.api_access:
 
            log.debug('Checking API KEY access for %s', cls)
 
            if user.api_key == request.GET.get('api_key'):
 
                api_access_ok = True
 
            else:
 
                log.debug("API KEY token not valid")
 

	
 
        log.debug('Checking if %s is authenticated @ %s', user.username, cls)
 
        if user.is_authenticated or api_access_ok:
 
            log.debug('user %s is authenticated', user.username)
 
            return func(*fargs, **fkwargs)
 
        else:
 
            log.warn('user %s NOT authenticated', user.username)
rhodecode/lib/base.py
Show inline comments
 
"""The base Controller API
 

	
 
Provides the BaseController class for subclassing.
 
"""
 
import logging
 

	
 
from pylons import config, tmpl_context as c, request, session, url
 
from pylons.controllers import WSGIController
 
from pylons.controllers.util import redirect
 
from pylons.templating import render_mako as render
 

	
 
from rhodecode import __version__
 
from rhodecode.lib.auth import AuthUser
 
from rhodecode.lib.utils import get_repo_slug
 
from rhodecode.model import meta
 
from rhodecode.model.scm import ScmModel
 
from rhodecode import BACKENDS
 
from rhodecode.model.db import Repository
 

	
 
log = logging.getLogger(__name__)
 

	
 
class BaseController(WSGIController):
 

	
 
    def __before__(self):
 
        c.rhodecode_version = __version__
 
        c.rhodecode_name = config.get('rhodecode_title')
 
        c.ga_code = config.get('rhodecode_ga_code')
 
        c.repo_name = get_repo_slug(request)
 
        c.backends = BACKENDS.keys()
 
        self.cut_off_limit = int(config.get('cut_off_limit'))
 

	
 
        self.sa = meta.Session()
 
        self.scm_model = ScmModel(self.sa)
 

	
 
        #c.unread_journal = scm_model.get_unread_journal()
 

	
 
    def __call__(self, environ, start_response):
 
        """Invoke the Controller"""
 
        # WSGIController.__call__ dispatches to the Controller method
 
        # the request is routed to. This routing information is
 
        # available in environ['pylons.routes_dict']
 
        try:
 
            # putting this here makes sure that we update permissions each time
 
            api_key = request.GET.get('api_key')
 
            user_id = getattr(session.get('rhodecode_user'), 'user_id', None)
 
            self.rhodecode_user = c.rhodecode_user = AuthUser(user_id, api_key)
 
            self.rhodecode_user.set_authenticated(
 
                                        getattr(session.get('rhodecode_user'),
 
                                       'is_authenticated', False))
 
            session['rhodecode_user'] = self.rhodecode_user
 
            session.save()
 
            return WSGIController.__call__(self, environ, start_response)
 
        finally:
 
            meta.Session.remove()
 

	
 

	
 
class BaseRepoController(BaseController):
 
    """
 
    Base class for controllers responsible for loading all needed data
 
    for those controllers, loaded items are
 

	
 
    c.rhodecode_repo: instance of scm repository (taken from cache)
 

	
 
    """
 

	
 
    def __before__(self):
 
        super(BaseRepoController, self).__before__()
 
        if c.repo_name:
 

	
 
            c.rhodecode_db_repo = Repository.by_repo_name(c.repo_name)
 
            c.rhodecode_db_repo = Repository.get_by_repo_name(c.repo_name)
 
            c.rhodecode_repo = c.rhodecode_db_repo.scm_instance
 

	
 
            if c.rhodecode_repo is None:
 
                log.error('%s this repository is present in database but it '
 
                          'cannot be created as an scm instance', c.repo_name)
 

	
 
                redirect(url('home'))
 

	
 
            c.repository_followers = \
 
                self.scm_model.get_followers(c.repo_name)
 
            c.repository_forks = self.scm_model.get_forks(c.repo_name)
 

	
rhodecode/lib/middleware/simplegit.py
Show inline comments
 
@@ -169,121 +169,121 @@ class SimpleGit(object):
 
                        user = self.__get_user(username)
 
                        username = user.username
 
                    except:
 
                        log.error(traceback.format_exc())
 
                        return HTTPInternalServerError()(environ,
 
                                                         start_response)
 

	
 
                    #check permissions for this repository
 
                    perm = self.__check_permission(action, user,
 
                                                   repo_name)
 
                    if perm is not True:
 
                        return HTTPForbidden()(environ, start_response)
 

	
 
        extras = {'ip': ipaddr,
 
                  'username': username,
 
                  'action': action,
 
                  'repository': repo_name}
 

	
 
        #===================================================================
 
        # GIT REQUEST HANDLING
 
        #===================================================================
 

	
 
        repo_path = safe_str(os.path.join(self.basepath, repo_name))
 
        log.debug('Repository path is %s' % repo_path)
 

	
 
        # quick check if that dir exists...
 
        if is_valid_repo(repo_name, self.basepath) is False:
 
            return HTTPNotFound()(environ, start_response)
 

	
 
        try:
 
            #invalidate cache on push
 
            if action == 'push':
 
                self.__invalidate_cache(repo_name)
 

	
 
            app = self.__make_app(repo_name, repo_path)
 
            return app(environ, start_response)
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            return HTTPInternalServerError()(environ, start_response)
 

	
 
    def __make_app(self, repo_name, repo_path):
 
        """
 
        Make an wsgi application using dulserver
 
        
 
        :param repo_name: name of the repository
 
        :param repo_path: full path to the repository
 
        """
 

	
 
        _d = {'/' + repo_name: Repo(repo_path)}
 
        backend = dulserver.DictBackend(_d)
 
        gitserve = HTTPGitApplication(backend)
 

	
 
        return gitserve
 

	
 
    def __check_permission(self, action, user, repo_name):
 
        """
 
        Checks permissions using action (push/pull) user and repository
 
        name
 

	
 
        :param action: push or pull action
 
        :param user: user instance
 
        :param repo_name: repository name
 
        """
 
        if action == 'push':
 
            if not HasPermissionAnyMiddleware('repository.write',
 
                                              'repository.admin')(user,
 
                                                                  repo_name):
 
                return False
 

	
 
        else:
 
            #any other action need at least read permission
 
            if not HasPermissionAnyMiddleware('repository.read',
 
                                              'repository.write',
 
                                              'repository.admin')(user,
 
                                                                  repo_name):
 
                return False
 

	
 
        return True
 

	
 
    def __get_repository(self, environ):
 
        """
 
        Get's repository name out of PATH_INFO header
 

	
 
        :param environ: environ where PATH_INFO is stored
 
        """
 
        try:
 
            repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
 
            if repo_name.endswith('/'):
 
                repo_name = repo_name.rstrip('/')
 
        except:
 
            log.error(traceback.format_exc())
 
            raise
 
        repo_name = repo_name.split('/')[0]
 
        return repo_name
 

	
 
    def __get_user(self, username):
 
        return User.by_username(username)
 
        return User.get_by_username(username)
 

	
 
    def __get_action(self, environ):
 
        """Maps git request commands into a pull or push command.
 

	
 
        :param environ:
 
        """
 
        service = environ['QUERY_STRING'].split('=')
 
        if len(service) > 1:
 
            service_cmd = service[1]
 
            mapping = {'git-receive-pack': 'push',
 
                       'git-upload-pack': 'pull',
 
                       }
 

	
 
            return mapping.get(service_cmd,
 
                               service_cmd if service_cmd else 'other')
 
        else:
 
            return 'other'
 

	
 
    def __invalidate_cache(self, repo_name):
 
        """we know that some change was made to repositories and we should
 
        invalidate the cache to see the changes right away but only for
 
        push requests"""
 
        invalidate_cache('get_repo_cached_%s' % repo_name)
 

	
rhodecode/lib/middleware/simplehg.py
Show inline comments
 
@@ -136,153 +136,153 @@ class SimpleHg(object):
 
                        username = user.username
 
                    except:
 
                        log.error(traceback.format_exc())
 
                        return HTTPInternalServerError()(environ,
 
                                                         start_response)
 

	
 
                    #check permissions for this repository
 
                    perm = self.__check_permission(action, user,
 
                                                   repo_name)
 
                    if perm is not True:
 
                        return HTTPForbidden()(environ, start_response)
 

	
 
        extras = {'ip': ipaddr,
 
                  'username': username,
 
                  'action': action,
 
                  'repository': repo_name}
 

	
 
        #======================================================================
 
        # MERCURIAL REQUEST HANDLING
 
        #======================================================================
 

	
 
        repo_path = safe_str(os.path.join(self.basepath, repo_name))
 
        log.debug('Repository path is %s' % repo_path)
 

	
 
        baseui = make_ui('db')
 
        self.__inject_extras(repo_path, baseui, extras)
 

	
 

	
 
        # quick check if that dir exists...
 
        if is_valid_repo(repo_name, self.basepath) is False:
 
            return HTTPNotFound()(environ, start_response)
 

	
 
        try:
 
            #invalidate cache on push
 
            if action == 'push':
 
                self.__invalidate_cache(repo_name)
 

	
 
            app = self.__make_app(repo_path, baseui, extras)
 
            return app(environ, start_response)
 
        except RepoError, e:
 
            if str(e).find('not found') != -1:
 
                return HTTPNotFound()(environ, start_response)
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            return HTTPInternalServerError()(environ, start_response)
 

	
 
    def __make_app(self, repo_name, baseui, extras):
 
        """
 
        Make an wsgi application using hgweb, and inject generated baseui
 
        instance, additionally inject some extras into ui object
 
        """
 
        return hgweb_mod.hgweb(repo_name, name=repo_name, baseui=baseui)
 

	
 

	
 
    def __check_permission(self, action, user, repo_name):
 
        """
 
        Checks permissions using action (push/pull) user and repository
 
        name
 

	
 
        :param action: push or pull action
 
        :param user: user instance
 
        :param repo_name: repository name
 
        """
 
        if action == 'push':
 
            if not HasPermissionAnyMiddleware('repository.write',
 
                                              'repository.admin')(user,
 
                                                                  repo_name):
 
                return False
 

	
 
        else:
 
            #any other action need at least read permission
 
            if not HasPermissionAnyMiddleware('repository.read',
 
                                              'repository.write',
 
                                              'repository.admin')(user,
 
                                                                  repo_name):
 
                return False
 

	
 
        return True
 

	
 
    def __get_repository(self, environ):
 
        """
 
        Get's repository name out of PATH_INFO header
 

	
 
        :param environ: environ where PATH_INFO is stored
 
        """
 
        try:
 
            repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
 
            if repo_name.endswith('/'):
 
                repo_name = repo_name.rstrip('/')
 
        except:
 
            log.error(traceback.format_exc())
 
            raise
 

	
 
        return repo_name
 

	
 
    def __get_user(self, username):
 
        return User.by_username(username)
 
        return User.get_by_username(username)
 

	
 
    def __get_action(self, environ):
 
        """
 
        Maps mercurial request commands into a clone,pull or push command.
 
        This should always return a valid command string
 

	
 
        :param environ:
 
        """
 
        mapping = {'changegroup': 'pull',
 
                   'changegroupsubset': 'pull',
 
                   'stream_out': 'pull',
 
                   'listkeys': 'pull',
 
                   'unbundle': 'push',
 
                   'pushkey': 'push', }
 
        for qry in environ['QUERY_STRING'].split('&'):
 
            if qry.startswith('cmd'):
 
                cmd = qry.split('=')[-1]
 
                if cmd in mapping:
 
                    return mapping[cmd]
 
                else:
 
                    return 'pull'
 

	
 
    def __invalidate_cache(self, repo_name):
 
        """we know that some change was made to repositories and we should
 
        invalidate the cache to see the changes right away but only for
 
        push requests"""
 
        invalidate_cache('get_repo_cached_%s' % repo_name)
 

	
 
    def __inject_extras(self, repo_path, baseui, extras={}):
 
        """
 
        Injects some extra params into baseui instance
 
        
 
        also overwrites global settings with those takes from local hgrc file
 
        
 
        :param baseui: baseui instance
 
        :param extras: dict with extra params to put into baseui
 
        """
 

	
 
        hgrc = os.path.join(repo_path, '.hg', 'hgrc')
 

	
 
        # make our hgweb quiet so it doesn't print output
 
        baseui.setconfig('ui', 'quiet', 'true')
 

	
 
        #inject some additional parameters that will be available in ui
 
        #for hooks
 
        for k, v in extras.items():
 
            baseui.setconfig('rhodecode_extras', k, v)
 

	
 
        repoui = make_ui('file', hgrc, False)
 

	
 
        if repoui:
 
            #overwrite our ui instance with the section from hgrc file
 
            for section in ui_sections:
 
                for k, v in repoui.configitems(section):
 
                    baseui.setconfig(section, k, v)
 

	
rhodecode/lib/utils.py
Show inline comments
 
@@ -19,193 +19,193 @@
 
# 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 os
 
import logging
 
import datetime
 
import traceback
 
import paste
 
import beaker
 
from os.path import dirname as dn, join as jn
 

	
 
from paste.script.command import Command, BadCommand
 

	
 
from mercurial import ui, config
 

	
 
from webhelpers.text import collapse, remove_formatting, strip_tags
 

	
 
from vcs import get_backend
 
from vcs.backends.base import BaseChangeset
 
from vcs.utils.lazy import LazyProperty
 
from vcs.utils.helpers import get_scm
 
from vcs.exceptions import VCSError
 

	
 
from rhodecode.model import meta
 
from rhodecode.model.caching_query import FromCache
 
from rhodecode.model.db import Repository, User, RhodeCodeUi, UserLog, Group, \
 
    RhodeCodeSettings
 
from rhodecode.model.repo import RepoModel
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
def recursive_replace(str, replace=' '):
 
    """Recursive replace of given sign to just one instance
 

	
 
    :param str: given string
 
    :param replace: char to find and replace multiple instances
 

	
 
    Examples::
 
    >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
 
    'Mighty-Mighty-Bo-sstones'
 
    """
 

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

	
 

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

	
 
    slug = remove_formatting(value)
 
    slug = strip_tags(slug)
 

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

	
 

	
 
def get_repo_slug(request):
 
    return request.environ['pylons.routes_dict'].get('repo_name')
 

	
 

	
 
def action_logger(user, action, repo, ipaddr='', sa=None):
 
    """
 
    Action logger for various actions made by users
 

	
 
    :param user: user that made this action, can be a unique username string or
 
        object containing user_id attribute
 
    :param action: action to log, should be on of predefined unique actions for
 
        easy translations
 
    :param repo: string name of repository or object containing repo_id,
 
        that action was made on
 
    :param ipaddr: optional ip address from what the action was made
 
    :param sa: optional sqlalchemy session
 

	
 
    """
 

	
 
    if not sa:
 
        sa = meta.Session()
 

	
 
    try:
 
        if hasattr(user, 'user_id'):
 
            user_obj = user
 
        elif isinstance(user, basestring):
 
            user_obj = User.by_username(user)
 
            user_obj = User.get_by_username(user)
 
        else:
 
            raise Exception('You have to provide user object or username')
 

	
 
        rm = RepoModel()
 
        if hasattr(repo, 'repo_id'):
 
            repo_obj = rm.get(repo.repo_id, cache=False)
 
            repo_name = repo_obj.repo_name
 
        elif  isinstance(repo, basestring):
 
            repo_name = repo.lstrip('/')
 
            repo_obj = rm.get_by_repo_name(repo_name, cache=False)
 
        else:
 
            raise Exception('You have to provide repository to action logger')
 

	
 
        user_log = UserLog()
 
        user_log.user_id = user_obj.user_id
 
        user_log.action = action
 

	
 
        user_log.repository_id = repo_obj.repo_id
 
        user_log.repository_name = repo_name
 

	
 
        user_log.action_date = datetime.datetime.now()
 
        user_log.user_ip = ipaddr
 
        sa.add(user_log)
 
        sa.commit()
 

	
 
        log.info('Adding user %s, action %s on %s', user_obj, action, repo)
 
    except:
 
        log.error(traceback.format_exc())
 
        sa.rollback()
 

	
 

	
 
def get_repos(path, recursive=False):
 
    """
 
    Scans given path for repos and return (name,(type,path)) tuple
 

	
 
    :param path: path to scann for repositories
 
    :param recursive: recursive search and return names with subdirs in front
 
    """
 
    from vcs.utils.helpers import get_scm
 
    from vcs.exceptions import VCSError
 

	
 
    if path.endswith(os.sep):
 
        #remove ending slash for better results
 
        path = path[:-1]
 

	
 
    def _get_repos(p):
 
        if not os.access(p, os.W_OK):
 
            return
 
        for dirpath in os.listdir(p):
 
            if os.path.isfile(os.path.join(p, dirpath)):
 
                continue
 
            cur_path = os.path.join(p, dirpath)
 
            try:
 
                scm_info = get_scm(cur_path)
 
                yield scm_info[1].split(path)[-1].lstrip(os.sep), scm_info
 
            except VCSError:
 
                if not recursive:
 
                    continue
 
                #check if this dir containts other repos for recursive scan
 
                rec_path = os.path.join(p, dirpath)
 
                if os.path.isdir(rec_path):
 
                    for inner_scm in _get_repos(rec_path):
 
                        yield inner_scm
 

	
 
    return _get_repos(path)
 

	
 

	
 
def is_valid_repo(repo_name, base_path):
 
    """
 
    Returns True if given path is a valid repository False otherwise
 
    :param repo_name:
 
    :param base_path:
 

	
 
    :return True: if given path is a valid repository
 
    """
 
    full_path = os.path.join(base_path, repo_name)
 

	
 
    try:
 
        get_scm(full_path)
 
        return True
 
    except VCSError:
 
        return False
 

	
 
def is_valid_repos_group(repos_group_name, base_path):
 
    """
 
    Returns True if given path is a repos group False otherwise
 
    
 
    :param repo_name:
 
    :param base_path:
 
    """
 
    full_path = os.path.join(base_path, repos_group_name)
 

	
 
    # check if it's not a repo
 
    if is_valid_repo(repos_group_name, base_path):
 
        return False
 

	
rhodecode/model/db.py
Show inline comments
 
@@ -188,203 +188,202 @@ class RhodeCodeSettings(Base, BaseModel)
 

	
 

	
 
class RhodeCodeUi(Base, BaseModel):
 
    __tablename__ = 'rhodecode_ui'
 
    __table_args__ = (UniqueConstraint('ui_key'), {'extend_existing':True})
 

	
 
    HOOK_UPDATE = 'changegroup.update'
 
    HOOK_REPO_SIZE = 'changegroup.repo_size'
 
    HOOK_PUSH = 'pretxnchangegroup.push_logger'
 
    HOOK_PULL = 'preoutgoing.pull_logger'
 

	
 
    ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
 

	
 

	
 
    @classmethod
 
    def get_by_key(cls, key):
 
        return Session.query(cls).filter(cls.ui_key == key)
 

	
 

	
 
    @classmethod
 
    def get_builtin_hooks(cls):
 
        q = cls.query()
 
        q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE,
 
                                    cls.HOOK_REPO_SIZE,
 
                                    cls.HOOK_PUSH, cls.HOOK_PULL]))
 
        return q.all()
 

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

	
 
    @classmethod
 
    def create_or_update_hook(cls, key, val):
 
        new_ui = cls.get_by_key(key).scalar() or cls()
 
        new_ui.ui_section = 'hooks'
 
        new_ui.ui_active = True
 
        new_ui.ui_key = key
 
        new_ui.ui_value = val
 

	
 
        Session.add(new_ui)
 
        Session.commit()
 

	
 

	
 
class User(Base, BaseModel):
 
    __tablename__ = 'users'
 
    __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'extend_existing':True})
 
    user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    active = Column("active", Boolean(), nullable=True, unique=None, default=None)
 
    admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
 
    name = Column("name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
 
    ldap_dn = Column("ldap_dn", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 

	
 
    user_log = relationship('UserLog', cascade='all')
 
    user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
 

	
 
    repositories = relationship('Repository')
 
    user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
 
    repo_to_perm = relationship('RepoToPerm', primaryjoin='RepoToPerm.user_id==User.user_id', cascade='all')
 

	
 
    group_member = relationship('UsersGroupMember', cascade='all')
 

	
 
    @property
 
    def full_contact(self):
 
        return '%s %s <%s>' % (self.name, self.lastname, self.email)
 

	
 
    @property
 
    def short_contact(self):
 
        return '%s %s' % (self.name, self.lastname)
 

	
 
    @property
 
    def is_admin(self):
 
        return self.admin
 

	
 
    def __repr__(self):
 
        try:
 
            return "<%s('id:%s:%s')>" % (self.__class__.__name__,
 
                                             self.user_id, self.username)
 
        except:
 
            return self.__class__.__name__
 

	
 
    @classmethod
 
    def by_username(cls, username, case_insensitive=False):
 
    def get_by_username(cls, username, case_insensitive=False):
 
        if case_insensitive:
 
            return Session.query(cls).filter(cls.username.like(username)).one()
 
            return Session.query(cls).filter(cls.username.like(username)).scalar()
 
        else:
 
            return Session.query(cls).filter(cls.username == username).one()
 
            return Session.query(cls).filter(cls.username == username).scalar()
 

	
 
    @classmethod
 
    def get_by_api_key(cls, api_key):
 
        return Session.query(cls).filter(cls.api_key == api_key).one()
 

	
 

	
 
    def update_lastlogin(self):
 
        """Update user lastlogin"""
 

	
 
        self.last_login = datetime.datetime.now()
 
        Session.add(self)
 
        Session.commit()
 
        log.debug('updated user %s lastlogin', self.username)
 

	
 
    @classmethod
 
    def create(cls, form_data):
 
        from rhodecode.lib.auth import get_crypt_password
 

	
 
        try:
 
            new_user = cls()
 
            for k, v in form_data.items():
 
                if k == 'password':
 
                    v = get_crypt_password(v)
 
                setattr(new_user, k, v)
 

	
 
            new_user.api_key = generate_api_key(form_data['username'])
 
            Session.add(new_user)
 
            Session.commit()
 
            return new_user
 
        except:
 
            log.error(traceback.format_exc())
 
            Session.rollback()
 
            raise
 

	
 
class UserLog(Base, BaseModel):
 
    __tablename__ = 'user_logs'
 
    __table_args__ = {'extend_existing':True}
 
    user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 
    repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
 
    repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
 

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

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

	
 

	
 
class UsersGroup(Base, BaseModel):
 
    __tablename__ = 'users_groups'
 
    __table_args__ = {'extend_existing':True}
 

	
 
    users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    users_group_name = Column("users_group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
 
    users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
 

	
 
    members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
 

	
 
    def __repr__(self):
 
        return '<userGroup(%s)>' % (self.users_group_name)
 

	
 
    @classmethod
 
    def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
 
        if case_insensitive:
 
            gr = Session.query(cls)\
 
            .filter(cls.users_group_name.ilike(group_name))
 
        else:
 
            gr = Session.query(UsersGroup)\
 
                .filter(UsersGroup.users_group_name == group_name)
 
        if cache:
 
            gr = gr.options(FromCache("sql_cache_short",
 
                                          "get_user_%s" % group_name))
 
        return gr.scalar()
 

	
 

	
 
    @classmethod
 
    def get(cls, users_group_id, cache=False):
 
        users_group = Session.query(cls)
 
        if cache:
 
            users_group = users_group.options(FromCache("sql_cache_short",
 
                                    "get_users_group_%s" % users_group_id))
 
        return users_group.get(users_group_id)
 

	
 
    @classmethod
 
    def create(cls, form_data):
 
        try:
 
            new_users_group = cls()
 
            for k, v in form_data.items():
 
                setattr(new_users_group, k, v)
 

	
 
            Session.add(new_users_group)
 
            Session.commit()
 
            return new_users_group
 
        except:
 
            log.error(traceback.format_exc())
 
            Session.rollback()
 
            raise
 
@@ -394,193 +393,193 @@ class UsersGroup(Base, BaseModel):
 

	
 
        try:
 
            users_group = cls.get(users_group_id, cache=False)
 

	
 
            for k, v in form_data.items():
 
                if k == 'users_group_members':
 
                    users_group.members = []
 
                    Session.flush()
 
                    members_list = []
 
                    if v:
 
                        for u_id in set(v):
 
                            members_list.append(UsersGroupMember(
 
                                                            users_group_id,
 
                                                            u_id))
 
                    setattr(users_group, 'members', members_list)
 
                setattr(users_group, k, v)
 

	
 
            Session.add(users_group)
 
            Session.commit()
 
        except:
 
            log.error(traceback.format_exc())
 
            Session.rollback()
 
            raise
 

	
 
    @classmethod
 
    def delete(cls, users_group_id):
 
        try:
 

	
 
            # check if this group is not assigned to repo
 
            assigned_groups = UsersGroupRepoToPerm.query()\
 
                .filter(UsersGroupRepoToPerm.users_group_id ==
 
                        users_group_id).all()
 

	
 
            if assigned_groups:
 
                raise UsersGroupsAssignedException('Group assigned to %s' %
 
                                                   assigned_groups)
 

	
 
            users_group = cls.get(users_group_id, cache=False)
 
            Session.delete(users_group)
 
            Session.commit()
 
        except:
 
            log.error(traceback.format_exc())
 
            Session.rollback()
 
            raise
 

	
 

	
 
class UsersGroupMember(Base, BaseModel):
 
    __tablename__ = 'users_groups_members'
 
    __table_args__ = {'extend_existing':True}
 

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

	
 
    user = relationship('User', lazy='joined')
 
    users_group = relationship('UsersGroup')
 

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

	
 
class Repository(Base, BaseModel):
 
    __tablename__ = 'repositories'
 
    __table_args__ = (UniqueConstraint('repo_name'), {'extend_existing':True},)
 

	
 
    repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
 
    clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
 
    repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
 
    private = Column("private", Boolean(), nullable=True, unique=None, default=None)
 
    enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
 
    enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
 
    description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
 

	
 
    fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
 
    group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
 

	
 

	
 
    user = relationship('User')
 
    fork = relationship('Repository', remote_side=repo_id)
 
    group = relationship('Group')
 
    repo_to_perm = relationship('RepoToPerm', cascade='all', order_by='RepoToPerm.repo_to_perm_id')
 
    users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
 
    stats = relationship('Statistics', cascade='all', uselist=False)
 

	
 
    followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
 

	
 
    logs = relationship('UserLog', cascade='all')
 

	
 
    def __repr__(self):
 
        return "<%s('%s:%s')>" % (self.__class__.__name__,
 
                                  self.repo_id, self.repo_name)
 

	
 
    @classmethod
 
    def by_repo_name(cls, repo_name):
 
    def get_by_repo_name(cls, repo_name):
 
        q = Session.query(cls).filter(cls.repo_name == repo_name)
 

	
 
        q = q.options(joinedload(Repository.fork))\
 
            .options(joinedload(Repository.user))\
 
            .options(joinedload(Repository.group))\
 

	
 
        return q.one()
 

	
 
    @classmethod
 
    def get_repo_forks(cls, repo_id):
 
        return Session.query(cls).filter(Repository.fork_id == repo_id)
 

	
 
    @classmethod
 
    def base_path(cls):
 
        """
 
        Returns base path when all repos are stored
 
        
 
        :param cls:
 
        """
 
        q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/')
 
        q.options(FromCache("sql_cache_short", "repository_repo_path"))
 
        return q.one().ui_value
 

	
 
    @property
 
    def just_name(self):
 
        return self.repo_name.split(os.sep)[-1]
 

	
 
    @property
 
    def groups_with_parents(self):
 
        groups = []
 
        if self.group is None:
 
            return groups
 

	
 
        cur_gr = self.group
 
        groups.insert(0, cur_gr)
 
        while 1:
 
            gr = getattr(cur_gr, 'parent_group', None)
 
            cur_gr = cur_gr.parent_group
 
            if gr is None:
 
                break
 
            groups.insert(0, gr)
 

	
 
        return groups
 

	
 
    @property
 
    def groups_and_repo(self):
 
        return self.groups_with_parents, self.just_name
 

	
 
    @LazyProperty
 
    def repo_path(self):
 
        """
 
        Returns base full path for that repository means where it actually
 
        exists on a filesystem
 
        """
 
        q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/')
 
        q.options(FromCache("sql_cache_short", "repository_repo_path"))
 
        return q.one().ui_value
 

	
 
    @property
 
    def repo_full_path(self):
 
        p = [self.repo_path]
 
        # we need to split the name by / since this is how we store the
 
        # names in the database, but that eventually needs to be converted
 
        # into a valid system path
 
        p += self.repo_name.split('/')
 
        return os.path.join(*p)
 

	
 
    @property
 
    def _ui(self):
 
        """
 
        Creates an db based ui object for this repository
 
        """
 
        from mercurial import ui
 
        from mercurial import config
 
        baseui = ui.ui()
 

	
 
        #clean the baseui object
 
        baseui._ocfg = config.config()
 
        baseui._ucfg = config.config()
 
        baseui._tcfg = config.config()
 

	
 

	
 
        ret = Session.query(RhodeCodeUi)\
 
            .options(FromCache("sql_cache_short", "repository_repo_ui")).all()
 

	
 
        hg_ui = ret
 
        for ui_ in hg_ui:
 
            if ui_.ui_active:
 
                log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
 
                          ui_.ui_key, ui_.ui_value)
 
                baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
 

	
 
        return baseui
 

	
 
    @classmethod
 
    def is_valid(cls, repo_name):
rhodecode/model/forms.py
Show inline comments
 
""" this is forms validation classes
 
http://formencode.org/module-formencode.validators.html
 
for list off all availible validators
 

	
 
we can create our own validators
 

	
 
The table below outlines the options which can be used in a schema in addition to the validators themselves
 
pre_validators          []     These validators will be applied before the schema
 
chained_validators      []     These validators will be applied after the schema
 
allow_extra_fields      False     If True, then it is not an error when keys that aren't associated with a validator are present
 
filter_extra_fields     False     If True, then keys that aren't associated with a validator are removed
 
if_key_missing          NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
 
ignore_key_missing      False     If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
 

	
 

	
 
<name> = formencode.validators.<name of validator>
 
<name> must equal form name
 
list=[1,2,3,4,5]
 
for SELECT use formencode.All(OneOf(list), Int())
 

	
 
"""
 
import os
 
import re
 
import logging
 
import traceback
 

	
 
import formencode
 
from formencode import All
 
from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
 
    Email, Bool, StringBoolean, Set
 

	
 
from pylons.i18n.translation import _
 
from webhelpers.pylonslib.secure_form import authentication_token
 

	
 
from rhodecode.lib.utils import repo_name_slug
 
from rhodecode.lib.auth import authenticate, get_crypt_password
 
from rhodecode.lib.exceptions import LdapImportError
 
from rhodecode.model.user import UserModel
 
from rhodecode.model.repo import RepoModel
 
from rhodecode.model.db import User, UsersGroup, Group
 
from rhodecode import BACKENDS
 

	
 
log = logging.getLogger(__name__)
 

	
 
#this is needed to translate the messages using _() in validators
 
class State_obj(object):
 
    _ = staticmethod(_)
 

	
 
#==============================================================================
 
# VALIDATORS
 
#==============================================================================
 
class ValidAuthToken(formencode.validators.FancyValidator):
 
    messages = {'invalid_token':_('Token mismatch')}
 

	
 
    def validate_python(self, value, state):
 

	
 
        if value != authentication_token():
 
            raise formencode.Invalid(self.message('invalid_token', state,
 
                                            search_number=value), value, state)
 

	
 
def ValidUsername(edit, old_data):
 
    class _ValidUsername(formencode.validators.FancyValidator):
 

	
 
        def validate_python(self, value, state):
 
            if value in ['default', 'new_user']:
 
                raise formencode.Invalid(_('Invalid username'), value, state)
 
            #check if user is unique
 
            old_un = None
 
            if edit:
 
                old_un = UserModel().get(old_data.get('user_id')).username
 

	
 
            if old_un != value or not edit:
 
                if UserModel().get_by_username(value, cache=False,
 
                                               case_insensitive=True):
 
                if User.get_by_username(value, case_insensitive=True):
 
                    raise formencode.Invalid(_('This username already '
 
                                               'exists') , value, state)
 

	
 
            if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
 
                raise formencode.Invalid(_('Username may only contain '
 
                                           'alphanumeric characters '
 
                                           'underscores, periods or dashes '
 
                                           'and must begin with alphanumeric '
 
                                           'character'), value, state)
 

	
 
    return _ValidUsername
 

	
 

	
 
def ValidUsersGroup(edit, old_data):
 

	
 
    class _ValidUsersGroup(formencode.validators.FancyValidator):
 

	
 
        def validate_python(self, value, state):
 
            if value in ['default']:
 
                raise formencode.Invalid(_('Invalid group name'), value, state)
 
            #check if group is unique
 
            old_ugname = None
 
            if edit:
 
                old_ugname = UsersGroup.get(
 
                            old_data.get('users_group_id')).users_group_name
 

	
 
            if old_ugname != value or not edit:
 
                if UsersGroup.get_by_group_name(value, cache=False,
 
                                               case_insensitive=True):
 
                    raise formencode.Invalid(_('This users group '
 
                                               'already exists') , value,
 
                                             state)
 

	
 

	
 
            if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
 
                raise formencode.Invalid(_('Group name may only contain '
 
                                           'alphanumeric characters '
 
                                           'underscores, periods or dashes '
 
                                           'and must begin with alphanumeric '
 
                                           'character'), value, state)
 

	
 
    return _ValidUsersGroup
 

	
 

	
 
def ValidReposGroup(edit, old_data):
 
    class _ValidReposGroup(formencode.validators.FancyValidator):
 

	
 
        def validate_python(self, value, state):
 
            #TODO WRITE VALIDATIONS
 
            group_name = value.get('group_name')
 
            group_parent_id = int(value.get('group_parent_id') or - 1)
 

	
 
            # slugify repo group just in case :)
 
            slug = repo_name_slug(group_name)
 

	
 
            # check for parent of self
 
            if edit and old_data['group_id'] == group_parent_id:
 
                    e_dict = {'group_parent_id':_('Cannot assign this group '
 
                                                  'as parent')}
 
                    raise formencode.Invalid('', value, state,
 
                                             error_dict=e_dict)
 

	
 
            old_gname = None
 
            if edit:
 
                old_gname = Group.get(
 
                            old_data.get('group_id')).group_name
 

	
 
            if old_gname != group_name or not edit:
 
                # check filesystem
 
                gr = Group.query().filter(Group.group_name == slug)\
 
                    .filter(Group.group_parent_id == group_parent_id).scalar()
 

	
 
                if gr:
 
                    e_dict = {'group_name':_('This group already exists')}
 
                    raise formencode.Invalid('', value, state,
 
                                             error_dict=e_dict)
 

	
 
    return _ValidReposGroup
 

	
 
class ValidPassword(formencode.validators.FancyValidator):
 

	
 
    def to_python(self, value, state):
 

	
 
        if value:
 

	
 
            if value.get('password'):
 
                try:
 
                    value['password'] = get_crypt_password(value['password'])
 
                except UnicodeEncodeError:
 
                    e_dict = {'password':_('Invalid characters in password')}
 
                    raise formencode.Invalid('', value, state, error_dict=e_dict)
 

	
 
            if value.get('password_confirmation'):
 
                try:
 
                    value['password_confirmation'] = \
 
                        get_crypt_password(value['password_confirmation'])
 
                except UnicodeEncodeError:
 
                    e_dict = {'password_confirmation':_('Invalid characters in password')}
 
                    raise formencode.Invalid('', value, state, error_dict=e_dict)
 

	
 
            if value.get('new_password'):
 
                try:
 
                    value['new_password'] = \
 
                        get_crypt_password(value['new_password'])
 
                except UnicodeEncodeError:
 
                    e_dict = {'new_password':_('Invalid characters in password')}
 
                    raise formencode.Invalid('', value, state, error_dict=e_dict)
 

	
 
            return value
 

	
 
class ValidPasswordsMatch(formencode.validators.FancyValidator):
 

	
 
    def validate_python(self, value, state):
 

	
 
        if value['password'] != value['password_confirmation']:
 
            e_dict = {'password_confirmation':
 
                   _('Passwords do not match')}
 
            raise formencode.Invalid('', value, state, error_dict=e_dict)
 

	
 
class ValidAuth(formencode.validators.FancyValidator):
 
    messages = {
 
            'invalid_password':_('invalid password'),
 
            'invalid_login':_('invalid user name'),
 
            'disabled_account':_('Your account is disabled')
 

	
 
            }
 
    #error mapping
 
    e_dict = {'username':messages['invalid_login'],
 
              'password':messages['invalid_password']}
 
    e_dict_disable = {'username':messages['disabled_account']}
 

	
 
    def validate_python(self, value, state):
 
        password = value['password']
 
        username = value['username']
 
        user = UserModel().get_by_username(username)
 
        user = User.get_by_username(username)
 

	
 
        if authenticate(username, password):
 
            return value
 
        else:
 
            if user and user.active is False:
 
                log.warning('user %s is disabled', username)
 
                raise formencode.Invalid(self.message('disabled_account',
 
                                         state=State_obj),
 
                                         value, state,
 
                                         error_dict=self.e_dict_disable)
 
            else:
 
                log.warning('user %s not authenticated', username)
 
                raise formencode.Invalid(self.message('invalid_password',
 
                                         state=State_obj), value, state,
 
                                         error_dict=self.e_dict)
 

	
 
class ValidRepoUser(formencode.validators.FancyValidator):
 

	
 
    def to_python(self, value, state):
 
        try:
 
            User.query().filter(User.active == True)\
 
                .filter(User.username == value).one()
 
        except Exception:
 
            raise formencode.Invalid(_('This username is not valid'),
 
                                     value, state)
 
        return value
 

	
 
def ValidRepoName(edit, old_data):
 
    class _ValidRepoName(formencode.validators.FancyValidator):
 
        def to_python(self, value, state):
 

	
 
            repo_name = value.get('repo_name')
 

	
 
            slug = repo_name_slug(repo_name)
 
            if slug in ['_admin', '']:
 
                e_dict = {'repo_name': _('This repository name is disallowed')}
 
                raise formencode.Invalid('', value, state, error_dict=e_dict)
 

	
 

	
 
            if value.get('repo_group'):
 
                gr = Group.get(value.get('repo_group'))
 
                group_path = gr.full_path
 
                # value needs to be aware of group name in order to check
 
                # db key This is an actuall just the name to store in the
 
                # database
 
                repo_name_full = group_path + Group.url_sep() + repo_name
 
            else:
 
                group_path = ''
 
                repo_name_full = repo_name
 

	
 

	
 
            value['repo_name_full'] = repo_name_full
 
            if old_data.get('repo_name') != repo_name_full or not edit:
 

	
 
                if group_path != '':
 
                    if RepoModel().get_by_repo_name(repo_name_full,):
 
                        e_dict = {'repo_name':_('This repository already '
 
                                                'exists in group "%s"') %
 
                                  gr.group_name}
 
                        raise formencode.Invalid('', value, state,
 
                                                 error_dict=e_dict)
 

	
 
                else:
 
                    if RepoModel().get_by_repo_name(repo_name_full):
 
                        e_dict = {'repo_name':_('This repository '
 
                                                'already exists')}
 
                        raise formencode.Invalid('', value, state,
 
                                                 error_dict=e_dict)
 
            return value
 

	
 

	
 
    return _ValidRepoName
 

	
 
def ValidForkName():
 
    class _ValidForkName(formencode.validators.FancyValidator):
 
        def to_python(self, value, state):
 

	
 
            repo_name = value.get('fork_name')
 

	
 
            slug = repo_name_slug(repo_name)
 
            if slug in ['_admin', '']:
 
                e_dict = {'repo_name': _('This repository name is disallowed')}
 
                raise formencode.Invalid('', value, state, error_dict=e_dict)
 

	
 
            if RepoModel().get_by_repo_name(repo_name):
 
                e_dict = {'fork_name':_('This repository '
 
                                        'already exists')}
 
                raise formencode.Invalid('', value, state,
 
                                         error_dict=e_dict)
 
            return value
 
    return _ValidForkName
 

	
 

	
 
def SlugifyName():
 
    class _SlugifyName(formencode.validators.FancyValidator):
 

	
rhodecode/model/repo.py
Show inline comments
 
@@ -9,313 +9,311 @@
 
    :author: marcink
 
    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
import os
 
import shutil
 
import logging
 
import traceback
 
from datetime import datetime
 

	
 
from sqlalchemy.orm import joinedload, make_transient
 

	
 
from vcs.utils.lazy import LazyProperty
 
from vcs.backends import get_backend
 

	
 
from rhodecode.lib import safe_str
 

	
 
from rhodecode.model import BaseModel
 
from rhodecode.model.caching_query import FromCache
 
from rhodecode.model.db import Repository, RepoToPerm, User, Permission, \
 
    Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, Group
 
from rhodecode.model.user import UserModel
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class RepoModel(BaseModel):
 

	
 
    @LazyProperty
 
    def repos_path(self):
 
        """Get's the repositories root path from database
 
        """
 

	
 
        q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
 
        return q.ui_value
 

	
 
    def get(self, repo_id, cache=False):
 
        repo = self.sa.query(Repository)\
 
            .filter(Repository.repo_id == repo_id)
 

	
 
        if cache:
 
            repo = repo.options(FromCache("sql_cache_short",
 
                                          "get_repo_%s" % repo_id))
 
        return repo.scalar()
 

	
 
    def get_by_repo_name(self, repo_name, cache=False):
 
        repo = self.sa.query(Repository)\
 
            .filter(Repository.repo_name == repo_name)
 

	
 
        if cache:
 
            repo = repo.options(FromCache("sql_cache_short",
 
                                          "get_repo_%s" % repo_name))
 
        return repo.scalar()
 

	
 

	
 
    def get_users_js(self):
 

	
 
        users = self.sa.query(User).filter(User.active == True).all()
 
        u_tmpl = '''{id:%s, fname:"%s", lname:"%s", nname:"%s"},'''
 
        users_array = '[%s]' % '\n'.join([u_tmpl % (u.user_id, u.name,
 
                                                    u.lastname, u.username)
 
                                        for u in users])
 
        return users_array
 

	
 
    def get_users_groups_js(self):
 
        users_groups = self.sa.query(UsersGroup)\
 
            .filter(UsersGroup.users_group_active == True).all()
 

	
 
        g_tmpl = '''{id:%s, grname:"%s",grmembers:"%s"},'''
 

	
 
        users_groups_array = '[%s]' % '\n'.join([g_tmpl % \
 
                                    (gr.users_group_id, gr.users_group_name,
 
                                     len(gr.members))
 
                                        for gr in users_groups])
 
        return users_groups_array
 

	
 
    def update(self, repo_name, form_data):
 
        try:
 
            cur_repo = self.get_by_repo_name(repo_name, cache=False)
 

	
 
            #update permissions
 
            for member, perm, member_type in form_data['perms_updates']:
 
                if member_type == 'user':
 
                    r2p = self.sa.query(RepoToPerm)\
 
                            .filter(RepoToPerm.user == User.by_username(member))\
 
                            .filter(RepoToPerm.user == User.get_by_username(member))\
 
                            .filter(RepoToPerm.repository == cur_repo)\
 
                            .one()
 

	
 
                    r2p.permission = self.sa.query(Permission)\
 
                                        .filter(Permission.permission_name ==
 
                                                perm).scalar()
 
                    self.sa.add(r2p)
 
                else:
 
                    g2p = self.sa.query(UsersGroupRepoToPerm)\
 
                            .filter(UsersGroupRepoToPerm.users_group ==
 
                                    UsersGroup.get_by_group_name(member))\
 
                            .filter(UsersGroupRepoToPerm.repository ==
 
                                    cur_repo).one()
 

	
 
                    g2p.permission = self.sa.query(Permission)\
 
                                        .filter(Permission.permission_name ==
 
                                                perm).scalar()
 
                    self.sa.add(g2p)
 

	
 
            #set new permissions
 
            for member, perm, member_type in form_data['perms_new']:
 
                if member_type == 'user':
 
                    r2p = RepoToPerm()
 
                    r2p.repository = cur_repo
 
                    r2p.user = User.by_username(member)
 
                    r2p.user = User.get_by_username(member)
 

	
 
                    r2p.permission = self.sa.query(Permission)\
 
                                        .filter(Permission.
 
                                                permission_name == perm)\
 
                                                .scalar()
 
                    self.sa.add(r2p)
 
                else:
 
                    g2p = UsersGroupRepoToPerm()
 
                    g2p.repository = cur_repo
 
                    g2p.users_group = UsersGroup.get_by_group_name(member)
 
                    g2p.permission = self.sa.query(Permission)\
 
                                        .filter(Permission.
 
                                                permission_name == perm)\
 
                                                .scalar()
 
                    self.sa.add(g2p)
 

	
 
            #update current repo
 
            for k, v in form_data.items():
 
                if k == 'user':
 
                    cur_repo.user = User.by_username(v)
 
                    cur_repo.user = User.get_by_username(v)
 
                elif k == 'repo_name':
 
                    cur_repo.repo_name = form_data['repo_name_full']
 
                elif k == 'repo_group':
 
                    cur_repo.group_id = v
 

	
 
                else:
 
                    setattr(cur_repo, k, v)
 

	
 
            self.sa.add(cur_repo)
 

	
 
            if repo_name != form_data['repo_name_full']:
 
                # rename repository
 
                self.__rename_repo(old=repo_name,
 
                                   new=form_data['repo_name_full'])
 

	
 
            self.sa.commit()
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
 

	
 
    def create(self, form_data, cur_user, just_db=False, fork=False):
 

	
 
        try:
 
            if fork:
 
                repo_name = form_data['fork_name']
 
                org_name = form_data['repo_name']
 
                org_full_name = org_name
 

	
 
            else:
 
                org_name = repo_name = form_data['repo_name']
 
                repo_name_full = form_data['repo_name_full']
 

	
 
            new_repo = Repository()
 
            new_repo.enable_statistics = False
 
            for k, v in form_data.items():
 
                if k == 'repo_name':
 
                    if fork:
 
                        v = repo_name
 
                    else:
 
                        v = repo_name_full
 
                if k == 'repo_group':
 
                    k = 'group_id'
 

	
 
                if k == 'description':
 
                    v = v or repo_name
 

	
 
                setattr(new_repo, k, v)
 

	
 
            if fork:
 
                parent_repo = self.sa.query(Repository)\
 
                        .filter(Repository.repo_name == org_full_name).one()
 
                new_repo.fork = parent_repo
 

	
 
            new_repo.user_id = cur_user.user_id
 
            self.sa.add(new_repo)
 

	
 
            #create default permission
 
            repo_to_perm = RepoToPerm()
 
            default = 'repository.read'
 
            for p in UserModel(self.sa).get_by_username('default',
 
                                                    cache=False).user_perms:
 
            for p in User.get_by_username('default').user_perms:
 
                if p.permission.permission_name.startswith('repository.'):
 
                    default = p.permission.permission_name
 
                    break
 

	
 
            default_perm = 'repository.none' if form_data['private'] else default
 

	
 
            repo_to_perm.permission_id = self.sa.query(Permission)\
 
                    .filter(Permission.permission_name == default_perm)\
 
                    .one().permission_id
 

	
 
            repo_to_perm.repository = new_repo
 
            repo_to_perm.user_id = UserModel(self.sa)\
 
                .get_by_username('default', cache=False).user_id
 
            repo_to_perm.user_id = User.get_by_username('default').user_id
 

	
 
            self.sa.add(repo_to_perm)
 

	
 
            if not just_db:
 
                self.__create_repo(repo_name, form_data['repo_type'],
 
                                   form_data['repo_group'],
 
                                   form_data['clone_uri'])
 

	
 
            self.sa.commit()
 

	
 
            #now automatically start following this repository as owner
 
            from rhodecode.model.scm import ScmModel
 
            ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
 
                                             cur_user.user_id)
 

	
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
 

	
 
    def create_fork(self, form_data, cur_user):
 
        from rhodecode.lib.celerylib import tasks, run_task
 
        run_task(tasks.create_repo_fork, form_data, cur_user)
 

	
 
    def delete(self, repo):
 
        try:
 
            self.sa.delete(repo)
 
            self.__delete_repo(repo)
 
            self.sa.commit()
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
 

	
 
    def delete_perm_user(self, form_data, repo_name):
 
        try:
 
            self.sa.query(RepoToPerm)\
 
                .filter(RepoToPerm.repository \
 
                        == self.get_by_repo_name(repo_name))\
 
                .filter(RepoToPerm.user_id == form_data['user_id']).delete()
 
            self.sa.commit()
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
 

	
 
    def delete_perm_users_group(self, form_data, repo_name):
 
        try:
 
            self.sa.query(UsersGroupRepoToPerm)\
 
                .filter(UsersGroupRepoToPerm.repository \
 
                        == self.get_by_repo_name(repo_name))\
 
                .filter(UsersGroupRepoToPerm.users_group_id \
 
                        == form_data['users_group_id']).delete()
 
            self.sa.commit()
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
 

	
 
    def delete_stats(self, repo_name):
 
        try:
 
            self.sa.query(Statistics)\
 
                .filter(Statistics.repository == \
 
                        self.get_by_repo_name(repo_name)).delete()
 
            self.sa.commit()
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
 

	
 
    def __create_repo(self, repo_name, alias, new_parent_id, clone_uri=False):
 
        """
 
        makes repository on filesystem. It's group aware means it'll create
 
        a repository within a group, and alter the paths accordingly of
 
        group location
 

	
 
        :param repo_name:
 
        :param alias:
 
        :param parent_id:
 
        :param clone_uri:
 
        """
 
        from rhodecode.lib.utils import is_valid_repo
 

	
 
        if new_parent_id:
 
            paths = Group.get(new_parent_id).full_path.split(Group.url_sep())
 
            new_parent_path = os.sep.join(paths)
 
        else:
 
            new_parent_path = ''
 

	
 
        repo_path = os.path.join(*map(lambda x:safe_str(x),
 
                                [self.repos_path, new_parent_path, repo_name]))
 

	
 
        if is_valid_repo(repo_path, self.repos_path) is False:
 
            log.info('creating repo %s in %s @ %s', repo_name, repo_path,
 
                     clone_uri)
 
            backend = get_backend(alias)
rhodecode/model/scm.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.scm
 
    ~~~~~~~~~~~~~~~~~~~
 

	
 
    Scm model for RhodeCode
 

	
 
    :created_on: Apr 9, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
import os
 
import time
 
import traceback
 
import logging
 

	
 
from sqlalchemy.exc import DatabaseError
 

	
 
from vcs import get_backend
 
from vcs.exceptions import RepositoryError
 
from vcs.utils.lazy import LazyProperty
 
from vcs.nodes import FileNode
 

	
 
from rhodecode import BACKENDS
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib import safe_str
 
from rhodecode.lib.auth import HasRepoPermissionAny
 
from rhodecode.lib.utils import get_repos as get_filesystem_repos, make_ui, \
 
    action_logger, EmptyChangeset
 
from rhodecode.model import BaseModel
 
from rhodecode.model.user import UserModel
 
from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
 
    UserFollowing, UserLog
 
    UserFollowing, UserLog, User
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class UserTemp(object):
 
    def __init__(self, user_id):
 
        self.user_id = user_id
 

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

	
 

	
 
class RepoTemp(object):
 
    def __init__(self, repo_id):
 
        self.repo_id = repo_id
 

	
 
    def __repr__(self):
 
        return "<%s('id:%s')>" % (self.__class__.__name__, self.repo_id)
 

	
 
class CachedRepoList(object):
 

	
 
    def __init__(self, db_repo_list, repos_path, order_by=None):
 
        self.db_repo_list = db_repo_list
 
        self.repos_path = repos_path
 
        self.order_by = order_by
 
        self.reversed = (order_by or '').startswith('-')
 

	
 
    def __len__(self):
 
        return len(self.db_repo_list)
 

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

	
 
    def __iter__(self):
 
        for dbr in self.db_repo_list:
 

	
 
            scmr = dbr.scm_instance_cached
 

	
 
            # check permission at this level
 
            if not HasRepoPermissionAny('repository.read', 'repository.write',
 
                                        'repository.admin')(dbr.repo_name,
 
                                                            'get repo check'):
 
                continue
 

	
 
            if scmr is None:
 
                log.error('%s this repository is present in database but it '
 
                          'cannot be created as an scm instance',
 
                          dbr.repo_name)
 
                continue
 

	
 
            last_change = scmr.last_change
 
            tip = h.get_changeset_safe(scmr, 'tip')
 

	
 
            tmp_d = {}
 
            tmp_d['name'] = dbr.repo_name
 
            tmp_d['name_sort'] = tmp_d['name'].lower()
 
            tmp_d['description'] = dbr.description
 
            tmp_d['description_sort'] = tmp_d['description']
 
            tmp_d['last_change'] = last_change
 
            tmp_d['last_change_sort'] = time.mktime(last_change \
 
                                                    .timetuple())
 
            tmp_d['tip'] = tip.raw_id
 
            tmp_d['tip_sort'] = tip.revision
 
            tmp_d['rev'] = tip.revision
 
            tmp_d['contact'] = dbr.user.full_contact
 
            tmp_d['contact_sort'] = tmp_d['contact']
 
            tmp_d['owner_sort'] = tmp_d['contact']
 
            tmp_d['repo_archives'] = list(scmr._get_archives())
 
            tmp_d['last_msg'] = tip.message
 
            tmp_d['author'] = tip.author
 
            tmp_d['dbrepo'] = dbr.get_dict()
 
            tmp_d['dbrepo_fork'] = dbr.fork.get_dict() if dbr.fork \
 
                                                                    else {}
 
            yield tmp_d
 

	
 
class ScmModel(BaseModel):
 
    """Generic Scm Model
 
    """
 

	
 
    @LazyProperty
 
    def repos_path(self):
 
        """Get's the repositories root path from database
 
        """
 

	
 
        q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
 

	
 
        return q.ui_value
 

	
 
    def repo_scan(self, repos_path=None):
 
        """Listing of repositories in given path. This path should not be a
 
        repository itself. Return a dictionary of repository objects
 

	
 
        :param repos_path: path to directory containing repositories
 
        """
 

	
 
        log.info('scanning for repositories in %s', repos_path)
 
@@ -190,216 +188,216 @@ class ScmModel(BaseModel):
 
    def mark_for_invalidation(self, repo_name):
 
        """Puts cache invalidation task into db for
 
        further global cache invalidation
 

	
 
        :param repo_name: this repo that should invalidation take place
 
        """
 

	
 
        log.debug('marking %s for invalidation', repo_name)
 
        cache = self.sa.query(CacheInvalidation)\
 
            .filter(CacheInvalidation.cache_key == repo_name).scalar()
 

	
 
        if cache:
 
            # mark this cache as inactive
 
            cache.cache_active = False
 
        else:
 
            log.debug('cache key not found in invalidation db -> creating one')
 
            cache = CacheInvalidation(repo_name)
 

	
 
        try:
 
            self.sa.add(cache)
 
            self.sa.commit()
 
        except (DatabaseError,):
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 

	
 
    def toggle_following_repo(self, follow_repo_id, user_id):
 

	
 
        f = self.sa.query(UserFollowing)\
 
            .filter(UserFollowing.follows_repo_id == follow_repo_id)\
 
            .filter(UserFollowing.user_id == user_id).scalar()
 

	
 
        if f is not None:
 

	
 
            try:
 
                self.sa.delete(f)
 
                self.sa.commit()
 
                action_logger(UserTemp(user_id),
 
                              'stopped_following_repo',
 
                              RepoTemp(follow_repo_id))
 
                return
 
            except:
 
                log.error(traceback.format_exc())
 
                self.sa.rollback()
 
                raise
 

	
 
        try:
 
            f = UserFollowing()
 
            f.user_id = user_id
 
            f.follows_repo_id = follow_repo_id
 
            self.sa.add(f)
 
            self.sa.commit()
 
            action_logger(UserTemp(user_id),
 
                          'started_following_repo',
 
                          RepoTemp(follow_repo_id))
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
 

	
 
    def toggle_following_user(self, follow_user_id, user_id):
 
        f = self.sa.query(UserFollowing)\
 
            .filter(UserFollowing.follows_user_id == follow_user_id)\
 
            .filter(UserFollowing.user_id == user_id).scalar()
 

	
 
        if f is not None:
 
            try:
 
                self.sa.delete(f)
 
                self.sa.commit()
 
                return
 
            except:
 
                log.error(traceback.format_exc())
 
                self.sa.rollback()
 
                raise
 

	
 
        try:
 
            f = UserFollowing()
 
            f.user_id = user_id
 
            f.follows_user_id = follow_user_id
 
            self.sa.add(f)
 
            self.sa.commit()
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
 

	
 
    def is_following_repo(self, repo_name, user_id, cache=False):
 
        r = self.sa.query(Repository)\
 
            .filter(Repository.repo_name == repo_name).scalar()
 

	
 
        f = self.sa.query(UserFollowing)\
 
            .filter(UserFollowing.follows_repository == r)\
 
            .filter(UserFollowing.user_id == user_id).scalar()
 

	
 
        return f is not None
 

	
 
    def is_following_user(self, username, user_id, cache=False):
 
        u = UserModel(self.sa).get_by_username(username)
 
        u = User.get_by_username(username)
 

	
 
        f = self.sa.query(UserFollowing)\
 
            .filter(UserFollowing.follows_user == u)\
 
            .filter(UserFollowing.user_id == user_id).scalar()
 

	
 
        return f is not None
 

	
 
    def get_followers(self, repo_id):
 
        if not isinstance(repo_id, int):
 
            repo_id = getattr(Repository.by_repo_name(repo_id), 'repo_id')
 
            repo_id = getattr(Repository.get_by_repo_name(repo_id), 'repo_id')
 

	
 
        return self.sa.query(UserFollowing)\
 
                .filter(UserFollowing.follows_repo_id == repo_id).count()
 

	
 
    def get_forks(self, repo_id):
 
        if not isinstance(repo_id, int):
 
            repo_id = getattr(Repository.by_repo_name(repo_id), 'repo_id')
 
            repo_id = getattr(Repository.get_by_repo_name(repo_id), 'repo_id')
 

	
 
        return self.sa.query(Repository)\
 
                .filter(Repository.fork_id == repo_id).count()
 

	
 
    def pull_changes(self, repo_name, username):
 
        dbrepo = Repository.by_repo_name(repo_name)
 
        dbrepo = Repository.get_by_repo_name(repo_name)
 
        clone_uri = dbrepo.clone_uri
 
        if not clone_uri:
 
            raise Exception("This repository doesn't have a clone uri")
 
        
 
        repo = dbrepo.scm_instance
 
        try:
 
            extras = {'ip': '',
 
                      'username': username,
 
                      'action': 'push_remote',
 
                      'repository': repo_name}
 

	
 
            #inject ui extra param to log this action via push logger
 
            for k, v in extras.items():
 
                repo._repo.ui.setconfig('rhodecode_extras', k, v)
 

	
 
            repo.pull(clone_uri)
 
            self.mark_for_invalidation(repo_name)
 
        except:
 
            log.error(traceback.format_exc())
 
            raise
 

	
 
    def commit_change(self, repo, repo_name, cs, user, author, message, content,
 
                      f_path):
 

	
 
        if repo.alias == 'hg':
 
            from vcs.backends.hg import MercurialInMemoryChangeset as IMC
 
        elif repo.alias == 'git':
 
            from vcs.backends.git import GitInMemoryChangeset as IMC
 

	
 
        # decoding here will force that we have proper encoded values
 
        # in any other case this will throw exceptions and deny commit
 
        content = safe_str(content)
 
        message = safe_str(message)
 
        path = safe_str(f_path)
 
        author = safe_str(author)
 
        m = IMC(repo)
 
        m.change(FileNode(path, content))
 
        tip = m.commit(message=message,
 
                 author=author,
 
                 parents=[cs], branch=cs.branch)
 

	
 
        new_cs = tip.short_id
 
        action = 'push_local:%s' % new_cs
 

	
 
        action_logger(user, action, repo_name)
 

	
 
        self.mark_for_invalidation(repo_name)
 

	
 
    def create_node(self, repo, repo_name, cs, user, author, message, content,
 
                      f_path):
 
        if repo.alias == 'hg':
 
            from vcs.backends.hg import MercurialInMemoryChangeset as IMC
 
        elif repo.alias == 'git':
 
            from vcs.backends.git import GitInMemoryChangeset as IMC
 
        # decoding here will force that we have proper encoded values
 
        # in any other case this will throw exceptions and deny commit
 
        
 
        if isinstance(content,(basestring,)):
 
            content = safe_str(content)
 
        elif isinstance(content,file):
 
            content = content.read()
 
            
 
        message = safe_str(message)
 
        path = safe_str(f_path)
 
        author = safe_str(author)
 
        m = IMC(repo)
 

	
 
        if isinstance(cs, EmptyChangeset):
 
            # Emptychangeset means we we're editing empty repository
 
            parents = None
 
        else:
 
            parents = [cs]
 

	
 
        m.add(FileNode(path, content=content))
 
        tip = m.commit(message=message,
 
                 author=author,
 
                 parents=parents, branch=cs.branch)
 
        new_cs = tip.short_id
 
        action = 'push_local:%s' % new_cs
 

	
 
        action_logger(user, action, repo_name)
 

	
 
        self.mark_for_invalidation(repo_name)
 

	
 

	
 
    def get_unread_journal(self):
 
        return self.sa.query(UserLog).count()
 

	
 
    def _should_invalidate(self, repo_name):
 
        """Looks up database for invalidation signals for this repo_name
 

	
 
        :param repo_name:
 
        """
 

	
 
        ret = self.sa.query(CacheInvalidation)\
 
            .filter(CacheInvalidation.cache_key == repo_name)\
rhodecode/tests/functional/test_login.py
Show inline comments
 
@@ -153,109 +153,109 @@ class TestLoginController(TestController
 
    def test_register_special_chars(self):
 
        response = self.app.post(url(controller='login', action='register'),
 
                                            {'username':'xxxaxn',
 
                                             'password':'ąćźżąśśśś',
 
                                             'password_confirmation':'ąćźżąśśśś',
 
                                             'email':'goodmailm@test.plx',
 
                                             'name':'test',
 
                                             'lastname':'test'})
 

	
 
        self.assertEqual(response.status , '200 OK')
 
        assert 'Invalid characters in password' in response.body
 

	
 

	
 
    def test_register_password_mismatch(self):
 
        response = self.app.post(url(controller='login', action='register'),
 
                                            {'username':'xs',
 
                                             'password':'123qwe',
 
                                             'password_confirmation':'qwe123',
 
                                             'email':'goodmailm@test.plxa',
 
                                             'name':'test',
 
                                             'lastname':'test'})
 

	
 
        self.assertEqual(response.status , '200 OK')
 
        assert 'Passwords do not match' in response.body
 

	
 
    def test_register_ok(self):
 
        username = 'test_regular4'
 
        password = 'qweqwe'
 
        email = 'marcin@test.com'
 
        name = 'testname'
 
        lastname = 'testlastname'
 

	
 
        response = self.app.post(url(controller='login', action='register'),
 
                                            {'username':username,
 
                                             'password':password,
 
                                             'password_confirmation':password,
 
                                             'email':email,
 
                                             'name':name,
 
                                             'lastname':lastname})
 
        self.assertEqual(response.status , '302 Found')
 
        assert 'You have successfully registered into rhodecode' in response.session['flash'][0], 'No flash message about user registration'
 

	
 
        ret = self.sa.query(User).filter(User.username == 'test_regular4').one()
 
        assert ret.username == username , 'field mismatch %s %s' % (ret.username, username)
 
        assert check_password(password, ret.password) == True , 'password mismatch'
 
        assert ret.email == email , 'field mismatch %s %s' % (ret.email, email)
 
        assert ret.name == name , 'field mismatch %s %s' % (ret.name, name)
 
        assert ret.lastname == lastname , 'field mismatch %s %s' % (ret.lastname, lastname)
 

	
 

	
 
    def test_forgot_password_wrong_mail(self):
 
        response = self.app.post(url(controller='login', action='password_reset'),
 
                                            {'email':'marcin@wrongmail.org', })
 

	
 
        assert "This e-mail address doesn't exist" in response.body, 'Missing error message about wrong email'
 

	
 
    def test_forgot_password(self):
 
        response = self.app.get(url(controller='login',
 
                                    action='password_reset'))
 
        self.assertEqual(response.status , '200 OK')
 

	
 
        username = 'test_password_reset_1'
 
        password = 'qweqwe'
 
        email = 'marcin@python-works.com'
 
        name = 'passwd'
 
        lastname = 'reset'
 

	
 
        new = User()
 
        new.username = username
 
        new.password = password
 
        new.email = email
 
        new.name = name
 
        new.lastname = lastname
 
        new.api_key = generate_api_key(username)
 
        self.sa.add(new)
 
        self.sa.commit()
 

	
 
        response = self.app.post(url(controller='login',
 
                                     action='password_reset'),
 
                                 {'email':email, })
 

	
 
        self.checkSessionFlash(response, 'Your password reset link was sent')
 

	
 
        response = response.follow()
 

	
 
        # BAD KEY
 

	
 
        key = "bad"
 
        response = self.app.get(url(controller='login',
 
                                    action='password_reset_confirmation',
 
                                    key=key))
 
        self.assertEqual(response.status, '302 Found')
 
        self.assertTrue(response.location.endswith(url('reset_password')))
 

	
 
        # GOOD KEY
 

	
 
        key = User.by_username(username).api_key
 
        key = User.get_by_username(username).api_key
 

	
 
        response = self.app.get(url(controller='login',
 
                                    action='password_reset_confirmation',
 
                                    key=key))
 
        self.assertEqual(response.status, '302 Found')
 
        self.assertTrue(response.location.endswith(url('login_home')))
 

	
 
        self.checkSessionFlash(response,
 
                               ('Your password reset was successful, '
 
                                'new password has been sent to your email'))
 

	
 
        response = response.follow()
rhodecode/tests/functional/test_summary.py
Show inline comments
 
from rhodecode.tests import *
 
from rhodecode.model.db import Repository
 
from rhodecode.lib.utils import invalidate_cache
 

	
 
class TestSummaryController(TestController):
 

	
 
    def test_index(self):
 
        self.log_user()
 
        response = self.app.get(url(controller='summary',
 
                                    action='index', repo_name=HG_REPO))
 

	
 
        #repo type
 
        self.assertTrue("""<img style="margin-bottom:2px" class="icon" """
 
                        """title="Mercurial repository" alt="Mercurial """
 
                        """repository" src="/images/icons/hgicon.png"/>"""
 
                        in response.body)
 
        self.assertTrue("""<img style="margin-bottom:2px" class="icon" """
 
                        """title="public repository" alt="public """
 
                        """repository" src="/images/icons/lock_open.png"/>"""
 
                        in response.body)
 

	
 
        #codes stats
 
        self._enable_stats()
 

	
 

	
 
        invalidate_cache('get_repo_cached_%s' % HG_REPO)
 
        response = self.app.get(url(controller='summary', action='index',
 
                                    repo_name=HG_REPO))
 

	
 
        self.assertTrue("""var data = {"py": {"count": 42, "desc": """
 
                        """["Python"]}, "rst": {"count": 11, "desc": """
 
                        """["Rst"]}, "sh": {"count": 2, "desc": ["Bash"]}, """
 
                        """"makefile": {"count": 1, "desc": ["Makefile", """
 
                        """"Makefile"]}, "cfg": {"count": 1, "desc": ["Ini"]},"""
 
                        """ "css": {"count": 1, "desc": ["Css"]}, "bat": """
 
                        """{"count": 1, "desc": ["Batch"]}};"""
 
                        in response.body)
 

	
 
        # clone url...
 
        self.assertTrue("""<input type="text" id="clone_url" readonly="readonly" value="hg clone http://test_admin@localhost:80/%s" size="70"/>""" % HG_REPO in response.body)
 

	
 

	
 
    def _enable_stats(self):
 
        r = Repository.by_repo_name(HG_REPO)
 
        r = Repository.get_by_repo_name(HG_REPO)
 
        r.enable_statistics = True
 
        self.sa.add(r)
 
        self.sa.commit()
rhodecode/tests/test_hg_operations.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.tests.test_hg_operations
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Test suite for making push/pull operations
 

	
 
    :created_on: Dec 30, 2010
 
    :copyright: (c) 2010 by marcink.
 
    :license: LICENSE_NAME, see LICENSE_FILE for more details.
 
"""
 

	
 
import os
 
import time
 
import sys
 
import shutil
 
import logging
 

	
 
from os.path import join as jn
 
from os.path import dirname as dn
 

	
 
from tempfile import _RandomNameSequence
 
from subprocess import Popen, PIPE
 

	
 
from paste.deploy import appconfig
 
from pylons import config
 
from sqlalchemy import engine_from_config
 

	
 
from rhodecode.lib.utils import add_cache
 
from rhodecode.model import init_model
 
from rhodecode.model import meta
 
from rhodecode.model.db import User, Repository, UserLog
 
from rhodecode.lib.auth import get_crypt_password
 

	
 
from rhodecode.tests import TESTS_TMP_PATH, NEW_HG_REPO, HG_REPO
 
from rhodecode.config.environment import load_environment
 

	
 
rel_path = dn(dn(dn(os.path.abspath(__file__))))
 
conf = appconfig('config:development.ini', relative_to=rel_path)
 
load_environment(conf.global_conf, conf.local_conf)
 

	
 
add_cache(conf)
 

	
 
USER = 'test_admin'
 
PASS = 'test12'
 
HOST = '127.0.0.1:5000'
 
DEBUG = bool(int(sys.argv[1]))
 
DEBUG = True if sys.argv[1:] else False
 
print 'DEBUG:', DEBUG
 
log = logging.getLogger(__name__)
 

	
 

	
 
class Command(object):
 

	
 
    def __init__(self, cwd):
 
        self.cwd = cwd
 

	
 
    def execute(self, cmd, *args):
 
        """Runs command on the system with given ``args``.
 
        """
 

	
 
        command = cmd + ' ' + ' '.join(args)
 
        log.debug('Executing %s' % command)
 
        if DEBUG:
 
            print command
 
        p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE, cwd=self.cwd)
 
        stdout, stderr = p.communicate()
 
        if DEBUG:
 
            print stdout, stderr
 
        return stdout, stderr
 

	
 

	
 
def test_wrapp(func):
 

	
 
    def __wrapp(*args, **kwargs):
 
        print '###%s###' % func.__name__
 
        print '>>>%s' % func.__name__
 
        try:
 
            res = func(*args, **kwargs)
 
        except Exception, e:
 
            print ('###############\n-'
 
                   '--%s failed %s--\n'
 
                   '###############\n' % (func.__name__, e))
 
            sys.exit()
 
        print '++OK++'
 
        return res
 
    return __wrapp
 

	
 
def get_session():
 
    engine = engine_from_config(conf, 'sqlalchemy.db1.')
 
    init_model(engine)
 
    sa = meta.Session
 
    return sa
 

	
 

	
 
def create_test_user(force=True):
 
    print '\tcreating test user'
 
    sa = get_session()
 

	
 
    user = sa.query(User).filter(User.username == USER).scalar()
 

	
 
    if force and user is not None:
 
        print '\tremoving current user'
 
        for repo in sa.query(Repository).filter(Repository.user == user).all():
 
            sa.delete(repo)
 
        sa.delete(user)
 
        sa.commit()
 

	
 
    if user is None or force:
 
        print '\tcreating new one'
 
        new_usr = User()
 
        new_usr.username = USER
 
        new_usr.password = get_crypt_password(PASS)
 
        new_usr.email = 'mail@mail.com'
 
        new_usr.name = 'test'
 
        new_usr.lastname = 'lasttestname'
 
        new_usr.active = True
 
        new_usr.admin = True
 
        sa.add(new_usr)
 
        sa.commit()
 

	
 
    print '\tdone'
 

	
 

	
 
def create_test_repo(force=True):
 
    from rhodecode.model.repo import RepoModel
 
    sa = get_session()
 

	
 
    user = sa.query(User).filter(User.username == USER).scalar()
 
    if user is None:
 
        raise Exception('user not found')
 

	
 

	
 
    repo = sa.query(Repository).filter(Repository.repo_name == HG_REPO).scalar()
 

	
 
    if repo is None:
 
        print '\trepo not found creating'
 

	
 
        form_data = {'repo_name':HG_REPO,
 
                     'repo_type':'hg',
 
                     'private':False,
 
                     'clone_uri':'' }
 
        rm = RepoModel(sa)
 
        rm.base_path = '/home/hg'
 
        rm.create(form_data, user)
 

	
 

	
 
def set_anonymous_access(enable=True):
 
    sa = get_session()
 
    user = sa.query(User).filter(User.username == 'default').one()
 
    sa.expire(user)
 
    user.active = enable
 
    sa.add(user)
 
    sa.commit()
 
    sa.remove()
 
    import time;time.sleep(3)
 
    print '\tanonymous access is now:', enable
 

	
 

	
 
def get_anonymous_access():
 
    sa = get_session()
 
    obj1 = sa.query(User).filter(User.username == 'default').one()
 
    sa.expire(obj1)
 
    return obj1.active
 

	
 

	
 
#==============================================================================
 
# TESTS
 
#==============================================================================
 
@test_wrapp
 
def test_clone_with_credentials(no_errors=False):
 
    cwd = path = jn(TESTS_TMP_PATH, HG_REPO)
 

	
test.ini
Show inline comments
 
################################################################################
 
################################################################################
 
# RhodeCode - Pylons environment configuration                                 #
 
#                                                                              # 
 
# The %(here)s variable will be replaced with the parent directory of this file#
 
################################################################################
 

	
 
[DEFAULT]
 
debug = true
 
pdebug = false
 
################################################################################
 
## Uncomment and replace with the address which should receive                ## 
 
## any error reports after application crash                                  ##
 
## Additionally those settings will be used by RhodeCode mailing system       ##
 
################################################################################
 
#email_to = admin@localhost
 
#error_email_from = paste_error@localhost
 
#app_email_from = rhodecode-noreply@localhost
 
#error_message =
 

	
 
#smtp_server = mail.server.com
 
#smtp_username = 
 
#smtp_password = 
 
#smtp_port = 
 
#smtp_use_tls = false
 
#smtp_use_ssl = true
 

	
 
[server:main]
 
##nr of threads to spawn
 
threadpool_workers = 5
 

	
 
##max request before thread respawn
 
threadpool_max_requests = 2
 

	
 
##option to use threads of process
 
use_threadpool = true
 

	
 
use = egg:Paste#http
 
host = 127.0.0.1
 
port = 5000
 

	
 
[app:main]
 
use = egg:rhodecode
 
full_stack = true
 
static_files = true
 
lang=en
 
cache_dir = /tmp/data
 
index_dir = /tmp/index
 
app_instance_uuid = develop-test
 
cut_off_limit = 256000
 
force_https = false
 
commit_parse_limit = 25
 
use_gravatar = true
 

	
 
####################################
 
###        CELERY CONFIG        ####
 
####################################
 
use_celery = false
 
broker.host = localhost
 
broker.vhost = rabbitmqhost
 
broker.port = 5672
 
broker.user = rabbitmq
 
broker.password = qweqwe
 

	
 
celery.imports = rhodecode.lib.celerylib.tasks
 

	
 
celery.result.backend = amqp
 
celery.result.dburi = amqp://
 
celery.result.serialier = json
 

	
 
#celery.send.task.error.emails = true
 
#celery.amqp.task.result.expires = 18000
 

	
 
celeryd.concurrency = 2
 
#celeryd.log.file = celeryd.log
 
celeryd.log.level = debug
 
celeryd.max.tasks.per.child = 1
 

	
 
#tasks will never be sent to the queue, but executed locally instead.
 
celery.always.eager = false
 

	
 
####################################
 
###         BEAKER CACHE        ####
 
####################################
 
beaker.cache.data_dir=/tmp/data/cache/data
 
beaker.cache.lock_dir=/tmp/data/cache/lock
 
beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
 

	
 
beaker.cache.super_short_term.type=memory
 
beaker.cache.super_short_term.expire=10
 

	
 
beaker.cache.short_term.type=memory
 
beaker.cache.short_term.expire=60
 

	
 
beaker.cache.long_term.type=memory
 
beaker.cache.long_term.expire=36000
 

	
 

	
 
beaker.cache.sql_cache_short.type=memory
 
beaker.cache.sql_cache_short.expire=10
 

	
 
beaker.cache.sql_cache_med.type=memory
 
beaker.cache.sql_cache_med.expire=360
 

	
 
beaker.cache.sql_cache_long.type=file
 
beaker.cache.sql_cache_long.expire=3600
 

	
 
####################################
 
###       BEAKER SESSION        ####
 
####################################
 
## Type of storage used for the session, current types are 
 
## dbm, file, memcached, database, and memory. 
 
## The storage uses the Container API 
 
##that is also used by the cache system.
 
beaker.session.type = file
 

	
 
beaker.session.key = rhodecode
 
beaker.session.secret = g654dcno0-9873jhgfreyu
 
beaker.session.timeout = 36000
 

	
 
##auto save the session to not to use .save()
 
beaker.session.auto = False
 

	
 
##true exire at browser close
 
#beaker.session.cookie_expires = 3600
 

	
 
    
 
################################################################################
 
## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*  ##
 
## Debug mode will enable the interactive debugging tool, allowing ANYONE to  ##
 
## execute malicious code after an exception is raised.                       ##
 
################################################################################
 
#set debug = false
 

	
 
##################################
 
###       LOGVIEW CONFIG       ###
 
##################################
 
logview.sqlalchemy = #faa
 
logview.pylons.templating = #bfb
 
logview.pylons.util = #eee
 

	
 
#########################################################
 
### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG    ###
 
#########################################################
 
sqlalchemy.db1.url = sqlite:///%(here)s/test.db
 
#sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode_tests
 
#sqlalchemy.db1.echo = False
 
#sqlalchemy.db1.pool_recycle = 3600
 
sqlalchemy.convert_unicode = true
 

	
 
################################
 
### LOGGING CONFIGURATION   ####
 
################################
 
[loggers]
 
keys = root, routes, rhodecode, sqlalchemy,beaker,templates
 

	
 
[handlers]
 
keys = console
 

	
 
[formatters]
 
keys = generic,color_formatter
 

	
 
#############
 
## LOGGERS ##
 
#############
 
[logger_root]
 
level = ERROR
 
handlers = console
 

	
 
[logger_routes]
 
level = ERROR
 
handlers = console
 
handlers = 
 
qualname = routes.middleware
 
# "level = DEBUG" logs the route matched and routing variables.
 
propagate = 1
 

	
 
[logger_beaker]
 
level = DEBUG
 
handlers = 
 
qualname = beaker.container
 
propagate = 1
 

	
 
[logger_templates]
 
level = INFO
 
handlers = 
 
qualname = pylons.templating
 
propagate = 1
 

	
 
[logger_rhodecode]
 
level = ERROR
 
handlers = console
 
handlers = 
 
qualname = rhodecode
 
propagate = 0
 
propagate = 1
 

	
 
[logger_sqlalchemy]
 
level = ERROR
 
handlers = console
 
qualname = sqlalchemy.engine
 
propagate = 0
 

	
 
##############
 
## HANDLERS ##
 
##############
 

	
 
[handler_console]
 
class = StreamHandler
 
args = (sys.stderr,)
 
level = NOTSET
 
formatter = color_formatter
 
formatter = generic
 

	
 
################
 
## FORMATTERS ##
 
################
 

	
 
[formatter_generic]
 
format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
 
datefmt = %Y-%m-%d %H:%M:%S
 

	
 
[formatter_color_formatter]
 
class=rhodecode.lib.colored_formatter.ColorFormatter
 
format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
 
datefmt = %Y-%m-%d %H:%M:%S
 
\ No newline at end of file
0 comments (0 inline, 0 general)