Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #1761: feedback for password changing #1824

Merged
merged 1 commit into from
May 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion web/client/components/security/forms/PasswordReset.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ const PasswordReset = React.createClass({

// I18N
newPasswordText: React.PropTypes.node,
passwordCheckText: React.PropTypes.node
passwordCheckText: React.PropTypes.node,
changed: React.PropTypes.bool,
error: React.PropTypes.object
},
contextTypes: {
messages: React.PropTypes.object
Expand Down Expand Up @@ -69,6 +71,15 @@ const PasswordReset = React.createClass({
}
return null;
},
renderStatus() {
if (this.props.changed) {
return <Alert bsStyle="success"><Message msgId="user.passwordChanged"/></Alert>;
}
if (this.props.error) {
return <Alert bsStyle="danger"><Message msgId="user.passwordError"/></Alert>;
}
return null;
},
render() {
return (<form ref="loginForm" onSubmit={this.handleSubmit}>
<FormGroup validationState={this.getPwStyle()}>
Expand All @@ -91,6 +102,7 @@ const PasswordReset = React.createClass({
placeholder={LocaleUtils.getMessageById(this.context.messages, "user.retypePwd")} />
</FormGroup>
{this.renderWarning()}
{this.renderStatus()}
</form>);
},
isValid(password, passwordcheck) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@ describe("Test the password reset form component", () => {
expect(cmp).toExist();
});

it('alert for success', () => {
const cmp = ReactDOM.render(<PasswordReset changed={true}/>, document.getElementById("container"));
expect(cmp).toExist();
let alert = ReactDOM.findDOMNode(ReactTestUtils.scryRenderedDOMComponentsWithClass(cmp, "alert-success")[0]);
expect(alert).toExist();
});

it('alert for error', () => {
const cmp = ReactDOM.render(<PasswordReset error={{message: 'error'}}/>, document.getElementById("container"));
expect(cmp).toExist();
let alert = ReactDOM.findDOMNode(ReactTestUtils.scryRenderedDOMComponentsWithClass(cmp, "alert-danger")[0]);
expect(alert).toExist();
});

it('test component validity', () => {
const cmp = ReactDOM.render(<PasswordReset />, document.getElementById("container"));
expect(cmp).toExist();
Expand Down
5 changes: 4 additions & 1 deletion web/client/components/security/modals/PasswordResetModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ const PasswordResetModal = React.createClass({
closeGlyph: React.PropTypes.string,
style: React.PropTypes.object,
buttonSize: React.PropTypes.string,
includeCloseButton: React.PropTypes.bool
includeCloseButton: React.PropTypes.bool,
changed: React.PropTypes.bool,
error: React.PropTypes.object
},
getDefaultProps() {
return {
Expand Down Expand Up @@ -92,6 +94,7 @@ const PasswordResetModal = React.createClass({
},
getBody() {
return (<PasswordReset role="body" ref="passwordResetForm"
changed={this.props.changed}
onChange={(password, valid) => {
this.setState({passwordValid: valid, password});
}} />);
Expand Down
4 changes: 3 additions & 1 deletion web/client/plugins/login/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ const UserDetails = connect((state) => ({

const PasswordReset = connect((state) => ({
user: state.security && state.security.user,
show: state.controls.ResetPassword && state.controls.ResetPassword.enabled
show: state.controls.ResetPassword && state.controls.ResetPassword.enabled,
changed: state.security && state.security.passwordChanged && true || false,
error: state.security && state.security.passwordError
}), {
onPasswordChange: (user, pass) => { return geoStoreChangePassword(user, pass); },
onClose: setControlProperty.bind(null, "ResetPassword", "enabled", false, false)
Expand Down
18 changes: 17 additions & 1 deletion web/client/reducers/__tests__/security-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/
var expect = require('expect');
var security = require('../security');
var {LOGIN_SUCCESS, LOGIN_FAIL, RESET_ERROR, LOGOUT} = require('../../actions/security');
var {LOGIN_SUCCESS, LOGIN_FAIL, RESET_ERROR, LOGOUT, CHANGE_PASSWORD_SUCCESS, CHANGE_PASSWORD_FAIL} = require('../../actions/security');
var {USERMANAGER_UPDATE_USER} = require('../../actions/users');

describe('Test the security reducer', () => {
Expand Down Expand Up @@ -87,4 +87,20 @@ describe('Test the security reducer', () => {
expect(state).toExist();
expect(state.user.name).toBe("user");
});

it('change password success', () => {
let state = security({user: testUser.User}, {type: CHANGE_PASSWORD_SUCCESS, user: {
id: 6,
password: "newpassword"
}});
expect(state).toExist();
expect(state.user.password).toBe("newpassword");
expect(state.passwordChanged).toBe(true);
});

it('change password fail', () => {
let state = security({user: testUser.User}, {type: CHANGE_PASSWORD_FAIL, error: {message: 'error'}});
expect(state).toExist();
expect(state.passwordError).toExist();
});
});
20 changes: 18 additions & 2 deletions web/client/reducers/security.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
* LICENSE file in the root directory of this source tree.
*/

const { LOGIN_SUCCESS, LOGIN_FAIL, LOGOUT, CHANGE_PASSWORD_SUCCESS, RESET_ERROR } = require('../actions/security');
const { LOGIN_SUCCESS, LOGIN_FAIL, LOGOUT, CHANGE_PASSWORD_SUCCESS, CHANGE_PASSWORD_FAIL, RESET_ERROR } = require('../actions/security');
const { SET_CONTROL_PROPERTY } = require('../actions/controls');
const { USERMANAGER_UPDATE_USER } = require('../actions/users');

const SecurityUtils = require('../utils/SecurityUtils');
Expand All @@ -23,6 +24,14 @@ function security(state = {user: null, errorCause: null}, action) {
});
}
return state;
case SET_CONTROL_PROPERTY:
if (action.control === 'ResetPassword' && action.property === 'enabled') {
return assign({}, state, {
passwordChanged: false,
passwordError: null
});
}
return state;
case LOGIN_SUCCESS:
const userAttributes = SecurityUtils.getUserAttributes(action.userDetails.User);
const userUuid = head(userAttributes.filter(attribute => attribute.name.toLowerCase() === 'uuid'));
Expand Down Expand Up @@ -50,7 +59,14 @@ function security(state = {user: null, errorCause: null}, action) {
case CHANGE_PASSWORD_SUCCESS:
return assign({}, state, {
user: assign({}, state.user, assign({}, action.user, {date: new Date().getUTCMilliseconds()})),
authHeader: action.authHeader
authHeader: action.authHeader,
passwordChanged: true,
passwordError: null
});
case CHANGE_PASSWORD_FAIL:
return assign({}, state, {
passwordError: action.error,
passwordChanged: false
});
default:
return state;
Expand Down
2 changes: 2 additions & 0 deletions web/client/translations/data.de-DE
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,8 @@
"passwordCheckFail": "Passwörter sind nicht identisch!",
"username": "Benutzername",
"password": "Passwort",
"passwordChanged": "Passwort geändert",
"passwordError": "Fehler beim Ändern des Passworts",
"signIn":"Anmelden",
"loginFail":"Anmeldung gescheitert",
"loginFailedStatusMessages": {
Expand Down
2 changes: 2 additions & 0 deletions web/client/translations/data.en-US
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,8 @@
"passwordCheckFail": "Passwords do not match!",
"username": "Username",
"password": "Password",
"passwordChanged": "Password changed",
"passwordError": "Error changing password",
"signIn":"Sign-in",
"loginFail":"Login Fail",
"loginFailedStatusMessages": {
Expand Down
2 changes: 2 additions & 0 deletions web/client/translations/data.fr-FR
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,8 @@
"passwordCheckFail": "Les deux mots de passe ne correspondent pas!",
"username": "Nom d'utilisateur",
"password": "Mot de passe",
"passwordChanged": "Mot de passe changé",
"passwordError": "Erreur de changement de mot de passe",
"signIn":"S'authentifier",
"loginFail":"Erreur d'authentification",
"loginFailedStatusMessages": {
Expand Down
2 changes: 2 additions & 0 deletions web/client/translations/data.it-IT
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,8 @@
"passwordCheckFail": "Le due password non corrispondono",
"username": "Username",
"password": "Password",
"passwordChanged": "La password è stata cambiata",
"passwordError": "Errore nel cambio della password",
"signIn":"Accedi",
"loginFail":"Login Fallito",
"loginFailedStatusMessages": {
Expand Down