Changeset - a886f5eba757
[Not reviewed]
default
0 6 0
marcink - 16 years ago 2010-04-07 17:28:10

implemented admin page login
6 files changed with 85 insertions and 50 deletions:
0 comments (0 inline, 0 general)
pylons_app/controllers/admin.py
Show inline comments
 
import logging
 

	
 
from pylons import request, response, session, tmpl_context as c, url, app_globals as g
 
from pylons.controllers.util import abort, redirect
 

	
 
from pylons_app.lib.base import BaseController, render
 
import os
 
from mercurial import ui, hg
 
from mercurial.error import RepoError
 
from ConfigParser import ConfigParser
 
from pylons_app.lib import auth
 
from pylons_app.model.forms import LoginForm
 
import formencode
 
import formencode.htmlfill as htmlfill
 
log = logging.getLogger(__name__)
 

	
 
class AdminController(BaseController):
 

	
 

	
 
    def __before__(self):
 
        c.staticurl = g.statics
 
        c.admin_user = True
 
        c.admin_user = session.get('admin_user')
 
        c.admin_username = session.get('admin_username')
 
        
 
    def index(self):
 
        # Return a rendered template
 
        if request.POST:
 
            #import Login Form validator class
 
            login_form = LoginForm()
 

	
 
            try:
 
                c.form_result = login_form.to_python(dict(request.params))
 
                if auth.authfunc(None, c.form_result['username'], c.form_result['password']) and\
 
                    c.form_result['username'] == 'admin':
 
                    session['admin_user'] = True
 
                    session['admin_username'] = c.form_result['username']
 
                    session.save()
 
                    return redirect(url('admin_home'))
 
                else:
 
                    raise formencode.Invalid('Login Error', None, None,
 
                                             error_dict={'username':'invalid login',
 
                                                         'password':'invalid password'})
 
                                      
 
            except formencode.Invalid, error:
 
                c.form_result = error.value
 
                c.form_errors = error.error_dict or {}
 
                html = render('/admin.html')
 

	
 
                return htmlfill.render(
 
                    html,
 
                    defaults=c.form_result,
 
                    encoding="UTF-8"
 
                )
 
        return render('/admin.html')
 

	
 
    def repos_manage(self):
 
        return render('/repos_manage.html')
 
    
 
    def users_manage(self):
 
        conn, cur = auth.get_sqlite_conn_cur()
 
        cur.execute('SELECT * FROM users')
 
        c.users_list = cur.fetchall()        
 
        return render('/users_manage.html')
 
                
 
    def manage_hgrc(self):
 
        pass
 

	
 
    def hgrc(self, dirname):
 
        filename = os.path.join(dirname, '.hg', 'hgrc')
 
        return filename
 

	
 
    def add_repo(self, new_repo):
 
        
 

	
 
        #extra check it can be add since it's the command
 
        if new_repo == '_admin':
 
            c.msg = 'DENIED'
 
            c.new_repo = ''
 
            return render('add.html')
 

	
 
        new_repo = new_repo.replace(" ", "_")
 
        new_repo = new_repo.replace("-", "_")
 

	
 
        try:
 
            self._create_repo(new_repo)
 
            c.new_repo = new_repo
 
            c.msg = 'added repo'
 
        except Exception as e:
 
            c.new_repo = 'Exception when adding: %s' % new_repo
 
            c.msg = str(e)
 

	
 
        return render('add.html')
 

	
 
    def _check_repo(self, repo_name):
 
        p = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
 
        config_path = os.path.join(p, 'hgwebdir.config')
 

	
 
        cp = ConfigParser()
 

	
 
        cp.read(config_path)
 
        repos_path = cp.get('paths', '/').replace("**", '')
pylons_app/lib/auth.py
Show inline comments
 
import sqlite3
 
import os
 
import logging
 
from os.path import dirname as dn
 
from datetime import datetime
 
import crypt
 

	
 
log = logging.getLogger(__name__)
 
