From 53257c17a9ee248b12d86c821d457edcccf72007 Mon Sep 17 00:00:00 2001 From: Matt Wright Date: Wed, 22 Aug 2012 15:15:39 -0400 Subject: [PATCH] Update `send_mail` api and add welcome email for user registration. Also add security state to template context for emails for more complex template rendering. --- flask_security/confirmable.py | 15 ++++++++++----- flask_security/passwordless.py | 6 +----- flask_security/recoverable.py | 11 ++++------- .../security/email/confirmation_instructions.html | 4 +--- .../security/email/confirmation_instructions.txt | 4 +--- .../templates/security/email/welcome.html | 7 +++++++ .../templates/security/email/welcome.txt | 7 +++++++ flask_security/utils.py | 4 ++-- flask_security/views.py | 13 ++++++++----- tests/functional_tests.py | 1 - 10 files changed, 41 insertions(+), 31 deletions(-) create mode 100644 flask_security/templates/security/email/welcome.html create mode 100644 flask_security/templates/security/email/welcome.txt diff --git a/flask_security/confirmable.py b/flask_security/confirmable.py index 692c99c..6ed24cc 100644 --- a/flask_security/confirmable.py +++ b/flask_security/confirmable.py @@ -26,19 +26,24 @@ _security = LocalProxy(lambda: app.extensions['security']) _datastore = LocalProxy(lambda: _security.datastore) +def generate_confirmation_link(user): + token = generate_confirmation_token(user) + url = url_for_security('confirm_email', token=token) + return request.url_root[:-1] + url, token + + def send_confirmation_instructions(user): """Sends the confirmation instructions email for the specified user. :param user: The user to send the instructions to :param token: The confirmation token """ - token = generate_confirmation_token(user) - url = url_for_security('confirm_email', token=token) - confirmation_link = request.url_root[:-1] + url - ctx = dict(user=user, confirmation_link=confirmation_link) + + confirmation_link, token = generate_confirmation_link(user) send_mail('Please confirm your email', user.email, - 'confirmation_instructions', ctx) + 'confirmation_instructions', + user=user, confirmation_link=confirmation_link) confirm_instructions_sent.send(user, app=app._get_current_object()) return token diff --git a/flask_security/passwordless.py b/flask_security/passwordless.py index 49394a4..eb0d22b 100644 --- a/flask_security/passwordless.py +++ b/flask_security/passwordless.py @@ -32,15 +32,11 @@ def send_login_instructions(user, next): :param token: The login token """ token = generate_login_token(user, next) - url = url_for_security('token_login', token=token) - login_link = request.url_root[:-1] + url - ctx = dict(user=user, login_link=login_link) - send_mail('Login Instructions', user.email, - 'login_instructions', ctx) + 'login_instructions', user=user, login_link=login_link) login_instructions_sent.send(dict(user=user, login_token=token), app=app._get_current_object()) diff --git a/flask_security/recoverable.py b/flask_security/recoverable.py index a038f46..7dce717 100644 --- a/flask_security/recoverable.py +++ b/flask_security/recoverable.py @@ -34,10 +34,9 @@ def send_reset_password_instructions(user): url = url_for_security('reset_password', token=token) reset_link = request.url_root[:-1] + url - send_mail('Password reset instructions', - user.email, + send_mail('Password reset instructions', user.email, 'reset_instructions', - dict(user=user, reset_link=reset_link)) + user=user, reset_link=reset_link) reset_password_instructions_sent.send(dict(user=user, token=token), app=app._get_current_object()) @@ -48,10 +47,8 @@ def send_password_reset_notice(user): :param user: The user to send the notice to """ - send_mail('Your password has been reset', - user.email, - 'reset_notice', - dict(user=user)) + send_mail('Your password has been reset', user.email, + 'reset_notice', user=user) def generate_reset_password_token(user): diff --git a/flask_security/templates/security/email/confirmation_instructions.html b/flask_security/templates/security/email/confirmation_instructions.html index 92badd0..5082a9a 100644 --- a/flask_security/templates/security/email/confirmation_instructions.html +++ b/flask_security/templates/security/email/confirmation_instructions.html @@ -1,5 +1,3 @@ -

Welcome {{ user.email }}!

- -

You can confirm your email through the link below:

+

Please confirm your email through the link below:

Confirm my account

\ No newline at end of file diff --git a/flask_security/templates/security/email/confirmation_instructions.txt b/flask_security/templates/security/email/confirmation_instructions.txt index e6a4a3a..fb435b5 100644 --- a/flask_security/templates/security/email/confirmation_instructions.txt +++ b/flask_security/templates/security/email/confirmation_instructions.txt @@ -1,5 +1,3 @@ -Welcome {{ user.email }}! - -You can confirm your email through the link below: +Please confirm your email through the link below: {{ confirmation_link }} \ No newline at end of file diff --git a/flask_security/templates/security/email/welcome.html b/flask_security/templates/security/email/welcome.html new file mode 100644 index 0000000..55eaed6 --- /dev/null +++ b/flask_security/templates/security/email/welcome.html @@ -0,0 +1,7 @@ +

Welcome {{ user.email }}!

+ +{% if security.confirmable %} +

You can confirm your email through the link below:

+ +

Confirm my account

+{% endif %} \ No newline at end of file diff --git a/flask_security/templates/security/email/welcome.txt b/flask_security/templates/security/email/welcome.txt new file mode 100644 index 0000000..fb6ee5b --- /dev/null +++ b/flask_security/templates/security/email/welcome.txt @@ -0,0 +1,7 @@ +Welcome {{ user.email }}! + +{% if security.confirmable %} +You can confirm your email through the link below: + +{{ confirmation_link }} +{% endif %} \ No newline at end of file diff --git a/flask_security/utils.py b/flask_security/utils.py index eb95c50..2256fbb 100644 --- a/flask_security/utils.py +++ b/flask_security/utils.py @@ -230,7 +230,7 @@ def get_within_delta(key, app=None): return timedelta(**{values[1]: int(values[0])}) -def send_mail(subject, recipient, template, context=None): +def send_mail(subject, recipient, template, **context): """Send an email via the Flask-Mail extension. :param subject: Email subject @@ -241,7 +241,7 @@ def send_mail(subject, recipient, template, context=None): from flask.ext.mail import Message mail = current_app.extensions.get('mail') - context = context or {} + context.setdefault('security', _security) msg = Message(subject, sender=_security.email_sender, diff --git a/flask_security/views.py b/flask_security/views.py index 37d8309..ed9b126 100644 --- a/flask_security/views.py +++ b/flask_security/views.py @@ -14,8 +14,8 @@ from flask import current_app as app, redirect, request, \ from werkzeug.datastructures import MultiDict from werkzeug.local import LocalProxy -from flask_security.confirmable import confirm_by_token, \ - send_confirmation_instructions, requires_confirmation +from flask_security.confirmable import generate_confirmation_link, \ + send_confirmation_instructions, requires_confirmation, confirm_by_token from flask_security.decorators import login_required from flask_security.exceptions import ConfirmationError, ResetPasswordError, \ PasswordlessLoginError @@ -26,7 +26,7 @@ from flask_security.recoverable import reset_by_token, \ send_reset_password_instructions from flask_security.signals import user_registered from flask_security.utils import get_url, get_post_login_redirect, do_flash, \ - get_message, config_value, login_user, logout_user, \ + get_message, config_value, login_user, logout_user, send_mail, \ anonymous_user_required, url_for_security as url_for, verify_password @@ -142,17 +142,20 @@ def register(): register_user_form=form, **_ctx('register')) - token = None + confirmation_link, token = None, None user = _datastore.create_user(**form.to_dict()) _commit() if _security.confirmable: - token = send_confirmation_instructions(user) + confirmation_link, token = generate_confirmation_link(user) do_flash(*get_message('CONFIRM_REGISTRATION', email=user.email)) user_registered.send(dict(user=user, confirm_token=token), app=app._get_current_object()) + send_mail('Welcome', user.email, 'welcome', + user=user, confirmation_link=confirmation_link) + _logger.debug('User %s registered' % user) if not _security.confirmable or _security.login_without_confirmation: diff --git a/tests/functional_tests.py b/tests/functional_tests.py index 70f055a..902c692 100644 --- a/tests/functional_tests.py +++ b/tests/functional_tests.py @@ -362,7 +362,6 @@ class ExpiredConfirmationTest(SecurityTest): r = self.client.get('/confirm/' + token, follow_redirects=True) self.assertEqual(len(outbox), 1) - self.assertIn(e, outbox[0].html) self.assertNotIn(token, outbox[0].html) expire_text = self.AUTH_CONFIG['SECURITY_CONFIRM_EMAIL_WITHIN']