OMG..lots of changes for sake of mobile login / user menu etc.
Feeling a bit sloppy right about now...oh well good enough
This commit is contained in:
parent
e3ae427e37
commit
ee0bdc4b74
|
@ -19,13 +19,13 @@ div.field-wrapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
div.field-wrapper label {
|
div.field-wrapper label {
|
||||||
margin: 0px;
|
|
||||||
padding-top: 3px;
|
|
||||||
text-align: right;
|
text-align: right;
|
||||||
width: 100px;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.field-wrapper input {
|
div.field-wrapper div.field input[type="text"],
|
||||||
|
div.field-wrapper div.field input[type="password"] {
|
||||||
|
margin-left: 1em;
|
||||||
width: 150px;
|
width: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
14
tailbone/static/css/mobile.css
Normal file
14
tailbone/static/css/mobile.css
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
|
||||||
|
/****************************************
|
||||||
|
* Global styles for mobile templates
|
||||||
|
****************************************/
|
||||||
|
|
||||||
|
.replacement-header {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* used by login page */
|
||||||
|
.error {
|
||||||
|
color: red;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
39
tailbone/static/js/tailbone.mobile.js
Normal file
39
tailbone/static/js/tailbone.mobile.js
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
*
|
||||||
|
* tailbone.mobile.js
|
||||||
|
*
|
||||||
|
* Global logic for mobile app
|
||||||
|
*
|
||||||
|
************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
|
||||||
|
// must init header/footer toolbars since ours are "external"
|
||||||
|
$('[data-role="header"], [data-role="footer"]').toolbar({theme: 'a'});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
$(document).on('pagecontainerchange', function(event, ui) {
|
||||||
|
|
||||||
|
// in some cases (i.e. when no user is logged in) we may want the (external)
|
||||||
|
// header toolbar button to change between pages. here's how we do that.
|
||||||
|
// note however that we do this *always* even when not technically needed
|
||||||
|
var link = $('[data-role="header"] a');
|
||||||
|
var newlink = ui.toPage.find('.replacement-header a');
|
||||||
|
link.text(newlink.text());
|
||||||
|
link.attr('href', newlink.attr('href'));
|
||||||
|
link.removeClass('ui-icon-home ui-icon-user');
|
||||||
|
link.addClass(newlink.attr('class'));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
$(document).on('pageshow', function() {
|
||||||
|
|
||||||
|
// on login page, auto-focus username
|
||||||
|
el = $('#username');
|
||||||
|
if (el.is(':visible')) {
|
||||||
|
el.focus();
|
||||||
|
}
|
||||||
|
});
|
|
@ -8,3 +8,6 @@
|
||||||
% for name, version in packages.iteritems():
|
% for name, version in packages.iteritems():
|
||||||
<h3>${name} ${version}</h3>
|
<h3>${name} ${version}</h3>
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<p>Please see <a href="https://rattailproject.org/">rattailproject.org</a> for more info.</p>
|
||||||
|
|
|
@ -10,33 +10,31 @@
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="logo()">
|
<%def name="logo()">
|
||||||
${h.image(request.static_url('tailbone:static/img/home_logo.png'), "Rattail Logo", id='logo')}
|
${h.image(request.static_url('tailbone:static/img/home_logo.png'), "Rattail Logo", id='logo')}
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<%def name="login_form()">
|
||||||
|
<div class="form">
|
||||||
|
${form.begin(**{'data-ajax': 'false'})}
|
||||||
|
${form.hidden('referrer', value=referrer)}
|
||||||
|
|
||||||
|
## this is used by mobile view
|
||||||
|
% if error:
|
||||||
|
<div class="error">${error}</div>
|
||||||
|
% endif
|
||||||
|
|
||||||
|
${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>
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
${self.logo()}
|
${self.logo()}
|
||||||
|
|
||||||
<div class="form">
|
${self.login_form()}
|
||||||
${h.form('')}
|
|
||||||
<input type="hidden" name="referrer" value="${referrer}" />
|
|
||||||
|
|
||||||
% if error:
|
|
||||||
<div class="error">${error}</div>
|
|
||||||
% endif
|
|
||||||
|
|
||||||
<div class="field-wrapper">
|
|
||||||
<label for="username">Username</label>
|
|
||||||
<input type="text" name="username" id="username" value="" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="field-wrapper">
|
|
||||||
<label for="password">Password</label>
|
|
||||||
<input type="password" name="password" id="password" value="" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="buttons">
|
|
||||||
${h.submit('submit', "Login")}
|
|
||||||
<input type="reset" value="Reset" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
${h.end_form()}
|
|
||||||
</div>
|
|
||||||
|
|
|
@ -3,40 +3,92 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
|
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
|
||||||
<title>${self.global_title()} » ${capture(self.title)}</title>
|
<title>${self.global_title()} » ${self.title()}</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
${h.javascript_link('https://code.jquery.com/jquery-1.12.4.min.js')}
|
${h.javascript_link('https://code.jquery.com/jquery-1.12.4.min.js')}
|
||||||
${h.javascript_link('https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js')}
|
${h.javascript_link('https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js')}
|
||||||
${h.stylesheet_link('https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css')}
|
${h.stylesheet_link('https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css')}
|
||||||
|
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.mobile.js'))}
|
||||||
|
${h.stylesheet_link(request.static_url('tailbone:static/css/mobile.css'))}
|
||||||
% if not request.rattail_config.production():
|
% if not request.rattail_config.production():
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
.ui-page-theme-a { background-image: url(${request.static_url('tailbone:static/img/testing.png')}); }
|
.ui-page-theme-a { background-image: url(${request.static_url('tailbone:static/img/testing.png')}); }
|
||||||
</style>
|
</style>
|
||||||
% endif
|
% endif
|
||||||
</head>
|
</head>
|
||||||
|
${self.mobile_body()}
|
||||||
<body>
|
|
||||||
<div data-role="page">
|
|
||||||
|
|
||||||
<div data-role="header">
|
|
||||||
${h.link_to("Home", url('mobile.home'), class_='ui-btn-left')}
|
|
||||||
${h.link_to("About", url('mobile.about'), class_='ui-btn-right')}
|
|
||||||
<h1>${self.global_title()}</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div role="main" class="ui-content">
|
|
||||||
% if capture(self.title):
|
|
||||||
<h2>${self.title()}</h2>
|
|
||||||
% endif
|
|
||||||
${self.body()}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div data-role="footer">
|
|
||||||
<h4>powered by ${h.link_to("Rattail", url('mobile.about'))}</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
<%def name="global_title()">${"[STAGE] " if not request.rattail_config.production() else ''}Rattail Demo</%def>
|
<%def name="mobile_body()">
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div data-role="page" data-url="${self.page_url()}"${' data-rel="dialog"' if dialog else ''|n}>
|
||||||
|
|
||||||
|
${self.mobile_usermenu()}
|
||||||
|
|
||||||
|
${self.mobile_header()}
|
||||||
|
|
||||||
|
${self.mobile_page_body()}
|
||||||
|
|
||||||
|
${self.mobile_footer()}
|
||||||
|
|
||||||
|
</div><!-- page -->
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<%def name="app_title()">Rattail Demo</%def>
|
||||||
|
|
||||||
|
<%def name="global_title()">${"[STAGE] " if not request.rattail_config.production() else ''}${self.app_title()}</%def>
|
||||||
|
|
||||||
|
<%def name="page_url()">${request.current_route_url()}</%def>
|
||||||
|
|
||||||
|
<%def name="page_title()">${self.title()}</%def>
|
||||||
|
|
||||||
|
<%def name="mobile_header()">
|
||||||
|
<div data-role="header">
|
||||||
|
${self.mobile_header_link()}
|
||||||
|
<h1>${self.global_title()}</h1>
|
||||||
|
</div>
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<%def name="mobile_header_link()">
|
||||||
|
% if request.user:
|
||||||
|
${h.link_to(request.user.get_short_name(), '#usermenu', class_='ui-btn-left ui-btn ui-btn-inline ui-mini ui-corner-all ui-btn-icon-left ui-icon-user')}
|
||||||
|
% elif request.matched_route.name in ('mobile.login', 'mobile.about'):
|
||||||
|
${h.link_to("Home", url('mobile.home'), class_='ui-btn-left ui-btn ui-btn-inline ui-mini ui-corner-all ui-btn-icon-left ui-icon-home')}
|
||||||
|
% else:
|
||||||
|
${h.link_to("Login", url('mobile.login'), class_='ui-btn-left ui-btn ui-btn-inline ui-mini ui-corner-all ui-btn-icon-left ui-icon-user')}
|
||||||
|
% endif
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<%def name="mobile_usermenu()">
|
||||||
|
<div id="usermenu" data-role="panel" data-display="overlay">
|
||||||
|
<ul data-role="listview">
|
||||||
|
<li data-icon="home">${h.link_to("Home", url('mobile.home'))}</li>
|
||||||
|
<li data-icon="user">${h.link_to("Logout", url('logout'), **{'data-ajax': 'false'})}</li>
|
||||||
|
<li data-icon="info">${h.link_to("About {}".format(capture(self.app_title)), url('mobile.about'))}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<%def name="mobile_page_body()">
|
||||||
|
<div role="main" class="ui-content">
|
||||||
|
% if capture(self.page_title):
|
||||||
|
<h2>${self.page_title()}</h2>
|
||||||
|
% endif
|
||||||
|
|
||||||
|
${self.body()}
|
||||||
|
|
||||||
|
<div class="replacement-header">
|
||||||
|
${self.mobile_header_link()}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<%def name="mobile_footer()">
|
||||||
|
<div data-role="footer">
|
||||||
|
<h4>powered by ${h.link_to("Rattail", url('mobile.about'))}</h4>
|
||||||
|
</div>
|
||||||
|
</%def>
|
||||||
|
|
20
tailbone/templates/mobile/base_external_toolbars.mako
Normal file
20
tailbone/templates/mobile/base_external_toolbars.mako
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
## -*- coding: utf-8 -*-
|
||||||
|
<%inherit file="tailbone:templates/mobile/base.mako" />
|
||||||
|
|
||||||
|
<%def name="mobile_body()">
|
||||||
|
<body>
|
||||||
|
|
||||||
|
${self.mobile_header()}
|
||||||
|
|
||||||
|
<div data-role="page" data-url="${self.page_url()}"${' data-rel="dialog"' if dialog else ''|n}>
|
||||||
|
|
||||||
|
${self.mobile_usermenu()}
|
||||||
|
|
||||||
|
${self.mobile_page_body()}
|
||||||
|
|
||||||
|
</div><!-- page -->
|
||||||
|
|
||||||
|
${self.mobile_footer()}
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</%def>
|
|
@ -1,7 +1,9 @@
|
||||||
## -*- coding: utf-8 -*-
|
## -*- coding: utf-8 -*-
|
||||||
<%inherit file="/mobile/base.mako" />
|
<%inherit file="/mobile/base.mako" />
|
||||||
|
|
||||||
<%def name="title()"></%def>
|
<%def name="title()">Home</%def>
|
||||||
|
|
||||||
|
<%def name="page_title()"></%def>
|
||||||
|
|
||||||
<div style="text-align: center;">
|
<div style="text-align: center;">
|
||||||
${h.image(request.static_url('tailbone:static/img/home_logo.png'), "Rattail Logo", width='400')}
|
${h.image(request.static_url('tailbone:static/img/home_logo.png'), "Rattail Logo", width='400')}
|
||||||
|
|
7
tailbone/templates/mobile/login.mako
Normal file
7
tailbone/templates/mobile/login.mako
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
## -*- coding: utf-8 -*-
|
||||||
|
<%inherit file="/mobile/base.mako" />
|
||||||
|
<%namespace file="/login.mako" import="login_form" />
|
||||||
|
|
||||||
|
<%def name="title()">Login</%def>
|
||||||
|
|
||||||
|
${login_form()}
|
|
@ -28,164 +28,181 @@ 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
|
import formencode as fe
|
||||||
from pyramid.httpexceptions import HTTPFound, HTTPForbidden
|
from pyramid.httpexceptions import HTTPForbidden
|
||||||
from pyramid.security import remember, forget
|
from pyramid.security import remember, forget
|
||||||
from pyramid_simpleform import Form
|
from pyramid_simpleform import Form
|
||||||
from webhelpers.html import literal
|
from webhelpers.html import tags, literal
|
||||||
from webhelpers.html import tags
|
|
||||||
|
|
||||||
|
from tailbone import forms
|
||||||
from tailbone.db import Session
|
from tailbone.db import Session
|
||||||
from tailbone.forms.simpleform import FormRenderer
|
from tailbone.views import View
|
||||||
|
|
||||||
|
|
||||||
def forbidden(request):
|
class UserLogin(fe.Schema):
|
||||||
"""
|
|
||||||
Access forbidden view.
|
|
||||||
|
|
||||||
This is triggered whenever access is not allowed for an otherwise
|
|
||||||
appropriate view.
|
|
||||||
"""
|
|
||||||
msg = literal("You do not have permission to do that.")
|
|
||||||
if not request.authenticated_userid:
|
|
||||||
msg += literal(" (Perhaps you should %s?)" %
|
|
||||||
tags.link_to("log in", request.route_url('login')))
|
|
||||||
# Store current URL in session, for smarter redirect after login.
|
|
||||||
request.session['next_url'] = request.current_route_url()
|
|
||||||
request.session.flash(msg, allow_duplicate=False)
|
|
||||||
return HTTPFound(location=request.get_referrer())
|
|
||||||
|
|
||||||
|
|
||||||
class UserLogin(formencode.Schema):
|
|
||||||
allow_extra_fields = True
|
allow_extra_fields = True
|
||||||
filter_extra_fields = True
|
filter_extra_fields = True
|
||||||
username = formencode.validators.NotEmpty()
|
username = fe.validators.NotEmpty()
|
||||||
password = formencode.validators.NotEmpty()
|
password = fe.validators.NotEmpty()
|
||||||
|
|
||||||
|
|
||||||
def login(request):
|
class CurrentPasswordCorrect(fe.validators.FancyValidator):
|
||||||
"""
|
|
||||||
The login view, responsible for displaying and handling the login form.
|
|
||||||
"""
|
|
||||||
referrer = request.get_referrer()
|
|
||||||
|
|
||||||
# Redirect if already logged in.
|
|
||||||
if request.user:
|
|
||||||
return HTTPFound(location=referrer)
|
|
||||||
|
|
||||||
form = Form(request, schema=UserLogin)
|
|
||||||
if form.validate():
|
|
||||||
user = authenticate_user(Session(),
|
|
||||||
form.data['username'],
|
|
||||||
form.data['password'])
|
|
||||||
if user:
|
|
||||||
headers = remember(request, user.uuid)
|
|
||||||
# Treat URL from session as referrer, if available.
|
|
||||||
referrer = request.session.pop('next_url', referrer)
|
|
||||||
return HTTPFound(location=referrer, headers=headers)
|
|
||||||
request.session.flash("Invalid username or password")
|
|
||||||
|
|
||||||
return {'form': FormRenderer(form), 'referrer': referrer}
|
|
||||||
|
|
||||||
|
|
||||||
def logout(request):
|
|
||||||
"""
|
|
||||||
View responsible for logging out the current user.
|
|
||||||
|
|
||||||
This deletes/invalidates the current session and then redirects to the
|
|
||||||
login page.
|
|
||||||
"""
|
|
||||||
|
|
||||||
request.session.delete()
|
|
||||||
request.session.invalidate()
|
|
||||||
headers = forget(request)
|
|
||||||
referrer = request.get_referrer()
|
|
||||||
return HTTPFound(location=referrer, headers=headers)
|
|
||||||
|
|
||||||
|
|
||||||
def become_root(request):
|
|
||||||
"""
|
|
||||||
Elevate the current request to 'root' for full system access.
|
|
||||||
"""
|
|
||||||
if not request.is_admin:
|
|
||||||
raise HTTPForbidden()
|
|
||||||
request.session['is_root'] = True
|
|
||||||
request.session.flash("You have been elevated to 'root' and now have full system access")
|
|
||||||
return HTTPFound(location=request.get_referrer())
|
|
||||||
|
|
||||||
|
|
||||||
def stop_root(request):
|
|
||||||
"""
|
|
||||||
Lower the current request from 'root' back to normal access.
|
|
||||||
"""
|
|
||||||
if not request.is_admin:
|
|
||||||
raise HTTPForbidden()
|
|
||||||
request.session['is_root'] = False
|
|
||||||
request.session.flash("Your normal system access has been restored")
|
|
||||||
return HTTPFound(location=request.get_referrer())
|
|
||||||
|
|
||||||
|
|
||||||
class CurrentPasswordCorrect(formencode.validators.FancyValidator):
|
|
||||||
|
|
||||||
def _to_python(self, value, state):
|
def _to_python(self, value, state):
|
||||||
user = state
|
user = state
|
||||||
if not authenticate_user(Session, user.username, value):
|
if not authenticate_user(Session, user.username, value):
|
||||||
raise formencode.Invalid("The password is incorrect.", value, state)
|
raise fe.Invalid("The password is incorrect.", value, state)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
class ChangePassword(formencode.Schema):
|
class ChangePassword(fe.Schema):
|
||||||
|
|
||||||
allow_extra_fields = True
|
allow_extra_fields = True
|
||||||
filter_extra_fields = True
|
filter_extra_fields = True
|
||||||
|
|
||||||
current_password = formencode.All(
|
current_password = fe.All(
|
||||||
formencode.validators.NotEmpty(),
|
fe.validators.NotEmpty(),
|
||||||
CurrentPasswordCorrect())
|
CurrentPasswordCorrect())
|
||||||
|
|
||||||
new_password = formencode.validators.NotEmpty()
|
new_password = fe.validators.NotEmpty()
|
||||||
confirm_password = formencode.validators.NotEmpty()
|
confirm_password = fe.validators.NotEmpty()
|
||||||
|
|
||||||
chained_validators = [formencode.validators.FieldsMatch(
|
chained_validators = [fe.validators.FieldsMatch(
|
||||||
'new_password', 'confirm_password')]
|
'new_password', 'confirm_password')]
|
||||||
|
|
||||||
|
|
||||||
def change_password(request):
|
class AuthenticationView(View):
|
||||||
"""
|
|
||||||
Allows a user to change his or her password.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if not request.user:
|
def forbidden(self):
|
||||||
return HTTPFound(location=request.route_url('home'))
|
"""
|
||||||
|
Access forbidden view.
|
||||||
|
|
||||||
form = Form(request, schema=ChangePassword, state=request.user)
|
This is triggered whenever access is not allowed for an otherwise
|
||||||
if form.validate():
|
appropriate view.
|
||||||
set_user_password(request.user, form.data['new_password'])
|
"""
|
||||||
return HTTPFound(location=request.get_referrer())
|
msg = literal("You do not have permission to do that.")
|
||||||
|
if not self.request.authenticated_userid:
|
||||||
|
msg += literal(" (Perhaps you should %s?)" %
|
||||||
|
tags.link_to("log in", self.request.route_url('login')))
|
||||||
|
# Store current URL in session, for smarter redirect after login.
|
||||||
|
self.request.session['next_url'] = self.request.current_route_url()
|
||||||
|
self.request.session.flash(msg, allow_duplicate=False)
|
||||||
|
return self.redirect(self.request.get_referrer())
|
||||||
|
|
||||||
return {'form': FormRenderer(form)}
|
def login(self, mobile=False):
|
||||||
|
"""
|
||||||
|
The login view, responsible for displaying and handling the login form.
|
||||||
|
"""
|
||||||
|
home = 'mobile.home' if mobile else 'home'
|
||||||
|
referrer = self.request.get_referrer(default=self.request.route_url(home))
|
||||||
|
|
||||||
|
# redirect if already logged in
|
||||||
|
if self.request.user:
|
||||||
|
if not mobile:
|
||||||
|
self.request.session.flash("{} is already logged in".format(self.request.user), 'error')
|
||||||
|
return self.redirect(referrer)
|
||||||
|
|
||||||
def add_routes(config):
|
form = Form(self.request, schema=UserLogin)
|
||||||
config.add_route('login', '/login')
|
context = {'form': forms.FormRenderer(form), 'referrer': referrer, 'dialog': mobile}
|
||||||
config.add_route('logout', '/logout')
|
if form.validate():
|
||||||
config.add_route('become_root', '/root/yes')
|
user = authenticate_user(Session(),
|
||||||
config.add_route('stop_root', '/root/no')
|
form.data['username'],
|
||||||
config.add_route('change_password', '/change-password')
|
form.data['password'])
|
||||||
|
if user:
|
||||||
|
# okay now they're truly logged in
|
||||||
|
headers = remember(self.request, user.uuid)
|
||||||
|
# Treat URL from session as referrer, if available.
|
||||||
|
referrer = self.request.session.pop('next_url', referrer)
|
||||||
|
return self.redirect(referrer, headers=headers)
|
||||||
|
else:
|
||||||
|
if mobile:
|
||||||
|
context['error'] = "Invalid username or password"
|
||||||
|
else:
|
||||||
|
self.request.session.flash("Invalid username or password")
|
||||||
|
return context
|
||||||
|
|
||||||
|
def mobile_login(self):
|
||||||
|
return self.login(mobile=True)
|
||||||
|
|
||||||
|
def logout(self, mobile=False):
|
||||||
|
"""
|
||||||
|
View responsible for logging out the current user.
|
||||||
|
|
||||||
|
This deletes/invalidates the current session and then redirects to the
|
||||||
|
login page.
|
||||||
|
"""
|
||||||
|
self.request.session.delete()
|
||||||
|
self.request.session.invalidate()
|
||||||
|
headers = forget(self.request)
|
||||||
|
login = 'mobile.login' if mobile else 'login'
|
||||||
|
referrer = self.request.get_referrer(default=self.request.route_url(login))
|
||||||
|
return self.redirect(referrer, headers=headers)
|
||||||
|
|
||||||
|
def mobile_logout(self):
|
||||||
|
return self.logout(mobile=True)
|
||||||
|
|
||||||
|
def change_password(self):
|
||||||
|
"""
|
||||||
|
Allows a user to change his or her password.
|
||||||
|
"""
|
||||||
|
if not self.request.user:
|
||||||
|
return self.redirect(self.request.route_url('home'))
|
||||||
|
|
||||||
|
form = Form(self.request, schema=ChangePassword, state=self.request.user)
|
||||||
|
if form.validate():
|
||||||
|
set_user_password(self.request.user, form.data['new_password'])
|
||||||
|
return self.redirect(self.request.get_referrer())
|
||||||
|
|
||||||
|
return {'form': forms.FormRenderer(form)}
|
||||||
|
|
||||||
|
def become_root(self):
|
||||||
|
"""
|
||||||
|
Elevate the current request to 'root' for full system access.
|
||||||
|
"""
|
||||||
|
if not self.request.is_admin:
|
||||||
|
raise HTTPForbidden()
|
||||||
|
self.request.session['is_root'] = True
|
||||||
|
self.request.session.flash("You have been elevated to 'root' and now have full system access")
|
||||||
|
return self.redirect(self.request.get_referrer())
|
||||||
|
|
||||||
|
def stop_root(self):
|
||||||
|
"""
|
||||||
|
Lower the current request from 'root' back to normal access.
|
||||||
|
"""
|
||||||
|
if not self.request.is_admin:
|
||||||
|
raise HTTPForbidden()
|
||||||
|
self.request.session['is_root'] = False
|
||||||
|
self.request.session.flash("Your normal system access has been restored")
|
||||||
|
return self.redirect(self.request.get_referrer())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def defaults(cls, config):
|
||||||
|
|
||||||
|
# forbidden
|
||||||
|
config.add_forbidden_view(cls, attr='forbidden')
|
||||||
|
|
||||||
|
# login
|
||||||
|
config.add_route('login', '/login')
|
||||||
|
config.add_view(cls, attr='login', route_name='login', renderer='/login.mako')
|
||||||
|
config.add_route('mobile.login', '/mobile/login')
|
||||||
|
config.add_view(cls, attr='mobile_login', route_name='mobile.login', renderer='/mobile/login.mako')
|
||||||
|
|
||||||
|
# logout
|
||||||
|
config.add_route('logout', '/logout')
|
||||||
|
config.add_view(cls, attr='logout', route_name='logout')
|
||||||
|
config.add_route('mobile.logout', '/mobile/logout')
|
||||||
|
config.add_view(cls, attr='mobile_logout', route_name='mobile.logout')
|
||||||
|
|
||||||
|
# change password
|
||||||
|
config.add_route('change_password', '/change-password')
|
||||||
|
config.add_view(cls, attr='change_password', route_name='change_password', renderer='/change_password.mako')
|
||||||
|
|
||||||
|
# become/stop root
|
||||||
|
config.add_route('become_root', '/root/yes')
|
||||||
|
config.add_view(cls, attr='become_root', route_name='become_root')
|
||||||
|
config.add_route('stop_root', '/root/no')
|
||||||
|
config.add_view(cls, attr='stop_root', route_name='stop_root')
|
||||||
|
|
||||||
|
|
||||||
def includeme(config):
|
def includeme(config):
|
||||||
add_routes(config)
|
AuthenticationView.defaults(config)
|
||||||
|
|
||||||
config.add_forbidden_view(forbidden)
|
|
||||||
|
|
||||||
config.add_view(login, route_name='login',
|
|
||||||
renderer='/login.mako')
|
|
||||||
|
|
||||||
config.add_view(logout, route_name='logout')
|
|
||||||
|
|
||||||
config.add_view(become_root, route_name='become_root')
|
|
||||||
config.add_view(stop_root, route_name='stop_root')
|
|
||||||
|
|
||||||
config.add_view(change_password, route_name='change_password',
|
|
||||||
renderer='/change_password.mako')
|
|
||||||
|
|
Loading…
Reference in a new issue