changeset 186:556473ba0399

fixed menu in home page, and added login html with forms that validates username and password.
author Marcin Kuzminski <marcin@python-works.com>
date Sat, 22 May 2010 01:32:30 +0200
parents 3380ca40cdba
children 188e3db6977a
files pylons_app/controllers/login.py pylons_app/model/forms.py pylons_app/templates/index.html pylons_app/templates/login.html
diffstat 4 files changed, 155 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pylons_app/controllers/login.py	Sat May 22 01:32:30 2010 +0200
@@ -0,0 +1,37 @@
+import logging
+from formencode import htmlfill
+from pylons import request, response, session, tmpl_context as c, url
+from pylons.controllers.util import abort, redirect
+from pylons_app.lib.base import BaseController, render
+import formencode
+from pylons_app.model.forms import LoginForm
+from pylons_app.lib.auth import AuthUser
+
+log = logging.getLogger(__name__)
+
+class LoginController(BaseController):
+
+    def index(self):
+        if session.get('hg_app_user', AuthUser()).is_authenticated:
+            return redirect(url('hg_home'))
+        
+        if request.POST:
+            #import Login Form validator class
+            login_form = LoginForm()
+            try:
+                c.form_result = login_form.to_python(dict(request.POST))
+                return redirect(url('hg_home'))
+                               
+            except formencode.Invalid as errors:
+                c.form_errors = errors.error_dict
+                return htmlfill.render(
+                    render('/login.html'),
+                    defaults=errors.value,
+                    encoding="UTF-8")
+                        
+        return render('/login.html')
+    
+    def logout(self):
+        session['hg_app_user'] = AuthUser()
+        session.save()
+        redirect(url('hg_home'))
--- a/pylons_app/model/forms.py	Sat May 22 00:51:49 2010 +0200
+++ b/pylons_app/model/forms.py	Sat May 22 01:32:30 2010 +0200
@@ -16,24 +16,88 @@
 <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())
+for SELECT use formencode.All(OneOf(list), Int())
     
 """
-
+from formencode.validators import UnicodeString, OneOf, Int, Number, Regex
+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 Users
+from sqlalchemy.exc import OperationalError
+from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
+from webhelpers.pylonslib.secure_form import authentication_token
 import formencode
-from formencode.validators import UnicodeString, OneOf, Int, Number, Regex
-from pylons.i18n.translation import _
-from webhelpers.pylonslib.secure_form import authentication_token
+import logging
+log = logging.getLogger(__name__)
+
 
+#this is needed to translate the messages using _() in validators
+class State_obj(object):
+    _ = staticmethod(_)
+    
+#===============================================================================
+# 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)
+            raise formencode.Invalid(self.message('invalid_token', state,
+                                            search_number=value), value, state)
 
-
+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']}
+    
+    def validate_python(self, value, state):
+        sa = meta.Session
+        crypted_passwd = get_crypt_password(value['password'])
+        username = value['username']
+        try:
+            user = sa.query(Users).filter(Users.username == username).one()
+        except (NoResultFound, MultipleResultsFound, OperationalError) as e:
+            log.error(e)
+            user = None
+        print value
+        if user:
+            if user.active:
+                if user.username == username and user.password == crypted_passwd:
+                    log.info('user %s authenticated correctly', username)
+                    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()
+                    return value
+                else:
+                    log.warning('user %s not authenticated', username)
+                    raise formencode.Invalid(self.message('invalid_password',
+                                             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)
+            
+            
+        
+#===============================================================================
+# FORMS        
+#===============================================================================
 class LoginForm(formencode.Schema):
     allow_extra_fields = True
     filter_extra_fields = True
@@ -56,3 +120,7 @@
                                 )
 
 
+    #chained validators have access to all data
+    chained_validators = [ValidAuth]
+    
+
--- a/pylons_app/templates/index.html	Sat May 22 00:51:49 2010 +0200
+++ b/pylons_app/templates/index.html	Sat May 22 01:32:30 2010 +0200
@@ -10,10 +10,7 @@
 	${c.repos_prefix} Mercurial Repositories
 </%def>
 <%def name="page_nav()">
-	<ul class="page-nav">
-		<li class="current">${_('Home')}</li>
-		<li>${h.link_to(u'Admin',h.url('admin_home'))}</li>
-	</ul>
+	${self.menu('home')}
 </%def>
 <%def name="main()">
 	<%def name="get_sort(name)">
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pylons_app/templates/login.html	Sat May 22 01:32:30 2010 +0200
@@ -0,0 +1,42 @@
+## -*- coding: utf-8 -*-
+<%!
+from pylons_app.lib import filters
+%>
+<%inherit file="base/base.html"/>
+<%def name="title()">
+    ${c.repos_prefix} Mercurial Repositories
+</%def>
+<%def name="breadcrumbs()">
+	${c.repos_prefix} Mercurial Repositories
+</%def>
+<%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>
+            </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()}
+        </div>
+</%def>    
+
+