From 2e164af1b3681e8f44c31c108110a1cd7e3265e1 Mon Sep 17 00:00:00 2001 From: Stas Vilchik Date: Wed, 27 Jan 2016 15:00:10 +0100 Subject: [PATCH] SONAR-7231 improve rendering of password form --- .../should_change_password.html | 17 +-- server/sonar-web/src/main/js/api/users.js | 12 ++ .../js/apps/account/change-password-view.js | 67 ---------- .../js/apps/account/components/Password.js | 116 ++++++++++++++++-- .../js/apps/account/components/Security.js | 2 +- .../account/containers/SecurityContainer.js | 12 +- .../main/js/apps/account/store/reducers.js | 1 + .../templates/account-change-password.hbs | 26 ---- .../resources/org/sonar/l10n/core.properties | 8 +- 9 files changed, 137 insertions(+), 124 deletions(-) delete mode 100644 server/sonar-web/src/main/js/apps/account/change-password-view.js delete mode 100644 server/sonar-web/src/main/js/apps/account/templates/account-change-password.hbs diff --git a/it/it-tests/src/test/resources/user/MyAccountPageTest/should_change_password.html b/it/it-tests/src/test/resources/user/MyAccountPageTest/should_change_password.html index 50da6be2ed7..12e4a89af7d 100644 --- a/it/it-tests/src/test/resources/user/MyAccountPageTest/should_change_password.html +++ b/it/it-tests/src/test/resources/user/MyAccountPageTest/should_change_password.html @@ -44,16 +44,6 @@ id=change-password - - click - id=change-password - - - - waitForElementPresent - id=old_password - - type id=old_password @@ -71,7 +61,12 @@ click - commit + id=change-password + + + + waitForElementPresent + css=.alert-success diff --git a/server/sonar-web/src/main/js/api/users.js b/server/sonar-web/src/main/js/api/users.js index ec3052731c0..e9fc97df7b9 100644 --- a/server/sonar-web/src/main/js/api/users.js +++ b/server/sonar-web/src/main/js/api/users.js @@ -18,8 +18,20 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import $ from 'jquery'; +import { post, postJSON } from '../helpers/request.js'; export function getCurrentUser () { const url = baseUrl + '/api/users/current'; return $.get(url); } + +export function changePassword (login, password, previousPassword) { + const url = window.baseUrl + '/api/users/change_password'; + const data = { login, password }; + + if (previousPassword != null) { + data.previousPassword = previousPassword; + } + + return post(url, data); +} diff --git a/server/sonar-web/src/main/js/apps/account/change-password-view.js b/server/sonar-web/src/main/js/apps/account/change-password-view.js deleted file mode 100644 index 8f0cd4bc13d..00000000000 --- a/server/sonar-web/src/main/js/apps/account/change-password-view.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import $ from 'jquery'; -import ModalForm from '../../components/common/modal-form'; -import Template from './templates/account-change-password.hbs'; -import { translate } from '../../helpers/l10n'; - -export default ModalForm.extend({ - template: Template, - - onFormSubmit: function () { - ModalForm.prototype.onFormSubmit.apply(this, arguments); - if (this.checkPasswords()) { - this.sendRequest(); - } else { - this.showErrors([{ msg: translate('user.password_doesnt_match_confirmation') }]); - } - }, - - checkPasswords: function () { - var p1 = this.$('#password').val(), - p2 = this.$('#password_confirmation').val(); - return p1 === p2; - }, - - sendRequest: function () { - var that = this; - var data = { - login: window.SS.user, - password: this.$('#password').val(), - previousPassword: this.$('#old_password').val() - }; - var opts = { - type: 'POST', - url: baseUrl + '/api/users/change_password', - data: data, - statusCode: { - // do not show global error - 400: null - } - }; - this.disableForm(); - $.ajax(opts).done(function () { - that.destroy(); - }).fail(function (jqXHR) { - that.enableForm(); - that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); - }); - } -}); diff --git a/server/sonar-web/src/main/js/apps/account/components/Password.js b/server/sonar-web/src/main/js/apps/account/components/Password.js index 7da00b1e9f6..eaf01092dc0 100644 --- a/server/sonar-web/src/main/js/apps/account/components/Password.js +++ b/server/sonar-web/src/main/js/apps/account/components/Password.js @@ -19,23 +19,119 @@ */ import React, { Component } from 'react'; -import ChangePasswordView from '../change-password-view'; +import { changePassword } from '../../../api/users'; +import { translate } from '../../../helpers/l10n'; export default class Password extends Component { - handleChangePassword () { - new ChangePasswordView().render(); + state = { + success: false, + errors: null + } + + handleSuccessfulChange () { + this.refs.oldPassword.value = ''; + this.refs.password.value = ''; + this.refs.passwordConfirmation.value = ''; + this.setState({ success: true, errors: null }); + } + + handleFailedChange (e) { + e.response.json().then(r => { + this.refs.oldPassword.focus(); + this.setErrors(r.errors.map(e => e.msg)); + }); + } + + setErrors (errors) { + this.setState({ + success: false, + errors + }); + } + + handleChangePassword (e) { + e.preventDefault(); + + const { user } = this.props; + const oldPassword = this.refs.oldPassword.value; + const password = this.refs.password.value; + const passwordConfirmation = this.refs.passwordConfirmation.value; + + if (password !== passwordConfirmation) { + this.refs.password.focus(); + this.setErrors([translate('user.password_doesnt_match_confirmation')]); + } else { + changePassword(user.login, password, oldPassword) + .then(this.handleSuccessfulChange.bind(this)) + .catch(this.handleFailedChange.bind(this)); + } } render () { + const { success, errors } = this.state; + return (
-

Password

- +

+ {translate('my_profile.password.title')} +

+ +
+ {success && ( +
+ {translate('my_profile.password.changed')} +
+ )} + + {errors && errors.map((e, i) => ( +
{e}
+ ))} + +
+ + +
+
+ + +
+
+ + +
+
+ +
+
); } diff --git a/server/sonar-web/src/main/js/apps/account/components/Security.js b/server/sonar-web/src/main/js/apps/account/components/Security.js index 684fb74c56b..93426874058 100644 --- a/server/sonar-web/src/main/js/apps/account/components/Security.js +++ b/server/sonar-web/src/main/js/apps/account/components/Security.js @@ -31,7 +31,7 @@ export default function Security ({ user }) { {user.canChangePassword && (
- +
)} diff --git a/server/sonar-web/src/main/js/apps/account/containers/SecurityContainer.js b/server/sonar-web/src/main/js/apps/account/containers/SecurityContainer.js index 4fdb31f19bf..2e6561506f3 100644 --- a/server/sonar-web/src/main/js/apps/account/containers/SecurityContainer.js +++ b/server/sonar-web/src/main/js/apps/account/containers/SecurityContainer.js @@ -17,12 +17,14 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import React from 'react'; +import { connect } from 'react-redux'; import Security from './../components/Security'; -export default function SecurityContainer () { - const { user } = window.sonarqube; - - return ; +function mapStateToProps (state) { + return { + user: state.user + }; } + +export default connect(mapStateToProps)(Security); diff --git a/server/sonar-web/src/main/js/apps/account/store/reducers.js b/server/sonar-web/src/main/js/apps/account/store/reducers.js index 23921840d8b..626a3875ba4 100644 --- a/server/sonar-web/src/main/js/apps/account/store/reducers.js +++ b/server/sonar-web/src/main/js/apps/account/store/reducers.js @@ -48,6 +48,7 @@ function removeProjectNotifications (state, project) { } export const initialState = { + user: window.sonarqube.user, projectNotifications: window.sonarqube.notifications.project }; diff --git a/server/sonar-web/src/main/js/apps/account/templates/account-change-password.hbs b/server/sonar-web/src/main/js/apps/account/templates/account-change-password.hbs deleted file mode 100644 index 8cfe6bde02f..00000000000 --- a/server/sonar-web/src/main/js/apps/account/templates/account-change-password.hbs +++ /dev/null @@ -1,26 +0,0 @@ -
- - - - - -
diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 76b0d18e512..e46298ecc67 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -2141,11 +2141,11 @@ my_profile.email=Email my_profile.groups=Groups my_profile.scm_accounts=SCM Accounts my_profile.password.title=Change password -my_profile.password.old=Old value -my_profile.password.new=New value -my_profile.password.confirm=Confirm new value +my_profile.password.old=Old Password +my_profile.password.new=New Password +my_profile.password.confirm=Confirm Password my_profile.password.submit=Change password -my_profile.password.changed=Password changed +my_profile.password.changed=The password has been changed! my_profile.password.empty=Password can not be empty my_profile.password.wrong_old=Wrong old password my_profile.notifications.submit=Save changes -- 2.39.5