Changeset - 17ff5693566b
[Not reviewed]
beta
0 6 0
Marcin Kuzminski - 14 years ago 2012-04-23 18:32:30
marcin@python-works.com
white space cleanup
6 files changed with 8 insertions and 10 deletions:
0 comments (0 inline, 0 general)
rhodecode/controllers/admin/settings.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.admin.settings
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    settings controller for rhodecode admin
 

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

	
 
import logging
 
import traceback
 
import formencode
 
import pkg_resources
 
import platform
 

	
 
from sqlalchemy import func
 
from formencode import htmlfill
 
from pylons import request, session, tmpl_context as c, url, config
 
from pylons.controllers.util import abort, redirect
 
from pylons.i18n.translation import _
 

	
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
 
    HasPermissionAnyDecorator, NotAnonymous
 
from rhodecode.lib.base import BaseController, render
 
from rhodecode.lib.celerylib import tasks, run_task
 
from rhodecode.lib.utils import repo2db_mapper, invalidate_cache, \
 
    set_rhodecode_config, repo_name_slug
 
from rhodecode.model.db import RhodeCodeUi, Repository, RepoGroup, \
 
    RhodeCodeSetting
 
from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
 
    ApplicationUiSettingsForm
 
from rhodecode.model.scm import ScmModel
 
from rhodecode.model.user import UserModel
 
from rhodecode.model.db import User
 
from rhodecode.model.notification import EmailNotificationModel
 
