Refactor user login, change password to use colander/deform

This commit is contained in:
Lance Edgar 2018-02-10 16:47:53 -06:00
parent cff757fe9e
commit ec438ead51
5 changed files with 53 additions and 69 deletions

View file

@ -1,24 +1,24 @@
$(function() { $(function() {
$('#username').keydown(function(event) { $('input[name="username"]').keydown(function(event) {
if (event.which == 13) { if (event.which == 13) {
$('#password').focus().select(); $('input[name="password"]').focus().select();
return false; return false;
} }
return true; return true;
}); });
$('form').submit(function() { $('form').submit(function() {
if (! $('#username').val()) { if (! $('input[name="username"]').val()) {
with ($('#username').get(0)) { with ($('input[name="username"]').get(0)) {
select(); select();
focus(); focus();
} }
return false; return false;
} }
if (! $('#password').val()) { if (! $('input[name="password"]').val()) {
with ($('#password').get(0)) { with ($('input[name="password"]').get(0)) {
select(); select();
focus(); focus();
} }
@ -27,6 +27,6 @@ $(function() {
return true; return true;
}); });
$('#username').focus(); $('input[name="username"]').focus();
}); });

View file

@ -1,17 +1,8 @@
## -*- coding: utf-8 -*- ## -*- coding: utf-8; -*-
<%inherit file="/base.mako" /> <%inherit file="/base.mako" />
<%def name="title()">Change Password</%def> <%def name="title()">Change Password</%def>
<div class="form"> <div class="form">
${h.form(url('change_password'))} ${form.render_deform()|n}
${form.csrf_token()}
${form.referrer_field()}
${form.field_div('current_password', form.password('current_password'))}
${form.field_div('new_password', form.password('new_password'))}
${form.field_div('confirm_password', form.password('confirm_password'))}
<div class="buttons">
${h.submit('submit', "Change Password")}
</div>
${h.end_form()}
</div> </div>

View file

@ -76,6 +76,9 @@ ${h.csrf_token(request)}
## % if form.creating and form.allow_successive_creates: ## % if form.creating and form.allow_successive_creates:
## ${h.submit('create_and_continue', form.successive_create_label)} ## ${h.submit('create_and_continue', form.successive_create_label)}
## % endif ## % endif
% if getattr(form, 'show_reset', False):
<input type="reset" value="Reset" />
% endif
% if getattr(form, 'show_cancel', True): % if getattr(form, 'show_cancel', True):
${h.link_to("Cancel", form.cancel_url, class_='cancel button{}'.format(' autodisable' if form.auto_disable_cancel else ''))} ${h.link_to("Cancel", form.cancel_url, class_='cancel button{}'.format(' autodisable' if form.auto_disable_cancel else ''))}
% endif % endif

View file

@ -1,4 +1,4 @@
## -*- coding: utf-8 -*- ## -*- coding: utf-8; -*-
<%inherit file="/base.mako" /> <%inherit file="/base.mako" />
<%def name="title()">Login</%def> <%def name="title()">Login</%def>
@ -19,19 +19,7 @@
<%def name="login_form()"> <%def name="login_form()">
<div class="form"> <div class="form">
${form.begin(**{'data-ajax': 'false'})} ${form.render_deform(form_kwargs={'data-ajax': 'false'})|n}
${form.hidden('referrer', value=referrer)}
${form.csrf_token()}
${form.field_div('username', form.text('username'))}
${form.field_div('password', form.password('password'))}
<div class="buttons">
${form.submit('submit', "Login")}
<input type="reset" value="Reset" />
</div>
${form.end()}
</div> </div>
</%def> </%def>

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2017 Lance Edgar # Copyright © 2010-2018 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -28,47 +28,42 @@ from __future__ import unicode_literals, absolute_import
from rattail.db.auth import authenticate_user, set_user_password from rattail.db.auth import authenticate_user, set_user_password
import formencode as fe import colander
from deform import widget as dfwidget
from pyramid.httpexceptions import HTTPForbidden from pyramid.httpexceptions import HTTPForbidden
from pyramid_simpleform import Form
from webhelpers2.html import tags, literal from webhelpers2.html import tags, literal
from tailbone import forms from tailbone import forms2 as forms
from tailbone.db import Session from tailbone.db import Session
from tailbone.views import View from tailbone.views import View
from tailbone.auth import login_user, logout_user from tailbone.auth import login_user, logout_user
class UserLogin(fe.Schema): class UserLogin(colander.MappingSchema):
allow_extra_fields = True
filter_extra_fields = True username = colander.SchemaNode(colander.String())
username = fe.validators.NotEmpty()
password = fe.validators.NotEmpty() password = colander.SchemaNode(colander.String(),
widget=dfwidget.PasswordWidget())
class CurrentPasswordCorrect(fe.validators.FancyValidator): @colander.deferred
def current_password_correct(node, kw):
def _to_python(self, value, state): user = kw['user']
user = state def validate(node, value):
if not authenticate_user(Session, user.username, value): if not authenticate_user(Session(), user.username, value):
raise fe.Invalid("The password is incorrect.", value, state) raise colander.Invalid(node, "The password is incorrect")
return value return validate
class ChangePassword(fe.Schema): class ChangePassword(colander.MappingSchema):
allow_extra_fields = True current_password = colander.SchemaNode(colander.String(),
filter_extra_fields = True widget=dfwidget.PasswordWidget(),
validator=current_password_correct)
current_password = fe.All( new_password = colander.SchemaNode(colander.String(),
fe.validators.NotEmpty(), widget=dfwidget.CheckedPasswordWidget())
CurrentPasswordCorrect())
new_password = fe.validators.NotEmpty()
confirm_password = fe.validators.NotEmpty()
chained_validators = [fe.validators.FieldsMatch(
'new_password', 'confirm_password')]
class AuthenticationView(View): class AuthenticationView(View):
@ -103,10 +98,15 @@ class AuthenticationView(View):
self.request.session.flash("{} is already logged in".format(self.request.user), 'error') self.request.session.flash("{} is already logged in".format(self.request.user), 'error')
return self.redirect(referrer) return self.redirect(referrer)
form = forms.SimpleForm(self.request, UserLogin) form = forms.Form(schema=UserLogin(), request=self.request)
if form.validate(): form.save_label = "Login"
user = self.authenticate_user(form.data['username'], form.auto_disable_save = False
form.data['password']) form.auto_disable = False # TODO: deprecate / remove this
form.show_reset = True
form.show_cancel = False
if form.validate(newstyle=True):
user = self.authenticate_user(form.validated['username'],
form.validated['password'])
if user: if user:
# okay now they're truly logged in # okay now they're truly logged in
headers = login_user(self.request, user) headers = login_user(self.request, user)
@ -122,7 +122,7 @@ class AuthenticationView(View):
default=self.request.static_url('tailbone:static/img/home_logo.png')) default=self.request.static_url('tailbone:static/img/home_logo.png'))
return { return {
'form': forms.FormRenderer(form), 'form': form,
'referrer': referrer, 'referrer': referrer,
'image_url': image_url, 'image_url': image_url,
'dialog': mobile, 'dialog': mobile,
@ -169,12 +169,14 @@ class AuthenticationView(View):
self.request.session.flash("Cannot change password for 'chuck' in demo mode", 'error') self.request.session.flash("Cannot change password for 'chuck' in demo mode", 'error')
return self.redirect(self.request.get_referrer()) return self.redirect(self.request.get_referrer())
form = Form(self.request, schema=ChangePassword, state=self.request.user) schema = ChangePassword().bind(user=self.request.user)
if form.validate(): form = forms.Form(schema=schema, request=self.request)
set_user_password(self.request.user, form.data['new_password']) if form.validate(newstyle=True):
set_user_password(self.request.user, form.validated['new_password'])
self.request.session.flash("Your password has been changed.")
return self.redirect(self.request.get_referrer()) return self.redirect(self.request.get_referrer())
return {'form': forms.FormRenderer(form)} return {'form': form}
def become_root(self): def become_root(self):
""" """