Changeset - 55377fdc1fc6
[Not reviewed]
default
0 9 0
Marcin Kuzminski - 15 years ago 2010-08-01 18:36:00
marcin@python-works.com
cleared global application settings.
Made it much more extensible by keeping it key/value in the database.
9 files changed with 46 insertions and 36 deletions:
0 comments (0 inline, 0 general)
pylons_app/controllers/admin/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 July 14, 2010
 
settings controller for pylons
 
@author: marcink
 
"""
 
from formencode import htmlfill
 
from pylons import request, session, tmpl_context as c, url, app_globals as g, \
 
    config
 
from pylons.controllers.util import abort, redirect
 
from pylons.i18n.translation import _
 
from pylons_app.lib import helpers as h
 
from pylons_app.lib.auth import LoginRequired, HasPermissionAllDecorator, \
 
    HasPermissionAnyDecorator
 
from pylons_app.lib.base import BaseController, render
 
from pylons_app.lib.utils import repo2db_mapper, invalidate_cache, \
 
    set_hg_app_config
 
    set_hg_app_config, get_hg_settings
 
from pylons_app.model.db import User, UserLog, HgAppSettings
 
from pylons_app.model.forms import UserForm, ApplicationSettingsForm
 
from pylons_app.model.hg_model import HgModel
 
from pylons_app.model.user_model import UserModel
 
import formencode
 
import logging
 
import traceback
 
 
 
log = logging.getLogger(__name__)
 

	
 

	
 
class SettingsController(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('setting', 'settings', controller='admin/settings', 
 
    #         path_prefix='/admin', name_prefix='admin_')
 

	
 

	
 
    @LoginRequired()
 
    def __before__(self):
 
        c.admin_user = session.get('admin_user')
 
        c.admin_username = session.get('admin_username')
 
        super(SettingsController, self).__before__()
 
    
 
    
 
    @HasPermissionAllDecorator('hg.admin')    
 
    def index(self, format='html'):
 
        """GET /admin/settings: All items in the collection"""
 
        # url('admin_settings')
 

	
 
        hgsettings = self.sa.query(HgAppSettings).scalar()
 
        defaults = hgsettings.__dict__ if hgsettings else {}
 
        defaults = get_hg_settings()
 

	
 
        return htmlfill.render(
 
            render('admin/settings/settings.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False
 
        )  
 
    
 
    @HasPermissionAllDecorator('hg.admin')
 
    def create(self):
 
        """POST /admin/settings: Create a new item"""
 
        # url('admin_settings')
 
    
 
    @HasPermissionAllDecorator('hg.admin')
 
    def new(self, format='html'):
 
        """GET /admin/settings/new: Form to create a new item"""
 
        # url('admin_new_setting')
 
        
 
    @HasPermissionAllDecorator('hg.admin')
 
    def update(self, setting_id):
 
        """PUT /admin/settings/setting_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('admin_setting', setting_id=ID),
 
        #           method='put')
 
        # url('admin_setting', setting_id=ID)
 
        if setting_id == 'mapping':
 
            rm_obsolete = request.POST.get('destroy', False)
 
            log.debug('Rescanning directories with destroy=%s', rm_obsolete)
 

	
 
            initial = HgModel.repo_scan(g.paths[0][0], g.paths[0][1], g.baseui)
 
            repo2db_mapper(initial, rm_obsolete)
 
            invalidate_cache('cached_repo_list')
 
            h.flash(_('Repositories sucessfully rescanned'), category='success')            
 
        
 
        if setting_id == 'global':
 
            
 
            application_form = ApplicationSettingsForm()()
 
            try:
 
                form_result = application_form.to_python(dict(request.POST))
 
                title = form_result['app_title']
 
                realm = form_result['app_auth_realm']
 
            
 
                try:
 
                    hgsettings = self.sa.query(HgAppSettings).get(1)
 
                    hgsettings.app_auth_realm = realm
 
                    hgsettings.app_title = title
 
                    hgsettings1 = self.sa.query(HgAppSettings).filter(HgAppSettings.app_settings_name == 'title').one()
 
                    hgsettings1.app_settings_value = form_result['hg_app_title'] 
 
                    
 
                    self.sa.add(hgsettings)
 
                    hgsettings2 = self.sa.query(HgAppSettings).filter(HgAppSettings.app_settings_name == 'realm').one()
 
                    hgsettings2.app_settings_value = form_result['hg_app_realm'] 
 
                    
 
                    
 
                    self.sa.add(hgsettings1)
 
                    self.sa.add(hgsettings2)
 
                    self.sa.commit()
 
                    set_hg_app_config(config)
 
                    h.flash(_('Updated application settings'),
 
                            category='success')
 
                                    
 
                except:
 
                    log.error(traceback.format_exc())
 
                    h.flash(_('error occured during chaning application settings'),
 
                    h.flash(_('error occured during updating application settings'),
 
                            category='error')
 
                                
 
                    self.sa.rollback()
 
                    
 

	
 
            except formencode.Invalid as errors:
 
                return htmlfill.render(
 
                     render('admin/settings/settings.html'),
 
                     defaults=errors.value,
 
                     errors=errors.error_dict or {},
 
                     prefix_error=False,
 
                     encoding="UTF-8") 
 
                        
 
        return redirect(url('admin_settings'))
 
    
 
    @HasPermissionAllDecorator('hg.admin')
 
    def delete(self, setting_id):
 
        """DELETE /admin/settings/setting_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('admin_setting', setting_id=ID),
 
        #           method='delete')
 
        # url('admin_setting', setting_id=ID)
 
    
 
    @HasPermissionAllDecorator('hg.admin')
 
    def show(self, setting_id, format='html'):
 
        """GET /admin/settings/setting_id: Show a specific item"""
 
        # url('admin_setting', setting_id=ID)
 
    
 
    @HasPermissionAllDecorator('hg.admin')         
 
    def edit(self, setting_id, format='html'):
 
        """GET /admin/settings/setting_id/edit: Form to edit an existing item"""
 
        # url('admin_edit_setting', setting_id=ID)
 

	
 

	
 
    def my_account(self):
 
        """
 
        GET /_admin/my_account Displays info about my account 
 
        """
 
        # url('admin_settings_my_account')
 
        c.user = self.sa.query(User).get(c.hg_app_user.user_id)
 
        if c.user.username == 'default':
 
            h.flash(_("You can't edit this user since it's" 
 
              " crucial for entire application"), category='warning')
 
            return redirect(url('users'))
 
        
 
        defaults = c.user.__dict__
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 sqlalchemy.exc import OperationalError
 
from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
 
import crypt
 
from decorator import decorator
 
import logging
 
"""
 
Created on April 4, 2010
 

	
 
@author: marcink
 
"""
 

	
 
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
 
@@ -141,97 +141,96 @@ def fill_perms(user):
 
    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
 
    
 
    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_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()
 
        #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
 
    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()
 
    print user.permissions
 
    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__)
pylons_app/lib/base.py
Show inline comments
 
"""The base Controller API
 

	
 
Provides the BaseController class for subclassing.
 
"""
 
from pylons import config, tmpl_context as c, request, session
 
from pylons.controllers import WSGIController
 
from pylons.templating import render_mako as render
 
from pylons_app import __version__
 
from pylons_app.lib import auth
 
from pylons_app.lib.utils import get_repo_slug
 
from pylons_app.model import meta
 
from pylons_app.model.hg_model import _get_repos_cached, \
 
    _get_repos_switcher_cached
 

	
 
class BaseController(WSGIController):
 
    
 
    def __before__(self):
 
        c.hg_app_version = __version__
 
        c.hg_app_name = config['hg_app_name']
 
        c.hg_app_name = config['hg_app_title']
 
        c.repo_name = get_repo_slug(request)
 
        c.cached_repo_list = _get_repos_cached()
 
        c.repo_switcher_list = _get_repos_switcher_cached(c.cached_repo_list)
 
        self.sa = meta.Session
 
    
 
    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 every time
 
            c.hg_app_user = auth.get_user(session)
 
            return WSGIController.__call__(self, environ, start_response)
 
        finally:
 
            meta.Session.remove()
pylons_app/lib/db_manage.py
Show inline comments
 
@@ -76,108 +76,114 @@ class DbManage(object):
 
    
 
    def admin_prompt(self):
 
        import getpass
 
        username = raw_input('Specify admin username:')
 
        password = getpass.getpass('Specify admin password:')
 
        self.create_user(username, password, True)
 
    
 
    def config_prompt(self):
 
        log.info('Setting up repositories config')
 
        
 
        path = raw_input('Specify valid full path to your repositories'
 
                        ' you can change this later in application settings:')
 
        
 
        if not os.path.isdir(path):
 
            log.error('You entered wrong path')
 
            sys.exit()
 
        
 
        hooks = HgAppUi()
 
        hooks.ui_section = 'hooks'
 
        hooks.ui_key = 'changegroup'
 
        hooks.ui_value = 'hg update >&2'
 
        
 
        web1 = HgAppUi()
 
        web1.ui_section = 'web'
 
        web1.ui_key = 'push_ssl'
 
        web1.ui_value = 'false'
 
                
 
        web2 = HgAppUi()
 
        web2.ui_section = 'web'
 
        web2.ui_key = 'allow_archive'
 
        web2.ui_value = 'gz zip bz2'
 
                
 
        web3 = HgAppUi()
 
        web3.ui_section = 'web'
 
        web3.ui_key = 'allow_push'
 
        web3.ui_value = '*'
 
        
 
        web4 = HgAppUi()
 
        web4.ui_section = 'web'
 
        web4.ui_key = 'baseurl'
 
        web4.ui_value = '/'                        
 
        
 
        paths = HgAppUi()
 
        paths.ui_section = 'paths'
 
        paths.ui_key = '/'
 
        paths.ui_value = os.path.join(path, '*')
 
        
 
        
 
        hgsettings = HgAppSettings()
 
        hgsettings.app_auth_realm = 'hg-app authentication'
 
        hgsettings.app_title = 'hg-app'
 
        hgsettings1 = HgAppSettings()
 
        
 
        hgsettings1.app_settings_name = 'realm'
 
        hgsettings1.app_settings_value = 'hg-app authentication'
 
        
 
        hgsettings2 = HgAppSettings()
 
        hgsettings2.app_settings_name = 'title'
 
        hgsettings2.app_settings_value = 'hg-app'      
 
        
 
        try:
 
            #self.sa.add(hooks)
 
            self.sa.add(web1)
 
            self.sa.add(web2)
 
            self.sa.add(web3)
 
            self.sa.add(web4)
 
            self.sa.add(paths)
 
            self.sa.add(hgsettings)
 
            self.sa.add(hgsettings1)
 
            self.sa.add(hgsettings2)
 
            self.sa.commit()
 
        except:
 
            self.sa.rollback()
 
            raise        
 
        log.info('created ui config')
 
                    
 
    def create_user(self, username, password, admin=False):
 
        
 
        log.info('creating default user')
 
        #create default user for handling default permissions.
 
        def_user = User()
 
        def_user.username = 'default'
 
        def_user.password = get_crypt_password(str(uuid.uuid1())[:8])
 
        def_user.name = 'default'
 
        def_user.lastname = 'default'
 
        def_user.email = 'default@default.com'
 
        def_user.admin = False
 
        def_user.active = False
 
        
 
        log.info('creating administrator user %s', username)
 
        new_user = User()
 
        new_user.username = username
 
        new_user.password = get_crypt_password(password)
 
        new_user.name = 'Hg'
 
        new_user.lastname = 'Admin'
 
        new_user.email = 'admin@localhost'
 
        new_user.admin = admin
 
        new_user.active = True
 
        
 
        try:
 
            self.sa.add(def_user)
 
            self.sa.add(new_user)
 
            self.sa.commit()
 
        except:
 
            self.sa.rollback()
 
            raise
 
    
 
    def create_permissions(self):
 
        #module.(access|create|change|delete)_[name]
 
        #module.(read|write|owner)
 
        perms = [('repository.none', 'Repository no access'),
 
                 ('repository.read', 'Repository read access'),
 
                 ('repository.write', 'Repository write access'),
 
                 ('repository.admin', 'Repository admin access'),
 
                 ('repository.create', 'Repository create'),
 
                 ('hg.admin', 'Hg Administrator'),
 
                ]
 
        
pylons_app/lib/middleware/simplehg.py
Show inline comments
 
@@ -18,97 +18,97 @@
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
"""
 
Created on 2010-04-28
 

	
 
@author: marcink
 
SimpleHG middleware for handling mercurial protocol request (push/clone etc.)
 
It's implemented with basic auth function
 
"""
 
from datetime import datetime
 
from itertools import chain
 
from mercurial.error import RepoError
 
from mercurial.hgweb import hgweb
 
from mercurial.hgweb.request import wsgiapplication
 
from paste.auth.basic import AuthBasicAuthenticator
 
from paste.httpheaders import REMOTE_USER, AUTH_TYPE
 
from pylons_app.lib.auth import authfunc, HasPermissionAnyMiddleware, \
 
    get_user_cached
 
from pylons_app.lib.utils import is_mercurial, make_ui, invalidate_cache, \
 
    check_repo_fast
 
from pylons_app.model import meta
 
from pylons_app.model.db import UserLog, User
 
from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
 
import logging
 
import os
 
import pylons_app.lib.helpers as h
 
import traceback
 
 
 
log = logging.getLogger(__name__)
 

	
 
class SimpleHg(object):
 

	
 
    def __init__(self, application, config):
 
        self.application = application
 
        self.config = config
 
        #authenticate this mercurial request using 
 
        self.authenticate = AuthBasicAuthenticator('', authfunc)
 
        
 
    def __call__(self, environ, start_response):
 
        if not is_mercurial(environ):
 
            return self.application(environ, start_response)
 

	
 
        #===================================================================
 
        # AUTHENTICATE THIS MERCURIAL REQUEST
 
        #===================================================================
 
        username = REMOTE_USER(environ)
 
        if not username:
 
            self.authenticate.realm = self.config['hg_app_auth_realm']
 
            self.authenticate.realm = self.config['hg_app_realm']
 
            result = self.authenticate(environ)
 
            if isinstance(result, str):
 
                AUTH_TYPE.update(environ, 'basic')
 
                REMOTE_USER.update(environ, result)
 
            else:
 
                return result.wsgi_application(environ, start_response)
 
        
 
        try:
 
            repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
 
        except:
 
            log.error(traceback.format_exc())
 
            return HTTPInternalServerError()(environ, start_response)
 
        
 
        #===================================================================
 
        # CHECK PERMISSIONS FOR THIS REQUEST
 
        #===================================================================
 
        action = self.__get_action(environ)
 
        if action:
 
            username = self.__get_environ_user(environ)
 
            try:
 
                user = self.__get_user(username)
 
            except:
 
                log.error(traceback.format_exc())
 
                return HTTPInternalServerError()(environ, start_response)
 
            #check permissions for this repository
 
            if action == 'pull':
 
                if not HasPermissionAnyMiddleware('repository.read',
 
                                                  'repository.write',
 
                                                  'repository.admin')\
 
                                                    (user, repo_name):
 
                    return HTTPForbidden()(environ, start_response)
 
            if action == 'push':
 
                if not HasPermissionAnyMiddleware('repository.write',
 
                                                  'repository.admin')\
 
                                                    (user, repo_name):
 
                    return HTTPForbidden()(environ, start_response)
 
            
 
            #log action    
 
            proxy_key = 'HTTP_X_REAL_IP'
 
            def_key = 'REMOTE_ADDR'
 
            ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0'))
 
            self.__log_user_action(user, action, repo_name, ipaddr)            
 
        
 
        #===================================================================
 
        # MERCURIAL REQUEST HANDLING
 
        #===================================================================
 
        environ['PATH_INFO'] = '/'#since we wrap into hgweb, reset the path
 
        self.baseui = make_ui('db')
pylons_app/lib/utils.py
Show inline comments
 
@@ -55,153 +55,158 @@ def check_repo_dir(paths):
 
        repos_path[0] = '/'
 
    if not os.path.isdir(os.path.join(*repos_path)):
 
        raise Exception('Not a valid repository in %s' % paths[0][1])
 

	
 
def check_repo_fast(repo_name, base_path):
 
    if os.path.isdir(os.path.join(base_path, repo_name)):return False
 
    return True
 

	
 
def check_repo(repo_name, base_path, verify=True):
 

	
 
    repo_path = os.path.join(base_path, repo_name)
 

	
 
    try:
 
        if not check_repo_fast(repo_name, base_path):
 
            return False
 
        r = hg.repository(ui.ui(), repo_path)
 
        if verify:
 
            hg.verify(r)
 
        #here we hnow that repo exists it was verified
 
        log.info('%s repo is already created', repo_name)
 
        return False
 
    except RepoError:
 
        #it means that there is no valid repo there...
 
        log.info('%s repo is free for creation', repo_name)
 
        return True
 

	
 
def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
 
    while True:
 
        ok = raw_input(prompt)
 
        if ok in ('y', 'ye', 'yes'): return True
 
        if ok in ('n', 'no', 'nop', 'nope'): return False
 
        retries = retries - 1
 
        if retries < 0: raise IOError
 
        print complaint
 
        
 
@cache_region('super_short_term', 'cached_hg_ui')
 
def get_hg_ui_cached():
 
    try:
 
        sa = meta.Session
 
        ret = sa.query(HgAppUi).all()
 
    finally:
 
        meta.Session.remove()
 
    return ret
 

	
 

	
 
def get_hg_settings():
 
    try:
 
        sa = meta.Session
 
        ret = sa.query(HgAppSettings).scalar()
 
        ret = sa.query(HgAppSettings).all()
 
    finally:
 
        meta.Session.remove()
 
        
 
    if not ret:
 
        raise Exception('Could not get application settings !')
 
    return ret
 
    settings = {}
 
    for each in ret:
 
        settings['hg_app_' + each.app_settings_name] = each.app_settings_value    
 
    
 
    return settings
 
    
 
def make_ui(read_from='file', path=None, checkpaths=True):        
 
    """
 
    A function that will read python rc files or database
 
    and make an mercurial ui object from read options
 
    
 
    @param path: path to mercurial config file
 
    @param checkpaths: check the path
 
    @param read_from: read from 'file' or 'db'
 
    """
 
    #propagated from mercurial documentation
 
    sections = ['alias', 'auth',
 
                'decode/encode', 'defaults',
 
                'diff', 'email',
 
                'extensions', 'format',
 
                'merge-patterns', 'merge-tools',
 
                'hooks', 'http_proxy',
 
                'smtp', 'patch',
 
                'paths', 'profiling',
 
                'server', 'trusted',
 
                'ui', 'web', ]
 
    baseui = ui.ui()
 

	
 
                
 
    if read_from == 'file':
 
        if not os.path.isfile(path):
 
            log.warning('Unable to read config file %s' % path)
 
            return False
 
        
 
        cfg = config.config()
 
        cfg.read(path)
 
        for section in sections:
 
            for k, v in cfg.items(section):
 
                baseui.setconfig(section, k, v)
 
        if checkpaths:check_repo_dir(cfg.items('paths'))                
 
              
 
        
 
    elif read_from == 'db':
 
        hg_ui = get_hg_ui_cached()
 
        for ui_ in hg_ui:
 
            baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
 
        
 
    
 
    return baseui
 

	
 

	
 
def set_hg_app_config(config):
 
    hgsettings = get_hg_settings()
 
    config['hg_app_auth_realm'] = hgsettings.app_auth_realm
 
    config['hg_app_name'] = hgsettings.app_title
 
    
 
    for k, v in hgsettings.items():
 
        config[k] = v
 

	
 
def invalidate_cache(name, *args):
 
    """Invalidates given name cache"""
 
    
 
    from beaker.cache import region_invalidate
 
    log.info('INVALIDATING CACHE FOR %s', name)
 
    
 
    """propagate our arguments to make sure invalidation works. First
 
    argument has to be the name of cached func name give to cache decorator
 
    without that the invalidation would not work"""
 
    tmp = [name]
 
    tmp.extend(args)
 
    args = tuple(tmp)
 
    
 
    if name == 'cached_repo_list':
 
        from pylons_app.model.hg_model import _get_repos_cached
 
        region_invalidate(_get_repos_cached, None, *args)
 
        
 
    if name == 'full_changelog':
 
        from pylons_app.model.hg_model import _full_changelog_cached
 
        region_invalidate(_full_changelog_cached, None, *args)
 
        
 
class EmptyChangeset(BaseChangeset):
 
    
 
    revision = -1
 
    message = ''
 
    
 
    @LazyProperty
 
    def raw_id(self):
 
        """
 
        Returns raw string identifing this changeset, useful for web
 
        representation.
 
        """
 
        return '0' * 12
 

	
 

	
 
def repo2db_mapper(initial_repo_list, remove_obsolete=False):
 
    """
 
    maps all found repositories into db
 
    """
 
    from pylons_app.model.repo_model import RepoModel
 
    
 
    sa = meta.Session
 
    user = sa.query(User).filter(User.admin == True).first()
 
    
 
    rm = RepoModel()
 
    
 
    for name, repo in initial_repo_list.items():
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__ = {'useexisting':True}
 
    __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_title = Column("app_title", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    app_auth_realm = Column("auth_realm", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    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)
 

	
 
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)
pylons_app/model/forms.py
Show inline comments
 
@@ -252,55 +252,55 @@ def UserForm(edit=False, old_data={}):
 
        allow_extra_fields = True
 
        filter_extra_fields = True
 
        username = All(UnicodeString(strip=True, min=3, not_empty=True), ValidUsername(edit, old_data))
 
        if edit:
 
            new_password = All(UnicodeString(strip=True, min=3, not_empty=False), ValidPassword)
 
            admin = StringBoolean(if_missing=False)
 
        else:
 
            password = All(UnicodeString(strip=True, min=8, not_empty=True), ValidPassword)
 
        active = StringBoolean(if_missing=False)
 
        name = UnicodeString(strip=True, min=3, not_empty=True)
 
        lastname = UnicodeString(strip=True, min=3, not_empty=True)
 
        email = Email(not_empty=True)
 
        
 
    return _UserForm
 

	
 
RegisterForm = UserForm
 
    
 
    
 
def RepoForm(edit=False, old_data={}):
 
    class _RepoForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = False
 
        repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
 
        description = UnicodeString(strip=True, min=3, not_empty=True)
 
        private = StringBoolean(if_missing=False)
 
        
 
        if edit:
 
            user = All(Int(not_empty=True), ValidRepoUser)
 
        
 
        chained_validators = [ValidPerms]
 
    return _RepoForm
 

	
 
def RepoSettingsForm(edit=False, old_data={}):
 
    class _RepoForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = False
 
        repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
 
        description = UnicodeString(strip=True, min=3, not_empty=True)
 
        private = StringBoolean(if_missing=False)
 
        
 
        chained_validators = [ValidPerms, ValidSettings]
 
    return _RepoForm
 

	
 

	
 
def ApplicationSettingsForm():
 
    class _ApplicationSettingsForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = False
 
        app_title = UnicodeString(strip=True, min=3, not_empty=True)
 
        app_auth_realm = UnicodeString(strip=True, min=3, not_empty=True)
 
        hg_app_title = UnicodeString(strip=True, min=3, not_empty=True)
 
        hg_app_realm = UnicodeString(strip=True, min=3, not_empty=True)
 
        
 
    return _ApplicationSettingsForm
 
 
 

	
 

	
pylons_app/templates/admin/settings/settings.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
<%inherit file="/base/base.html"/>
 

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

	
 

	
 

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

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

	
 
<%def name="main()">
 
<div class="box">
 
    <!-- box / title -->
 
    <div class="title">
 
        ${self.breadcrumbs()}       
 
    </div>
 
    <!-- end box / title -->
 
    
 
    ${h.form(url('admin_setting', setting_id='mapping'),method='put')}
 
    <div class="form">
 
        <!-- fields -->
 
        <h3>${_('Remap and rescan repositories')}</h3>
 
        <div class="fields">
 
			<div class="field">
 
		        <div class="label label-checkbox">
 
		            <label for="-button">${_('rescan option')}:</label>
 
		            <label for="destroy">${_('rescan option')}:</label>
 
		        </div>
 
		        <div class="checkboxes">
 
		            <div class="checkbox">
 
		                ${h.checkbox('destroy',True)}
 
		                <label for="checkbox-1">
 
		                <span class="tooltip" tooltip_title="${h.tooltip(_('In case a repository was deleted from filesystem and there are leftovers in the database check this option to scan obsolete data in database and remove it.'))}">
 
		                ${_('destroy old data')}</span> </label>
 
		            </div>
 
		        </div>
 
			</div>
 
                            
 
            <div class="buttons">
 
            ${h.submit('rescan','rescan repositories',class_="ui-button ui-widget ui-state-default ui-corner-all")}
 
            </div>                                                          
 
        </div>
 
    </div>  
 
    ${h.end_form()}
 
     
 
    ${h.form(url('admin_setting', setting_id='global'),method='put')}
 
    <div class="form">
 
        <!-- fields -->
 
        <h3>${_('Global application settings')}</h3>
 
        <div class="fields">
 
             
 
             <div class="field">
 
                <div class="label">
 
                    <label for="input-small">${_('Application name')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('app_title',size=30)}
 
                    ${h.text('hg_app_title',size=30)}
 
                </div>
 
             </div>
 
                          
 
            <div class="field">
 
                <div class="label">
 
                    <label for="input-small">${_('Realm text')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('app_auth_realm',size=30)}
 
                    ${h.text('hg_app_realm',size=30)}
 
                </div>
 
            </div>
 
                                     
 
            <div class="buttons">
 
                ${h.submit('save','save settings',class_="ui-button ui-widget ui-state-default ui-corner-all")}
 
           </div>                                                          
 
        </div>
 
    </div>      
 
    ${h.end_form()}
 
    
 
</div>
 
</%def>    
0 comments (0 inline, 0 general)