From 7d6499b37ca0dc87daab2ddf7fb25ff7034c3028 Mon Sep 17 00:00:00 2001 From: Viktor Vorona Date: Mon, 17 Jul 2023 15:30:42 +0200 Subject: [PATCH] SONAR-19790 allow local admins to restore access on github projects --- .../js/apps/projectsManagement/ProjectRow.tsx | 8 ++- .../projectsManagement/ProjectRowActions.tsx | 21 ++++--- .../__tests__/ProjectManagementApp-it.tsx | 56 ++++++++++++++++--- 3 files changed, 65 insertions(+), 20 deletions(-) diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/ProjectRow.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/ProjectRow.tsx index 9a4c207e465..d2acb3e932b 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/ProjectRow.tsx +++ b/server/sonar-web/src/main/js/apps/projectsManagement/ProjectRow.tsx @@ -29,6 +29,7 @@ import { translate, translateWithParameters } from '../../helpers/l10n'; import { getComponentOverviewUrl } from '../../helpers/urls'; import { ComponentQualifier } from '../../types/component'; import { LoggedInUser } from '../../types/users'; +import { useGithubStatusQuery } from '../settings/components/authentication/queries/identity-provider'; import './ProjectRow.css'; import ProjectRowActions from './ProjectRowActions'; @@ -41,6 +42,7 @@ interface Props { export default function ProjectRow(props: Props) { const { currentUser, project, selected } = props; + const { data: githubProvisioningEnabled } = useGithubStatusQuery(); const handleProjectCheck = (checked: boolean) => { props.onProjectCheck(project, checked); @@ -68,9 +70,9 @@ export default function ProjectRow(props: Props) { {project.name} - {project.qualifier === ComponentQualifier.Project && !project.managed && ( - {translate('local')} - )} + {project.qualifier === ComponentQualifier.Project && + githubProvisioningEnabled && + !project.managed && {translate('local')}} diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/ProjectRowActions.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/ProjectRowActions.tsx index fa9064adf54..032e81f83f2 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/ProjectRowActions.tsx +++ b/server/sonar-web/src/main/js/apps/projectsManagement/ProjectRowActions.tsx @@ -26,10 +26,11 @@ import { translate, translateWithParameters } from '../../helpers/l10n'; import { getComponentPermissionsUrl } from '../../helpers/urls'; import { LoggedInUser } from '../../types/users'; import ApplyTemplate from '../permissions/project/components/ApplyTemplate'; +import { useGithubStatusQuery } from '../settings/components/authentication/queries/identity-provider'; import RestoreAccessModal from './RestoreAccessModal'; export interface Props { - currentUser: Pick; + currentUser: Pick; project: Project; } @@ -38,6 +39,7 @@ export default function ProjectRowActions({ currentUser, project }: Props) { const [hasAccess, setHasAccess] = useState(undefined); const [loading, setLoading] = useState(false); const [restoreAccessModal, setRestoreAccessModal] = useState(false); + const { data: githubProvisioningEnabled } = useGithubStatusQuery(); const fetchPermissions = () => { setLoading(true); @@ -87,14 +89,15 @@ export default function ProjectRowActions({ currentUser, project }: Props) { )} - {hasAccess === false && !project.managed && ( - setRestoreAccessModal(true)} - > - {translate('global_permissions.restore_access')} - - )} + {hasAccess === false && + (!project.managed || currentUser.local || !githubProvisioningEnabled) && ( + setRestoreAccessModal(true)} + > + {translate('global_permissions.restore_access')} + + )} )} diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/ProjectManagementApp-it.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/ProjectManagementApp-it.tsx index f4631ddc7db..6cbc90bcb76 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/ProjectManagementApp-it.tsx +++ b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/ProjectManagementApp-it.tsx @@ -367,7 +367,7 @@ it('should create project', async () => { expect(ui.successMsg.get(dialog)).toBeInTheDocument(); await user.click(ui.close.get(dialog)); expect(ui.row.getAll()).toHaveLength(6); - expect(ui.row.getAll()[1]).toHaveTextContent('qualifier.TRKa Testlocalvisibility.privatetest—'); + expect(ui.row.getAll()[1]).toHaveTextContent('qualifier.TRKa Testvisibility.privatetest—'); }); it('should edit permissions of single project', async () => { @@ -401,7 +401,7 @@ it('should apply template for single object', async () => { it('should restore access to admin', async () => { const user = userEvent.setup(); - renderProjectManagementApp({}, { login: 'gooduser2' }); + renderProjectManagementApp({}, { login: 'gooduser2', local: true }); await act(async () => user.click(await ui.firstProjectActions.find())); expect(await ui.restoreAccess.find()).toBeInTheDocument(); expect(ui.editPermissions.query()).not.toBeInTheDocument(); @@ -414,6 +414,44 @@ it('should restore access to admin', async () => { expect(ui.editPermissions.get()).toBeInTheDocument(); }); +it('should restore access for github project', async () => { + const user = userEvent.setup(); + authHandler.githubProvisioningStatus = true; + renderProjectManagementApp( + {}, + { login: 'gooduser2', local: true }, + { featureList: [Feature.GithubProvisioning] } + ); + await waitFor(() => expect(ui.row.getAll()).toHaveLength(5)); + const rows = ui.row.getAll(); + await act(async () => user.click(await ui.projectActions.find(rows[4]))); + expect(await ui.restoreAccess.find()).toBeInTheDocument(); + expect(ui.showPermissions.query()).not.toBeInTheDocument(); + await user.click(ui.restoreAccess.get()); + expect(ui.restoreAccessDialog.get()).toBeInTheDocument(); + await act(() => user.click(ui.restore.get(ui.restoreAccessDialog.get()))); + expect(ui.restoreAccessDialog.query()).not.toBeInTheDocument(); + await act(async () => user.click(await ui.projectActions.find(rows[4]))); + expect(ui.restoreAccess.query()).not.toBeInTheDocument(); + expect(ui.showPermissions.get()).toBeInTheDocument(); +}); + +it('should not allow to restore access on github project for GH user', async () => { + const user = userEvent.setup(); + authHandler.githubProvisioningStatus = true; + renderProjectManagementApp( + {}, + { login: 'gooduser2', local: false }, + { featureList: [Feature.GithubProvisioning] } + ); + await waitFor(() => expect(ui.row.getAll()).toHaveLength(5)); + const rows = ui.row.getAll(); + await act(async () => user.click(await ui.projectActions.find(rows[4]))); + expect(ui.restoreAccess.query()).not.toBeInTheDocument(); + await act(async () => user.click(await ui.projectActions.find(rows[1]))); + expect(ui.restoreAccess.get()).toBeInTheDocument(); +}); + it('should show github warning on changing default visibility to admin', async () => { const user = userEvent.setup(); authHandler.githubProvisioningStatus = true; @@ -428,10 +466,6 @@ it('should not allow apply permissions for managed projects', async () => { renderProjectManagementApp(); await waitFor(() => expect(ui.row.getAll()).toHaveLength(5)); const rows = ui.row.getAll(); - expect(rows[1]).toHaveTextContent('local'); - expect(rows[2]).toHaveTextContent('local'); - expect(rows[3]).toHaveTextContent('local'); - expect(rows[4]).not.toHaveTextContent('local'); expect(ui.checkbox.get(rows[4])).toHaveAttribute('aria-disabled', 'true'); expect(ui.checkbox.get(rows[1])).not.toHaveAttribute('aria-disabled'); await user.click(ui.checkAll.get()); @@ -439,7 +473,6 @@ it('should not allow apply permissions for managed projects', async () => { expect(ui.checkbox.get(rows[1])).toBeChecked(); await act(() => user.click(ui.projectActions.get(rows[4]))); expect(ui.applyPermissionTemplate.query()).not.toBeInTheDocument(); - expect(ui.restoreAccess.query()).not.toBeInTheDocument(); expect(ui.editPermissions.query()).not.toBeInTheDocument(); expect(ui.showPermissions.get()).toBeInTheDocument(); await act(() => user.click(ui.projectActions.get(rows[1]))); @@ -449,7 +482,8 @@ it('should not allow apply permissions for managed projects', async () => { }); it('should not show local badge for applications and portfolios', async () => { - renderProjectManagementApp(); + authHandler.githubProvisioningStatus = true; + renderProjectManagementApp({}, {}, { featureList: [Feature.GithubProvisioning] }); await waitFor(() => expect(screen.getAllByText('local')).toHaveLength(3)); await selectEvent.select(ui.qualifierFilter.get(), 'qualifiers.VW'); @@ -459,6 +493,12 @@ it('should not show local badge for applications and portfolios', async () => { expect(screen.queryByText('local')).not.toBeInTheDocument(); }); +it('should not show local badge if provisioning is not enabled', async () => { + renderProjectManagementApp(); + await waitFor(() => expect(ui.row.getAll()).toHaveLength(5)); + expect(screen.queryByText('local')).not.toBeInTheDocument(); +}); + function renderProjectManagementApp( overrides: Partial = {}, user: Partial = {}, -- 2.39.5