mirror of
https://github.com/wassname/flask-security.git
synced 2026-07-16 01:20:15 +08:00
Working on change password form
This commit is contained in:
@@ -97,7 +97,8 @@ _default_messages = {
|
||||
'DISABLED_ACCOUNT': ('Account is disabled.', 'error'),
|
||||
'PASSWORDLESS_LOGIN_SUCCESSFUL': ('You have successfuly logged in.', 'success'),
|
||||
'PASSWORD_RESET': ('You successfully reset your password and you have been logged in automatically.', 'success'),
|
||||
'PASSWORD_CHANGE': ('You successfully changes your password.', 'success'),
|
||||
'PASSWORD_CHANGE': ('You successfully changed your password.', 'success'),
|
||||
'INVALID_PASSWORD': ('Invalid password', 'error'),
|
||||
'LOGIN': ('Please log in to access this page.', 'info'),
|
||||
'REFRESH': ('Please reauthenticate to access this page.', 'info')
|
||||
}
|
||||
@@ -294,6 +295,9 @@ class _SecurityState(object):
|
||||
def reset_password_context_processor(self, fn):
|
||||
self._add_ctx_processor('reset_password', fn)
|
||||
|
||||
def change_password_context_processor(self, fn):
|
||||
self._add_ctx_processor('change_password', fn)
|
||||
|
||||
def send_confirmation_context_processor(self, fn):
|
||||
self._add_ctx_processor('send_confirmation', fn)
|
||||
|
||||
@@ -323,8 +327,8 @@ class Security(object):
|
||||
def init_app(self, app, datastore=None, register_blueprint=True,
|
||||
login_form=None, confirm_register_form=None,
|
||||
register_form=None, forgot_password_form=None,
|
||||
reset_password_form=None, send_confirmation_form=None,
|
||||
passwordless_login_form=None):
|
||||
reset_password_form=None, change_password_form=None,
|
||||
send_confirmation_form=None, passwordless_login_form=None):
|
||||
"""Initializes the Flask-Security extension for the specified
|
||||
application and datastore implentation.
|
||||
|
||||
@@ -348,6 +352,7 @@ class Security(object):
|
||||
register_form=register_form,
|
||||
forgot_password_form=forgot_password_form,
|
||||
reset_password_form=reset_password_form,
|
||||
change_password_form=change_password_form,
|
||||
send_confirmation_form=send_confirmation_form,
|
||||
passwordless_login_form=passwordless_login_form)
|
||||
|
||||
|
||||
+21
-4
@@ -15,10 +15,11 @@ from flask import request, current_app
|
||||
from flask.ext.wtf import Form as BaseForm, TextField, PasswordField, \
|
||||
SubmitField, HiddenField, Required, BooleanField, EqualTo, Email, \
|
||||
ValidationError, Length, Field
|
||||
from flask.ext.login import current_user
|
||||
from werkzeug.local import LocalProxy
|
||||
|
||||
from .confirmable import requires_confirmation
|
||||
from .utils import verify_and_update_password, get_message
|
||||
from .utils import verify_password, verify_and_update_password, get_message
|
||||
|
||||
# Convenient reference
|
||||
_datastore = LocalProxy(lambda: current_app.extensions['security'].datastore)
|
||||
@@ -83,6 +84,7 @@ class NewPasswordFormMixin():
|
||||
validators=[password_required,
|
||||
Length(min=6, max=128)])
|
||||
|
||||
|
||||
class PasswordConfirmFormMixin():
|
||||
password_confirm = PasswordField("Retype Password",
|
||||
validators=[EqualTo('password', message="Passwords do not match")])
|
||||
@@ -97,7 +99,8 @@ class RegisterFormMixin():
|
||||
|
||||
def to_dict(form):
|
||||
def is_field_and_user_attr(member):
|
||||
return isinstance(member, Field) and hasattr(_datastore.user_model, member.name)
|
||||
return isinstance(member, Field) and \
|
||||
hasattr(_datastore.user_model, member.name)
|
||||
|
||||
fields = inspect.getmembers(form, is_field_and_user_attr)
|
||||
return dict((key, value.data) for key, value in fields)
|
||||
@@ -172,7 +175,7 @@ class LoginForm(Form, NextFormMixin):
|
||||
self.email.errors.append('Specified user does not exist')
|
||||
return False
|
||||
if not verify_and_update_password(self.password.data, self.user):
|
||||
self.password.errors.append('Invalid password')
|
||||
self.password.errors.append(get_message('INVALID_PASSWORD')[0])
|
||||
return False
|
||||
if requires_confirmation(self.user):
|
||||
self.email.errors.append(get_message('CONFIRMATION_REQUIRED')[0])
|
||||
@@ -197,11 +200,25 @@ class ResetPasswordForm(Form, NewPasswordFormMixin, PasswordConfirmFormMixin):
|
||||
submit = SubmitField("Reset Password")
|
||||
|
||||
|
||||
class ChangePasswordForm(Form, PasswordFormMixin, PasswordConfirmFormMixin):
|
||||
class ChangePasswordForm(Form, PasswordFormMixin):
|
||||
"""The default Change password form"""
|
||||
|
||||
new_password = PasswordField("New Password",
|
||||
validators=[password_required,
|
||||
Length(min=6, max=128)])
|
||||
|
||||
new_password_confirm = PasswordField("Retype Password",
|
||||
validators=[EqualTo('new_password', message="Passwords do not match")])
|
||||
|
||||
submit = SubmitField("Change Password")
|
||||
|
||||
def validate(self):
|
||||
super(ChangePasswordForm, self).validate()
|
||||
|
||||
if self.password.data.strip() == '':
|
||||
self.password.errors.append('Password not provided')
|
||||
return False
|
||||
if not verify_and_update_password(self.password.data, current_user):
|
||||
self.password.errors.append(get_message('INVALID_PASSWORD')[0])
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
{% if security.registerable %}
|
||||
<li><a href="{{ url_for_security('register') }}">Register</a><br/></li>
|
||||
{% endif %}
|
||||
{% if security.changeable %}
|
||||
<li><a href="{{ url_for_security('change_password') }}">Change password</a></li>
|
||||
{% endif %}
|
||||
{% if security.recoverable %}
|
||||
<li><a href="{{ url_for_security('forgot_password') }}">Forgot password</a><br/></li>
|
||||
{% endif %}
|
||||
@@ -12,4 +15,4 @@
|
||||
<li><a href="{{ url_for_security('send_confirmation') }}">Confirm account</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
@@ -278,6 +278,32 @@ def reset_password(token):
|
||||
**_ctx('reset_password'))
|
||||
|
||||
|
||||
@login_required
|
||||
def change_password():
|
||||
"""View function which handles a change password request."""
|
||||
|
||||
form_class = _security.change_password_form
|
||||
|
||||
if request.json:
|
||||
form = form_class(MultiDict(request.json))
|
||||
else:
|
||||
form = form_class()
|
||||
|
||||
if form.validate_on_submit():
|
||||
#send_reset_password_instructions(form.user)
|
||||
print 'VALID'
|
||||
if request.json is None:
|
||||
#do_flash(*get_message('PASSWORD_CHANGE'))
|
||||
do_flash('dicks')
|
||||
|
||||
if request.json:
|
||||
return _render_json(form)
|
||||
|
||||
return render_template('security/change_password.html',
|
||||
change_password_form=form,
|
||||
**_ctx('change_password'))
|
||||
|
||||
|
||||
def create_blueprint(state, import_name):
|
||||
"""Creates the security extension blueprint"""
|
||||
|
||||
@@ -311,6 +337,11 @@ def create_blueprint(state, import_name):
|
||||
methods=['GET', 'POST'],
|
||||
endpoint='reset_password')(reset_password)
|
||||
|
||||
if state.changeable:
|
||||
bp.route(state.change_url,
|
||||
methods=['GET', 'POST'],
|
||||
endpoint='change_password')(change_password)
|
||||
|
||||
if state.confirmable:
|
||||
bp.route(state.confirm_url,
|
||||
methods=['GET', 'POST'],
|
||||
|
||||
@@ -327,12 +327,35 @@ class ChangePasswordTest(SecurityTest):
|
||||
|
||||
def test_change_password(self):
|
||||
self.authenticate()
|
||||
r = self.client.post('/change/' + t, data={
|
||||
r = self.client.get('/change', follow_redirects=True)
|
||||
self.assertIn('Change password', r.data)
|
||||
|
||||
def test_change_password_invalid(self):
|
||||
self.authenticate()
|
||||
r = self.client.post('/change', data={
|
||||
'password': 'notpassword',
|
||||
'new_password': 'newpassword',
|
||||
'new_password_confirm': 'newpassword'
|
||||
}, follow_redirects=True)
|
||||
print r
|
||||
self.assertIn('Invalid password', r.data)
|
||||
|
||||
def test_change_password_mismatch(self):
|
||||
self.authenticate()
|
||||
r = self.client.post('/change', data={
|
||||
'password': 'password',
|
||||
'new_password': 'newpassword',
|
||||
'new_password_confirm': 'notnewpassword'
|
||||
}, follow_redirects=True)
|
||||
self.assertIn('Passwords do not match', r.data)
|
||||
|
||||
def test_change_password_success(self):
|
||||
self.authenticate()
|
||||
r = self.client.post('/change', data={
|
||||
'password': 'password',
|
||||
'new_password': 'newpassword',
|
||||
'new_password_confirm': 'newpassword'
|
||||
}, follow_redirects=True)
|
||||
|
||||
self.assertIn('You successfully changed your password', r.data)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user