From 1a8e6f5cb6dc14b70b3f78e9ccd2b97803fc02a2 Mon Sep 17 00:00:00 2001 From: Matt Wright Date: Fri, 11 May 2012 13:57:35 -0400 Subject: [PATCH] Make datastore find_user method accept different params so a user can be retrieved by other such things such as a confirmation token --- flask_security/confirmable.py | 37 ++++++++++++-------------- flask_security/core.py | 4 +-- flask_security/datastore.py | 16 +++++------ flask_security/templates/login.html | 8 ++++++ flask_security/templates/register.html | 7 +++++ flask_security/utils.py | 15 ++++++++++- 6 files changed, 56 insertions(+), 31 deletions(-) create mode 100644 flask_security/templates/register.html diff --git a/flask_security/confirmable.py b/flask_security/confirmable.py index 5a9cf85..64ea932 100644 --- a/flask_security/confirmable.py +++ b/flask_security/confirmable.py @@ -1,37 +1,34 @@ from datetime import datetime -from flask import render_template, current_app, request, url_for -from flask.ext.security.utils import generate_token +from flask import current_app, request, url_for +from flask.ext.security.exceptions import UserNotFoundError +from flask.ext.security.utils import generate_token, send_mail from werkzeug.local import LocalProxy - +security = LocalProxy(lambda: current_app.security) logger = LocalProxy(lambda: current_app.logger) def send_confirmation_instructions(user): - from flask.ext.mail import Message + url = url_for('flask_security.confirm', + confirmation_token=user.confirmation_token) - msg = Message("Please confirm your email", - sender=current_app.security.email_sender, - recipients=[user.email]) + confirmation_link = request.url_root[:-1] + url - confirmation_link = request.url_root[:-1] + \ - url_for('flask_security.confirm', - confirmation_token=user.confirmation_token) - - ctx = dict(user=user, confirmation_link=confirmation_link) - msg.body = render_template('email/confirmation_instructions.txt', **ctx) - msg.html = render_template('email/confirmation_instructions.html', **ctx) - - logger.debug("Sending confirmation instructions") - logger.debug(msg.html) - - current_app.mail.send(msg) + send_mail('Please confirm your email', user.email, + 'confirmation_instructions', + dict(user=user, confirmation_link=confirmation_link)) def generate_confirmation_token(user): - token = generate_token() + while True: + token = generate_token() + try: + security.datastore.find_user(confirmation_token=token) + except UserNotFoundError: + break + now = datetime.utcnow() if isinstance(user, dict): diff --git a/flask_security/core.py b/flask_security/core.py index 95d55e5..9e1736a 100644 --- a/flask_security/core.py +++ b/flask_security/core.py @@ -337,7 +337,7 @@ class AuthenticationProvider(object): return self.do_authenticate(form.email.data, form.password.data) - def do_authenticate(self, user_identifier, password): + def do_authenticate(self, email, password): """Returns the authenticated user if authentication is successfull. If authentication fails an appropriate error is raised @@ -345,7 +345,7 @@ class AuthenticationProvider(object): :param password: The user's unencrypted password """ try: - user = current_app.security.datastore.find_user(user_identifier) + user = current_app.security.datastore.find_user(email=email) except AttributeError, e: self.auth_error("Could not find user datastore: %s" % e) except exceptions.UserNotFoundError, e: diff --git a/flask_security/datastore.py b/flask_security/datastore.py index 87b6587..1c3d3c6 100644 --- a/flask_security/datastore.py +++ b/flask_security/datastore.py @@ -36,11 +36,11 @@ class UserDatastore(object): raise NotImplementedError( "User datastore does not implement _do_with_id method") - def _do_find_user(self): + def _do_find_user(self, **kwargs): raise NotImplementedError( "User datastore does not implement _do_find_user method") - def _do_find_role(self): + def _do_find_role(self, **kwargs): raise NotImplementedError( "User datastore does not implement _do_find_role method") @@ -86,12 +86,12 @@ class UserDatastore(object): return user raise exceptions.UserIdNotFoundError() - def find_user(self, user): + def find_user(self, **kwargs): """Returns a user based on the specified identifier. :param user: User identifier, usually email address """ - user = self._do_find_user(user) + user = self._do_find_user(**kwargs) if user: return user raise exceptions.UserNotFoundError() @@ -203,8 +203,8 @@ class SQLAlchemyUserDatastore(UserDatastore): def _do_with_id(self, id): return self.user_model.query.get(id) - def _do_find_user(self, user): - return self.user_model.query.filter_by(email=user).first() + def _do_find_user(self, **kwargs): + return self.user_model.query.filter_by(**kwargs).first() def _do_find_role(self, role): return self.role_model.query.filter_by(name=role).first() @@ -248,8 +248,8 @@ class MongoEngineUserDatastore(UserDatastore): except: return None - def _do_find_user(self, user): - return self.user_model.objects(email=user).first() + def _do_find_user(self, **kwargs): + return self.user_model.objects(**kwargs).first() def _do_find_role(self, role): return self.role_model.objects(name=role).first() diff --git a/flask_security/templates/login.html b/flask_security/templates/login.html index e69de29..28d979c 100644 --- a/flask_security/templates/login.html +++ b/flask_security/templates/login.html @@ -0,0 +1,8 @@ +
+ {{ form.hidden_tag() }} + {{ form.email.label }} {{ form.email }}
+ {{ form.password.label }} {{ form.password }}
+ {{ form.remember.label }} {{ form.remember }}
+ {{ form.next }} + {{ form.submit }} +
\ No newline at end of file diff --git a/flask_security/templates/register.html b/flask_security/templates/register.html new file mode 100644 index 0000000..c875955 --- /dev/null +++ b/flask_security/templates/register.html @@ -0,0 +1,7 @@ +
+ {{ form.hidden_tag() }} + {{ form.email.label }} {{ form.email }}
+ {{ form.password.label }} {{ form.password }}
+ {{ form.password_confirm.label }} {{ form.password_confirm }}
+ {{ form.submit }} +
\ No newline at end of file diff --git a/flask_security/utils.py b/flask_security/utils.py index 5a4bd97..ca9ae6b 100644 --- a/flask_security/utils.py +++ b/flask_security/utils.py @@ -14,7 +14,7 @@ import os from importlib import import_module -from flask import url_for, flash, current_app, request, session +from flask import url_for, flash, current_app, request, session, render_template def generate_token(): @@ -63,3 +63,16 @@ def find_redirect(key): def config_value(app, key, default=None): return app.config.get('SECURITY_' + key.upper(), default) + + +def send_mail(subject, recipient, template, context): + from flask.ext.mail import Message + + msg = Message(subject, + sender=current_app.security.email_sender, + recipients=[recipient]) + + msg.body = render_template('email/%s.txt' % template, **context) + msg.html = render_template('email/%s.html' % template, **context) + + current_app.mail.send(msg)