Add ability to define a send_mail_task which could be used to send mails instead of the default flask-mail plugin. Could also be used to send mail asynchronously. Make flask-mail required as well.

This commit is contained in:
Matt Wright
2012-08-23 13:01:11 -04:00
parent 1af774dcb7
commit b0b09aea49
4 changed files with 35 additions and 7 deletions
+8 -5
View File
@@ -210,6 +210,7 @@ class _SecurityState(object):
def __init__(self, **kwargs):
for key, value in kwargs.items():
setattr(self, key.lower(), value)
self._send_mail_task = None
def _add_ctx_processor(self, endpoint, fn):
c = self.context_processors
@@ -256,6 +257,9 @@ class _SecurityState(object):
def mail_context_processor(self, fn):
self._add_ctx_processor('mail', fn)
def send_mail_task(self, fn):
self._send_mail_task = fn
class Security(object):
"""The :class:`Security` class initializes the Flask-Security extension.
@@ -270,7 +274,7 @@ class Security(object):
if app is not None and datastore is not None:
self._state = self.init_app(app, datastore, **kwargs)
def init_app(self, app, datastore=None, register_blueprint=True):
def init_app(self, app, datastore=None, register_blueprint=True, **kwargs):
"""Initializes the Flask-Security extension for the specified
application and datastore implentation.
@@ -295,7 +299,7 @@ class Security(object):
template_folder='templates')
app.register_blueprint(bp)
state = self._get_state(app, datastore)
state = self._get_state(app, datastore, **kwargs)
app.extensions['security'] = state
@@ -304,12 +308,10 @@ class Security(object):
return state
def _get_state(self, app, datastore):
def _get_state(self, app, datastore, **kwargs):
assert app is not None
assert datastore is not None
kwargs = {}
for key, value in get_config(app).items():
kwargs[key.lower()] = value
@@ -329,6 +331,7 @@ class Security(object):
_get_reset_serializer(app) if kwargs['recoverable'] else None)
kwargs['confirm_serializer'] = (
_get_confirm_serializer(app) if kwargs['confirmable'] else None)
return _SecurityState(**kwargs)
def __getattr__(self, name):
+7 -2
View File
@@ -20,6 +20,7 @@ from flask import url_for, flash, current_app, request, session, redirect, \
render_template
from flask.ext.login import login_user as _login_user, \
logout_user as _logout_user
from flask.ext.mail import Message
from flask.ext.principal import Identity, AnonymousIdentity, identity_changed
from werkzeug.local import LocalProxy
@@ -238,9 +239,7 @@ def send_mail(subject, recipient, template, **context):
:param template: The name of the email template
:param context: The context to render the template with
"""
from flask.ext.mail import Message
mail = current_app.extensions.get('mail')
context.setdefault('security', _security)
context.update(_security._run_ctx_processor('mail'))
@@ -251,6 +250,12 @@ def send_mail(subject, recipient, template, **context):
ctx = ('security/email', template)
msg.body = render_template('%s/%s.txt' % ctx, **context)
msg.html = render_template('%s/%s.html' % ctx, **context)
if _security._send_mail_task:
_security._send_mail_task(msg)
return
mail = current_app.extensions.get('mail')
mail.send(msg)
+1
View File
@@ -36,6 +36,7 @@ setup(
install_requires=[
'Flask>=0.9',
'Flask-Login>=0.1.3',
'Flask-Mail>=0.6.1',
'Flask-Principal>=0.3',
'Flask-WTF>=0.5.4',
'itsdangerous>=0.15',
+19
View File
@@ -590,3 +590,22 @@ class MongoEngineDatastoreTests(DefaultDatastoreTests):
def _create_app(self, auth_config):
from tests.test_app.mongoengine import create_app
return create_app(auth_config)
class AsyncMailTaskTests(SecurityTest):
AUTH_CONFIG = {
'SECURITY_RECOVERABLE': True,
}
def setUp(self):
super(AsyncMailTaskTests, self).setUp()
self.mail_sent = False
def test_send_email_task_is_called(self):
@self.app.security.send_mail_task
def send_email(msg):
self.mail_sent = True
self.client.post('/reset', data=dict(email='joe@lp.com'))
self.assertTrue(self.mail_sent)