ROOT = dn(dn(dn(os.path.realpath(__file__))))
 

	
 
def get_sqlite_conn_cur():
 
    conn = sqlite3.connect(os.path.join(ROOT, 'auth.sqlite'))
 
    cur = conn.cursor()
 
    return conn, cur
 

	
 
def authfunc(environ, username, password):
 
    conn, cur = get_sqlite_conn_cur()
 
    password_crypt = crypt.crypt(password, '6a')
 

	
 
    try:
 
        cur.execute("SELECT * FROM users WHERE username=?", (username,))
 
        data = cur.fetchone()
 
    except sqlite3.OperationalError as e:
 
        data = None
 
        log.error(e)
 

	
 
    if data:
 
        if data[3]:
 
            if data[1] == username and data[2] == password_crypt:
 
                log.info('user %s authenticated correctly', username)
 
                
 
                http_accept = environ.get('HTTP_ACCEPT')
 
        
 
                if http_accept.startswith('application/mercurial') or \
 
                    environ['PATH_INFO'].find('raw-file') != -1:
 
                    cmd = environ['PATH_INFO']
 
                    for qry in environ['QUERY_STRING'].split('&'):
 
                        if qry.startswith('cmd'):
 
                            cmd += "|" + qry
 
                            
 
                            try:
 
                                cur.execute('''INSERT INTO 
 
                                                    user_logs 
 
                                               VALUES(?,?,?,?)''',
 
                                                (None, data[0], cmd, datetime.now()))
 
                                conn.commit()
 
                            except Exception as e:
 
                                conn.rollback()
 
                                log.error(e)
 
                            
 
                if environ:
 
                    http_accept = environ.get('HTTP_ACCEPT')
 
            
 
                    if http_accept.startswith('application/mercurial') or \
 
                        environ['PATH_INFO'].find('raw-file') != -1:
 
                        cmd = environ['PATH_INFO']
 
                        for qry in environ['QUERY_STRING'].split('&'):
 
                            if qry.startswith('cmd'):
 
                                cmd += "|" + qry
 
                                
 
                                try:
 
                                    cur.execute('''INSERT INTO 
 
                                                        user_logs 
 
                                                   VALUES(?,?,?,?)''',
 
                                                    (None, data[0], cmd, datetime.now()))
 
                                    conn.commit()
 
                                except Exception as e:
 
                                    conn.rollback()
 
                                    log.error(e)
 
                                  
 
                return True
 
        else:
 
            log.error('user %s is disabled', username)
 
            
 
    return False
 

	
 
def create_user_table():
 
    '''
 
    Create a auth database
 
    '''
 
    conn, cur = get_sqlite_conn_cur()
 
    try:
 
        log.info('creating table %s', 'users')
 
        cur.execute('''DROP TABLE IF EXISTS users ''')
 
        cur.execute('''CREATE TABLE users
 
                        (id INTEGER PRIMARY KEY AUTOINCREMENT, 
 
                         username TEXT, 
 
                         password TEXT,
 
                         active INTEGER)''')
 
        log.info('creating table %s', 'user_logs')
 
        cur.execute('''DROP TABLE IF EXISTS user_logs ''')
 
        cur.execute('''CREATE TABLE user_logs
 
                        (id INTEGER PRIMARY KEY AUTOINCREMENT,
 
                            user_id INTEGER,
 
                            last_action TEXT, 
 
                            last_action_date DATETIME)''')
 
        conn.commit()
 
    except:
 
        conn.rollback()
 
        raise
 
    
 
    cur.close()
 
    
 
def create_user(username, password):
 
    conn, cur = get_sqlite_conn_cur()    
 
    password_crypt = crypt.crypt(password, '6a')
 
    cur_date = datetime.now()
 
    log.info('creating user %s', username)
 
    try:
 
        cur.execute('''INSERT INTO users values (?,?,?,?) ''',
 
                    (None, username, password_crypt, 1,))     
 
        conn.commit()
 
    except:
 
        conn.rollback()
 
        raise
 
    
 