from rhodecode.model.meta import Session
 

	
 
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')
 
        c.modules = sorted([(p.project_name, p.version) 
 
        c.modules = sorted([(p.project_name, p.version)
 
                            for p in pkg_resources.working_set])
 
        c.py_version = platform.python_version()
 
        c.platform = platform.platform()        
 
        c.platform = platform.platform()
 
        super(SettingsController, self).__before__()
 

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

	
 
        defaults = RhodeCodeSetting.get_app_settings()
 
        defaults.update(self.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 = ScmModel().repo_scan()
 
            log.debug('invalidating all repositories')
 
            for repo_name in initial.keys():
 
                invalidate_cache('get_repo_cached_%s' % repo_name)
 

	
 
            added, removed = repo2db_mapper(initial, rm_obsolete)
 

	
 
            h.flash(_('Repositories successfully'
 
                      ' rescanned added: %s,removed: %s') % (added, removed),
 
                    category='success')
 

	
 
        if setting_id == 'whoosh':
 
            repo_location = self.get_hg_ui_settings()['paths_root_path']
 
            full_index = request.POST.get('full_index', False)
 
            run_task(tasks.whoosh_index, repo_location, full_index)
 

	
 
            h.flash(_('Whoosh reindex task scheduled'), category='success')
 
        if setting_id == 'global':
 

	
 
            application_form = ApplicationSettingsForm()()
 
            try:
 
                form_result = application_form.to_python(dict(request.POST))
 

	
 
                try:
 
                    hgsettings1 = RhodeCodeSetting.get_by_name('title')
 
                    hgsettings1.app_settings_value = \
 
                        form_result['rhodecode_title']
 

	
 
                    hgsettings2 = RhodeCodeSetting.get_by_name('realm')
 
                    hgsettings2.app_settings_value = \
 
                        form_result['rhodecode_realm']
 

	
 
                    hgsettings3 = RhodeCodeSetting.get_by_name('ga_code')
 
                    hgsettings3.app_settings_value = \
 
                        form_result['rhodecode_ga_code']
 

	
 
                    self.sa.add(hgsettings1)
 
                    self.sa.add(hgsettings2)
 
                    self.sa.add(hgsettings3)
 
                    self.sa.commit()
 
                    set_rhodecode_config(config)
 
                    h.flash(_('Updated application settings'),
 
                            category='success')
 

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

	
 
                    self.sa.rollback()
 

	
 
            except formencode.Invalid, 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(RhodeCodeUi)\
 
                    .filter(RhodeCodeUi.ui_key == 'push_ssl').one()
 
                    hgsettings1.ui_value = form_result['web_push_ssl']
 

	
 
                    hgsettings2 = self.sa.query(RhodeCodeUi)\
 
                    .filter(RhodeCodeUi.ui_key == '/').one()
 
                    hgsettings2.ui_value = form_result['paths_root_path']
 

	
 
                    #HOOKS
 
                    hgsettings3 = self.sa.query(RhodeCodeUi)\
 
                    .filter(RhodeCodeUi.ui_key == 'changegroup.update').one()
 
                    hgsettings3.ui_active = \
 
                        bool(form_result['hooks_changegroup_update'])
 

	
 
                    hgsettings4 = self.sa.query(RhodeCodeUi)\
 
                    .filter(RhodeCodeUi.ui_key ==
 
                            'changegroup.repo_size').one()
 
                    hgsettings4.ui_active = \
 
                        bool(form_result['hooks_changegroup_repo_size'])
 

	
 
                    hgsettings5 = self.sa.query(RhodeCodeUi)\
 
                    .filter(RhodeCodeUi.ui_key ==
 
                            'pretxnchangegroup.push_logger').one()
 
                    hgsettings5.ui_active = \
 
                        bool(form_result['hooks_pretxnchangegroup'
 
                                         '_push_logger'])
 

	
 
                    hgsettings6 = self.sa.query(RhodeCodeUi)\
 
                    .filter(RhodeCodeUi.ui_key ==
 
                            'preoutgoing.pull_logger').one()
 
                    hgsettings6.ui_active = \
 
                        bool(form_result['hooks_preoutgoing_pull_logger'])
 

	
 
                    self.sa.add(hgsettings1)
 
                    self.sa.add(hgsettings2)
 
                    self.sa.add(hgsettings3)
 
                    self.sa.add(hgsettings4)
 
                    self.sa.add(hgsettings5)
 
                    self.sa.add(hgsettings6)
 
                    self.sa.commit()
 

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

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

	
 
                    self.sa.rollback()
 

	
 
            except formencode.Invalid, 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 == 'hooks':
 
            ui_key = request.POST.get('new_hook_ui_key')
 
            ui_value = request.POST.get('new_hook_ui_value')
 
            try:
 

	
 
                if ui_value and ui_key:
 
                    RhodeCodeUi.create_or_update_hook(ui_key, ui_value)
 
                    h.flash(_('Added new hook'),
 
                            category='success')
 

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

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

	
 
            return redirect(url('admin_edit_setting', setting_id='hooks'))
 

	
 
        if setting_id == 'email':
 
            test_email = request.POST.get('test_email')
 
            test_email_subj = 'RhodeCode TestEmail'
 
            test_email_body = 'RhodeCode Email test'
 

	
 
            test_email_html_body = EmailNotificationModel()\
 
                .get_email_tmpl(EmailNotificationModel.TYPE_DEFAULT,
 
                                body=test_email_body)
 

	
 
            recipients = [test_email] if [test_email] else None
 

	
 
            run_task(tasks.send_email, recipients, test_email_subj,
 
                     test_email_body, test_email_html_body)
 

	
 
            h.flash(_('Email task created'), category='success')
 
        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)
 
        if setting_id == 'hooks':
 
            hook_id = request.POST.get('hook_id')
 
            RhodeCodeUi.delete(hook_id)
 
            self.sa.commit()
 

	
 
    @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)
 

	
 
        c.hooks = RhodeCodeUi.get_builtin_hooks()
 
        c.custom_hooks = RhodeCodeUi.get_custom_hooks()
 

	
 
        return htmlfill.render(
 
            render('admin/settings/hooks.html'),
 
            defaults={},
 
            encoding="UTF-8",
 
            force_defaults=False
 
        )
 

	
 
    @NotAnonymous()
 
    def my_account(self):
 
        """
 
        GET /_admin/my_account Displays info about my account
 
        """
 
        # url('admin_settings_my_account')
 

	
 
        c.user = User.get(self.rhodecode_user.user_id)
 
        all_repos = self.sa.query(Repository)\
 
                     .filter(Repository.user_id == c.user.user_id)\
 
                     .order_by(func.lower(Repository.repo_name)).all()
 

	
 
        c.user_repos = ScmModel().get_repos(all_repos)
 

	
 
        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.get_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 = self.rhodecode_user.user_id
 
        _form = UserForm(edit=True,
 
                         old_data={'user_id': uid,
 
                                   'email': self.rhodecode_user.email})()
 
        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 successfully'),
 
                    category='success')
 
            Session.commit()
 
        except formencode.Invalid, errors:
 
            c.user = User.get(self.rhodecode_user.user_id)
 
            all_repos = self.sa.query(Repository)\
 
                .filter(Repository.user_id == c.user.user_id)\
 
                .order_by(func.lower(Repository.repo_name))\
 
                .all()
 
            c.user_repos = ScmModel().get_repos(all_repos)
 

	
 
            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 occurred during update of user %s') \
 
                    % form_result.get('username'), category='error')
 

	
 
        return redirect(url('my_account'))
 

	
 
    @NotAnonymous()
 
    @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
 
    def create_repository(self):
 
        """GET /_admin/create_repository: Form to create a new item"""
 

	
 
        c.repo_groups = RepoGroup.groups_choices()
 
        c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
 

	
 
        new_repo = request.GET.get('repo', '')
 
        c.new_repo = repo_name_slug(new_repo)
 

	
 
        return render('admin/repos/repo_add_create_repository.html')
 

	
 
    def get_hg_ui_settings(self):
 
        ret = self.sa.query(RhodeCodeUi).all()
 

	
 
        if not ret:
 
            raise Exception('Could not get application ui settings !')
 
        settings = {}
 
        for each in ret:
 
            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
