2012-04-16 20:04:48 -05:00
|
|
|
#!/usr/bin/env python
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
################################################################################
|
|
|
|
#
|
|
|
|
# edbob -- Pythonic Software Framework
|
|
|
|
# Copyright © 2010-2012 Lance Edgar
|
|
|
|
#
|
|
|
|
# This file is part of edbob.
|
|
|
|
#
|
|
|
|
# edbob is free software: you can redistribute it and/or modify it under the
|
|
|
|
# terms of the GNU Affero General Public License as published by the Free
|
|
|
|
# Software Foundation, either version 3 of the License, or (at your option)
|
|
|
|
# any later version.
|
|
|
|
#
|
|
|
|
# edbob 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 Affero General Public License for
|
|
|
|
# more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
|
|
# along with edbob. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#
|
|
|
|
################################################################################
|
|
|
|
|
|
|
|
"""
|
|
|
|
``edbob.pyramid.views.auth`` -- Auth Views
|
|
|
|
"""
|
|
|
|
|
|
|
|
from pyramid.httpexceptions import HTTPFound
|
|
|
|
from pyramid.security import remember, forget
|
2012-11-06 15:32:49 -08:00
|
|
|
|
|
|
|
import formencode
|
2012-04-16 20:04:48 -05:00
|
|
|
from pyramid_simpleform import Form
|
2012-11-06 15:32:49 -08:00
|
|
|
import pyramid_simpleform.renderers
|
|
|
|
|
|
|
|
from webhelpers.html import tags
|
|
|
|
from webhelpers.html.builder import HTML
|
2012-04-16 20:04:48 -05:00
|
|
|
|
|
|
|
import edbob
|
2012-11-06 15:32:49 -08:00
|
|
|
from edbob.db.auth import authenticate_user, set_user_password
|
2012-04-16 20:04:48 -05:00
|
|
|
from edbob.pyramid import Session
|
2012-11-06 15:32:49 -08:00
|
|
|
from edbob.util import prettify
|
|
|
|
|
|
|
|
|
|
|
|
class FormRenderer(pyramid_simpleform.renderers.FormRenderer):
|
|
|
|
"""
|
|
|
|
Customized form renderer. Provides some extra methods for convenience.
|
|
|
|
"""
|
2012-04-16 20:04:48 -05:00
|
|
|
|
2012-11-06 15:32:49 -08:00
|
|
|
# Note that as of this writing, this renderer is used only by the
|
|
|
|
# ``change_password`` view. This should probably change, and this class
|
|
|
|
# definition should be moved elsewhere.
|
|
|
|
|
|
|
|
def field_div(self, name, field, label=None):
|
|
|
|
errors = self.errors_for(name)
|
|
|
|
if errors:
|
|
|
|
errors = [HTML.tag('div', class_='field-error', c=x) for x in errors]
|
|
|
|
errors = tags.literal('').join(errors)
|
|
|
|
|
|
|
|
label = HTML.tag('label', for_=name, c=label or prettify(name))
|
|
|
|
inner = HTML.tag('div', class_='field', c=field)
|
|
|
|
|
|
|
|
outer_class = 'field-wrapper'
|
|
|
|
if errors:
|
|
|
|
outer_class += ' error'
|
|
|
|
outer = HTML.tag('div', class_=outer_class, c=(errors or '') + label + inner)
|
|
|
|
return outer
|
|
|
|
|
|
|
|
def referrer_field(self):
|
|
|
|
return self.hidden('referrer', value=self.form.request.get_referrer())
|
|
|
|
|
2012-04-16 20:04:48 -05:00
|
|
|
|
|
|
|
class UserLogin(formencode.Schema):
|
|
|
|
allow_extra_fields = True
|
|
|
|
filter_extra_fields = True
|
|
|
|
username = formencode.validators.NotEmpty()
|
|
|
|
password = formencode.validators.NotEmpty()
|
|
|
|
|
|
|
|
|
2012-08-16 09:06:17 -07:00
|
|
|
def login(request):
|
2012-04-16 20:04:48 -05:00
|
|
|
"""
|
|
|
|
The login view, responsible for displaying and handling the login form.
|
|
|
|
"""
|
|
|
|
|
2012-08-29 11:08:43 -07:00
|
|
|
referrer = request.get_referrer()
|
2012-04-16 20:04:48 -05:00
|
|
|
|
|
|
|
# Redirect if already logged in.
|
|
|
|
if request.user:
|
2012-08-29 11:08:43 -07:00
|
|
|
return HTTPFound(location=referrer)
|
2012-04-16 20:04:48 -05:00
|
|
|
|
|
|
|
form = Form(request, schema=UserLogin)
|
|
|
|
if form.validate():
|
|
|
|
user = authenticate_user(form.data['username'],
|
|
|
|
form.data['password'],
|
|
|
|
session=Session())
|
|
|
|
if user:
|
|
|
|
request.session.flash("%s logged in at %s" % (
|
|
|
|
user.display_name,
|
|
|
|
edbob.local_time().strftime('%I:%M %p')))
|
|
|
|
headers = remember(request, user.uuid)
|
2012-08-29 11:08:43 -07:00
|
|
|
return HTTPFound(location=referrer, headers=headers)
|
2012-04-16 20:04:48 -05:00
|
|
|
request.session.flash("Invalid username or password")
|
2012-04-17 14:01:56 -05:00
|
|
|
|
|
|
|
url = edbob.config.get('edbob.pyramid', 'login.logo_url',
|
|
|
|
default=request.static_url('edbob.pyramid:static/img/logo.jpg'))
|
2012-04-21 12:45:58 -05:00
|
|
|
kwargs = eval(edbob.config.get('edbob.pyramid', 'login.logo_kwargs',
|
|
|
|
default="dict(width=500)"))
|
2012-04-17 14:01:56 -05:00
|
|
|
|
2012-08-29 11:08:43 -07:00
|
|
|
return {'form': FormRenderer(form), 'referrer': referrer,
|
2012-04-21 12:45:58 -05:00
|
|
|
'logo_url': url, 'logo_kwargs': kwargs}
|
2012-04-16 20:04:48 -05:00
|
|
|
|
|
|
|
|
2012-08-16 09:06:17 -07:00
|
|
|
def logout(request):
|
2012-04-21 12:45:58 -05:00
|
|
|
"""
|
|
|
|
View responsible for logging out the current user.
|
|
|
|
|
|
|
|
This deletes/invalidates the current session and then redirects to the
|
|
|
|
login page.
|
|
|
|
"""
|
|
|
|
|
2012-04-16 20:04:48 -05:00
|
|
|
request.session.delete()
|
2012-04-21 12:45:58 -05:00
|
|
|
request.session.invalidate()
|
2012-04-16 20:04:48 -05:00
|
|
|
headers = forget(request)
|
2012-08-29 11:08:43 -07:00
|
|
|
referrer = request.get_referrer()
|
|
|
|
return HTTPFound(location=referrer, headers=headers)
|
2012-04-16 20:04:48 -05:00
|
|
|
|
|
|
|
|
2012-11-06 15:32:49 -08:00
|
|
|
class CurrentPasswordCorrect(formencode.validators.FancyValidator):
|
|
|
|
|
|
|
|
def _to_python(self, value, state):
|
|
|
|
user = state
|
|
|
|
if not authenticate_user(user.username, value, session=Session()):
|
|
|
|
raise formencode.Invalid("The password is incorrect.", value, state)
|
|
|
|
return value
|
|
|
|
|
|
|
|
|
|
|
|
class ChangePassword(formencode.Schema):
|
|
|
|
|
|
|
|
allow_extra_fields = True
|
|
|
|
filter_extra_fields = True
|
|
|
|
|
|
|
|
current_password = formencode.All(
|
|
|
|
formencode.validators.NotEmpty(),
|
|
|
|
CurrentPasswordCorrect())
|
|
|
|
|
|
|
|
new_password = formencode.validators.NotEmpty()
|
|
|
|
confirm_password = formencode.validators.NotEmpty()
|
|
|
|
|
|
|
|
chained_validators = [formencode.validators.FieldsMatch(
|
|
|
|
'new_password', 'confirm_password')]
|
|
|
|
|
|
|
|
|
|
|
|
def change_password(request):
|
|
|
|
"""
|
|
|
|
Allows a user to change his or her password.
|
|
|
|
"""
|
|
|
|
|
|
|
|
if not request.user:
|
|
|
|
return HTTPFound(location=request.route_url('home'))
|
|
|
|
|
|
|
|
form = Form(request, schema=ChangePassword, state=request.user)
|
|
|
|
if form.validate():
|
|
|
|
set_user_password(request.user, form.data['new_password'])
|
|
|
|
return HTTPFound(location=request.get_referrer())
|
|
|
|
|
|
|
|
return {'form': FormRenderer(form)}
|
|
|
|
|
|
|
|
|
2012-04-16 20:04:48 -05:00
|
|
|
def includeme(config):
|
2012-04-21 12:45:58 -05:00
|
|
|
|
2012-04-16 20:04:48 -05:00
|
|
|
config.add_route('login', '/login')
|
2012-04-17 14:01:56 -05:00
|
|
|
config.add_view(login, route_name='login', renderer='/login.mako')
|
|
|
|
|
2012-04-16 20:04:48 -05:00
|
|
|
config.add_route('logout', '/logout')
|
2012-04-17 14:01:56 -05:00
|
|
|
config.add_view(logout, route_name='logout')
|
2012-11-06 15:32:49 -08:00
|
|
|
|
|
|
|
config.add_route('change_password', '/change-password')
|
|
|
|
config.add_view(change_password, route_name='change_password', renderer='/change_password.mako')
|