if __name__ == "__main__":
 
    create_user_table()
pylons_app/lib/helpers.py
Show inline comments
 
"""Helper functions
 

	
 
Consists of functions to typically be used within templates, but also
 
available to Controllers. This module is available to both as 'h'.
 
"""
 
from pylons import url
 
from webhelpers.html import (literal, HTML, escape)
 
from webhelpers.html.tools import (auto_link, button_to, highlight, js_obfuscate
 
                                   , mail_to, strip_links, strip_tags, tag_re)
 
from webhelpers.html.tags import (auto_discovery_link, checkbox, css_classes,
 
                                  end_form, file, form, hidden, image,
 
                                  javascript_link, link_to, link_to_if,
 
                                  link_to_unless, ol, required_legend,
 
                                  select, stylesheet_link,
 
                                  submit, text, textarea, title, ul, xml_declaration)
 
                                  submit, text, password, textarea, title, ul, xml_declaration)
 
from webhelpers.text import (chop_at, collapse, convert_accented_entities,
 
                             convert_misc_characters, convert_misc_entities,
 
                             lchop, plural, rchop, remove_formatting, replace_whitespace,
 
                             urlify)
 

	
 
from webhelpers.pylonslib import Flash as _Flash
 
from webhelpers.pylonslib.secure_form import secure_form
 

	
 
#Custom helper here :)
 
class _Link(object):
 
    '''
 
    Make a url based on label and url with help of url_for
 
    @param label:name of link    if not defined url is used
 
    @param url: the url for link
 
    '''
 

	
 
    def __call__(self, label='', *url_, **urlargs):
 
        if label is None or '':
 
            label = url
 
        link_fn = link_to(label, url(*url_, **urlargs))
 
        return link_fn
 

	
 

	
 
class _GetError(object):
 

	
 
    def __call__(self, field_name, form_errors):
 
        tmpl = """<span class="error_msg">%s</span>"""
 
        if form_errors and form_errors.has_key(field_name):
 
            return literal(tmpl % form_errors.get(field_name))
 

	
 
link = _Link()
 
flash = _Flash()
 
get_error = _GetError()
pylons_app/model/forms.py
Show inline comments
 