rhodecode/lib/middleware/simplegit.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.middleware.simplegit
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    SimpleGit middleware for handling git protocol request (push/clone etc.)
 
    It's implemented with basic auth function
 

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

	
 
import os
 
import re
 
import logging
 
import traceback
 

	
 
from dulwich import server as dulserver
 

	
 

	
 
class SimpleGitUploadPackHandler(dulserver.UploadPackHandler):
 

	
 
    def handle(self):
 
        write = lambda x: self.proto.write_sideband(1, x)
 

	
 
        graph_walker = dulserver.ProtocolGraphWalker(self,
 
                                                     self.repo.object_store,
 
                                                     self.repo.get_peeled)
 
        objects_iter = self.repo.fetch_objects(
 
          graph_walker.determine_wants, graph_walker, self.progress,
 
          get_tagged=self.get_tagged)
 

	
 
        # Did the process short-circuit (e.g. in a stateless RPC call)? Note
 
        # that the client still expects a 0-object pack in most cases.
 
        if objects_iter is None:
 
            return
 

	
 
        self.progress("counting objects: %d, done.\n" % len(objects_iter))
 
        dulserver.write_pack_objects(dulserver.ProtocolFile(None, write),
 
                                     objects_iter)
 
        messages = []
 
        messages.append('thank you for using rhodecode')
 

	
 
        for msg in messages:
 
            self.progress(msg + "\n")
 
        # we are done
 
        self.proto.write("0000")
 

	
 

	
 
dulserver.DEFAULT_HANDLERS = {
 
  'git-upload-pack': SimpleGitUploadPackHandler,
 
  'git-receive-pack': dulserver.ReceivePackHandler,
 
}
 

	
 
from dulwich.repo import Repo
 
from dulwich.web import make_wsgi_chain
 

	
 
from paste.httpheaders import REMOTE_USER, AUTH_TYPE
 

	
 
from rhodecode.lib.utils2 import safe_str
 
from rhodecode.lib.base import BaseVCSController
 
from rhodecode.lib.auth import get_container_username
 
from rhodecode.lib.utils import is_valid_repo, make_ui
 
from rhodecode.model.db import User
 

	
 
from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
GIT_PROTO_PAT = re.compile(r'^/(.+)/(info/refs|git-upload-pack|git-receive-pack)')
 

	
 

	
 
def is_git(environ):
 
    path_info = environ['PATH_INFO']
 
    isgit_path = GIT_PROTO_PAT.match(path_info)
 
    log.debug('pathinfo: %s detected as GIT %s' % (
 
        path_info, isgit_path != None)
 
    )
 
    return isgit_path
 

	
 

	
 
