Changeset - e8af467b5a60
[Not reviewed]
default
0 4 0
Marcin Kuzminski - 15 years ago 2010-08-06 02:40:57
marcin@python-works.com
Added hooks managment into application settings
4 files changed with 48 insertions and 5 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, get_hg_settings, get_hg_ui_settings, make_ui
 
from pylons_app.model.db import User, UserLog, HgAppSettings, HgAppUi
 
from pylons_app.model.forms import UserForm, ApplicationSettingsForm, \
 
    ApplicationUiSettingsForm
 
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')
 

	
 
        defaults = get_hg_settings()
 
        defaults.update(get_hg_ui_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))
 
            
 
                try:
 
                    hgsettings1 = self.sa.query(HgAppSettings)\
 
                    .filter(HgAppSettings.app_settings_name == 'title').one()
 
                    hgsettings1.app_settings_value = form_result['hg_app_title'] 
 
                    
 
                    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 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") 
 
        
 
        if setting_id == 'mercurial':
 
            application_form = ApplicationUiSettingsForm()()
 
            try:
 
                form_result = application_form.to_python(dict(request.POST))
 
            
 
                try:
 
                    
 
                    hgsettings1 = self.sa.query(HgAppUi)\
 
                    .filter(HgAppUi.ui_key == 'push_ssl').one()
 
                    hgsettings1.ui_value = form_result['web_push_ssl']
 
                    
 
                    hgsettings2 = self.sa.query(HgAppUi)\
 
                    .filter(HgAppUi.ui_key == '/').one()
 
                    hgsettings2.ui_value = form_result['paths_root_path']                    
 
                    
 
                    
 
                    #HOOKS
 
                    hgsettings3 = self.sa.query(HgAppUi)\
 
                    .filter(HgAppUi.ui_key == 'changegroup.update').one()
 
                    hgsettings3.ui_active = bool(form_result['hooks_changegroup_update'])  
 
                    
 
                    hgsettings4 = self.sa.query(HgAppUi)\
 
                    .filter(HgAppUi.ui_key == 'changegroup.repo_size').one()
 
                    hgsettings4.ui_active = bool(form_result['hooks_changegroup_repo_size'])                                          
 
                    
 
                    
 
                    
 
                    
 
                    self.sa.add(hgsettings1)
 
                    self.sa.add(hgsettings2)
 
                    self.sa.add(hgsettings3)
 
                    self.sa.add(hgsettings4)
 
                    self.sa.commit()
 
                    
 
                    h.flash(_('Updated application settings'),
 
                            category='success')
 
                                    
 
                except:
 
                    log.error(traceback.format_exc())
 
                    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__
 
        return htmlfill.render(
 
            render('admin/users/user_edit_my_account.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False
 
        ) 
 

	
 
    def my_account_update(self):
 
        """PUT /_admin/my_account_update: 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_settings_my_account_update'),
 
        #           method='put')
 
        # url('admin_settings_my_account_update', id=ID)
 
        user_model = UserModel()
 
        uid = c.hg_app_user.user_id
 
        _form = UserForm(edit=True, old_data={'user_id':uid})()
 
        form_result = {}
 
        try:
 
            form_result = _form.to_python(dict(request.POST))
 
            user_model.update_my_account(uid, form_result)
 
            h.flash(_('Your account was updated succesfully'), category='success')
 
                           
 
        except formencode.Invalid as errors:
 
            #c.user = self.sa.query(User).get(c.hg_app_user.user_id)
 
            return htmlfill.render(
 
                render('admin/users/user_edit_my_account.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 user %s') \
 
                    % form_result.get('username'), category='error')
 
                    
 
        return redirect(url('my_account'))
 
    
 
    @HasPermissionAnyDecorator('repository.create', 'hg.admin')
 
    def create_repository(self):
 
        """GET /_admin/create_repository: Form to create a new item"""
 
        new_repo = request.GET.get('repo', '')
 
        c.new_repo = h.repo_name_slug(new_repo)
 

	
 
        return render('admin/repos/repo_add_create_repository.html')
 
        
pylons_app/lib/utils.py
Show inline comments
 
#!/usr/bin/env python
 
# encoding: utf-8
 
# Utilities for hg app
 
# 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 18, 2010
 
Utilities for hg app
 
@author: marcink
 
"""
 
from beaker.cache import cache_region
 
from mercurial import ui, config, hg
 
from mercurial.error import RepoError
 
from pylons_app.model import meta
 
from pylons_app.model.db import Repository, User, HgAppUi, HgAppSettings
 
from vcs.backends.base import BaseChangeset
 
from vcs.utils.lazy import LazyProperty
 
import logging
 
import os
 
log = logging.getLogger(__name__)
 

	
 

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

	
 
def is_mercurial(environ):
 
    """
 
    Returns True if request's target is mercurial server - header
 
    ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
 
    """
 
    http_accept = environ.get('HTTP_ACCEPT')
 
    if http_accept and http_accept.startswith('application/mercurial'):
 
        return True
 
    return False
 

	
 
def check_repo_dir(paths):
 
    repos_path = paths[0][1].split('/')
 
    if repos_path[-1] in ['*', '**']:
 
        repos_path = repos_path[:-1]
 
    if repos_path[0] != '/':
 
        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).all()
 
    finally:
 
        meta.Session.remove()
 
        
 
    if not ret:
 
        raise Exception('Could not get application settings !')
 
    settings = {}
 
    for each in ret:
 
        settings['hg_app_' + each.app_settings_name] = each.app_settings_value    
 
    
 
    return settings
 

	
 
