diff --git a/example/app.py b/example/app.py index 985a3c6..6ef31b2 100644 --- a/example/app.py +++ b/example/app.py @@ -19,6 +19,7 @@ from flask.ext.security.datastore import SQLAlchemyUserDatastore, \ from flask.ext.security.decorators import http_auth_required, \ auth_token_required from flask.ext.security.exceptions import RoleNotFoundError +from flask.ext.security.utils import encrypt_password def create_roles(): @@ -34,7 +35,7 @@ def create_users(): ('jill@lp.com', 'password', ['author'], True), ('tiya@lp.com', 'password', [], False)): current_app.security.datastore.create_user( - email=u[0], password=u[1], roles=u[2], active=u[3]) + email=u[0], password=encrypt_password(u[1]), roles=u[2], active=u[3]) current_app.security.datastore._commit() diff --git a/flask_security/core.py b/flask_security/core.py index dbb6f3e..d850f17 100644 --- a/flask_security/core.py +++ b/flask_security/core.py @@ -75,6 +75,7 @@ _default_messages = { 'EMAIL_CONFIRMED': ('Thank you. Your email has been confirmed.', 'success'), 'ALREADY_CONFIRMED': ('Your email has already been confirmed.', 'info'), 'INVALID_CONFIRMATION_TOKEN': ('Invalid confirmation token.', 'error'), + 'ALREADY_CONFIRMED': ('This email has already been confirmed', 'info'), 'PASSWORD_RESET_REQUEST': ('Instructions to reset your password have been sent to %(email)s.', 'info'), 'PASSWORD_RESET_EXPIRED': ('You did not reset your password within %(within)s. New instructions have been sent to %(email)s.', 'error'), 'INVALID_RESET_PASSWORD_TOKEN': ('Invalid reset password token.', 'error'), @@ -273,6 +274,7 @@ class Security(object): :param app: The application. :param datastore: An instance of a user datastore. """ + datastore = datastore or self.datastore for key, value in _default_config.items(): app.config.setdefault('SECURITY_' + key, value) @@ -290,7 +292,7 @@ class Security(object): template_folder='templates') app.register_blueprint(bp) - state = self._get_state(app, datastore or self.datastore) + state = self._get_state(app, datastore) app.extensions['security'] = state diff --git a/flask_security/datastore.py b/flask_security/datastore.py index 6cf4ede..06aa014 100644 --- a/flask_security/datastore.py +++ b/flask_security/datastore.py @@ -28,6 +28,9 @@ class UserDatastore(object): :param user_model: A user model class definition :param role_model: A role model class definition """ + pwd_context = None + default_roles = [] + def __init__(self, db, user_model, role_model): self.db = db self.user_model = user_model @@ -82,7 +85,6 @@ class UserDatastore(object): def _prepare_create_user_args(self, **kwargs): kwargs.setdefault('active', True) - kwargs.setdefault('roles', _security.default_roles) roles = kwargs.get('roles', []) for i, role in enumerate(roles): @@ -91,12 +93,6 @@ class UserDatastore(object): roles[i] = self.find_role(rn) kwargs['roles'] = roles - pwd_context = _security.pwd_context - pw = kwargs['password'] - - if not pwd_context.identify(pw): - pwd_hash = utils.encrypt_password(pw) - kwargs['password'] = pwd_hash return kwargs diff --git a/flask_security/forms.py b/flask_security/forms.py index 1c46c48..0784d13 100644 --- a/flask_security/forms.py +++ b/flask_security/forms.py @@ -129,7 +129,8 @@ class RegisterForm(Form, submit = SubmitField("Register") def to_dict(self): - return dict(email=self.email.data, password=self.password.data) + return dict(email=self.email.data, + password=self.password.data) class ResetPasswordForm(Form, diff --git a/flask_security/views.py b/flask_security/views.py index 20f429c..9aa6270 100644 --- a/flask_security/views.py +++ b/flask_security/views.py @@ -204,9 +204,13 @@ def send_confirmation(): if form.validate_on_submit(): user = _datastore.find_user(**form.to_dict()) - send_confirmation_instructions(user) - _logger.debug('%s request confirmation instructions' % user) - do_flash(*get_message('CONFIRMATION_REQUEST', email=user.email)) + if user.confirmed_at is None: + send_confirmation_instructions(user) + msg = get_message('CONFIRMATION_REQUEST', email=user.email) + _logger.debug('%s request confirmation instructions' % user) + else: + msg = get_message('ALREADY_CONFIRMED') + do_flash(*msg) return render_template('security/send_confirmation.html', reset_confirmation_form=form, diff --git a/tests/functional_tests.py b/tests/functional_tests.py index e812070..75a07cf 100644 --- a/tests/functional_tests.py +++ b/tests/functional_tests.py @@ -287,6 +287,18 @@ class ConfirmableTests(SecurityTest): r = self.authenticate(email=e) self.assertIn(self.get_message('CONFIRMATION_REQUIRED'), r.data) + def test_send_confirmation_of_already_confirmed_account(self): + e = 'dude@lp.com' + + with capture_registrations() as registrations: + self.register(e) + token = registrations[0]['confirm_token'] + + self.client.get('/confirm/' + token, follow_redirects=True) + self.logout() + r = self.client.post('/confirm', data=dict(email=e)) + self.assertIn(self.get_message('ALREADY_CONFIRMED'), r.data) + def test_register_sends_confirmation_email(self): e = 'dude@lp.com' with self.app.mail.record_messages() as outbox: