aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStas Vilchik <vilchiks@gmail.com>2016-01-26 15:46:59 +0100
committerStas Vilchik <vilchiks@gmail.com>2016-01-28 16:14:24 +0100
commitf87501399cd3a6ad2970606521daa2867313bfff (patch)
tree7a13155db2c44eaa579c0ed5cd15f2dfc1cfcac2
parentde0b07fffd01cc2552c9a4a50ebbc994fb684400 (diff)
downloadsonarqube-f87501399cd3a6ad2970606521daa2867313bfff.tar.gz
sonarqube-f87501399cd3a6ad2970606521daa2867313bfff.zip
SONAR-7231 Create new "Security" page in "My Space"
-rw-r--r--it/it-tests/src/test/java/it/Category1Suite.java4
-rw-r--r--it/it-tests/src/test/java/it/user/MyAccountPageTest.java51
-rw-r--r--it/it-tests/src/test/resources/user/MyAccountPageTest/should_change_password.html110
-rw-r--r--server/sonar-web/src/main/js/apps/account/app.js2
-rw-r--r--server/sonar-web/src/main/js/apps/account/components/Nav.js5
-rw-r--r--server/sonar-web/src/main/js/apps/account/components/Password.js42
-rw-r--r--server/sonar-web/src/main/js/apps/account/components/Security.js39
-rw-r--r--server/sonar-web/src/main/js/apps/account/components/Tokens.js54
-rw-r--r--server/sonar-web/src/main/js/apps/account/containers/SecurityContainer.js28
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/app/views/account/index.html.erb1
-rw-r--r--sonar-core/src/main/resources/org/sonar/l10n/core.properties1
11 files changed, 317 insertions, 20 deletions
diff --git a/it/it-tests/src/test/java/it/Category1Suite.java b/it/it-tests/src/test/java/it/Category1Suite.java
index 16333217c23..5153eb1c298 100644
--- a/it/it-tests/src/test/java/it/Category1Suite.java
+++ b/it/it-tests/src/test/java/it/Category1Suite.java
@@ -65,6 +65,7 @@ import it.settings.PropertySetsTest;
import it.settings.SettingsTest;
import it.settings.SettingsTestRestartingOrchestrator;
import it.settings.SubCategoriesTest;
+import it.user.MyAccountPageTest;
import org.junit.ClassRule;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@@ -110,7 +111,8 @@ import static util.ItUtils.xooPlugin;
TimeMachineTest.class,
// action plan
ActionPlanTest.class,
- ActionPlanUiTest.class
+ ActionPlanUiTest.class,
+ MyAccountPageTest.class
})
public class Category1Suite {
diff --git a/it/it-tests/src/test/java/it/user/MyAccountPageTest.java b/it/it-tests/src/test/java/it/user/MyAccountPageTest.java
index e3425497689..5188171ec23 100644
--- a/it/it-tests/src/test/java/it/user/MyAccountPageTest.java
+++ b/it/it-tests/src/test/java/it/user/MyAccountPageTest.java
@@ -22,26 +22,31 @@ package it.user;
import com.sonar.orchestrator.Orchestrator;
import com.sonar.orchestrator.selenium.Selenese;
import it.Category1Suite;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.sonar.wsclient.SonarClient;
-import org.sonar.wsclient.user.UserParameters;
+import org.junit.*;
+import org.sonarqube.ws.client.PostRequest;
+import org.sonarqube.ws.client.WsClient;
import util.selenium.SeleneseTest;
+import static util.ItUtils.newAdminWsClient;
+
public class MyAccountPageTest {
@ClassRule
public static Orchestrator orchestrator = Category1Suite.ORCHESTRATOR;
+ private static WsClient adminWsClient;
@BeforeClass
- public static void initUser() {
+ public static void setUp() {
+ adminWsClient = newAdminWsClient(orchestrator);
+ }
+
+ @Before
+ public void initUser() {
createUser("account-user", "User With Account", "user@example.com");
}
- @AfterClass
- public static void deleteTestUser() {
+ @After
+ public void deleteTestUser() {
deactivateUser("account-user");
}
@@ -53,19 +58,27 @@ public class MyAccountPageTest {
new SeleneseTest(selenese).runOn(orchestrator);
}
+ @Test
+ public void should_change_password() throws Exception {
+ Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("should_change_password",
+ "/user/MyAccountPageTest/should_change_password.html"
+ ).build();
+ new SeleneseTest(selenese).runOn(orchestrator);
+ }
+
private static void createUser(String login, String name, String email) {
- SonarClient client = orchestrator.getServer().adminWsClient();
- UserParameters userCreationParameters = UserParameters.create()
- .login(login)
- .name(name)
- .email(email)
- .password("password")
- .passwordConfirmation("password");
- client.userClient().create(userCreationParameters);
+ adminWsClient.wsConnector().call(
+ new PostRequest("api/users/create")
+ .setParam("login", login)
+ .setParam("name", name)
+ .setParam("email", email)
+ .setParam("password", "password"));
}
- private static void deactivateUser(String user) {
- orchestrator.getServer().adminWsClient().userClient().deactivate(user);
+ private static void deactivateUser(String login) {
+ adminWsClient.wsConnector().call(
+ new PostRequest("api/users/deactivate")
+ .setParam("login", login));
}
}
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
new file mode 100644
index 00000000000..50da6be2ed7
--- /dev/null
+++ b/it/it-tests/src/test/resources/user/MyAccountPageTest/should_change_password.html
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ <link rel="selenium.base" href="http://localhost:49506"/>
+ <title>should_change_password</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr>
+<td rowspan="1" colspan="3">should_change_password</td>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>open</td>
+ <td>/sonar/sessions/login</td>
+ <td></td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>login</td>
+ <td>account-user</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>password</td>
+ <td>password</td>
+</tr>
+<tr>
+ <td>clickAndWait</td>
+ <td>commit</td>
+ <td></td>
+</tr>
+<tr>
+ <td>open</td>
+ <td>/sonar/account/security</td>
+ <td></td>
+</tr>
+<tr>
+ <td>waitForElementPresent</td>
+ <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>
+ <td>password</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>id=password</td>
+ <td>new_password</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>id=password_confirmation</td>
+ <td>new_password</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>commit</td>
+ <td></td>
+</tr>
+<tr>
+ <td>open</td>
+ <td>/sonar/sessions/logout</td>
+ <td></td>
+</tr>
+<tr>
+ <td>open</td>
+ <td>/sonar/sessions/login</td>
+ <td></td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>login</td>
+ <td>account-user</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>password</td>
+ <td>new_password</td>
+</tr>
+<tr>
+ <td>clickAndWait</td>
+ <td>commit</td>
+ <td></td>
+</tr>
+<tr>
+ <td>waitForText</td>
+ <td>id=global-navigation</td>
+ <td>*User With Account*</td>
+</tr>
+</tbody>
+</table>
+</body>
+</html>
diff --git a/server/sonar-web/src/main/js/apps/account/app.js b/server/sonar-web/src/main/js/apps/account/app.js
index 4a78a6a04fb..fe969e8ad7d 100644
--- a/server/sonar-web/src/main/js/apps/account/app.js
+++ b/server/sonar-web/src/main/js/apps/account/app.js
@@ -27,6 +27,7 @@ import configureStore from './store/configureStore';
import AccountApp from './containers/AccountApp';
import Home from './components/Home';
import NotificationsContainer from './containers/NotificationsContainer';
+import SecurityContainer from './containers/SecurityContainer';
window.sonarqube.appStarted.then(options => {
const el = document.querySelector(options.el);
@@ -46,6 +47,7 @@ window.sonarqube.appStarted.then(options => {
<Route path="/" component={AccountApp}>
<IndexRoute component={Home}/>
<Route path="notifications" component={NotificationsContainer}/>
+ <Route path="security" component={SecurityContainer}/>
<Redirect from="/index" to="/"/>
</Route>
diff --git a/server/sonar-web/src/main/js/apps/account/components/Nav.js b/server/sonar-web/src/main/js/apps/account/components/Nav.js
index e19213d3062..4a49e1f7520 100644
--- a/server/sonar-web/src/main/js/apps/account/components/Nav.js
+++ b/server/sonar-web/src/main/js/apps/account/components/Nav.js
@@ -43,6 +43,11 @@ const Nav = () => (
{translate('my_account.notifications')}
</IndexLink>
</li>
+ <li>
+ <IndexLink to="security" activeClassName="active">
+ {translate('my_account.security')}
+ </IndexLink>
+ </li>
</ul>
</div>
</nav>
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
new file mode 100644
index 00000000000..7da00b1e9f6
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/account/components/Password.js
@@ -0,0 +1,42 @@
+/*
+ * 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 React, { Component } from 'react';
+
+import ChangePasswordView from '../change-password-view';
+
+export default class Password extends Component {
+ handleChangePassword () {
+ new ChangePasswordView().render();
+ }
+
+ render () {
+ return (
+ <section>
+ <h2 className="spacer-bottom">Password</h2>
+ <button
+ id="change-password"
+ onClick={this.handleChangePassword.bind(this)}
+ type="submit">
+ Change Password
+ </button>
+ </section>
+ );
+ }
+}
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
new file mode 100644
index 00000000000..684fb74c56b
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/account/components/Security.js
@@ -0,0 +1,39 @@
+/*
+ * 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 React from 'react';
+
+import Password from './Password';
+import Tokens from './Tokens';
+
+export default function Security ({ user }) {
+ return (
+ <div className="columns">
+ <div className="column-half">
+ <Tokens user={user}/>
+ </div>
+
+ {user.canChangePassword && (
+ <div className="column-half">
+ <Password/>
+ </div>
+ )}
+ </div>
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/account/components/Tokens.js b/server/sonar-web/src/main/js/apps/account/components/Tokens.js
new file mode 100644
index 00000000000..8c3170380ef
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/account/components/Tokens.js
@@ -0,0 +1,54 @@
+/*
+ * 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 Backbone from 'backbone';
+import React, { Component } from 'react';
+
+import TokensView from '../tokens-view';
+
+export default class Tokens extends Component {
+ componentDidMount () {
+ this.renderView();
+ }
+
+ componentWillUnmount () {
+ this.destroyView();
+ }
+
+ renderView () {
+ const account = new Backbone.Model({
+ id: this.props.user.login
+ });
+
+ this.tokensView = new TokensView({
+ el: this.refs.container,
+ model: account
+ }).render();
+ }
+
+ destroyView () {
+ if (this.destroyView) {
+ this.tokensView.destroy();
+ }
+ }
+
+ render () {
+ return <div ref="container"></div>;
+ }
+}
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
new file mode 100644
index 00000000000..4fdb31f19bf
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/account/containers/SecurityContainer.js
@@ -0,0 +1,28 @@
+/*
+ * 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 React from 'react';
+
+import Security from './../components/Security';
+
+export default function SecurityContainer () {
+ const { user } = window.sonarqube;
+
+ return <Security user={user}/>;
+}
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/account/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/account/index.html.erb
index f5a9a100226..8a6209d7daa 100644
--- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/account/index.html.erb
+++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/account/index.html.erb
@@ -4,6 +4,7 @@
login: '<%= escape_javascript current_user.login -%>',
name: '<%= escape_javascript current_user.name -%>',
email: '<%= escape_javascript current_user.email -%>',
+ canChangePassword: <%= User.editable_password? ? 'true' : 'false' -%>,
groups: [
<% current_user.groups.sort.each do |group| -%>
'<%= escape_javascript group.name -%>',
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 fad0339a29d..76b0d18e512 100644
--- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties
+++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
@@ -2161,6 +2161,7 @@ my_account.favorite_issue_filters=Favorite Issue Filters
my_account.favorite_measure_filters=Favorite Measure Filters
my_account.notifications=Notifications
my_account.no_project_notifications=You have not set project notifications yet.
+my_account.security=Security