class SimpleGit(BaseVCSController):
 

	
 
    def _handle_request(self, environ, start_response):
 

	
 
        if not is_git(environ):
 
            return self.application(environ, start_response)
 

	
 
        ipaddr = self._get_ip_addr(environ)
 
        username = None
 
        self._git_first_op = False
 
        # skip passing error to error controller
 
        environ['pylons.status_code_redirect'] = True
 

	
 
        #======================================================================
 
        # EXTRACT REPOSITORY NAME FROM ENV
 
        #======================================================================
 
        try:
 
            repo_name = self.__get_repository(environ)
 
            log.debug('Extracted repo name is %s' % repo_name)
 
        except:
 
            return HTTPInternalServerError()(environ, start_response)
 

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

	
 
        #======================================================================
 
        # GET ACTION PULL or PUSH
 
        #======================================================================
 
        action = self.__get_action(environ)
 

	
 
        #======================================================================
 
        # CHECK ANONYMOUS PERMISSION
 
        #======================================================================
 
        if action in ['pull', 'push']:
 
            anonymous_user = self.__get_user('default')
 
            username = anonymous_user.username
 
            anonymous_perm = self._check_permission(action, anonymous_user,
 
                                                    repo_name)
 

	
 
            if anonymous_perm is not True or anonymous_user.active is False:
 
                if anonymous_perm is not True:
 
                    log.debug('Not enough credentials to access this '
 
                              'repository as anonymous user')
 
                if anonymous_user.active is False:
 
                    log.debug('Anonymous access is disabled, running '
 
                              'authentication')
 
                #==============================================================
 
                # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
 
                # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
 
                #==============================================================
 

	
 
                # Attempting to retrieve username from the container
 
                username = get_container_username(environ, self.config)
 

	
 
                # If not authenticated by the container, running basic auth
 
                if not username:
 
                    self.authenticate.realm = \
 
                        safe_str(self.config['rhodecode_realm'])
 
                    result = self.authenticate(environ)
 
                    if isinstance(result, str):
 
                        AUTH_TYPE.update(environ, 'basic')
 
                        REMOTE_USER.update(environ, result)
 
                        username = result
 
                    else:
 
                        return result.wsgi_application(environ, start_response)
 

	
 
                #==============================================================
 
                # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
 
                #==============================================================
 
                if action in ['pull', 'push']:
 
                    try:
 
                        user = self.__get_user(username)
 
                        if user is None or not user.active:
 
                            return HTTPForbidden()(environ, start_response)
 
                        username = user.username
 
                    except:
 
                        log.error(traceback.format_exc())
 
                        return HTTPInternalServerError()(environ,
 
                                                         start_response)
 

	
 
                    #check permissions for this repository
 
                    perm = self._check_permission(action, user, repo_name)
 
                    if perm is not True:
 
                        return HTTPForbidden()(environ, start_response)
 
        extras = {
 
            'ip': ipaddr,
 
            'username': username,
 
            'action': action,
 
            'repository': repo_name,
 
            'scm': 'git',
 
        }
 

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

	
 
        baseui = make_ui('db')
 
        for k, v in extras.items():
 
            baseui.setconfig('rhodecode_extras', k, v)
 

	
 
        try:
 
            # invalidate cache on push
 
            if action == 'push':
 
                self._invalidate_cache(repo_name)
 
            self._handle_githooks(action, baseui, environ)
 

	
 
            log.info('%s action on GIT repo "%s"' % (action, repo_name))
 
            app = self.__make_app(repo_name, repo_path)
 
            return app(environ, start_response)
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            return HTTPInternalServerError()(environ, start_response)
 

	
 
    def __make_app(self, repo_name, repo_path):
 
        """
 
        Make an wsgi application using dulserver
 

	
 
        :param repo_name: name of the repository
 
        :param repo_path: full path to the repository
 
        """
 
        _d = {'/' + repo_name: Repo(repo_path)}
 
        backend = dulserver.DictBackend(_d)
 
        gitserve = make_wsgi_chain(backend)
 

	
 
        return gitserve
 

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

	
 
        :param environ: environ where PATH_INFO is stored
 
        """
 
        try:
 
            environ['PATH_INFO'] = self._get_by_id(environ['PATH_INFO'])
 
            repo_name = GIT_PROTO_PAT.match(environ['PATH_INFO']).group(1)
 
        except:
 
            log.error(traceback.format_exc())
 
            raise
 

	
 
        return repo_name
 

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

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

	
 
        :param environ:
 
        """
 
        service = environ['QUERY_STRING'].split('=')
 

	
 
        if len(service) > 1:
 
            service_cmd = service[1]
 
            mapping = {
 
                'git-receive-pack': 'push',
 
                'git-upload-pack': 'pull',
 
            }
 
            op = mapping[service_cmd]
 
            self._git_stored_op = op
 
            return op
 
        else:
 
            # try to fallback to stored variable as we don't know if the last
 
            # operation is pull/push
 
            op = getattr(self, '_git_stored_op', 'pull')
 
        return op
 

	
 
    def _handle_githooks(self, action, baseui, environ):
 

	
 
        from rhodecode.lib.hooks import log_pull_action, log_push_action
 
        service = environ['QUERY_STRING'].split('=')
 
        if len(service) < 2:
 
            return
 

	
 
        class cont(object):
 
            pass
 

	
 
        repo = cont()
 
        setattr(repo, 'ui', baseui)
 

	
 
        push_hook = 'pretxnchangegroup.push_logger'
 
        pull_hook = 'preoutgoing.pull_logger'
 
        _hooks = dict(baseui.configitems('hooks')) or {}
 
        if action == 'push' and _hooks.get(push_hook):
 
            log_push_action(ui=baseui, repo=repo)
 
        elif action == 'pull' and _hooks.get(pull_hook):
 
            log_pull_action(ui=baseui, repo=repo)
 

	
rhodecode/lib/utils2.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.utils
 
    ~~~~~~~~~~~~~~~~~~~
 

	
 
    Some simple helper functions
 

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

	
 
import re
 
from rhodecode.lib.vcs.utils.lazy import LazyProperty
 

	
 

	
 
def __get_lem():
 
    """
 
    Get language extension map based on what's inside pygments lexers
 
    """
 
    from pygments import lexers
 
    from string import lower
 
    from collections import defaultdict
 

	
 
    d = defaultdict(lambda: [])
 

	
 
    def __clean(s):
 
        s = s.lstrip('*')
 
        s = s.lstrip('.')
 

	
 
        if s.find('[') != -1:
 
            exts = []
 
            start, stop = s.find('['), s.find(']')
 

	
 
            for suffix in s[start + 1:stop]:
 
                exts.append(s[:s.find('[')] + suffix)
 
            return map(lower, exts)
 
        else:
 
            return map(lower, [s])
 

	
 
    for lx, t in sorted(lexers.LEXERS.items()):
 
        m = map(__clean, t[-2])
 
        if m:
 
            m = reduce(lambda x, y: x + y, m)
 
            for ext in m:
 
                desc = lx.replace('Lexer', '')
 
                d[ext].append(desc)
 

	
 
    return dict(d)
 

	
 
