Changeset - a55c17874486
[Not reviewed]
default
0 6 1
Marcin Kuzminski - 15 years ago 2010-05-30 17:55:56
marcin@python-works.com
Rewrite of user managment, improved forms, added some user info
7 files changed with 131 insertions and 16 deletions:
0 comments (0 inline, 0 general)
pylons_app/controllers/users.py
Show inline comments
 
from formencode import htmlfill
 
from pylons import request, response, session, tmpl_context as c, url, \
 
    app_globals as g
 
from pylons.i18n.translation import _
 
from pylons_app.lib import helpers as h    
 
from pylons.controllers.util import abort, redirect
 
from pylons_app.lib.auth import LoginRequired
 
from pylons_app.lib.base import BaseController, render
 
from pylons_app.model.db import User, UserLog
 
from pylons_app.model.forms import UserForm
 
from pylons_app.model.user_model import UserModel
 
import formencode
 
import logging
 

	
 

	
 

	
 
log = logging.getLogger(__name__)
 
@@ -28,77 +30,79 @@ class UsersController(BaseController):
 
    def index(self, format='html'):
 
        """GET /users: All items in the collection"""
 
        # url('users')
 
        
 
        c.users_list = self.sa.query(User).all()     
 
        return render('admin/users/users.html')
 
    
 
    def create(self):
 
        """POST /users: Create a new item"""
 
        # url('users')
 
        
 
        user_model = UserModel()
 
        login_form = UserForm()
 
        login_form = UserForm()()
 
        try:
 
            form_result = login_form.to_python(dict(request.POST))
 
            user_model.create(form_result)
 
            h.flash(_('created user %s') % form_result['username'], category='success')
 
            return redirect(url('users'))
 
                           
 
        except formencode.Invalid as errors:
 
            c.form_errors = errors.error_dict
 
            return htmlfill.render(
 
                 render('admin/users/user_add.html'),
 
                defaults=errors.value,
 
                encoding="UTF-8")
 
    
 
    def new(self, format='html'):
 
        """GET /users/new: Form to create a new item"""
 
        # url('new_user')
 
        return render('admin/users/user_add.html')
 

	
 
    def update(self, id):
 
        """PUT /users/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('user', id=ID),
 
        #           method='put')
 
        # url('user', id=ID)
 
        user_model = UserModel()
 
        login_form = UserForm()
 
        login_form = UserForm(edit=True)()
 
        try:
 
            form_result = login_form.to_python(dict(request.POST))
 
            user_model.update(id, form_result)
 
            h.flash(_('User updated succesfully'), category='success')
 
            return redirect(url('users'))
 
                           
 
        except formencode.Invalid as errors:
 
            errors.value
 
            c.user = user_model.get_user(id)
 
            c.form_errors = errors.error_dict
 
            return htmlfill.render(
 
                 render('admin/users/user_edit.html'),
 
                defaults=errors.value,
 
                encoding="UTF-8")
 
    
 
    def delete(self, id):
 
        """DELETE /users/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('user', id=ID),
 
        #           method='delete')
 
        # url('user', id=ID)
 
        try:
 
            self.sa.delete(self.sa.query(User).get(id))
 
            self.sa.commit()
 
            h.flash(_('sucessfully deleted user'), category='success')
 
        except:
 
            self.sa.rollback()
 
            raise
 
        return redirect(url('users'))
 
        
 
    def show(self, id, format='html'):
 
        """GET /users/id: Show a specific item"""
 
        # url('user', id=ID)
 
    
 
    
 
    def edit(self, id, format='html'):
 
        """GET /users/id/edit: Form to edit an existing item"""
pylons_app/model/forms.py
Show inline comments
 
@@ -10,25 +10,27 @@ chained_validators      []     These val
 
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())
 
    
 
