Skip to content

Commit

Permalink
v0.6.4: Moved custom params from __init__() to init_app(). Added send…
Browse files Browse the repository at this point in the history
…_reset_password_email().
  • Loading branch information
lingthio committed Jul 28, 2015
1 parent 1bb3aa3 commit 0ba1f5d
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 38 deletions.
1 change: 1 addition & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ Documentation

Revision History
----------------
* v0.6.4 Moved custom params from __init__() to init_app(). Added send_reset_password_email().
* v0.6.3 Fix for Python 3.4 and signals. Added UserMixin.has_role() and @roles_accepted().
* v0.6.2 Added support for invitation-only registrations.
* v0.6.1 Added Chinese (Simplified) and French translations`.
Expand Down
45 changes: 35 additions & 10 deletions flask_user/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
:license: Simplified BSD License, see LICENSE.txt for more details."""

from passlib.context import CryptContext
from flask import Blueprint, current_app
from flask import Blueprint, current_app, url_for
from flask_login import LoginManager, UserMixin as LoginUserMixin, make_secure_token
from flask_user.db_adapters import DBAdapter
from .db_adapters import SQLAlchemyAdapter
Expand All @@ -16,6 +16,7 @@
from . import tokens
from . import translations
from . import views
from . import signals
from .translations import get_translations

# Enable the following: from flask.ext.user import current_user
Expand All @@ -26,7 +27,7 @@
# Enable the following: from flask.ext.user import user_logged_in
from .signals import *

__version__ = '0.6.3'
__version__ = '0.6.4'

def _flask_user_context_processor():
""" Make 'user_manager' available to Jinja2 templates"""
Expand All @@ -35,7 +36,16 @@ def _flask_user_context_processor():
class UserManager(object):
""" This is the Flask-User object that manages the User management process."""

def __init__(self, db_adapter, app=None,
def __init__(self, db_adapter=None, app=None, **kwargs):
""" Create the UserManager object """
self.db_adapter = db_adapter
self.app = app

if db_adapter is not None and app is not None:
self.init_app(app, db_adapter, **kwargs)


def init_app(self, app, db_adapter=None,
# Forms
add_email_form=forms.AddEmailForm,
change_password_form=forms.ChangePasswordForm,
Expand Down Expand Up @@ -73,8 +83,10 @@ def __init__(self, db_adapter, app=None,
token_manager=tokens.TokenManager(),
legacy_check_password_hash=None
):
""" Initialize the UserManager with custom or built-in attributes"""
self.db_adapter = db_adapter
""" Initialize the UserManager object """
self.app = app
if db_adapter is not None:
self.db_adapter = db_adapter
# Forms
self.add_email_form = add_email_form
self.change_password_form = change_password_form
Expand Down Expand Up @@ -112,11 +124,6 @@ def __init__(self, db_adapter, app=None,
self.send_email_function = send_email_function
self.legacy_check_password_hash = legacy_check_password_hash

self.app = app
if app:
self.init_app(app)

def init_app(self, app):
""" Initialize app.user_manager."""
# Bind Flask-USER to app
app.user_manager = self
Expand Down Expand Up @@ -338,6 +345,24 @@ def username_is_available(self, new_username):
# See if new_username is available
return self.find_user_by_username(new_username)==None

def send_reset_password_email(self, email):
# Find user by email
user, user_email = self.find_user_by_email(email)
if user:
# Generate reset password link
token = self.generate_token(int(user.get_id()))
reset_password_link = url_for('user.reset_password', token=token, _external=True)

# Send forgot password email
emails.send_forgot_password_email(user, user_email, reset_password_link)

# Store token
if hasattr(user, 'reset_password_token'):
self.db_adapter.update_object(user, reset_password_token=token)
self.db_adapter.commit()

# Send forgot_password signal
signals.user_forgot_password.send(current_app._get_current_object(), user=user)


class UserMixin(LoginUserMixin):
Expand Down
14 changes: 9 additions & 5 deletions flask_user/emails.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,16 @@ class SendEmailError(Exception):
except smtplib.SMTPAuthenticationError:
raise SendEmailError('SMTP Authentication error: Check your MAIL_USERNAME and MAIL_PASSWORD settings.')

def _get_primary_email(user):
def get_primary_user_email(user):
user_manager = current_app.user_manager
db_adapter = user_manager.db_adapter
if db_adapter.UserEmailClass:
user_email = db_adapter.find_first_object(db_adapter.UserEmailClass,
user_id=int(user.get_id()),
is_primary=True)
return user_email.email if user_email else None
return user_email
else:
return user.email
return user


def send_confirm_email_email(user, user_email, confirm_email_link):
Expand Down Expand Up @@ -113,7 +113,9 @@ def send_password_changed_email(user):
if not user_manager.send_password_changed_email: return

# Retrieve email address from User or UserEmail object
email = _get_primary_email(user)
user_email = get_primary_user_email(user)
assert(user_email)
email = user_email.email
assert(email)

# Render subject, html message and text message
Expand Down Expand Up @@ -152,7 +154,9 @@ def send_username_changed_email(user): # pragma: no cover
if not user_manager.send_username_changed_email: return

# Retrieve email address from User or UserEmail object
email = _get_primary_email(user)
user_email = get_primary_user_email(user)
assert(user_email)
email = user_email.email
assert(email)

# Render subject, html message and text message
Expand Down
35 changes: 13 additions & 22 deletions flask_user/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,13 @@ def confirm_email(token):
flash(_('Invalid confirmation token.'), 'error')
return redirect(url_for('user.login'))

# Confirm email by setting User.active=True and User.confirmed_at=utcnow()
# Confirm email by setting User.confirmed_at=utcnow() or UserEmail.confirmed_at=utcnow()
user = None
if db_adapter.UserEmailClass:
user_email = user_manager.get_user_email_by_id(object_id)
if user_email:
user_email.confirmed_at = datetime.utcnow()
user = user_email.user
else:
user = None
else:
user_email = None
user = user_manager.get_user_by_id(object_id)
Expand Down Expand Up @@ -192,24 +191,7 @@ def forgot_password():
# Process valid POST
if request.method=='POST' and form.validate():
email = form.email.data

# Find user by email
user, user_email = user_manager.find_user_by_email(email)
if user:
# Generate reset password link
token = user_manager.generate_token(int(user.get_id()))
reset_password_link = url_for('user.reset_password', token=token, _external=True)

# Send forgot password email
emails.send_forgot_password_email(user, user_email, reset_password_link)

# Store token
if hasattr(user, 'reset_password_token'):
db_adapter.update_object(user, reset_password_token=token)
db_adapter.commit()

# Send forgot_password signal
signals.user_forgot_password.send(current_app._get_current_object(), user=user)
user_manager.send_reset_password_email(email)

# Prepare one-time system message
flash(_("A reset password email has been sent to '%(email)s'. Open that email and follow the instructions to reset your password.", email=email), 'success')
Expand Down Expand Up @@ -556,6 +538,9 @@ def reset_password(token):
user_manager = current_app.user_manager
db_adapter = user_manager.db_adapter

if current_user.is_authenticated():
logout_user()

is_valid, has_expired, user_id = user_manager.verify_token(
token,
user_manager.reset_password_expiration)
Expand All @@ -579,6 +564,10 @@ def reset_password(token):
flash(_('Your reset password token is invalid.'), 'error')
return redirect(_endpoint_url(user_manager.login_endpoint))

# Mark email as confirmed
user_email = emails.get_primary_user_email(user)
user_email.confirmed_at = datetime.utcnow()

# Initialize form
form = user_manager.reset_password_form(request.form)

Expand All @@ -599,7 +588,7 @@ def reset_password(token):
emails.send_password_changed_email(user)

# Prepare one-time system message
flash(_("Your password has been reset successfully. Please sign in with your new password"), 'success')
flash(_("Your password has been reset successfully."), 'success')

# Auto-login after reset password or redirect to login page
next = request.args.get('next', _endpoint_url(user_manager.after_reset_password_endpoint))
Expand Down Expand Up @@ -733,3 +722,5 @@ def _endpoint_url(endpoint):
if endpoint:
url = url_for(endpoint)
return url


2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@

setup(
name='Flask-User',
version='0.6.3',
version='0.6.4',
url='http://github.com/lingthio/Flask-User',
license='BSD License',
author='Ling Thio',
Expand Down

0 comments on commit 0ba1f5d

Please sign in to comment.