Changeset - f5c1eec9f376
[Not reviewed]
default
0 7 0
Marcin Kuzminski - 15 years ago 2010-08-08 01:27:14
marcin@python-works.com
rename repo2perm into repo_to_perm
added UserToPerm models for user global permissions
7 files changed with 46 insertions and 32 deletions:
0 comments (0 inline, 0 general)
pylons_app/controllers/admin/repos.py
Show inline comments
 
@@ -129,106 +129,106 @@ class ReposController(BaseController):
 
            invalidate_cache('cached_repo_list')
 
            h.flash(_('Repository %s updated succesfully' % repo_name),
 
                    category='success')
 
            changed_name = form_result['repo_name']
 
        except formencode.Invalid as errors:
 
            c.repo_info = repo_model.get(repo_name)
 
            c.users_array = repo_model.get_users_js()
 
            errors.value.update({'user':c.repo_info.user.username})
 
            return htmlfill.render(
 
                render('admin/repos/repo_edit.html'),
 
                defaults=errors.value,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8")
 
 
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('error occured during update of repository %s') \
 
                    % repo_name, category='error')
 
            
 
        return redirect(url('edit_repo', repo_name=changed_name))
 
    
 
    @HasPermissionAllDecorator('hg.admin')
 
    def delete(self, repo_name):
 
        """DELETE /repos/repo_name: Delete an existing item"""
 
        # Forms posted to this method should contain a hidden field:
 
        #    <input type="hidden" name="_method" value="DELETE" />
 
        # Or using helpers:
 
        #    h.form(url('repo', repo_name=ID),
 
        #           method='delete')
 
        # url('repo', repo_name=ID)
 
        
 
        repo_model = RepoModel()
 
        repo = repo_model.get(repo_name)
 
        if not repo:
 
            h.flash(_('%s repository is not mapped to db perhaps' 
 
                      ' it was moved or renamed  from the filesystem'
 
                      ' please run the application again'
 
                      ' in order to rescan repositories') % repo_name,
 
                      category='error')
 
        
 
            return redirect(url('repos'))
 
        try:
 
            repo_model.delete(repo)            
 
            invalidate_cache('cached_repo_list')
 
            h.flash(_('deleted repository %s') % repo_name, category='success')
 
        except Exception:
 
            h.flash(_('An error occured 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 as e:
 
            h.flash(_('An error occured during deletion of repository user'),
 
                    category='error')
 
            raise HTTPInternalServerError()
 
    
 
    @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)
 
        repo_model = RepoModel()
 
        c.repo_info = repo = repo_model.get(repo_name)
 
        if not repo:
 
            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'))        
 
        defaults = c.repo_info.__dict__
 
        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})
 
            
 
        c.users_array = repo_model.get_users_js()
 
        
 
        for p in c.repo_info.repo2perm:
 
        for p in c.repo_info.repo_to_perm:
 
            defaults.update({'perm_%s' % p.user.username: 
 
                             p.permission.permission_name})
 
            
 
        return htmlfill.render(
 
            render('admin/repos/repo_edit.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False
 
        )          
pylons_app/controllers/settings.py
Show inline comments
 
#!/usr/bin/env python
 
# encoding: utf-8
 
# settings controller for pylons
 
# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
 
# 
 
# 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; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
# 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, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
"""
 
Created on June 30, 2010
 
settings controller for pylons
 
@author: marcink
 
"""
 
from formencode import htmlfill
 
from pylons import tmpl_context as c, request, url
 
from pylons.controllers.util import redirect
 
from pylons.i18n.translation import _
 
from pylons_app.lib.auth import LoginRequired, HasRepoPermissionAllDecorator
 
from pylons_app.lib.base import BaseController, render
 
from pylons_app.lib.utils import invalidate_cache
 
from pylons_app.model.forms import RepoSettingsForm
 
from pylons_app.model.repo_model import RepoModel
 
import formencode
 
import logging
 
import pylons_app.lib.helpers as h
 
import traceback
 

	
 
log = logging.getLogger(__name__)
 

	
 
class SettingsController(BaseController):
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAllDecorator('repository.admin')           
 
    def __before__(self):
 
        super(SettingsController, self).__before__()
 
        
 
    def index(self, repo_name):
 
        repo_model = RepoModel()
 
        c.repo_info = repo = repo_model.get(repo_name)
 
        if not repo:
 
            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'))        
 
        defaults = c.repo_info.__dict__
 
        defaults.update({'user':c.repo_info.user.username})
 
        c.users_array = repo_model.get_users_js()
 
        
 
        for p in c.repo_info.repo2perm:
 
        for p in c.repo_info.repo_to_perm:
 
            defaults.update({'perm_%s' % p.user.username: 
 
                             p.permission.permission_name})
 
            
 
        return htmlfill.render(
 
            render('settings/repo_settings.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False
 
        )  
 

	
 
    def update(self, repo_name):
 
        repo_model = RepoModel()
 
        changed_name = repo_name
 
        _form = RepoSettingsForm(edit=True, old_data={'repo_name':repo_name})()
 
        try:
 
            form_result = _form.to_python(dict(request.POST))
 
            repo_model.update(repo_name, form_result)
 
            invalidate_cache('cached_repo_list')
 
            h.flash(_('Repository %s updated succesfully' % repo_name),
 
                    category='success')
 
            changed_name = form_result['repo_name']               
 
        except formencode.Invalid as errors:
 
            c.repo_info = repo_model.get(repo_name)
 
            c.users_array = repo_model.get_users_js()
 
            errors.value.update({'user':c.repo_info.user.username})
 
            return htmlfill.render(
 
                render('settings/repo_settings.html'),
 
                defaults=errors.value,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8") 
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('error occured during update of repository %s') \
 
                    % repo_name, category='error')
 
                    
 
        return redirect(url('repo_settings_home', repo_name=changed_name))
pylons_app/lib/auth.py
Show inline comments
 
#!/usr/bin/env python
 
# encoding: utf-8
 
# authentication and permission libraries
 
# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
 
#
 
# 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; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
# 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, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
"""
 
Created on April 4, 2010
 

	
 
@author: marcink
 
"""
 
from beaker.cache import cache_region
 
from pylons import config, session, url, request
 
from pylons.controllers.util import abort, redirect
 
from pylons_app.lib.utils import get_repo_slug
 
from pylons_app.model import meta
 
from pylons_app.model.db import User, Repo2Perm, Repository, Permission
 
from pylons_app.model.db import User, RepoToPerm, Repository, Permission
 
from sqlalchemy.exc import OperationalError
 
from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
 
import crypt
 
from decorator import decorator
 
import logging
 

	
 
log = logging.getLogger(__name__) 
 

	
 
def get_crypt_password(password):
 
    """
 
    Cryptographic function used for password hashing
 
    @param password: password to hash
 
    """
 
    return crypt.crypt(password, '6a')
 

	
 

	
 
@cache_region('super_short_term', 'cached_user')
 
def get_user_cached(username):
 
    sa = meta.Session
 
    try:
 
        user = sa.query(User).filter(User.username == username).one()
 
    finally:
 
        meta.Session.remove()
 
    return user
 

	
 
def authfunc(environ, username, password):
 
    password_crypt = get_crypt_password(password)
 
    try:
 
        user = get_user_cached(username)
 
    except (NoResultFound, MultipleResultsFound, OperationalError) as e:
 
        log.error(e)
 
        user = None
 
        
 
    if user:
 
        if user.active:
 
            if user.username == username and user.password == password_crypt:
 
                log.info('user %s authenticated correctly', username)
 
                return True
 
        else:
 
            log.error('user %s is disabled', username)
 
            
 
    return False
 

	
 
class  AuthUser(object):
 
    """
 
    A simple object that handles a mercurial username for authentication
 
    """
 
    def __init__(self):
 
        self.username = 'None'
 
        self.name = ''
 
        self.lastname = ''
 
        self.user_id = None
 
        self.is_authenticated = False
 
        self.is_admin = False
 
        self.permissions = {}
 

	
 

	
 
def set_available_permissions(config):
 
    """
 
    This function will propagate pylons globals with all available defined
 
    permission given in db. We don't wannt 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:
 
    """
 
    log.info('getting information about all available permissions')
 
    try:
 
        sa = meta.Session
 
        all_perms = sa.query(Permission).all()
 
    finally:
 
        meta.Session.remove()
 
    
 
    config['available_permissions'] = [x.permission_name for x in all_perms]
 

	
 
def set_base_path(config):
 
    config['base_path'] = config['pylons.app_globals'].base_path
 

	
 
def fill_data(user):
 
    """
 
    Fills user data with those from database and log out user if not present
 
    in database
 
    @param user:
 
    """
 
    sa = meta.Session
 
    dbuser = sa.query(User).get(user.user_id)
 
    if dbuser:
 
        user.username = dbuser.username
 
        user.is_admin = dbuser.admin
 
        user.name = dbuser.name
 
        user.lastname = dbuser.lastname
 
    else:
 
        user.is_authenticated = False
 
    meta.Session.remove()
 
    return user
 
            
 
def fill_perms(user):
 
    """
 
    Fills user permission attribute with permissions taken from database
 
    @param user:
 
    """
 
    
 
    sa = meta.Session
 
    user.permissions['repositories'] = {}
 
    user.permissions['global'] = set()
 
    
 
    #first fetch default permissions
 
    default_perms = sa.query(Repo2Perm, Repository, Permission)\
 
        .join((Repository, Repo2Perm.repository_id == Repository.repo_id))\
 
        .join((Permission, Repo2Perm.permission_id == Permission.permission_id))\
 
        .filter(Repo2Perm.user_id == sa.query(User).filter(User.username == 
 
    default_perms = sa.query(RepoToPerm, Repository, Permission)\
 
        .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
 
        .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
 
        .filter(RepoToPerm.user_id == sa.query(User).filter(User.username == 
 
                                            'default').one().user_id).all()
 

	
 
    if user.is_admin:
 
        user.permissions['global'].add('hg.admin')
 
        #admin have all rights set to admin
 
        for perm in default_perms:
 
            p = 'repository.admin'
 
            user.permissions['repositories'][perm.Repo2Perm.repository.repo_name] = p
 
            user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
 
    
 
    else:
 
        user.permissions['global'].add('repository.create')
 
        for perm in default_perms:
 
            if perm.Repository.private and not perm.Repository.user_id == user.user_id:
 
                #disable defaults for private repos,
 
                p = 'repository.none'
 
            elif perm.Repository.user_id == user.user_id:
 
                #set admin if owner
 
                p = 'repository.admin'
 
            else:
 
                p = perm.Permission.permission_name
 
                
 
            user.permissions['repositories'][perm.Repo2Perm.repository.repo_name] = p
 
            user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
 
                                                
 
        
 
        user_perms = sa.query(Repo2Perm, Permission, Repository)\
 
            .join((Repository, Repo2Perm.repository_id == Repository.repo_id))\
 
            .join((Permission, Repo2Perm.permission_id == Permission.permission_id))\
 
            .filter(Repo2Perm.user_id == user.user_id).all()
 
        user_perms = sa.query(RepoToPerm, Permission, Repository)\
 
            .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
 
            .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
 
            .filter(RepoToPerm.user_id == user.user_id).all()
 
        #overwrite userpermissions with defaults
 
        for perm in user_perms:
 
            #set write if owner
 
            if perm.Repository.user_id == user.user_id:
 
                p = 'repository.write'
 
            else:
 
                p = perm.Permission.permission_name
 
            user.permissions['repositories'][perm.Repo2Perm.repository.repo_name] = p
 
            user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
 
    meta.Session.remove()         
 
    return user
 
    
 
def get_user(session):
 
    """
 
    Gets user from session, and wraps permissions into user
 
    @param session:
 
    """
 
    user = session.get('hg_app_user', AuthUser())
 
    if user.is_authenticated:
 
        user = fill_data(user)
 
        user = fill_perms(user)
 
    session['hg_app_user'] = user
 
    session.save()
 
    return user
 
        
 
#===============================================================================
 
# CHECK DECORATORS
 
#===============================================================================
 
class LoginRequired(object):
 
    """Must be logged in to execute this function else redirect to login page"""
 
   
 
    def __call__(self, func):
 
        return decorator(self.__wrapper, func)
 
    
 
    def __wrapper(self, func, *fargs, **fkwargs):
 
        user = session.get('hg_app_user', AuthUser())
 
        log.debug('Checking login required for user:%s', user.username)
 
        if user.is_authenticated:
 
            log.debug('user %s is authenticated', user.username)
 
            return func(*fargs, **fkwargs)
 
        else:
 
            log.warn('user %s not authenticated', user.username)
 
            log.debug('redirecting to login page')
 
            return redirect(url('login_home'))
 

	
 
class PermsDecorator(object):
 
    """Base class for decorators"""
 
    
 
    def __init__(self, *required_perms):
 
        available_perms = config['available_permissions']
 
        for perm in required_perms:
 
            if perm not in available_perms:
 
                raise Exception("'%s' permission is not defined" % perm)
 
        self.required_perms = set(required_perms)
 
        self.user_perms = None
 
        
 
    def __call__(self, func):
 
        return decorator(self.__wrapper, func)
 
    
 
    
 
    def __wrapper(self, func, *fargs, **fkwargs):
 
#        _wrapper.__name__ = func.__name__
 
#        _wrapper.__dict__.update(func.__dict__)
 
#        _wrapper.__doc__ = func.__doc__
 

	
 
        self.user_perms = session.get('hg_app_user', AuthUser()).permissions
 
        log.debug('checking %s permissions %s for %s',
 
           self.__class__.__name__, self.required_perms, func.__name__)
 
        
 
        if self.check_permissions():
 
            log.debug('Permission granted for %s', func.__name__)
 
            
 
            return func(*fargs, **fkwargs)
 
        
 
        else:
 
            log.warning('Permission denied for %s', func.__name__)
 
            #redirect with forbidden ret code
 
            return abort(403)
 

	
 
        
 
        
 
    def check_permissions(self):
 
        """Dummy function for overriding"""
 
        raise Exception('You have to write this function in child class')
 

	
 
class HasPermissionAllDecorator(PermsDecorator):
 
    """Checks for access permission for all given predicates. All of them 
 
    have to be meet in order to fulfill the request
 
    """
 
        
 
    def check_permissions(self):
 
        if self.required_perms.issubset(self.user_perms.get('global')):
 
            return True
 
        return False
 
            
 

	
 
class HasPermissionAnyDecorator(PermsDecorator):
 
    """Checks for access permission for any of given predicates. In order to 
 
    fulfill the request any of predicates must be meet
 
    """
 
    
 
    def check_permissions(self):
 
        if self.required_perms.intersection(self.user_perms.get('global')):
 
            return True
 
        return False
pylons_app/model/db.py
Show inline comments
 
from pylons_app.model.meta import Base
 
from sqlalchemy.orm import relation, backref
 
from sqlalchemy import *
 
from vcs.utils.lazy import LazyProperty
 

	
 
class HgAppSettings(Base):
 
    __tablename__ = 'hg_app_settings'
 
    __table_args__ = (UniqueConstraint('app_settings_name'), {'useexisting':True})
 
    app_settings_id = Column("app_settings_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
 
    app_settings_name = Column("app_settings_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    app_settings_value = Column("app_settings_value", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 

	
 
class HgAppUi(Base):
 
    __tablename__ = 'hg_app_ui'
 
    __table_args__ = {'useexisting':True}
 
    ui_id = Column("ui_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
 
    ui_section = Column("ui_section", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    ui_key = Column("ui_key", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    ui_value = Column("ui_value", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    ui_active = Column("ui_active", BOOLEAN(), nullable=True, unique=None, default=True)
 
    
 
    
 
class User(Base): 
 
    __tablename__ = 'users'
 
    __table_args__ = {'useexisting':True}
 
    user_id = Column("user_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
 
    username = Column("username", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    password = Column("password", TEXT(length=None, 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", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    lastname = Column("lastname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    email = Column("email", TEXT(length=None, 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)
 
    
 
    user_log = relation('UserLog')
 
    
 
    @LazyProperty
 
    def full_contact(self):
 
        return '%s %s <%s>' % (self.name, self.lastname, self.email)
 
        
 
    def __repr__(self):
 
        return "<User('%s:%s')>" % (self.user_id, self.username)
 
      
 
class UserLog(Base): 
 
    __tablename__ = 'user_logs'
 
    __table_args__ = {'useexisting':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(u'users.user_id'), nullable=False, unique=None, default=None)
 
    user_ip = Column("user_ip", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) 
 
    repository = Column("repository", TEXT(length=None, convert_unicode=False, assert_unicode=None), ForeignKey(u'repositories.repo_name'), nullable=False, unique=None, default=None)
 
    action = Column("action", TEXT(length=None, 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)
 
    
 
    user = relation('User')
 
    
 
class Repository(Base):
 
    __tablename__ = 'repositories'
 
    __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
 
    repo_id = Column("repo_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
 
    repo_name = Column("repo_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
 
    user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=False, default=None)
 
    private = Column("private", BOOLEAN(), nullable=True, unique=None, default=None)
 
    description = Column("description", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    
 
    user = relation('User')
 
    repo2perm = relation('Repo2Perm', cascade='all')
 
    repo_to_perm = relation('RepoToPerm', cascade='all')
 
    
 
class Permission(Base):
 
    __tablename__ = 'permissions'
 
    __table_args__ = {'useexisting':True}
 
    permission_id = Column("permission_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
 
    permission_name = Column("permission_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    permission_longname = Column("permission_longname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    
 
    def __repr__(self):
 
        return "<Permission('%s:%s')>" % (self.permission_id, self.permission_name)
 

	
 
class Repo2Perm(Base):
 
class RepoToPerm(Base):
 
    __tablename__ = 'repo_to_perm'
 
    __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
 
    repo2perm_id = Column("repo2perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
 
    repo_to_perm_id = Column("repo_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
 
    user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
 
    permission_id = Column("permission_id", INTEGER(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
 
    repository_id = Column("repository_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None) 
 
    
 
    user = relation('User')
 
    permission = relation('Permission')
 
    repository = relation('Repository')
 

	
 
class UserToPerm(Base):
 
    __tablename__ = 'user_to_perm'
 
    __table_args__ = {'useexisting':True}
 
    user_to_perm_id = Column("user_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
 
    user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
 
    permission_id = Column("permission_id", INTEGER(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
 
    
 
    user = relation('User')
 
    permission = relation('Permission')
 

	
 

	
 

	
 

	
pylons_app/model/repo_model.py
Show inline comments
 
#!/usr/bin/env python
 
# encoding: utf-8
 
# model for handling repositories actions
 
# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
 
# 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; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
# 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, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
"""
 
Created on Jun 5, 2010
 
model for handling repositories actions
 
@author: marcink
 
"""
 
from datetime import datetime
 
from pylons import app_globals as g
 
from pylons_app.lib.utils import check_repo
 
from pylons_app.model.db import Repository, Repo2Perm, User, Permission
 
from pylons_app.model.db import Repository, RepoToPerm, User, Permission
 
from pylons_app.model.meta import Session
 
import logging
 
import os
 
import shutil
 
import traceback
 
log = logging.getLogger(__name__)
 

	
 
class RepoModel(object):
 
    
 
    def __init__(self):
 
        self.sa = Session()
 
    
 
    def get(self, id):
 
        return self.sa.query(Repository).filter(Repository.repo_name == id).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 update(self, repo_name, form_data):
 
        try:
 

	
 
            #update permissions
 
            for username, perm in form_data['perms_updates']:
 
                r2p = self.sa.query(Repo2Perm)\
 
                        .filter(Repo2Perm.user == self.sa.query(User)\
 
                r2p = self.sa.query(RepoToPerm)\
 
                        .filter(RepoToPerm.user == self.sa.query(User)\
 
                                .filter(User.username == username).one())\
 
                        .filter(Repo2Perm.repository == self.get(repo_name))\
 
                        .filter(RepoToPerm.repository == self.get(repo_name))\
 
                        .one()
 
                
 
                r2p.permission_id = self.sa.query(Permission).filter(
 
                                                Permission.permission_name == 
 
                                                perm).one().permission_id
 
                self.sa.add(r2p)
 
            
 
            #set new permissions
 
            for username, perm in form_data['perms_new']:
 
                r2p = Repo2Perm()
 
                r2p = RepoToPerm()
 
                r2p.repository = self.get(repo_name)
 
                r2p.user = self.sa.query(User)\
 
                                .filter(User.username == username).one()
 
                
 
                r2p.permission_id = self.sa.query(Permission).filter(
 
                                        Permission.permission_name == perm)\
 
                                        .one().permission_id
 
                self.sa.add(r2p)
 
            
 
            #update current repo
 
            cur_repo = self.get(repo_name)
 
             
 
            for k, v in form_data.items():
 
                if k == 'user':
 
                    cur_repo.user_id = v
 
                else:
 
                    setattr(cur_repo, k, v)
 
                                                        
 
            self.sa.add(cur_repo)
 
            
 
            if repo_name != form_data['repo_name']:
 
                #rename our data
 
                self.__rename_repo(repo_name, form_data['repo_name'])            
 
            
 
            self.sa.commit()
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise    
 
    
 
    def create(self, form_data, cur_user, just_db=False):
 
        try:
 
            repo_name = form_data['repo_name']
 
            new_repo = Repository()
 
            for k, v in form_data.items():
 
                setattr(new_repo, k, v)
 
                
 
            new_repo.user_id = cur_user.user_id
 
            self.sa.add(new_repo)
 
            
 
            #create default permission
 
            repo2perm = Repo2Perm()
 
            repo_to_perm = RepoToPerm()
 
            default_perm = 'repository.none' if form_data['private'] \
 
                                                        else 'repository.read'
 
            repo2perm.permission_id = self.sa.query(Permission)\
 
            repo_to_perm.permission_id = self.sa.query(Permission)\
 
                    .filter(Permission.permission_name == default_perm)\
 
                    .one().permission_id
 
                        
 
            repo2perm.repository_id = new_repo.repo_id
 
            repo2perm.user_id = self.sa.query(User)\
 
            repo_to_perm.repository_id = new_repo.repo_id
 
            repo_to_perm.user_id = self.sa.query(User)\
 
                    .filter(User.username == 'default').one().user_id 
 
            
 
            self.sa.add(repo2perm)
 
            self.sa.add(repo_to_perm)
 
            self.sa.commit()
 
            if not just_db:
 
                self.__create_repo(repo_name)
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise    
 
                     
 
    def delete(self, repo):
 
        try:
 
            self.sa.delete(repo)
 
            self.sa.commit()
 
            self.__delete_repo(repo.repo_name)
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
 
        
 
    def delete_perm_user(self, form_data, repo_name):
 
        try:
 
            self.sa.query(Repo2Perm)\
 
                .filter(Repo2Perm.repository == self.get(repo_name))\
 
                .filter(Repo2Perm.user_id == form_data['user_id']).delete()
 
            self.sa.query(RepoToPerm)\
 
                .filter(RepoToPerm.repository == self.get(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 __create_repo(self, repo_name):        
 
        repo_path = os.path.join(g.base_path, repo_name)
 
        if check_repo(repo_name, g.base_path):
 
            log.info('creating repo %s in %s', repo_name, repo_path)
 
            from vcs.backends.hg import MercurialRepository
 
            MercurialRepository(repo_path, create=True)
 

	
 
    def __rename_repo(self, old, new):
 
        log.info('renaming repo from %s to %s', old, new)
 
        
 
        old_path = os.path.join(g.base_path, old)
 
        new_path = os.path.join(g.base_path, new)
 
        if os.path.isdir(new_path):
 
            raise Exception('Was trying to rename to already existing dir %s',
 
                            new_path)        
 
        shutil.move(old_path, new_path)
 
    
 
    def __delete_repo(self, name):
 
        rm_path = os.path.join(g.base_path, name)
 
        log.info("Removing %s", rm_path)
 
        #disable hg 
 
        shutil.move(os.path.join(rm_path, '.hg'), os.path.join(rm_path, 'rm__.hg'))
 
        #disable repo
 
        shutil.move(rm_path, os.path.join(g.base_path, 'rm__%s__%s' \
 
                                          % (datetime.today(), name)))
pylons_app/templates/admin/repos/repo_edit.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
<%inherit file="/base/base.html"/>
 

	
 
<%def name="title()">
 
    ${_('Repositories administration')}
 
</%def>
 

	
 
<%def name="breadcrumbs_links()">
 
    ${h.link_to(_('Admin'),h.url('admin_home'))} 
 
    &raquo; 
 
    ${h.link_to(_('Repositories'),h.url('repos'))} 
 
    &raquo;
 
    ${_('edit')} "${c.repo_name}"
 
</%def>
 

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

	
 
<%def name="main()">
 
<div class="box">
 
    <!-- box / title -->
 
    <div class="title">
 
        ${self.breadcrumbs()}      
 
    </div>
 
    ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='put')}
 
    <div class="form">
 
        <!-- fields -->
 
        <div class="fields">
 
            <div class="field">
 
                <div class="label">
 
                    <label for="repo_name">${_('Name')}:</label>
 
                </div>
 
                <div class="input input-medium">
 
                    ${h.text('repo_name')}
 
                </div>
 
             </div>
 
             
 
            <div class="field">
 
                <div class="label label-textarea">
 
                    <label for="description">${_('Description')}:</label>
 
                </div>
 
                <div class="textarea text-area editor">
 
                    ${h.textarea('description',cols=23,rows=5)}
 
                </div>
 
            </div>
 
            
 
            <div class="field">
 
                <div class="label label-checkbox">
 
                    <label for="private">${_('Private')}:</label>
 
                </div>
 
                <div class="checkboxes">
 
                    ${h.checkbox('private',value="True")}
 
                </div>
 
            </div>
 
             
 
            <div class="field">
 
                <div class="label label-checkbox">
 
                    <label for="user">${_('Owner')}:</label>
 
                </div>
 
                <div class="input input-small ac">
 
                    <div class="perm_ac">
 
                       ${h.text('user',class_='yui-ac-input')}
 
                       <div id="owner_container"></div>
 
                    </div>
 
                </div>
 
             </div>                
 
             
 
            <div class="field">
 
                <div class="label">
 
                    <label for="input">${_('Permissions')}:</label>
 
                </div>
 
                <div class="input">
 
                    <table id="permissions_manage">
 
                        <tr>
 
                            <td>${_('none')}</td>
 
                            <td>${_('read')}</td>
 
                            <td>${_('write')}</td>
 
                            <td>${_('admin')}</td>
 
                            <td>${_('user')}</td>
 
                            <td></td>
 
                        </tr>
 
                        
 
                        %for r2p in c.repo_info.repo2perm:
 
                        %for r2p in c.repo_info.repo_to_perm:
 
                            %if r2p.user.username =='default' and c.repo_info.private:
 
                                <tr>
 
                                    <td colspan="4">
 
                                        <span class="private_repo_msg">
 
                                        ${_('private repository')}
 
                                        </span>
 
                                    </td>
 
                                    <td class="private_repo_msg">${r2p.user.username}</td>
 
                                </tr>
 
                            %else:
 
                            <tr id="id${id(r2p.user.username)}">
 
                                <td>${h.radio('perm_%s' % r2p.user.username,'repository.none')}</td>
 
                                <td>${h.radio('perm_%s' % r2p.user.username,'repository.read')}</td>
 
                                <td>${h.radio('perm_%s' % r2p.user.username,'repository.write')}</td>
 
                                <td>${h.radio('perm_%s' % r2p.user.username,'repository.admin')}</td>
 
                                <td>${r2p.user.username}</td>
 
                                <td>
 
                                  %if r2p.user.username !='default':
 
                                    <span class="delete_icon action_button" onclick="ajaxAction(${r2p.user.user_id},'${'id%s'%id(r2p.user.username)}')">
 
                                        <script type="text/javascript">
 
                                            function ajaxAction(user_id,field_id){
 
                                                var sUrl = "${h.url('delete_repo_user',repo_name=c.repo_name)}";
 
                                                var callback = { success:function(o){
 
                                                var tr = YAHOO.util.Dom.get(String(field_id));
 
                                                tr.parentNode.removeChild(tr);},failure:function(o){
 
                                                    alert("${_('Failed to remove user')}");},};
 
                                                var postData = '_method=delete&user_id='+user_id; 
 
                                                var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);};
 
                                        </script>           
 
                                    </span>
 
                                  %endif                    
 
                                </td>
 
                            </tr>
 
                            %endif
 
                        %endfor
 

	
 
                        <tr id="add_perm_input">
 
                            <td>${h.radio('perm_new_user','repository.none')}</td>
 
                            <td>${h.radio('perm_new_user','repository.read')}</td>
 
                            <td>${h.radio('perm_new_user','repository.write')}</td>
 
                            <td>${h.radio('perm_new_user','repository.admin')}</td>
 
                            <td class='ac'>
 
                                <div class="perm_ac" id="perm_ac">
 
                                    ${h.text('perm_new_user_name',class_='yui-ac-input')}
 
                                    <div id="perm_container"></div>
 
                                </div>
 
                            </td>
 
                            <td></td>
 
                        </tr>
 
                        <tr>
 
                            <td colspan="6">
 
                                <span id="add_perm" class="add_icon" style="cursor: pointer;">
 
                                ${_('Add another user')}
 
                                </span>
 
                            </td>
 
                        </tr>
 
                    </table>             
 
             </div>
 
             
 
            <div class="buttons">
 
              ${h.submit('save','save',class_="ui-button ui-widget ui-state-default ui-corner-all")}
 
            </div>                                                          
 
        </div>
 
    </div>
 
    </div>    
 
    ${h.end_form()}
 
        <script type="text/javascript">
 
            YAHOO.util.Event.onDOMReady(function(){
 
                var D = YAHOO.util.Dom;
 
                if(!D.hasClass('perm_new_user_name','error')){
 
                    D.setStyle('add_perm_input','display','none');
 
                }
 
                YAHOO.util.Event.addListener('add_perm','click',function(){
 
                    D.setStyle('add_perm_input','display','');
 
                    D.setStyle('add_perm','opacity','0.6');
 
                    D.setStyle('add_perm','cursor','default');
 
                });
 
            });
 
        </script>
 
        <script type="text/javascript">    
 
        YAHOO.example.FnMultipleFields = function(){
 
            var myContacts = ${c.users_array|n}
 
            
 
            // Define a custom search function for the DataSource
 
            var matchNames = function(sQuery) {
 
                // Case insensitive matching
 
                var query = sQuery.toLowerCase(),
 
                    contact,
 
                    i=0,
 
                    l=myContacts.length,
 
                    matches = [];
 
                
 
                // Match against each name of each contact
 
                for(; i<l; i++) {
 
                    contact = myContacts[i];
 
                    if((contact.fname.toLowerCase().indexOf(query) > -1) ||
pylons_app/templates/settings/repo_settings.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
<%inherit file="/base/base.html"/>
 

	
 
<%def name="title()">
 
    ${_('Repositories administration')}
 
</%def>
 

	
 
<%def name="breadcrumbs_links()">
 
    ${h.link_to(c.repo_info.repo_name,h.url('summary_home',repo_name=c.repo_info.repo_name))} 
 
    &raquo; 
 
    ${_('Settings')} 
 
    
 
</%def>
 
<%def name="page_nav()">
 
    ${self.menu('settings')}
 
</%def>
 
<%def name="main()">
 
<div class="box">
 
    <!-- box / title -->
 
    <div class="title">
 
        ${self.breadcrumbs()}      
 
    </div>
 
    ${h.form(url('repo_settings_update', repo_name=c.repo_info.repo_name),method='put')}
 
    <div class="form">
 
        <!-- fields -->
 
        <div class="fields">
 
            <div class="field">
 
                <div class="label">
 
                    <label for="repo_name">${_('Name')}:</label>
 
                </div>
 
                <div class="input input-medium">
 
                    ${h.text('repo_name')}
 
                </div>
 
             </div>
 
             
 
            <div class="field">
 
                <div class="label label-textarea">
 
                    <label for="description">${_('Description')}:</label>
 
                </div>
 
                <div class="textarea text-area editor">
 
                    ${h.textarea('description',cols=23,rows=5)}
 
                </div>
 
            </div>
 
            
 
            <div class="field">
 
                <div class="label label-checkbox">
 
                    <label for="private">${_('Private')}:</label>
 
                </div>
 
                <div class="checkboxes">
 
                    ${h.checkbox('private',value="True")}
 
                </div>
 
            </div>
 
             
 
             <div class="field">
 
                <div class="label">
 
                    <label for="">${_('Permissions')}:</label>
 
                </div>
 
                <div class="input">
 
                    <table id="permissions_manage">
 
                        <tr>
 
                            <td>${_('none')}</td>
 
                            <td>${_('read')}</td>
 
                            <td>${_('write')}</td>
 
                            <td>${_('admin')}</td>
 
                            <td>${_('user')}</td>
 
                            <td></td>
 
                        </tr>
 
                        
 
                        %for r2p in c.repo_info.repo2perm:
 
                        %for r2p in c.repo_info.repo_to_perm:
 
                            %if r2p.user.username =='default' and c.repo_info.private:
 
                                <tr>
 
                                    <td colspan="4">
 
                                        <span class="private_repo_msg">
 
                                        ${_('private repository')}
 
                                        </span>
 
                                    </td>
 
                                    <td class="private_repo_msg">${r2p.user.username}</td>
 
                                </tr>
 
                            %else:
 
                            <tr id="id${id(r2p.user.username)}">
 
                                <td>${h.radio('perm_%s' % r2p.user.username,'repository.none')}</td>
 
                                <td>${h.radio('perm_%s' % r2p.user.username,'repository.read')}</td>
 
                                <td>${h.radio('perm_%s' % r2p.user.username,'repository.write')}</td>
 
                                <td>${h.radio('perm_%s' % r2p.user.username,'repository.admin')}</td>
 
                                <td>${r2p.user.username}</td>
 
                                <td>
 
                                  %if r2p.user.username !='default':
 
                                    <span class="delete_icon action_button" onclick="ajaxAction(${r2p.user.user_id},'${'id%s'%id(r2p.user.username)}')">
 
                                        <script type="text/javascript">
 
                                            function ajaxAction(user_id,field_id){
 
                                                var sUrl = "${h.url('delete_repo_user',repo_name=c.repo_name)}";
 
                                                var callback = { success:function(o){
 
                                                var tr = YAHOO.util.Dom.get(String(field_id));
 
                                                tr.parentNode.removeChild(tr);},failure:function(o){
 
                                                	alert("${_('Failed to remove user')}");},};
 
                                                var postData = '_method=delete&user_id='+user_id; 
 
                                                var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);};
 
                                        </script>           
 
                                    </span>
 
                                  %endif                    
 
                                </td>
 
                            </tr>
 
                            %endif
 
                        %endfor
 

	
 

	
 
                        <tr id="add_perm_input">
 
                            <td>${h.radio('perm_new_user','repository.none')}</td>
 
                            <td>${h.radio('perm_new_user','repository.read')}</td>
 
                            <td>${h.radio('perm_new_user','repository.write')}</td>
 
                            <td>${h.radio('perm_new_user','repository.admin')}</td>
 
                            <td class='ac'>
 
                                <div class="perm_ac" id="perm_ac">
 
                                    ${h.text('perm_new_user_name',class_='yui-ac-input')}
 
                                    <div id="perm_container"></div>
 
                                </div>
 
                            </td>
 
                            <td></td>
 
                        </tr>
 
                        <tr>
 
                            <td colspan="6">
 
                                <span id="add_perm" class="add_icon" style="cursor: pointer;">
 
                                ${_('Add another user')}
 
                                </span>
 
                            </td>
 
                        </tr>
 
                    </table>             
 
             </div>
 
             
 
            <div class="buttons">
 
              ${h.submit('update','update',class_="ui-button ui-widget ui-state-default ui-corner-all")}
 
            </div>                                                          
 
        </div>
 
    </div>    
 
    ${h.end_form()}
 
        <script type="text/javascript">
 
            YAHOO.util.Event.onDOMReady(function(){
 
                var D = YAHOO.util.Dom;
 
                if(!D.hasClass('perm_new_user_name','error')){
 
                    D.setStyle('add_perm_input','display','none');
 
                }
 
                YAHOO.util.Event.addListener('add_perm','click',function(){
 
                    D.setStyle('add_perm_input','display','');
 
                    D.setStyle('add_perm','opacity','0.6');
 
                    D.setStyle('add_perm','cursor','default');
 
                });
 
            });
 
        </script>
 
        <script type="text/javascript">    
 
        YAHOO.example.FnMultipleFields = function(){
 
            var myContacts = ${c.users_array|n}
 
            
 
            // Define a custom search function for the DataSource
 
            var matchNames = function(sQuery) {
 
                // Case insensitive matching
 
                var query = sQuery.toLowerCase(),
 
                    contact,
 
                    i=0,
 
                    l=myContacts.length,
 
                    matches = [];
 
                
 
                // Match against each name of each contact
 
                for(; i<l; i++) {
 
                    contact = myContacts[i];
 
                    if((contact.fname.toLowerCase().indexOf(query) > -1) ||
0 comments (0 inline, 0 general)