Paths for templates are now configurable

This commit is contained in:
Chris Haines
2013-01-29 22:24:11 -05:00
parent 3f243d1c11
commit 02c49ee423
11 changed files with 125 additions and 8 deletions
+29
View File
@@ -96,6 +96,35 @@ URLs and Views
=============================== ================================================
Template Paths
--------------
.. tabularcolumns:: |p{6.5cm}|p{8.5cm}|
======================================== =======================================
``SECURITY_FORGOT_PASSWORD_TEMPLATE`` Specifies the path to the template for
the forgot password page. Defaults to
``security/forgot_password.html``.
``SECURITY_LOGIN_USER_TEMPLATE`` Specifies the path to the template for
the user login page. Defaults to
``security/login_user.html``.
``SECURITY_REGISTER_USER_TEMPLATE`` Specifies the path to the template for
the user registration page. Defaults to
``security/register_user.html``.
``SECURITY_RESET_PASSWORD_TEMPLATE`` Specifies the path to the template for
the reset password page. Defaults to
``security/reset_password.html``.
``SECURITY_SEND_CONFIRMATION_TEMPLATE`` Specifies the path to the template for
the resend confirmation instructions
page. Defaults to
``security/send_confirmation.html``.
``SECURITY_SEND_LOGIN_TEMPLATE`` Specifies the path to the template for
the send login instructions page for
passwordless logins. Defaults to
``security/send_login.html``.
======================================== =======================================
Feature Flags
-------------
+3 -1
View File
@@ -26,9 +26,11 @@ Overriding these templates is simple:
1. Create a folder named ``security`` within your application's templates folder
2. Create a template with the same name for the template you wish to override
You can also specify custom template file paths in the :doc:`configuration <configuration>`.
Each template is passed a template context object that includes the following,
including the objects/values that are passed to the template by the main
Flask application context processory:
Flask application context processor:
* ``<template_name>_form``: A form object for the view
* ``security``: The Flask-Security extension object
+6
View File
@@ -48,6 +48,12 @@ _default_config = {
'POST_CONFIRM_VIEW': None,
'POST_RESET_VIEW': None,
'UNAUTHORIZED_VIEW': None,
'FORGOT_PASSWORD_TEMPLATE': 'security/forgot_password.html',
'LOGIN_USER_TEMPLATE': 'security/login_user.html',
'REGISTER_USER_TEMPLATE': 'security/register_user.html',
'RESET_PASSWORD_TEMPLATE': 'security/reset_password.html',
'SEND_CONFIRMATION_TEMPLATE': 'security/send_confirmation.html',
'SEND_LOGIN_TEMPLATE': 'security/send_login.html',
'CONFIRMABLE': False,
'REGISTERABLE': False,
'RECOVERABLE': False,
+8 -7
View File
@@ -23,7 +23,8 @@ from .recoverable import reset_password_token_status, \
send_reset_password_instructions, update_password
from .registerable import register_user
from .utils import get_url, get_post_login_redirect, do_flash, \
get_message, login_user, logout_user, url_for_security as url_for
get_message, login_user, logout_user, url_for_security as url_for, \
config_value
# Convenient references
@@ -81,7 +82,7 @@ def login():
if request.json:
return _render_json(form, True)
return render_template('security/login_user.html',
return render_template(config_value('LOGIN_USER_TEMPLATE'),
login_user_form=form,
**_ctx('login'))
@@ -127,7 +128,7 @@ def register():
if request.json:
return _render_json(form)
return render_template('security/register_user.html',
return render_template(config_value('REGISTER_USER_TEMPLATE'),
register_user_form=form,
**_ctx('register'))
@@ -150,7 +151,7 @@ def send_login():
if request.json:
return _render_json(form)
return render_template('security/send_login.html',
return render_template(config_value('SEND_LOGIN_TEMPLATE'),
send_login_form=form,
**_ctx('send_login'))
@@ -195,7 +196,7 @@ def send_confirmation():
if request.json:
return _render_json(form)
return render_template('security/send_confirmation.html',
return render_template(config_value('SEND_CONFIRMATION_TEMPLATE'),
send_confirmation_form=form,
**_ctx('send_confirmation'))
@@ -243,7 +244,7 @@ def forgot_password():
if request.json:
return _render_json(form)
return render_template('security/forgot_password.html',
return render_template(config_value('FORGOT_PASSWORD_TEMPLATE'),
forgot_password_form=form,
**_ctx('forgot_password'))
@@ -272,7 +273,7 @@ def reset_password(token):
return redirect(get_url(_security.post_reset_view) or
get_url(_security.post_login_view))
return render_template('security/reset_password.html',
return render_template(config_value('RESET_PASSWORD_TEMPLATE'),
reset_password_form=form,
reset_password_token=token,
**_ctx('reset_password'))
+73
View File
@@ -107,6 +107,79 @@ class BadConfiguredSecurityTests(SecurityTest):
self.assertRaises(RuntimeError, self.authenticate)
class DefaultTemplatePathTests(SecurityTest):
AUTH_CONFIG = {
'SECURITY_LOGIN_USER_TEMPLATE': 'custom_security/login_user.html',
}
def test_login_user_template(self):
r = self._get('/login')
self.assertIn('CUSTOM LOGIN USER', r.data)
class RegisterableTemplatePathTests(SecurityTest):
AUTH_CONFIG = {
'SECURITY_REGISTERABLE': True,
'SECURITY_REGISTER_USER_TEMPLATE': 'custom_security/register_user.html'
}
def test_register_user_template(self):
r = self._get('/register')
self.assertIn('CUSTOM REGISTER USER', r.data)
class RecoverableTemplatePathTests(SecurityTest):
AUTH_CONFIG = {
'SECURITY_RECOVERABLE': True,
'SECURITY_FORGOT_PASSWORD_TEMPLATE': 'custom_security/forgot_password.html',
'SECURITY_RESET_PASSWORD_TEMPLATE': 'custom_security/reset_password.html',
}
def test_forgot_password_template(self):
r = self._get('/reset')
self.assertIn('CUSTOM FORGOT PASSWORD', r.data)
def test_reset_password_template(self):
with capture_reset_password_requests() as requests:
r = self.client.post('/reset',
data=dict(email='joe@lp.com'),
follow_redirects=True)
t = requests[0]['token']
r = self._get('/reset/' + t)
self.assertIn('CUSTOM RESET PASSWORD', r.data)
class ConfirmableTemplatePathTests(SecurityTest):
AUTH_CONFIG = {
'SECURITY_CONFIRMABLE': True,
'SECURITY_SEND_CONFIRMATION_TEMPLATE': 'custom_security/send_confirmation.html'
}
def test_send_confirmation_template(self):
r = self._get('/confirm')
self.assertIn('CUSTOM SEND CONFIRMATION', r.data)
class PasswordlessTemplatePathTests(SecurityTest):
AUTH_CONFIG = {
'SECURITY_PASSWORDLESS': True,
'SECURITY_SEND_LOGIN_TEMPLATE': 'custom_security/send_login.html'
}
def test_send_login_template(self):
r = self._get('/login')
self.assertIn('CUSTOM SEND LOGIN', r.data)
class RegisterableTests(SecurityTest):
AUTH_CONFIG = {
'SECURITY_REGISTERABLE': True,
@@ -0,0 +1 @@
CUSTOM FORGOT PASSWORD
@@ -0,0 +1 @@
CUSTOM LOGIN USER
@@ -0,0 +1 @@
CUSTOM REGISTER USER
@@ -0,0 +1 @@
CUSTOM RESET PASSWORD
@@ -0,0 +1 @@
CUSTOM SEND CONFIRMATION
@@ -0,0 +1 @@
CUSTOM SEND LOGIN