From 3991002357c06e6c575c038f2c7345ddc5d9e42d Mon Sep 17 00:00:00 2001 From: Jeremy Davis Date: Mon, 29 Nov 2021 18:29:47 +0100 Subject: [PATCH] SONAR-15702 Prevent displaying App if no access to child projects --- .../app/components/NonAdminPagesContainer.tsx | 58 +++++++++++++ .../__tests__/NonAdminPagesContainer-test.tsx | 69 +++++++++++++++ .../NonAdminPagesContainer-test.tsx.snap | 21 +++++ .../src/main/js/app/utils/startReactApp.tsx | 84 ++++++++++--------- .../resources/org/sonar/l10n/core.properties | 8 ++ 5 files changed, 201 insertions(+), 39 deletions(-) create mode 100644 server/sonar-web/src/main/js/app/components/NonAdminPagesContainer.tsx create mode 100644 server/sonar-web/src/main/js/app/components/__tests__/NonAdminPagesContainer-test.tsx create mode 100644 server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/NonAdminPagesContainer-test.tsx.snap diff --git a/server/sonar-web/src/main/js/app/components/NonAdminPagesContainer.tsx b/server/sonar-web/src/main/js/app/components/NonAdminPagesContainer.tsx new file mode 100644 index 00000000000..57d7e3ab19f --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/NonAdminPagesContainer.tsx @@ -0,0 +1,58 @@ +/* + * 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 { Alert } from '../../components/ui/Alert'; +import { translate } from '../../helpers/l10n'; +import { BranchLike } from '../../types/branch-like'; +import { isApplication } from '../../types/component'; + +export interface NonAdminPagesContainerProps { + children: JSX.Element; + branchLike?: BranchLike; + branchLikes: BranchLike[]; + component: T.Component; + isInProgress?: boolean; + isPending?: boolean; + onBranchesChange: () => void; + onComponentChange: (changes: {}) => void; +} + +export default function NonAdminPagesContainer(props: NonAdminPagesContainerProps) { + const { children, component } = props; + + /* + * Catch Applications for which the user does not have access to all child projects + * and prevent displaying whatever page was requested. + * This doesn't apply to admin pages (those are not within this container) + */ + if (isApplication(component.qualifier) && !component.canBrowseAllChildProjects) { + return ( +
+ +

{translate('application.cannot_access_all_child_projects1')}

+
+

{translate('application.cannot_access_all_child_projects2')}

+
+
+ ); + } + + return React.cloneElement(children, props); +} diff --git a/server/sonar-web/src/main/js/app/components/__tests__/NonAdminPagesContainer-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/NonAdminPagesContainer-test.tsx new file mode 100644 index 00000000000..d1acdc80073 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/__tests__/NonAdminPagesContainer-test.tsx @@ -0,0 +1,69 @@ +/* + * 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 { mockComponent } from '../../../helpers/mocks/component'; +import { ComponentQualifier } from '../../../types/component'; +import NonAdminPagesContainer, { NonAdminPagesContainerProps } from '../NonAdminPagesContainer'; + +function Child() { + return
; +} + +it('should render correctly', () => { + expect( + shallowRender() + .find(Child) + .exists() + ).toBe(true); + + expect( + shallowRender({ + component: mockComponent({ + qualifier: ComponentQualifier.Application, + canBrowseAllChildProjects: true + }) + }) + .find(Child) + .exists() + ).toBe(true); + + const wrapper = shallowRender({ + component: mockComponent({ + qualifier: ComponentQualifier.Application + }) + }); + + expect(wrapper.find(Child).exists()).toBe(false); + expect(wrapper).toMatchSnapshot(); +}); + +function shallowRender(props: Partial = {}) { + return shallow( + + + + ); +} diff --git a/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/NonAdminPagesContainer-test.tsx.snap b/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/NonAdminPagesContainer-test.tsx.snap new file mode 100644 index 00000000000..e3c581a762d --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/NonAdminPagesContainer-test.tsx.snap @@ -0,0 +1,21 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` +
+ +

+ application.cannot_access_all_child_projects1 +

+
+

+ application.cannot_access_all_child_projects2 +

+
+
+`; diff --git a/server/sonar-web/src/main/js/app/utils/startReactApp.tsx b/server/sonar-web/src/main/js/app/utils/startReactApp.tsx index e5eaed2b30a..1758c81ed31 100644 --- a/server/sonar-web/src/main/js/app/utils/startReactApp.tsx +++ b/server/sonar-web/src/main/js/app/utils/startReactApp.tsx @@ -67,6 +67,7 @@ import App from '../components/App'; import GlobalContainer from '../components/GlobalContainer'; import { PageContext } from '../components/indexation/PageUnavailableDueToIndexation'; import MigrationContainer from '../components/MigrationContainer'; +import NonAdminPagesContainer from '../components/NonAdminPagesContainer'; import getStore from './getStore'; /* @@ -156,46 +157,51 @@ function renderRedirects() { function renderComponentRoutes() { return ( import('../components/ComponentContainer'))}> - - - - - - import('../components/extensions/ProjectPageExtension'))} - /> - { - if (query.types) { - if (query.types === 'SECURITY_HOTSPOT') { - replace({ - pathname: '/security_hotspots', - query: { ...pick(query, ['id', 'branch', 'pullRequest']), assignedToMe: false } - }); - } else { - query.types = query.types - .split(',') - .filter((type: string) => type !== 'SECURITY_HOTSPOT') - .join(','); + {/* This container is a catch-all for all non-admin pages */} + + + + + + + + import('../components/extensions/ProjectPageExtension') + )} + /> + { + if (query.types) { + if (query.types === 'SECURITY_HOTSPOT') { + replace({ + pathname: '/security_hotspots', + query: { ...pick(query, ['id', 'branch', 'pullRequest']), assignedToMe: false } + }); + } else { + query.types = query.types + .split(',') + .filter((type: string) => type !== 'SECURITY_HOTSPOT') + .join(','); + } } - } - }} - /> - - import('../../apps/security-hotspots/SecurityHotspotsApp') - )} - /> - - - + }} + /> + + import('../../apps/security-hotspots/SecurityHotspotsApp') + )} + /> + + + + import('../components/ProjectAdminContainer'))}>