def str2bool(_str):
 
    """
 
    returs True/False value from given string, it tries to translate the
 
    string into boolean
 

	
 
    :param _str: string value to translate into boolean
 
    :rtype: boolean
 
    :returns: boolean from given string
 
    """
 
    if _str is None:
 
        return False
 
    if _str in (True, False):
 
        return _str
 
    _str = str(_str).strip().lower()
 
    return _str in ('t', 'true', 'y', 'yes', 'on', '1')
 

	
 

	
 
def convert_line_endings(line, mode):
 
    """
 
    Converts a given line  "line end" accordingly to given mode
 

	
 
    Available modes are::
 
        0 - Unix
 
        1 - Mac
 
        2 - DOS
 

	
 
    :param line: given line to convert
 
    :param mode: mode to convert to
 
    :rtype: str
 
    :return: converted line according to mode
 
    """
 
    from string import replace
 

	
 
    if mode == 0:
 
            line = replace(line, '\r\n', '\n')
 
            line = replace(line, '\r', '\n')
 
    elif mode == 1:
 
            line = replace(line, '\r\n', '\r')
 
            line = replace(line, '\n', '\r')
 
    elif mode == 2:
 
            line = re.sub("\r(?!\n)|(?<!\r)\n", "\r\n", line)
 
    return line
 

	
 

	
 
def detect_mode(line, default):
 
    """
 
    Detects line break for given line, if line break couldn't be found
 
    given default value is returned
 

	
 
    :param line: str line
 
    :param default: default
 
    :rtype: int
 
    :return: value of line end on of 0 - Unix, 1 - Mac, 2 - DOS
 
    """
 
    if line.endswith('\r\n'):
 
        return 2
 
    elif line.endswith('\n'):
 
        return 0
 
    elif line.endswith('\r'):
 
        return 1
 
    else:
 
        return default
 

	
 

	
 
def generate_api_key(username, salt=None):
 
    """
 
    Generates unique API key for given username, if salt is not given
 
    it'll be generated from some random string
 

	
 
    :param username: username as string
 
    :param salt: salt to hash generate KEY
 
    :rtype: str
 
    :returns: sha1 hash from username+salt
 
    """
 
    from tempfile import _RandomNameSequence
 
    import hashlib
 

	
 
    if salt is None:
 
        salt = _RandomNameSequence().next()
 

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

	
 

	
 
def safe_unicode(str_, from_encoding=None):
 
    """
 
    safe unicode function. Does few trick to turn str_ into unicode
 

	
 
    In case of UnicodeDecode error we try to return it with encoding detected
 
    by chardet library if it fails fallback to unicode with errors replaced
 

	
 
    :param str_: string to decode
 
    :rtype: unicode
 
    :returns: unicode object
 
    """
 
    if isinstance(str_, unicode):
 
        return str_
 

	
 
    if not from_encoding:
 
        import rhodecode
 
        DEFAULT_ENCODING = rhodecode.CONFIG.get('default_encoding','utf8')
 
        from_encoding = DEFAULT_ENCODING
 

	
 
    try:
 
        return unicode(str_)
 
    except UnicodeDecodeError:
 
        pass
 

	
 
    try:
 
        return unicode(str_, from_encoding)
 
    except UnicodeDecodeError:
 
        pass
 

	
 
    try:
 
        import chardet
 
        encoding = chardet.detect(str_)['encoding']
 
        if encoding is None:
 
            raise Exception()
 
        return str_.decode(encoding)
 
    except (ImportError, UnicodeDecodeError, Exception):
 
        return unicode(str_, from_encoding, 'replace')
 

	
 

	
 
def safe_str(unicode_, to_encoding=None):
 
    """
 
    safe str function. Does few trick to turn unicode_ into string
 

	
 
    In case of UnicodeEncodeError we try to return it with encoding detected
 
    by chardet library if it fails fallback to string with errors replaced
 

	
 
    :param unicode_: unicode to encode
 
    :rtype: str
 
    :returns: str object
 
    """
 

	
 
    # if it's not basestr cast to str
 
    if not isinstance(unicode_, basestring):
 
        return str(unicode_)
 

	
 
    if isinstance(unicode_, str):
 
        return unicode_
 

	
 
    if not to_encoding:
 
        import rhodecode
 
        DEFAULT_ENCODING = rhodecode.CONFIG.get('default_encoding','utf8')
 
        to_encoding = DEFAULT_ENCODING
 

	
 
    try:
 
        return unicode_.encode(to_encoding)
 
    except UnicodeEncodeError:
 
        pass
 

	
 
    try:
 
        import chardet
 
        encoding = chardet.detect(unicode_)['encoding']
 
        print encoding
 
        if encoding is None:
 
            raise UnicodeEncodeError()
 

	
 
        return unicode_.encode(encoding)
 
    except (ImportError, UnicodeEncodeError):
 
        return unicode_.encode(to_encoding, 'replace')
 

	
 
    return safe_str
 

	
 

	
 