""" this is forms validation classes
 
http://formencode.org/module-formencode.validators.html
 
for list off all availible validators
 

	
 
we can create our own validators
 

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

	
 
import formencode
 
from formencode.validators import UnicodeString, OneOf, Int, Number, Regex
 
from pylons.i18n.translation import _
 
from webhelpers.pylonslib.secure_form import authentication_token
 

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

	
 
    def validate_python(self, value, state):
 

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

	
 

	
 
class WireTransferForm(object):
 
    '''
 
    A factory wrapper class. It might return the instance of class for a validation, but also it can
 
    return the list for select fields values.
 
    @param ret_type: type to return defaut: 'class'
 
    '''
 
    #class attributes here
 
    #it might be fetched from db,from models and so on
 
    recipients_list = [
 
                       (1, 'a'),
 
                       (2, 'b')
 
                       ]
 
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')}
 
                            )
 

	
 
    def _form(self):
 
        class _WireTransferForm(formencode.Schema):
 
            allow_extra_fields = True
 
            _authentication_token = ValidAuthToken()
 
            account_number = Regex(r'[0-9]{26}', not_empty = True, messages = {
 
                                                'invalid': _("Account number is invalid, it must be 26 digits")})
 
            title = UnicodeString(not_empty = True, min = 3, strip = True)
 
            recipient = formencode.All(OneOf([i[0] for i in WireTransferForm.recipients_list],
 
                                             testValueList = True, hideList = True), Int())
 
            recipient_address = UnicodeString(not_empty = True, strip = True)
 
            amount = Number(not_empty = True, min = 1)
 
    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')}
 
                                )
 

	
 
        return _WireTransferForm()
 

	
pylons_app/templates/admin.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
<%inherit file="base/base.html"/>
 
 <%def name="get_form_error(element)">
 
    %if type(c.form_errors) == dict:
 
        %if c.form_errors.get(element,False):
 
            <span class="error-message">
 
                ${c.form_errors.get(element,'')}
 
            </span>
 
        %endif
 
    %endif           
 
 </%def>
 
<%def name="title()">
 
    ${_('Repository managment')}
 
</%def>
 
<%def name="breadcrumbs()">
 
	${h.link_to(u'Home',h.url('/'))}
 
	 / 
 
	${h.link_to(u'Admin',h.url('admin_home'))}
 
</%def>
 
<%def name="page_nav()">
 
<li>${h.link_to(u'Home',h.url('/'))}</li>
 
<li class="current">${_('Admin')}</li>
 
</%def>
 
<%def name="main()">
 
    %if c.admin_user:
 
    <ul class="submenu">
 
        <li>
 
            ${h.link_to(u'Repos managment',h.url('admin_repos_manage'))}
 
        </li>
 
        <li>
 
            ${h.link_to(u'Users managment',h.url('admin_users_manage'))}
 
        </li>
 
    </ul>
 
    <br/>
 
    <div>
 
    
 
        <h2>Hi !</h2>
 
    </div>
 
    %else:
 
        <div>
 
        <br />
 
        <h2>${_('Login')}</h2>
 
        ${h.form(h.url.current())}
 
        <table>
 
            <tr>
 
                <td>${_('Username')}</td>
 
                <td>${h.text('username')}</td>
 
                <td>${get_form_error('username')} </td>
 
            </tr>
 
            <tr>
 
                <td>${_('Password')}</td>
 
                <td>${h.text('password')}</td>
 
                <td>${h.password('password')}</td>
 
                <td>${get_form_error('password')}</td> 
 
            </tr>
 
            <tr>
 
                <td></td>
 
                <td>${h.submit('login','login')}</td>
 
            </tr>            
 
        </table>
 
        ${h.end_form()}
 
        </div>
 
    %endif
 
    
 
</%def>
 
\ No newline at end of file
pylons_app/templates/monoblue_custom/index.tmpl
Show inline comments
 
## -*- coding: utf-8 -*-
 
{header}
 
    <title>{repo|escape}: Mercurial repositories index</title>
 
</head>
 

	
 
<body>
 
<div id="container">
 
    <div class="page-header">
 
        <h1>${c.repos_prefix} Mercurial Repositories</h1>
 
        <ul class="page-nav">
 
            <li class="current">Home</li>
 
            <li>${h.link_to(u'Admin',h.url('admin_home'))}</li>
 
            <li><a href="/_admin/">Admin</a></li>
 
        </ul>
 
    </div>
 
    
 
    <table cellspacing="0">
 
        <tr>
 
            <td><a href="?sort={sort_name}">Name</a></td>
 
            <td><a href="?sort={sort_description}">Description</a></td>
 
            <td><a href="?sort={sort_contact}">Contact</a></td>
 
            <td><a href="?sort={sort_lastchange}">Last change</a></td>
 
            <td>&nbsp;</td>
 
            <td>&nbsp;</td>
 
        </tr>
 
        {entries%indexentry}
 
    </table>
 
    <div class="page-footer">
 
        {motd}
 
    </div>
 

	
 
    <div id="powered-by">
 
        <p><a href="http://mercurial.selenic.com/" title="Mercurial"><img src="{staticurl}hglogo.png" width="75" height="90" alt="mercurial"/></a></p>
 
    </div>
 

	
 
    <div id="corner-top-left"></div>
 
    <div id="corner-top-right"></div>
 
    <div id="corner-bottom-left"></div>
 
    <div id="corner-bottom-right"></div>
 

	
 
</div>
 
</body>
 
</html>
0 comments (0 inline, 0 general)