]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7231 improve rendering of password form
authorStas Vilchik <vilchiks@gmail.com>
Wed, 27 Jan 2016 14:00:10 +0000 (15:00 +0100)
committerStas Vilchik <vilchiks@gmail.com>
Thu, 28 Jan 2016 15:14:24 +0000 (16:14 +0100)
it/it-tests/src/test/resources/user/MyAccountPageTest/should_change_password.html
server/sonar-web/src/main/js/api/users.js
server/sonar-web/src/main/js/apps/account/change-password-view.js [deleted file]
server/sonar-web/src/main/js/apps/account/components/Password.js
server/sonar-web/src/main/js/apps/account/components/Security.js
server/sonar-web/src/main/js/apps/account/containers/SecurityContainer.js
server/sonar-web/src/main/js/apps/account/store/reducers.js
server/sonar-web/src/main/js/apps/account/templates/account-change-password.hbs [deleted file]
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 50da6be2ed737dfc24436217c7e48e56036c0b3a..12e4a89af7d42dd75f1035ea5cc1c5e6e9131bc5 100644 (file)
        <td>id=change-password</td>
        <td></td>
 </tr>
-<tr>
-       <td>click</td>
-       <td>id=change-password</td>
-       <td></td>
-</tr>
-<tr>
-       <td>waitForElementPresent</td>
-       <td>id=old_password</td>
-       <td></td>
-</tr>
 <tr>
        <td>type</td>
        <td>id=old_password</td>
 </tr>
 <tr>
        <td>click</td>
-       <td>commit</td>
+       <td>id=change-password</td>
+       <td></td>
+</tr>
+<tr>
+       <td>waitForElementPresent</td>
+       <td>css=.alert-success</td>
        <td></td>
 </tr>
 <tr>
index ec3052731c08457ef5cf762437c9edf20bb8317b..e9fc97df7b9f64aa69b90f0d71a2d81776cc9dd8 100644 (file)
  * 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 (file)
index 8f0cd4b..0000000
+++ /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);
-    });
-  }
-});
index 7da00b1e9f60fa7e1ff23bc194de93287c15fe06..eaf01092dc00339711fb4273ba549d69fb6515c6 100644 (file)
  */
 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 (
         <section>
-          <h2 className="spacer-bottom">Password</h2>
-          <button
-              id="change-password"
-              onClick={this.handleChangePassword.bind(this)}
-              type="submit">
-            Change Password
-          </button>
+          <h2 className="spacer-bottom">
+            {translate('my_profile.password.title')}
+          </h2>
+
+          <form onSubmit={this.handleChangePassword.bind(this)}>
+            {success && (
+                <div className="alert alert-success">
+                  {translate('my_profile.password.changed')}
+                </div>
+            )}
+
+            {errors && errors.map((e, i) => (
+                <div key={i} className="alert alert-danger">{e}</div>
+            ))}
+
+            <div className="modal-field">
+              <label htmlFor="old_password">
+                {translate('my_profile.password.old')}
+                <em className="mandatory">*</em>
+              </label>
+              <input
+                  ref="oldPassword"
+                  autoComplete="off"
+                  id="old_password"
+                  name="old_password"
+                  required={true}
+                  type="password"/>
+            </div>
+            <div className="modal-field">
+              <label htmlFor="password">
+                {translate('my_profile.password.new')}
+                <em className="mandatory">*</em>
+              </label>
+              <input
+                  ref="password"
+                  autoComplete="off"
+                  id="password"
+                  name="password"
+                  required={true}
+                  type="password"/>
+            </div>
+            <div className="modal-field">
+              <label htmlFor="password_confirmation">
+                {translate('my_profile.password.confirm')}
+                <em className="mandatory">*</em>
+              </label>
+              <input
+                  ref="passwordConfirmation"
+                  autoComplete="off"
+                  id="password_confirmation"
+                  name="password_confirmation"
+                  required={true}
+                  type="password"/>
+            </div>
+            <div className="modal-field">
+              <button id="change-password" type="submit">
+                {translate('my_profile.password.submit')}
+              </button>
+            </div>
+          </form>
         </section>
     );
   }
index 684fb74c56bb397357f9080c5fdc4912e77a2b84..9342687405809c6d2666953900e91e6686f6380e 100644 (file)
@@ -31,7 +31,7 @@ export default function Security ({ user }) {
 
         {user.canChangePassword && (
             <div className="column-half">
-              <Password/>
+              <Password user={user}/>
             </div>
         )}
       </div>
index 4fdb31f19bf4bd9f15225cdf4c0b5639cc41a04f..2e6561506f38d9e2a08d00487fcc1428fb74c614 100644 (file)
  * 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 <Security user={user}/>;
+function mapStateToProps (state) {
+  return {
+    user: state.user
+  };
 }
+
+export default connect(mapStateToProps)(Security);
index 23921840d8ba9c4e59fac49cf4ffb3e9a446e803..626a3875ba459555b8c5866c1ed7bc0a923b9ed8 100644 (file)
@@ -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 (file)
index 8cfe6bd..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<form id="pass_form_tag" name="pass_form_tag">
-  <div class="modal-head">
-    <h2>{{t 'my_profile.password.title'}}</h2>
-  </div>
-
-  <div class="modal-body">
-    <div class="js-modal-messages"></div>
-    <div class="modal-field">
-      <label for="old_password">{{t 'my_profile.password.old'}}<em class="mandatory">*</em></label>
-      <input autocomplete="off" id="old_password" name="old_password" required type="password">
-    </div>
-    <div class="modal-field">
-      <label for="password">{{t 'my_profile.password.new'}}<em class="mandatory">*</em></label>
-      <input autocomplete="off" id="password" name="password" required type="password">
-    </div>
-    <div class="modal-field">
-      <label for="password_confirmation">{{t 'my_profile.password.confirm'}}<em class="mandatory">*</em></label>
-      <input autocomplete="off" id="password_confirmation" name="password_confirmation" required type="password">
-    </div>
-  </div>
-
-  <div class="modal-foot">
-    <input name="commit" type="submit" value="{{t 'my_profile.password.submit'}}">
-    <a class="js-modal-close" href="#">{{t 'cancel'}}</a>
-  </div>
-</form>
index 76b0d18e512ac8035fc9bcd1e8e0bd8d8e890799..e46298ecc674d71aef4dcd7f9fee916f1df05886 100644 (file)
@@ -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