]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-14662 New risk consent page
authorJeremy Davis <jeremy.davis@sonarsource.com>
Fri, 9 Apr 2021 09:27:07 +0000 (11:27 +0200)
committersonartech <sonartech@sonarsource.com>
Thu, 15 Apr 2021 20:03:44 +0000 (20:03 +0000)
server/sonar-web/src/main/js/app/components/PluginRiskConsent.css [new file with mode: 0644]
server/sonar-web/src/main/js/app/components/PluginRiskConsent.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/app/components/ResetPassword.tsx
server/sonar-web/src/main/js/app/components/__tests__/PluginRiskConsent-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/app/components/__tests__/ResetPassword-test.tsx
server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/PluginRiskConsent-test.tsx.snap [new file with mode: 0644]
server/sonar-web/src/main/js/app/utils/startReactApp.tsx

diff --git a/server/sonar-web/src/main/js/app/components/PluginRiskConsent.css b/server/sonar-web/src/main/js/app/components/PluginRiskConsent.css
new file mode 100644 (file)
index 0000000..7d44b2f
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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;
+}
diff --git a/server/sonar-web/src/main/js/app/components/PluginRiskConsent.tsx b/server/sonar-web/src/main/js/app/components/PluginRiskConsent.tsx
new file mode 100644 (file)
index 0000000..e251fba
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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));
index 672c3f9fc18222d065cfd8b3aac51cea5cc6a0eb..9a55f23a4d25d34b0b636c3c40533b5c60bc4ffd 100644 (file)
@@ -21,19 +21,17 @@ import * as React from 'react';
 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 (
@@ -50,4 +48,4 @@ export function ResetPassword(props: ResetPasswordProps) {
   );
 }
 
-export default whenLoggedIn(withRouter(ResetPassword));
+export default whenLoggedIn(ResetPassword);
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/PluginRiskConsent-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/PluginRiskConsent-test.tsx
new file mode 100644 (file)
index 0000000..5aedf55
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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}
+    />
+  );
+}
index ef2a7dd7983f2c3c2178b5750735ee8bbff04857..0f3093f3f5142716d695ea306f53a230784aed5a 100644 (file)
@@ -19,7 +19,7 @@
  */
 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', () => {
@@ -27,7 +27,5 @@ it('should render correctly', () => {
 });
 
 function shallowRender(props: Partial<ResetPasswordProps> = {}) {
-  return shallow(
-    <ResetPassword currentUser={mockLoggedInUser()} router={mockRouter()} {...props} />
-  );
+  return shallow(<ResetPassword currentUser={mockLoggedInUser()} {...props} />);
 }
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/PluginRiskConsent-test.tsx.snap b/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/PluginRiskConsent-test.tsx.snap
new file mode 100644 (file)
index 0000000..aecc22a
--- /dev/null
@@ -0,0 +1,57 @@
+// 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>
+`;
index 65afaf311a4dac89b0a4e5583f047b0248c1ec78..6bf4a7bacbcd6b0d5ff5f2fcb4085a0b88031554 100644 (file)
@@ -332,6 +332,12 @@ export default function startReactApp(
                       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'))}