aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/EmailAlreadyExistsPage.java48
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/Navigation.java5
-rw-r--r--server/sonar-web/scripts/start.js2
-rw-r--r--server/sonar-web/src/main/js/apps/sessions/components/EmailAlreadyExists.tsx138
-rw-r--r--server/sonar-web/src/main/js/apps/sessions/components/SimpleSessionsContainer.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/sessions/components/__tests__/EmailAlreadyExists-test.tsx58
-rw-r--r--server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/EmailAlreadyExists-test.tsx.snap108
-rw-r--r--server/sonar-web/src/main/js/apps/sessions/routes.ts6
-rw-r--r--sonar-core/src/main/resources/org/sonar/l10n/core.properties6
9 files changed, 371 insertions, 2 deletions
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/EmailAlreadyExistsPage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/EmailAlreadyExistsPage.java
new file mode 100644
index 00000000000..2dfdb005d00
--- /dev/null
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/EmailAlreadyExistsPage.java
@@ -0,0 +1,48 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.
+ */
+package org.sonarqube.qa.util.pageobjects;
+
+import static com.codeborne.selenide.Condition.text;
+import static com.codeborne.selenide.Condition.visible;
+import static com.codeborne.selenide.Selenide.$;
+
+public class EmailAlreadyExistsPage extends Navigation {
+
+ public EmailAlreadyExistsPage shouldHaveExistingAccount(String login) {
+ $(".js-existing-account").shouldHave(text(login));
+ return this;
+ }
+
+ public EmailAlreadyExistsPage shouldHaveNewAccount(String login) {
+ $(".js-new-account").shouldHave(text(login));
+ return this;
+ }
+
+ public void clickContinue() {
+ $(".js-continue").click();
+ $(".js-continue").shouldNotBe(visible);
+ }
+
+ public void clickCancel() {
+ $(".js-cancel").click();
+ $(".js-cancel").shouldNotBe(visible);
+ }
+
+}
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/Navigation.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/Navigation.java
index f4e37dce67f..ede43929a06 100644
--- a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/Navigation.java
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/Navigation.java
@@ -258,6 +258,10 @@ public class Navigation {
return Selenide.$("#error");
}
+ public EmailAlreadyExistsPage asEmailAlreadyExistsPage() {
+ return new EmailAlreadyExistsPage();
+ }
+
private static SelenideElement logInLink() {
return Selenide.$(By.linkText("Log in"));
}
@@ -268,6 +272,7 @@ public class Navigation {
/**
* Safe encoding for URL parameters
+ *
* @param parameter the parameter to escape value
* @return the escaped value of parameter
*/
diff --git a/server/sonar-web/scripts/start.js b/server/sonar-web/scripts/start.js
index 21776e5036b..53969869f33 100644
--- a/server/sonar-web/scripts/start.js
+++ b/server/sonar-web/scripts/start.js
@@ -35,7 +35,7 @@ const config = getConfig({ production: false });
const port = process.env.PORT || 3000;
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
const host = process.env.HOST || 'localhost';
-const proxy = 'http://localhost:9000';
+const proxy = process.env.PROXY || 'http://localhost:9000';
const compiler = setupCompiler(host, port, protocol);
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/EmailAlreadyExists.tsx b/server/sonar-web/src/main/js/apps/sessions/components/EmailAlreadyExists.tsx
new file mode 100644
index 00000000000..2e2c92a8a61
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/sessions/components/EmailAlreadyExists.tsx
@@ -0,0 +1,138 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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 * as React from 'react';
+import { FormattedMessage } from 'react-intl';
+import { getIdentityProviders, IdentityProvider } from '../../../api/users';
+import { translate } from '../../../helpers/l10n';
+import { getBaseUrl } from '../../../helpers/urls';
+
+interface Props {
+ location: {
+ query: {
+ email: string;
+ login: string;
+ provider: string;
+ existingLogin: string;
+ existingProvider: string;
+ };
+ };
+}
+
+interface State {
+ identityProviders: IdentityProvider[];
+ loading: boolean;
+}
+
+export default class EmailAlreadyExists extends React.PureComponent<Props, State> {
+ mounted: boolean;
+ state: State = { identityProviders: [], loading: true };
+
+ componentDidMount() {
+ this.mounted = true;
+ this.fetchIdentityProviders();
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ fetchIdentityProviders = () => {
+ this.setState({ loading: true });
+ getIdentityProviders().then(
+ ({ identityProviders }) => {
+ if (this.mounted) {
+ this.setState({ identityProviders, loading: false });
+ }
+ },
+ () => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ }
+ );
+ };
+
+ renderIdentityProvier = (provider: string, login: string) => {
+ const identityProvider = this.state.identityProviders.find(p => p.key === provider);
+
+ return identityProvider ? (
+ <div
+ className="identity-provider"
+ style={{ backgroundColor: identityProvider.backgroundColor }}>
+ <img
+ alt={identityProvider.name}
+ className="little-spacer-right"
+ src={getBaseUrl() + identityProvider.iconPath}
+ width="14"
+ height="14"
+ />
+ {login}
+ </div>
+ ) : (
+ <div>
+ {provider !== 'sonarqube' && provider} {login}
+ </div>
+ );
+ };
+
+ render() {
+ const { query } = this.props.location;
+
+ return (
+ <div>
+ <div className="big-spacer-bottom js-existing-account">
+ <p className="little-spacer-bottom">
+ <FormattedMessage
+ defaultMessage={translate('sessions.email_already_exists.1')}
+ id="sessions.email_already_exists.1"
+ values={{ email: <strong>{query.email}</strong> }}
+ />
+ </p>
+ {this.renderIdentityProvier(query.existingProvider, query.existingLogin)}
+ </div>
+
+ <div className="big-spacer-bottom js-new-account">
+ <p className="little-spacer-bottom">{translate('sessions.email_already_exists.2')}</p>
+ {this.renderIdentityProvier(query.provider, query.login)}
+ </div>
+
+ <div className="alert alert-warning">
+ {translate('sessions.email_already_exists.3')}
+ <ul className="list-styled">
+ <li className="spacer-top">{translate('sessions.email_already_exists.4')}</li>
+ <li className="spacer-top">{translate('sessions.email_already_exists.5')}</li>
+ <li className="spacer-top">{translate('sessions.email_already_exists.6')}</li>
+ </ul>
+ </div>
+
+ <div className="big-spacer-top text-right">
+ <a
+ className="button js-continue"
+ href={`${getBaseUrl()}/sessions/init/${query.provider}?allowEmailShift=true`}>
+ {translate('continue')}
+ </a>
+ <a className="big-spacer-left js-cancel" href={getBaseUrl() + '/'}>
+ {translate('cancel')}
+ </a>
+ </div>
+ </div>
+ );
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/SimpleSessionsContainer.tsx b/server/sonar-web/src/main/js/apps/sessions/components/SimpleSessionsContainer.tsx
index ffca1290264..6e7df5248e9 100644
--- a/server/sonar-web/src/main/js/apps/sessions/components/SimpleSessionsContainer.tsx
+++ b/server/sonar-web/src/main/js/apps/sessions/components/SimpleSessionsContainer.tsx
@@ -21,7 +21,7 @@ import * as React from 'react';
import SimpleContainer from '../../../app/components/SimpleContainer';
interface Props {
- children?: React.ReactElement<any>;
+ children?: React.ReactNode;
}
export default function SimpleSessionsContainer({ children }: Props) {
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/EmailAlreadyExists-test.tsx b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/EmailAlreadyExists-test.tsx
new file mode 100644
index 00000000000..f0a4baca93d
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/EmailAlreadyExists-test.tsx
@@ -0,0 +1,58 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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 * as React from 'react';
+import { shallow } from 'enzyme';
+import EmailAlreadyExists from '../EmailAlreadyExists';
+
+jest.mock('../../../../api/users', () => ({
+ getIdentityProviders: () =>
+ Promise.resolve({
+ identityProviders: [
+ {
+ key: 'bitbucket',
+ name: 'Bitbucket',
+ iconPath: '/static/authbitbucket/bitbucket.svg',
+ backgroundColor: '#205081'
+ },
+ {
+ key: 'github',
+ name: 'GitHub',
+ iconPath: '/static/authgithub/github.svg',
+ backgroundColor: '#444444'
+ }
+ ]
+ })
+}));
+
+it('render', async () => {
+ const query = {
+ email: 'mail@example.com',
+ login: 'foo',
+ provider: 'github',
+ existingLogin: 'bar',
+ existingProvider: 'bitbucket'
+ };
+ const wrapper = shallow(<EmailAlreadyExists location={{ query }} />);
+ (wrapper.instance() as EmailAlreadyExists).mounted = true;
+ (wrapper.instance() as EmailAlreadyExists).fetchIdentityProviders();
+ await new Promise(setImmediate);
+ wrapper.update();
+ expect(wrapper).toMatchSnapshot();
+});
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/EmailAlreadyExists-test.tsx.snap b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/EmailAlreadyExists-test.tsx.snap
new file mode 100644
index 00000000000..95ec95ce038
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/EmailAlreadyExists-test.tsx.snap
@@ -0,0 +1,108 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`render 1`] = `
+<div>
+ <div
+ className="big-spacer-bottom js-existing-account"
+ >
+ <p
+ className="little-spacer-bottom"
+ >
+ <FormattedMessage
+ defaultMessage="sessions.email_already_exists.1"
+ id="sessions.email_already_exists.1"
+ values={
+ Object {
+ "email": <strong>
+ mail@example.com
+ </strong>,
+ }
+ }
+ />
+ </p>
+ <div
+ className="identity-provider"
+ style={
+ Object {
+ "backgroundColor": "#205081",
+ }
+ }
+ >
+ <img
+ alt="Bitbucket"
+ className="little-spacer-right"
+ height="14"
+ src="/static/authbitbucket/bitbucket.svg"
+ width="14"
+ />
+ bar
+ </div>
+ </div>
+ <div
+ className="big-spacer-bottom js-new-account"
+ >
+ <p
+ className="little-spacer-bottom"
+ >
+ sessions.email_already_exists.2
+ </p>
+ <div
+ className="identity-provider"
+ style={
+ Object {
+ "backgroundColor": "#444444",
+ }
+ }
+ >
+ <img
+ alt="GitHub"
+ className="little-spacer-right"
+ height="14"
+ src="/static/authgithub/github.svg"
+ width="14"
+ />
+ foo
+ </div>
+ </div>
+ <div
+ className="alert alert-warning"
+ >
+ sessions.email_already_exists.3
+ <ul
+ className="list-styled"
+ >
+ <li
+ className="spacer-top"
+ >
+ sessions.email_already_exists.4
+ </li>
+ <li
+ className="spacer-top"
+ >
+ sessions.email_already_exists.5
+ </li>
+ <li
+ className="spacer-top"
+ >
+ sessions.email_already_exists.6
+ </li>
+ </ul>
+ </div>
+ <div
+ className="big-spacer-top text-right"
+ >
+ <a
+ className="button js-continue"
+ href="/sessions/init/github?allowEmailShift=true"
+ >
+ continue
+ </a>
+ <a
+ className="big-spacer-left js-cancel"
+ href="/"
+ >
+ cancel
+ </a>
+ </div>
+</div>
+`;
diff --git a/server/sonar-web/src/main/js/apps/sessions/routes.ts b/server/sonar-web/src/main/js/apps/sessions/routes.ts
index d5f4afec31e..92b4d569909 100644
--- a/server/sonar-web/src/main/js/apps/sessions/routes.ts
+++ b/server/sonar-web/src/main/js/apps/sessions/routes.ts
@@ -37,6 +37,12 @@ const routes = [
getComponent(_: RouterState, callback: (err: any, component: RouteComponent) => any) {
import('./components/Unauthorized').then(i => callback(null, i.default));
}
+ },
+ {
+ path: 'email_already_exists',
+ getComponent(_: RouterState, callback: (err: any, component: RouteComponent) => any) {
+ import('./components/EmailAlreadyExists').then(i => callback(null, i.default));
+ }
}
];
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 f4e5b41e0eb..e9f5f8a0ed2 100644
--- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties
+++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
@@ -527,6 +527,12 @@ process.fail=Failed
#------------------------------------------------------------------------------
sessions.log_in=Log in
+sessions.email_already_exists.1=The email address {email} is already associated to this user account:
+sessions.email_already_exists.2=By clicking on "Continue" you will associate this email address to a new user account:
+sessions.email_already_exists.3=This means the following:
+sessions.email_already_exists.4=Your email address will be erased from this account.
+sessions.email_already_exists.5=You will no longer receive email notifications from this account.
+sessions.email_already_exists.6=Issues won't be automatically assigned on the first account anymore.
#------------------------------------------------------------------------------