--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.
+ */
+.plugin-risk-consent-page {
+ padding-top: 10vh;
+}
+
+.plugin-risk-consent-page h1 {
+ line-height: 1.5;
+ font-size: 24px;
+ font-weight: 300;
+ text-align: center;
+}
+
+.plugin-risk-consent-content {
+ min-width: 500px;
+ width: 40%;
+ margin: 0 auto;
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { Link } from 'react-router';
+import { Button } from 'sonar-ui-common/components/controls/buttons';
+import { translate } from 'sonar-ui-common/helpers/l10n';
+import { setSimpleSettingValue } from '../../api/settings';
+import { whenLoggedIn } from '../../components/hoc/whenLoggedIn';
+import { Router, withRouter } from '../../components/hoc/withRouter';
+import { hasGlobalPermission } from '../../helpers/users';
+import { Permissions } from '../../types/permissions';
+import { RiskConsent } from '../../types/plugins';
+import { SettingsKey } from '../../types/settings';
+import GlobalMessagesContainer from './GlobalMessagesContainer';
+import './PluginRiskConsent.css';
+
+export interface PluginRiskConsentProps {
+ currentUser: T.LoggedInUser;
+ router: Router;
+}
+
+export function PluginRiskConsent(props: PluginRiskConsentProps) {
+ const { router, currentUser } = props;
+
+ if (!hasGlobalPermission(currentUser, Permissions.Admin)) {
+ router.replace('/');
+ return null;
+ }
+
+ const acknowledgeRisk = async () => {
+ try {
+ await setSimpleSettingValue({
+ key: SettingsKey.PluginRiskConsent,
+ value: RiskConsent.Accepted
+ });
+
+ window.location.href = `/`; // force a refresh for the backend
+ } catch (_) {
+ /* Do nothing */
+ }
+ };
+
+ return (
+ <div className="plugin-risk-consent-page">
+ <GlobalMessagesContainer />
+
+ <div className="plugin-risk-consent-content boxed-group">
+ <div className="boxed-group-inner text-center">
+ <h1 className="big-spacer-bottom">{translate('plugin_risk_consent.title')}</h1>
+ <p className="big big-spacer-bottom">{translate('plugin_risk_consent.description')}</p>
+ <p className="big big-spacer-bottom">{translate('plugin_risk_consent.description2')}</p>
+ <p className="big huge-spacer-bottom">
+ <FormattedMessage
+ id="plugin_risk_consent.description3"
+ defaultMessage={translate('plugin_risk_consent.description3')}
+ values={{
+ link: (
+ <Link to="/documentation/instance-administration/marketplace/" target="_blank">
+ {translate('plugin_risk_consent.description3.link')}
+ </Link>
+ )
+ }}
+ />
+ </p>
+
+ <Button onClick={acknowledgeRisk}>{translate('plugin_risk_consent.action')}</Button>
+ </div>
+ </div>
+ </div>
+ );
+}
+
+export default whenLoggedIn(withRouter(PluginRiskConsent));
import { translate } from 'sonar-ui-common/helpers/l10n';
import ResetPasswordForm from '../../components/common/ResetPassword';
import { whenLoggedIn } from '../../components/hoc/whenLoggedIn';
-import { Router, withRouter } from '../../components/hoc/withRouter';
import GlobalMessagesContainer from './GlobalMessagesContainer';
import './ResetPassword.css';
export interface ResetPasswordProps {
currentUser: T.LoggedInUser;
- router: Router;
}
export function ResetPassword(props: ResetPasswordProps) {
- const { router, currentUser } = props;
+ const { currentUser } = props;
const redirect = () => {
- router.replace('/');
+ window.location.href = `/`; // force a refresh for the backend to handle additional redirects
};
return (
);
}
-export default whenLoggedIn(withRouter(ResetPassword));
+export default whenLoggedIn(ResetPassword);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import { Button } from 'sonar-ui-common/components/controls/buttons';
+import { setSimpleSettingValue } from '../../../api/settings';
+import { mockLoggedInUser, mockRouter } from '../../../helpers/testMocks';
+import { PluginRiskConsent, PluginRiskConsentProps } from '../PluginRiskConsent';
+
+jest.mock('../../../api/settings', () => ({
+ setSimpleSettingValue: jest.fn().mockResolvedValue({})
+}));
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot('default');
+});
+
+it('should redirect non-admin users', () => {
+ const replace = jest.fn();
+ const wrapper = shallowRender({
+ currentUser: mockLoggedInUser(),
+ router: mockRouter({ replace })
+ });
+ expect(wrapper.type()).toBeNull();
+ expect(replace).toBeCalled();
+});
+
+it('should handle acknowledgement and redirect', async () => {
+ const wrapper = shallowRender();
+
+ wrapper
+ .find(Button)
+ .first()
+ .simulate('click');
+
+ await new Promise(setImmediate);
+
+ expect(setSimpleSettingValue).toBeCalled();
+});
+
+function shallowRender(props: Partial<PluginRiskConsentProps> = {}) {
+ return shallow(
+ <PluginRiskConsent
+ currentUser={mockLoggedInUser({ permissions: { global: ['admin'] } })}
+ router={mockRouter()}
+ {...props}
+ />
+ );
+}
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import { mockLoggedInUser, mockRouter } from '../../../helpers/testMocks';
+import { mockLoggedInUser } from '../../../helpers/testMocks';
import { ResetPassword, ResetPasswordProps } from '../ResetPassword';
it('should render correctly', () => {
});
function shallowRender(props: Partial<ResetPasswordProps> = {}) {
- return shallow(
- <ResetPassword currentUser={mockLoggedInUser()} router={mockRouter()} {...props} />
- );
+ return shallow(<ResetPassword currentUser={mockLoggedInUser()} {...props} />);
}
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly: default 1`] = `
+<div
+ className="plugin-risk-consent-page"
+>
+ <Connect(GlobalMessages) />
+ <div
+ className="plugin-risk-consent-content boxed-group"
+ >
+ <div
+ className="boxed-group-inner text-center"
+ >
+ <h1
+ className="big-spacer-bottom"
+ >
+ plugin_risk_consent.title
+ </h1>
+ <p
+ className="big big-spacer-bottom"
+ >
+ plugin_risk_consent.description
+ </p>
+ <p
+ className="big big-spacer-bottom"
+ >
+ plugin_risk_consent.description2
+ </p>
+ <p
+ className="big huge-spacer-bottom"
+ >
+ <FormattedMessage
+ defaultMessage="plugin_risk_consent.description3"
+ id="plugin_risk_consent.description3"
+ values={
+ Object {
+ "link": <Link
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ target="_blank"
+ to="/documentation/instance-administration/marketplace/"
+ >
+ plugin_risk_consent.description3.link
+ </Link>,
+ }
+ }
+ />
+ </p>
+ <Button
+ onClick={[Function]}
+ >
+ plugin_risk_consent.action
+ </Button>
+ </div>
+ </div>
+</div>
+`;
import('../../apps/change-admin-password/ChangeAdminPasswordApp')
)}
/>
+ <Route
+ // We don't want this route to have any menu. This is why we define it here
+ // rather than under the admin routes.
+ path="admin/plugin_risk_consent"
+ component={lazyLoadComponent(() => import('../components/PluginRiskConsent'))}
+ />
<Route
path="not_found"
component={lazyLoadComponent(() => import('../components/NotFound'))}