def get_hg_ui_settings():
 
    try:
 
        sa = meta.Session
 
        ret = sa.query(HgAppUi).all()
 
    finally:
 
        meta.Session.remove()
 
        
 
    if not ret:
 
        raise Exception('Could not get application ui settings !')
 
    settings = {}
 
    for each in ret:
 
        k = each.ui_key if each.ui_key != '/' else 'root_path'
 
        settings[each.ui_section + '_' + k] = each.ui_value    
 
        k = each.ui_key
 
        v = each.ui_value
 
        if k == '/':
 
            k = 'root_path'
 
        
 
        if k.find('.') != -1:
 
            k = k.replace('.', '_')
 
        
 
        if each.ui_section == 'hooks':
 
            v = each.ui_active
 
        
 
        settings[each.ui_section + '_' + k] = v  
 
    
 
    return settings
 

	
 
#propagated from mercurial documentation
 
ui_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', ]
 
        
 
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'
 
    """
 

	
 
    baseui = ui.ui()
 

	
 
    if read_from == 'file':
 
        if not os.path.isfile(path):
 
            log.warning('Unable to read config file %s' % path)
 
            return False
 
        log.debug('reading hgrc from %s', path)
 
        cfg = config.config()
 
        cfg.read(path)
 
        for section in ui_sections:
 
            for k, v in cfg.items(section):
 
                baseui.setconfig(section, k, v)
 
                log.debug('settings ui from file[%s]%s:%s', 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:
 
            if ui_.ui_active:
 
                log.debug('settings ui from db[%s]%s:%s', ui_.ui_section, ui_.ui_key, ui_.ui_value)
 
                baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
 
        
 
    
 
    return baseui
 

	
 

	
 
def set_hg_app_config(config):
 
    hgsettings = get_hg_settings()
 
    
 
    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():
 
        if not sa.query(Repository).filter(Repository.repo_name == name).scalar():
 
            log.info('repository %s not found creating default', name)
 
                
 
            form_data = {
 
                         'repo_name':name,
 
                         'description':repo.description if repo.description != 'unknown' else \
 
                                        'auto description for %s' % name,
 
                         'private':False
 
                         }
 
            rm.create(form_data, user, just_db=True)
 

	
 

	
 
    if remove_obsolete:
 
        #remove from database those repositories that are not in the filesystem
 
        for repo in sa.query(Repository).all():
 
            if repo.repo_name not in initial_repo_list.keys():
 
                sa.delete(repo)
 
                sa.commit()
 

	
 
    
 
    meta.Session.remove()
 

	
 
from UserDict import DictMixin
 

	
 
class OrderedDict(dict, DictMixin):
 

	
 
    def __init__(self, *args, **kwds):
 
        if len(args) > 1:
 
            raise TypeError('expected at most 1 arguments, got %d' % len(args))
 
        try:
 
            self.__end
 
        except AttributeError:
 
            self.clear()
 
        self.update(*args, **kwds)
 

	
 
    def clear(self):
 
        self.__end = end = []
 
        end += [None, end, end]         # sentinel node for doubly linked list
 
        self.__map = {}                 # key --> [key, prev, next]
 
        dict.clear(self)
 

	
 
    def __setitem__(self, key, value):
 
        if key not in self:
 
            end = self.__end
 
            curr = end[1]
 
            curr[2] = end[1] = self.__map[key] = [key, curr, end]
 
        dict.__setitem__(self, key, value)
 

	
 
    def __delitem__(self, key):
 
        dict.__delitem__(self, key)
 
        key, prev, next = self.__map.pop(key)
 
        prev[2] = next
 
        next[1] = prev
 

	
 
    def __iter__(self):
 
        end = self.__end
 
        curr = end[2]
 
        while curr is not end:
 
            yield curr[0]
 
            curr = curr[2]
 

	
 
    def __reversed__(self):
 
        end = self.__end
 
        curr = end[1]
 
        while curr is not end:
 
            yield curr[0]
 
            curr = curr[1]
 

	
 
    def popitem(self, last=True):
 
        if not self:
 
            raise KeyError('dictionary is empty')
 
        if last:
 
            key = reversed(self).next()
 
        else:
 
            key = iter(self).next()
 
        value = self.pop(key)
 
        return key, value
 

	
 
    def __reduce__(self):
 
        items = [[k, self[k]] for k in self]
 
        tmp = self.__map, self.__end
 
        del self.__map, self.__end
 
        inst_dict = vars(self).copy()
 
        self.__map, self.__end = tmp
 
        if inst_dict:
 
            return (self.__class__, (items,), inst_dict)
 
        return self.__class__, (items,)
pylons_app/model/forms.py
Show inline comments
 
@@ -134,195 +134,197 @@ class ValidAuth(formencode.validators.Fa
 
                                             state=State_obj), value, state,
 
                                             error_dict=self.e_dict)
 
            else:
 
                log.warning('user %s is disabled', username)
 
                raise formencode.Invalid(self.message('disabled_account',
 
                                         state=State_obj),
 
                                         value, state,
 
                                         error_dict=self.e_dict_disable)
 
            
 
        meta.Session.remove()
 

	
 
                   
 
class ValidRepoUser(formencode.validators.FancyValidator):
 
            
 
    def to_python(self, value, state):
 
        sa = meta.Session
 
        try:
 
            self.user_db = sa.query(User)\
 
                .filter(User.active == True)\
 
                .filter(User.username == value).one()
 
        except Exception:
 
            raise formencode.Invalid(_('This username is not valid'),
 
                                     value, state)
 
        meta.Session.remove()            
 
        return self.user_db.user_id
 

	
 
def ValidRepoName(edit, old_data):    
 
    class _ValidRepoName(formencode.validators.FancyValidator):
 
            
 
        def to_python(self, value, state):
 
            slug = h.repo_name_slug(value)
 
            if slug in ['_admin']:
 
                raise formencode.Invalid(_('This repository name is disallowed'),
 
                                         value, state)
 
            if old_data.get('repo_name') != value or not edit:    
 
                sa = meta.Session
 
                if sa.query(Repository).filter(Repository.repo_name == slug).scalar():
 
                    raise formencode.Invalid(_('This repository already exists') ,
 
                                             value, state)
 
                meta.Session.remove()
 
            return slug 
 
        
 
        
 
    return _ValidRepoName
 

	
 
class ValidPerms(formencode.validators.FancyValidator):
 
    messages = {'perm_new_user_name':_('This username is not valid')}
 
    
 
    def to_python(self, value, state):
 
        perms_update = []
 
        perms_new = []
 
        #build a list of permission to update and new permission to create
 
        for k, v in value.items():
 
            if k.startswith('perm_'):
 
                if  k.startswith('perm_new_user'):
 
                    new_perm = value.get('perm_new_user', False)
 
                    new_user = value.get('perm_new_user_name', False)
 
                    if new_user and new_perm:
 
                        if (new_user, new_perm) not in perms_new:
 
                            perms_new.append((new_user, new_perm))
 
                else:
 
                    usr = k[5:]                    
 
                    if usr == 'default':
 
                        if value['private']:
 
                            #set none for default when updating to private repo
 
                            v = 'repository.none'
 
                    perms_update.append((usr, v))
 
        value['perms_updates'] = perms_update
 
        value['perms_new'] = perms_new
 
        sa = meta.Session
 
        for k, v in perms_new:
 
            try:
 
                self.user_db = sa.query(User)\
 
                    .filter(User.active == True)\
 
                    .filter(User.username == k).one()
 
            except Exception:
 
                msg = self.message('perm_new_user_name',
 
                                     state=State_obj)
 
                raise formencode.Invalid(msg, value, state, error_dict={'perm_new_user_name':msg})            
 
        return value
 
    
 
class ValidSettings(formencode.validators.FancyValidator):
 
    
 
    def to_python(self, value, state):
 
        #settings  form can't edit user
 
        if value.has_key('user'):
 
            del['value']['user']
 
        
 
        return value
 
    
 
class ValidPath(formencode.validators.FancyValidator):
 
    def to_python(self, value, state):
 
        isdir = os.path.isdir(value.replace('*', ''))
 
        if (value.endswith('/*') or value.endswith('/**')) and isdir:
 
            return value
 
        elif not isdir:
 
            msg = _('This is not a valid path') 
 
        else:
 
            msg = _('You need to specify * or ** at the end of path (ie. /tmp/*)')
 
        
 
        raise formencode.Invalid(msg, value, state,
 
                                     error_dict={'paths_root_path':msg})            
 
                       
 
#===============================================================================
 
# FORMS        
 
#===============================================================================
 
class LoginForm(formencode.Schema):
 
    allow_extra_fields = True
 
    filter_extra_fields = True
 
    username = UnicodeString(
 
                             strip=True,
 
                             min=3,
 
                             not_empty=True,
 
                             messages={
 
                                       'empty':_('Please enter a login'),
 
                                       'tooShort':_('Enter a value %(min)i characters long or more')}
 
                            )
 

	
 
    password = UnicodeString(
 
                            strip=True,
 
                            min=3,
 
                            not_empty=True,
 
                            messages={
 
                                      'empty':_('Please enter a password'),
 
                                      'tooShort':_('Enter a value %(min)i characters long or more')}
 
                                )
 

	
 

	
 
    #chained validators have access to all data
 
    chained_validators = [ValidAuth]
 
    
 
def UserForm(edit=False, old_data={}):
 
    class _UserForm(formencode.Schema):
 
        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
 
        hg_app_title = UnicodeString(strip=True, min=3, not_empty=True)
 
        hg_app_realm = UnicodeString(strip=True, min=3, not_empty=True)
 
        
 
    return _ApplicationSettingsForm
 
 
 
def ApplicationUiSettingsForm():
 
    class _ApplicationUiSettingsForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = False
 
        web_push_ssl = OneOf(['true', 'false'], if_missing='false')
 
        paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=3, not_empty=True))
 
        hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
 
        hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
 
        
 
    return _ApplicationUiSettingsForm
 

	
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 -->
 
    
 
    <h3>${_('Remap and rescan repositories')}</h3>
 
    ${h.form(url('admin_setting', setting_id='mapping'),method='put')}
 
    <div class="form">
 
        <!-- fields -->
 
        
 
        <div class="fields">
 
			<div class="field">
 
		        <div class="label label-checkbox">
 
		            <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()}
 
     
 
    <h3>${_('Global application settings')}</h3> 
 
    ${h.form(url('admin_setting', setting_id='global'),method='put')}
 
    <div class="form">
 
        <!-- fields -->
 
        
 
        <div class="fields">
 
             
 
             <div class="field">
 
                <div class="label">
 
                    <label for="hg_app_title">${_('Application name')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('hg_app_title',size=30)}
 
                </div>
 
             </div>
 
                          
 
            <div class="field">
 
                <div class="label">
 
                    <label for="hg_app_realm">${_('Realm text')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${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()}
 

	
 
    <h3>${_('Mercurial settings')}</h3> 
 
    ${h.form(url('admin_setting', setting_id='mercurial'),method='put')}
 
    <div class="form">
 
        <!-- fields -->
 
        
 
        <div class="fields">
 
             
 
             <div class="field">
 
                <div class="label label-checkbox">
 
                    <label for="web_push_ssl">${_('Push ssl')}:</label>
 
                    <label for="web_push_ssl">${_('Web')}:</label>
 
                </div>
 
                <div class="checkboxes">
 
					<div class="checkbox">
 
						${h.checkbox('web_push_ssl','true')}
 
						<label for="web_push_ssl">${_('require ssl for pushing')}</label>
 
					</div>
 
				</div>
 
             </div>						
 
							                          
 
            <div class="field">
 
                <div class="label label-checkbox">
 
                    <label for="web_push_ssl">${_('Hooks')}:</label>
 
                </div>
 
                <div class="checkboxes">
 
					<div class="checkbox">
 
						${h.checkbox('hooks_changegroup_update','True')}
 
						<label for="hooks_changegroup_update">${_('Update repository after push (hg update)')}</label>
 
					</div>
 
					<div class="checkbox">
 
						${h.checkbox('hooks_changegroup_repo_size','True')}
 
						<label for="hooks_changegroup_repo_size">${_('Show repository size after push')}</label>
 
					</div>					
 
				</div>
 
             </div>	
 
							                          
 
            <div class="field">
 
                <div class="label">
 
                    <label for="paths_root_path">${_('Repositories location')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('paths_root_path',size=30,disabled="disabled")}
 
                    ${h.text('paths_root_path',size=30,readonly="readonly")}
 
					<span id="path_unlock" class="tooltip" tooltip_title="${h.tooltip(_('This a crucial application setting. If You really sure you need to change this, you must restart application in order to make this settings take effect. Click this label to unlock.'))}">
 
		                ${_('unlock')}</span>
 
                </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()}
 
    
 
    <script type="text/javascript">
 
        YAHOO.util.Event.onDOMReady(function(){
 
            YAHOO.util.Event.addListener('path_unlock','click',function(){
 
                YAHOO.util.Dom.get('paths_root_path').disabled=false;
 
                YAHOO.util.Dom.get('paths_root_path').readonly=false;
 
            });
 
        });
 
    </script>
 
    
 
</div>
 
</%def>    
0 comments (0 inline, 0 general)