def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs):
 
    """
 
    Custom engine_from_config functions that makes sure we use NullPool for
 
    file based sqlite databases. This prevents errors on sqlite. This only
 
    applies to sqlalchemy versions < 0.7.0
 

	
 
    """
 
    import sqlalchemy
 
    from sqlalchemy import engine_from_config as efc
 
    import logging
 

	
 
    if int(sqlalchemy.__version__.split('.')[1]) < 7:
 

	
 
        # This solution should work for sqlalchemy < 0.7.0, and should use
 
        # proxy=TimerProxy() for execution time profiling
 

	
 
        from sqlalchemy.pool import NullPool
 
        url = configuration[prefix + 'url']
 

	
 
        if url.startswith('sqlite'):
 
            kwargs.update({'poolclass': NullPool})
 
        return efc(configuration, prefix, **kwargs)
 
    else:
 
        import time
 
        from sqlalchemy import event
 
        from sqlalchemy.engine import Engine
 

	
 
        log = logging.getLogger('sqlalchemy.engine')
 
        BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = xrange(30, 38)
 
        engine = efc(configuration, prefix, **kwargs)
 

	
 
        def color_sql(sql):
 
            COLOR_SEQ = "\033[1;%dm"
 
            COLOR_SQL = YELLOW
 
            normal = '\x1b[0m'
 
            return ''.join([COLOR_SEQ % COLOR_SQL, sql, normal])
 

	
 
        if configuration['debug']:
 
            #attach events only for debug configuration
 

	
 
            def before_cursor_execute(conn, cursor, statement,
 
                                    parameters, context, executemany):
 
                context._query_start_time = time.time()
 
                log.info(color_sql(">>>>> STARTING QUERY >>>>>"))
 

	
 

	
 
            def after_cursor_execute(conn, cursor, statement,
 
                                    parameters, context, executemany):
 
                total = time.time() - context._query_start_time
 
                log.info(color_sql("<<<<< TOTAL TIME: %f <<<<<" % total))
 

	
 
            event.listen(engine, "before_cursor_execute",
 
                         before_cursor_execute)
 
            event.listen(engine, "after_cursor_execute",
 
                         after_cursor_execute)
 

	
 
    return engine
 

	
 

	
 
def age(curdate):
 
    """
 
    turns a datetime into an age string.
 

	
 
    :param curdate: datetime object
 
    :rtype: unicode
 
    :returns: unicode words describing age
 
    """
 

	
 
    from datetime import datetime
 
    from webhelpers.date import time_ago_in_words
 

	
 
    _ = lambda s: s
 

	
 
    if not curdate:
 
        return ''
 

	
 
    agescales = [(_(u"year"), 3600 * 24 * 365),
 
                 (_(u"month"), 3600 * 24 * 30),
 
                 (_(u"day"), 3600 * 24),
 
                 (_(u"hour"), 3600),
 
                 (_(u"minute"), 60),
 
                 (_(u"second"), 1), ]
 

	
 
    age = datetime.now() - curdate
 
    age_seconds = (age.days * agescales[2][1]) + age.seconds
 
    pos = 1
 
    for scale in agescales:
 
        if scale[1] <= age_seconds:
 
            if pos == 6:
 
                pos = 5
 
            return '%s %s' % (time_ago_in_words(curdate,
 
                                                agescales[pos][0]), _('ago'))
 
        pos += 1
 

	
 
    return _(u'just now')
 

	
 

	
 
def uri_filter(uri):
 
    """
 
    Removes user:password from given url string
 

	
 
    :param uri:
 
    :rtype: unicode
 
    :returns: filtered list of strings
 
    """
 
    if not uri:
 
        return ''
 

	
 
    proto = ''
 

	
 
    for pat in ('https://', 'http://'):
 
        if uri.startswith(pat):
 
            uri = uri[len(pat):]
 
            proto = pat
 
            break
 

	
 
    # remove passwords and username
 
    uri = uri[uri.find('@') + 1:]
 

	
 
    # get the port
 
    cred_pos = uri.find(':')
 
    if cred_pos == -1:
 
        host, port = uri, None
 
    else:
 
        host, port = uri[:cred_pos], uri[cred_pos + 1:]
 

	
 
    return filter(None, [proto, host, port])
 

	
 

	
 