"""
 
from formencode.validators import UnicodeString, OneOf, Int, Number, Regex
 
from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
 
    Email, Bool, StringBoolean
 
from formencode import All
 
from pylons import session
 
from pylons.i18n.translation import _
 
from pylons_app.lib.auth import get_crypt_password
 
from pylons_app.model import meta
 
from pylons_app.model.db import User
 
from sqlalchemy.exc import OperationalError
 
from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
 
from webhelpers.pylonslib.secure_form import authentication_token
 
import formencode
 
import logging
 
log = logging.getLogger(__name__)
 

	
 
@@ -39,46 +41,58 @@ class State_obj(object):
 
    
 
#===============================================================================
 
# VALIDATORS
 
#===============================================================================
 
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)
 
class ValidUsername(formencode.validators.FancyValidator):
 

	
 
    def validate_python(self, value, state):
 
        pass
 
    
 
class ValidPassword(formencode.validators.FancyValidator):
 
    
 
    def to_python(self, value, state):
 
        return get_crypt_password(value)
 
        
 
class ValidAuth(formencode.validators.FancyValidator):
 
    messages = {
 
            'invalid_password':_('invalid password'),
 
            'invalid_login':_('invalid user name'),
 
            'disabled_account':_('Your acccount is disabled')
 
            
 
            }
 
    #error mapping
 
    e_dict = {'username':messages['invalid_login'],
 
              'password':messages['invalid_password']}
 
    e_dict_disable = {'username':messages['disabled_account']}
 
    
 
    def validate_python(self, value, state):
 
        sa = meta.Session
 
        crypted_passwd = get_crypt_password(value['password'])
 
        username = value['username']
 
        try:
 
            user = sa.query(User).filter(User.username == username).one()
 
        except (NoResultFound, MultipleResultsFound, OperationalError) as e:
 
            log.error(e)
 
            user = None
 
            raise formencode.Invalid(self.message('invalid_password',
 
                                     state=State_obj), value, state,
 
                                     error_dict=self.e_dict)            
 
        if user:
 
            if user.active:
 
                if user.username == username and user.password == crypted_passwd:
 
                    from pylons_app.lib.auth import AuthUser
 
                    auth_user = AuthUser()
 
                    auth_user.username = username
 
                    auth_user.is_authenticated = True
 
                    auth_user.is_admin = user.admin
 
                    session['hg_app_user'] = auth_user
 
                    session.save()
 
                    log.info('user %s is now authenticated', username)
 
                    return value
 
@@ -115,13 +129,27 @@ class LoginForm(formencode.Schema):
 
                            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):
 
    class _UserForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = True
 
        username = All(UnicodeString(strip=True, min=3, not_empty=True), ValidUsername)
 
        if edit:
 
            new_password = All(UnicodeString(strip=True, min=3, not_empty=False), ValidPassword)
 
        else:
 
            password = All(UnicodeString(strip=True, min=3, not_empty=False), 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
pylons_app/model/user_model.py
Show inline comments
 
new file 100644
 
#!/usr/bin/env python
 
# encoding: utf-8
 
#
 
# Copyright (c) 2010 marcink.  All rights reserved.
 
#
 
from pylons_app.model.db import User
 
from pylons_app.model.meta import Session
 
'''
 
Created on Apr 9, 2010
 

	
 
@author: marcink
 
'''
 

	
 
class UserModel(object):
 

	
 
    def __init__(self):
 
        self.sa = Session() 
 
    
 
    def get_user(self, id):
 
        return self.sa.query(User).get(id)
 
    
 
    def create(self, form_data):
 
        try:
 
            new_user = User()
 
            for k, v in form_data.items():
 
                setattr(new_user, k, v)
 
                
 
            self.sa.add(new_user)
 
            self.sa.commit()
 
        except:
 
            self.sa.rollback()
 
            raise      
 
    
 
    def update(self, id, form_data):
 
        try:
 
            new_user = self.sa.query(User).get(id)
 
            for k, v in form_data.items():
 
                if k == 'new_password' and v != '':
 
                    
 
                    new_user.password = v
 
                else:
 
                    setattr(new_user, k, v)
 
                
 
            self.sa.add(new_user)
 
            self.sa.commit()
 
        except:
 
            self.sa.rollback()
 
            raise      
pylons_app/templates/admin/users/user_add.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
<%inherit file="/base/base.html"/>
 

	
 
<%def name="title()">
 
    ${_('User administration')}
 
</%def>
 
<%def name="breadcrumbs()">
 
	${h.link_to(u'Admin',h.url('admin_home'))}
 
	 /  
 
	 ${_('Users')}
 
	${_('Users')}
 
</%def>
 
<%def name="page_nav()">
 
	${self.menu('admin')}
 
	${self.submenu('users')}
 
</%def>
 
<%def name="main()">
 
	<div>
 
        <h2>${_('User')} - ${_('add new')}</h2>
 
        ${h.form(url('users'))}
 
        <table>
 
        	<tr>
 
        		<td>${_('Username')}</td>
 
        		<td>${h.text('username')}</td>
 
        		<td>${self.get_form_error('username')}</td>
 
        	</tr>
 
        	<tr>
 
        		<td>${_('Password')}</td>
 
        		<td>${h.password('password')}</td>
 
        		<td>${self.get_form_error('password')}</td>
 
        	</tr>        	
 
        	<tr>
 
        		<td>${_('Name')}</td>
 
        		<td>${h.text('name')}</td>
 
        		<td>${self.get_form_error('name')}</td>
 
        	</tr>
 
        	<tr>
 
        		<td>${_('password')}</td>
 
        		<td>${h.text('password')}</td>
 
        		<td>${_('Lastname')}</td>
 
        		<td>${h.text('lastname')}</td>
 
        		<td>${self.get_form_error('lastname')}</td>
 
        	</tr>
 
        	<tr>
 
        		<td>${_('Email')}</td>
 
        		<td>${h.text('email')}</td>
 
        		<td>${self.get_form_error('email')}</td>
 
        	</tr>        	        	
 
        	<tr>
 
        		<td>${_('Active')}</td>
 
        		<td>${h.checkbox('active')}</td>
 
        		<td>${h.checkbox('active',value=True)}</td>
 
        		<td>${self.get_form_error('active')}</td>
 
        	</tr>
 
        	<tr>
 
        		<td></td>
 
        		<td>${h.submit('add','add')}</td>
 
        		<td>${h.submit('save','save')}</td>
 
        	</tr>
 
        	        	        	
 
        </table>
 
        ${h.end_form()}
 
    </div>
 
</%def>    
 
\ No newline at end of file
pylons_app/templates/admin/users/user_edit.html
Show inline comments
 
@@ -12,30 +12,48 @@
 
<%def name="page_nav()">
 
	${self.menu('admin')}
 
	${self.submenu('users')}
 
</%def>
 
<%def name="main()">
 
	<div>
 
        <h2>${_('User')} - ${c.user.username}</h2>
 
        ${h.form(url('user', id=c.user.user_id),method='put')}
 
        <table>
 
        	<tr>
 
        		<td>${_('Username')}</td>
 
        		<td>${h.text('username')}</td>
 
        		<td>${self.get_form_error('username')}</td>
 
        	</tr>
 
        	<tr>
 
        		<td>${_('New password')}</td>
 
        		<td>${h.text('new_password')}</td>
 
        		<td>${self.get_form_error('new_password')}</td>
 
        	</tr>
 
        	<tr>
 
        		<td>${_('Name')}</td>
 
        		<td>${h.text('name')}</td>
 
        		<td>${self.get_form_error('name')}</td>
 
        	</tr>
 
        	<tr>
 
        		<td>${_('Lastname')}</td>
 
        		<td>${h.text('lastname')}</td>
 
        		<td>${self.get_form_error('lastname')}</td>
 
        	</tr>
 
        	<tr>
 
        		<td>${_('Email')}</td>
 
        		<td>${h.text('email')}</td>
 
        		<td>${self.get_form_error('email')}</td>
 
        	</tr>        	        	
 
        	<tr>
 
        		<td>${_('Active')}</td>
 
        		<td>${h.checkbox('active',value=True)}</td>
 
        		<td>${self.get_form_error('active')}</td>
 
        	</tr>
 
        	<tr>
 
        		<td></td>
 
        		<td>${h.submit('save','save')}</td>
 
        	</tr>
 
        	        	        	
 
        </table>
 
        ${h.end_form()}
 
    </div>
 
</%def>  
 
\ No newline at end of file
pylons_app/templates/admin/users/users.html
Show inline comments
 
@@ -9,34 +9,36 @@
 
	 /  
 
	 ${_('Users')}
 
</%def>
 
<%def name="page_nav()">
 
	${self.menu('admin')}
 
	${self.submenu('users')}
 
</%def>
 
<%def name="main()">
 
	<div>
 
        <h2>${_('Mercurial users')}</h2>
 
        <table class="table_disp">
 
         <tr class="header">
 
            <td>${_('id')}</td>
 
            <td>${_('username')}</td>
 
            <td>${_('name')}</td>
 
            <td>${_('lastname')}</td>
 
            <td>${_('active')}</td>
 
            <td>${_('admin')}</td>
 
            <td>${_('action')}</td>
 
         </tr>
 
            %for user in c.users_list:
 
                <tr>
 
                    <td>${user.user_id}</td>
 
                    <td>${h.link_to(user.username,h.url('edit_user', id=user.user_id))}</td>
 
                    <td>${user.name}</td>
 
                    <td>${user.lastname}</td>
 
                    <td>${user.active}</td>
 
                    <td>${user.admin}</td>
 
                    <td>
 
	                    ${h.form(url('user', id=user.user_id),method='delete')}
 
	                    	${h.submit('remove','delete',class_="delete_icon action_button")}
 
	                    ${h.end_form()}
 
        			</td>
 
                </tr>
 
            %endfor
 
        </table>
 
        <span class="add_icon">${h.link_to(u'add user',h.url('new_user'))}</span>        
 
    </div>
pylons_app/templates/login.html
Show inline comments
 
@@ -12,27 +12,25 @@ from pylons_app.lib import filters
 
<%def name="page_nav()">
 
	${self.menu('home')}
 
</%def>
 
<%def name="main()">
 
        <div>
 
        <br />
 
        <h2>${_('Login')}</h2>
 
        ${h.form(h.url.current())}
 
        <table>
 
            <tr>
 
                <td>${_('Username')}</td>
 
                <td>${h.text('username')}</td>
 
                <td>${self.get_form_error('username')} 
 

	
 
                </td>
 
                <td>${self.get_form_error('username')}</td>
 
            </tr>
 
            <tr>
 
                <td>${_('Password')}</td>
 
                <td>${h.password('password')}</td>
 
                <td>${self.get_form_error('password')}</td> 
 
            </tr>
 
            <tr>
 
                <td></td>
 
                <td>${h.submit('login','login')}</td>
 
            </tr>            
 
        </table>
 
        ${h.end_form()}
0 comments (0 inline, 0 general)