Browse Source

SONAR-10338 Implement /sessions/email_already_exists page

tags/7.5
Stas Vilchik 6 years ago
parent
commit
8ef5511f69

+ 48
- 0
server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/EmailAlreadyExistsPage.java View File

@@ -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);
}

}

+ 5
- 0
server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/Navigation.java View File

@@ -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
*/

+ 1
- 1
server/sonar-web/scripts/start.js View File

@@ -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);


+ 138
- 0
server/sonar-web/src/main/js/apps/sessions/components/EmailAlreadyExists.tsx View File

@@ -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>
);
}
}

+ 1
- 1
server/sonar-web/src/main/js/apps/sessions/components/SimpleSessionsContainer.tsx View File

@@ -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) {

+ 58
- 0
server/sonar-web/src/main/js/apps/sessions/components/__tests__/EmailAlreadyExists-test.tsx View File

@@ -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();
});

+ 108
- 0
server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/EmailAlreadyExists-test.tsx.snap View File

@@ -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>
`;

+ 6
- 0
server/sonar-web/src/main/js/apps/sessions/routes.ts View File

@@ -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));
}
}
];


+ 6
- 0
sonar-core/src/main/resources/org/sonar/l10n/core.properties View File

@@ -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.


#------------------------------------------------------------------------------

Loading…
Cancel
Save