def credentials_filter(uri):
 
    """
 
    Returns a url with removed credentials
 

	
 
    :param uri:
 
    """
 

	
 
    uri = uri_filter(uri)
 
    #check if we have port
 
    if len(uri) > 2 and uri[2]:
 
        uri[2] = ':' + uri[2]
 

	
 
    return ''.join(uri)
 

	
 

	
 
def get_changeset_safe(repo, rev):
 
    """
 
    Safe version of get_changeset if this changeset doesn't exists for a
 
    repo it returns a Dummy one instead
 

	
 
    :param repo:
 
    :param rev:
 
    """
 
    from rhodecode.lib.vcs.backends.base import BaseRepository
 
    from rhodecode.lib.vcs.exceptions import RepositoryError
 
    if not isinstance(repo, BaseRepository):
 
        raise Exception('You must pass an Repository '
 
                        'object as first argument got %s', type(repo))
 

	
 
    try:
 
        cs = repo.get_changeset(rev)
 
    except RepositoryError:
 
        from rhodecode.lib.utils import EmptyChangeset
 
        cs = EmptyChangeset(requested_revision=rev)
 
    return cs
 

	
 

	
 
MENTIONS_REGEX = r'(?:^@|\s@)([a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+)(?:\s{1})'
 

	
 

	
 
def extract_mentioned_users(s):
 
    """
 
    Returns unique usernames from given string s that have @mention
 

	
 
    :param s: string to get mentions
 
    """
 
    usrs = set()
 
    for username in re.findall(MENTIONS_REGEX, s):
 
        usrs.add(username)
 

	
 
    return sorted(list(usrs), key=lambda k: k.lower())
 

	
rhodecode/lib/vcs/utils/hgcompat.py
Show inline comments
 
"""
 
Mercurial libs compatibility
 
"""
 

	
 
from mercurial import archival, merge as hg_merge, patch, ui
 
from mercurial.commands import clone, nullid, pull
 
from mercurial.context import memctx, memfilectx
 
from mercurial.error import RepoError, RepoLookupError, Abort
 
from mercurial.hgweb.common import get_contact
 
from mercurial.localrepo import localrepository
 
from mercurial.match import match
 
from mercurial.mdiff import diffopts
 
from mercurial.node import hex
 
from mercurial.encoding import tolocal
 
\ No newline at end of file
 
from mercurial.encoding import tolocal
rhodecode/templates/admin/notifications/notifications.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
<%inherit file="/base/base.html"/>
 

	
 
<%def name="title()">
 
    ${_('My Notifications')} ${c.rhodecode_user.username} - ${c.rhodecode_name}
 
</%def>
 

	
 
<%def name="breadcrumbs_links()">
 
    ${_('My Notifications')}
 
</%def>
 

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

	
 
<%def name="main()">
 
<div class="box">
 
    <!-- box / title -->
 
    <div class="title">
 
        ${self.breadcrumbs()}
 
        ##<ul class="links">
 
        ##    <li>
 
        ##      <span style="text-transform: uppercase;"><a href="#">${_('Compose message')}</a></span>
 
        ##    </li>
 
        ##</ul>
 
    </div>
 
    %if c.notifications:
 
      <div style="padding:14px 18px;text-align: right;float:right">
 
      <span id='mark_all_read' class="ui-btn">${_('Mark all read')}</span>
 
      </div>
 
    %endif
 
  <div id='notification_data'>
 
    <%include file='notifications_data.html'/>
 
  </div>
 
</div>
 
<script type="text/javascript">
 
var url_del = "${url('notification', notification_id='__NOTIFICATION_ID__')}";
 
YUE.on(YUQ('.delete-notification'),'click',function(e){
 
 var notification_id = e.currentTarget.id;
 
 deleteNotification(url_del,notification_id)
 
})
 
YUE.on('mark_all_read','click',function(e){
 
    var url = "${h.url('notifications_mark_all_read')}";
 
    ypjax(url,'notification_data',function(){
 
    	var notification_counter = YUD.get('notification_counter');
 
    	if(notification_counter){
 
    		notification_counter.innerHTML=0;	
 
    		notification_counter.innerHTML=0;
 
    	}
 
    	YUE.on(YUQ('.delete-notification'),'click',function(e){
 
    		 var notification_id = e.currentTarget.id;
 
    		 deleteNotification(url_del,notification_id)
 
    	})
 
    });
 
})
 
</script>
 
</%def>
rhodecode/templates/admin/settings/settings.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
<%inherit file="/base/base.html"/>
 

	
 
<%def name="title()">
 
    ${_('Settings administration')} - ${c.rhodecode_name}
 
