diff options
author | Stas Vilchik <vilchiks@gmail.com> | 2016-01-26 15:46:59 +0100 |
---|---|---|
committer | Stas Vilchik <vilchiks@gmail.com> | 2016-01-28 16:14:24 +0100 |
commit | f87501399cd3a6ad2970606521daa2867313bfff (patch) | |
tree | 7a13155db2c44eaa579c0ed5cd15f2dfc1cfcac2 | |
parent | de0b07fffd01cc2552c9a4a50ebbc994fb684400 (diff) | |
download | sonarqube-f87501399cd3a6ad2970606521daa2867313bfff.tar.gz sonarqube-f87501399cd3a6ad2970606521daa2867313bfff.zip |
SONAR-7231 Create new "Security" page in "My Space"
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 |