</%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="destroy">
 
		                <span class="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")}
 
            </div>
 
        </div>
 
    </div>
 
    ${h.end_form()}
 

	
 
    <h3>${_('Whoosh indexing')}</h3>
 
    ${h.form(url('admin_setting', setting_id='whoosh'),method='put')}
 
    <div class="form">
 
        <!-- fields -->
 

	
 
        <div class="fields">
 
            <div class="field">
 
                <div class="label label-checkbox">
 
                    <label>${_('index build option')}:</label>
 
                </div>
 
                <div class="checkboxes">
 
                    <div class="checkbox">
 
                        ${h.checkbox('full_index',True)}
 
                        <label for="full_index">${_('build from scratch')}</label>
 
                    </div>
 
                </div>
 
            </div>
 

	
 
            <div class="buttons">
 
            ${h.submit('reindex',_('Reindex'),class_="ui-button")}
 
            </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="rhodecode_title">${_('Application name')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('rhodecode_title',size=30)}
 
                </div>
 
             </div>
 

	
 
            <div class="field">
 
                <div class="label">
 
                    <label for="rhodecode_realm">${_('Realm text')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('rhodecode_realm',size=30)}
 
                </div>
 
            </div>
 

	
 
            <div class="field">
 
                <div class="label">
 
                    <label for="rhodecode_ga_code">${_('GA code')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('rhodecode_ga_code',size=30)}
 
                </div>
 
            </div>
 

	
 
            <div class="buttons">
 
                ${h.submit('save',_('Save settings'),class_="ui-button")}
 
                ${h.reset('reset',_('Reset'),class_="ui-button")}
 
           </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>${_('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>${_('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 class="checkbox">
 
                        ${h.checkbox('hooks_pretxnchangegroup_push_logger','True')}
 
                        <label for="hooks_pretxnchangegroup_push_logger">${_('Log user push commands')}</label>
 
                    </div>
 
                    <div class="checkbox">
 
                        ${h.checkbox('hooks_preoutgoing_pull_logger','True')}
 
                        <label for="hooks_preoutgoing_pull_logger">${_('Log user pull commands')}</label>
 
                    </div>
 
				</div>
 
                <div class="input" style="margin-top:10px">
 
                    ${h.link_to(_('advanced setup'),url('admin_edit_setting',setting_id='hooks'),class_="ui-btn")}
 
                </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,readonly="readonly")}
 
					<span id="path_unlock" class="tooltip"
 
						title="${h.tooltip(_('This a crucial application setting. If you are really sure you need to change this, you must restart application in order to make this setting take effect. Click this label to unlock.'))}">
 
		                ${_('unlock')}</span>
 
                </div>
 
            </div>
 

	
 
            <div class="buttons">
 
                ${h.submit('save',_('Save settings'),class_="ui-button")}
 
                ${h.reset('reset',_('Reset'),class_="ui-button")}
 
           </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').removeAttribute('readonly');
 
            });
 
        });
 
    </script>
 

	
 
    <h3>${_('Test Email')}</h3>
 
    ${h.form(url('admin_setting', setting_id='email'),method='put')}
 
    <div class="form">
 
        <!-- fields -->
 

	
 
        <div class="fields">
 
            <div class="field">
 
                <div class="label">
 
                    <label for="test_email">${_('Email to')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('test_email',size=30)}
 
                </div>
 
            </div>
 

	
 
            <div class="buttons">
 
            ${h.submit('send',_('Send'),class_="ui-button")}
 
            </div>
 
        </div>
 
    </div>
 
    ${h.end_form()}
 

	
 
    <h3>${_('System Info and Packages')}</h3>
 
    <div class="form">
 
    <div>
 
        <h5 id="expand_modules" style="cursor: pointer">&darr; ${_('show')} &darr;</h5>
 
    </div>
 
      <div id="expand_modules_table"  style="display:none">
 
      <h5>Python - ${c.py_version}</h5>
 
      <h5>System - ${c.platform}</h5>
 
      
 

	
 
      <table class="table" style="margin:0px 0px 0px 20px">
 
          <colgroup>
 
              <col style="width:220px">
 
          </colgroup>
 
          <tbody>
 
              %for key, value in c.modules:
 
                  <tr>
 
                      <th>${key}</th>
 
                      <td>${value}</td>
 
                  </tr>
 
              %endfor
 
          </tbody>
 
      </table>
 
      </div>    
 
      </div>
 
    </div>
 
    
 

	
 
    <script type="text/javascript">
 
    YUE.on('expand_modules','click',function(e){
 
    	YUD.setStyle('expand_modules_table','display','');
 
    	YUD.setStyle('expand_modules','display','none');
 
    })
 
    </script>
 
    
 

	
 
</div>
 
</%def>
0 comments (0 inline, 0 general)