Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Hippo.Web/ClientApp/src/Shared/RequireAupAgreement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ export const RequireAupAgreement = (props: Props) => {
const hasSystemPermission = context.user.permissions.some(
(p) => p.role === "System",
);
const hasClusterAdminPermission = context.user.permissions.some(
(p) => p.role === "ClusterAdmin" && p.cluster === clusterName,
);
const hasFinancialAdminPermission = context.user.permissions.some(
(p) => p.role === "FinancialAdmin",
(p) => p.role === "FinancialAdmin" && p.cluster === clusterName,
);
const cluster = context.clusters.find((c) => c.name === clusterName);
const account = context.accounts.find((a) => a.cluster === clusterName);
Expand Down Expand Up @@ -77,6 +80,7 @@ export const RequireAupAgreement = (props: Props) => {

if (
hasSystemPermission ||
hasClusterAdminPermission ||
!cluster.acceptableUsePolicyUrl ||
!cluster.acceptableUsePolicyUpdatedOn
) {
Expand Down
4 changes: 2 additions & 2 deletions Hippo.Web/ClientApp/src/Shared/usePermissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ export const usePermissions = () => {
);

const canViewGroup = (groupName: string) => {
if (isSystemAdmin || isClusterAdmin) return true;
if (!clusterName) return false;
if (isSystemAdmin || isClusterAdmin) return true;
const account = accounts.find((a) => a.cluster === clusterName);
if (!account) return false;
if (account.adminOfGroups.some((g) => g.name === groupName)) return true;
Expand All @@ -22,8 +22,8 @@ export const usePermissions = () => {
};

const canManageGroup = (groupName: string) => {
if (isSystemAdmin) return true;
if (!clusterName) return false;
if (isSystemAdmin || isClusterAdmin) return true;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there anything the system admin allows that we don't want a cluster admin to do?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so.

const account = accounts.find((a) => a.cluster === clusterName);
if (!account) return false;
if (account.adminOfGroups.some((g) => g.name === groupName)) return true;
Expand Down
53 changes: 46 additions & 7 deletions Hippo.Web/ClientApp/src/components/Account/Requests.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { MemoryRouter, Route, Routes } from "react-router-dom";

import {
fakeAccounts,
fakeClusterAdminAppContextNoAccount,
fakeGroupAdminAppContext,
fakeGroups,
fakeRequests,
Expand All @@ -12,17 +13,17 @@ import { responseMap } from "../../test/testHelpers";
import App from "../../App";
import { Requests } from "./Requests";
import { ModalProvider } from "react-modal-hook";
import { render, screen } from "@testing-library/react";
import { render, screen, within } from "@testing-library/react";
import "@testing-library/jest-dom";
import userEvent from "@testing-library/user-event";
import { act } from "react";
import { RequireAupAgreement } from "../../Shared/RequireAupAgreement";
import AppContext from "../../Shared/AppContext";

globalThis.IS_REACT_ACT_ENVIRONMENT = true;

const testCluster = fakeAccounts[0].cluster;
const approveUrl = `/${testCluster}/approve`;
const pendingRequestCountText = `There are ${fakeRequests.length} request(s) awaiting approval`;

beforeEach(() => {
const requestResponse = Promise.resolve({
Expand Down Expand Up @@ -74,11 +75,11 @@ it("shows pending approvals count", async () => {
);
});
expect(
await screen.findByText("There are 2 request(s) awaiting approval"),
await screen.findByText(pendingRequestCountText),
).toBeVisible();
});

it("shows approval button for each pending account", async () => {
it("shows approval buttons for each request the group admin can manage", async () => {
await act(async () => {
render(
<MemoryRouter initialEntries={[approveUrl]}>
Expand All @@ -92,7 +93,7 @@ it("shows approval button for each pending account", async () => {
).toHaveLength(2);
});

it("shows reject button for each pending account", async () => {
it("shows reject buttons for each request the group admin can manage", async () => {
await act(async () => {
render(
<MemoryRouter initialEntries={[approveUrl]}>
Expand All @@ -106,6 +107,44 @@ it("shows reject button for each pending account", async () => {
);
});

it("shows action buttons for CreateGroup requests for cluster admins without an account", async () => {
(global as any).Hippo = fakeClusterAdminAppContextNoAccount;

await act(async () => {
render(
<MemoryRouter initialEntries={[approveUrl]}>
<App />
</MemoryRouter>,
);
});

expect(
await screen.findByText(pendingRequestCountText),
).toBeVisible();
const createGroupCell = (await screen.findAllByText("Create Group")).find(
(element) => element.tagName === "TD",
);
expect(createGroupCell).toBeDefined();
const createGroupRow = createGroupCell?.closest("tr");
expect(createGroupRow).not.toBeNull();
if (!createGroupRow) {
throw new Error("Expected Create Group request row to be present");
}
expect(
await screen.findAllByRole("button", { name: "Approve" }),
).toHaveLength(fakeRequests.length);
expect(
await screen.findAllByRole("button", { name: "Reject" }),
).toHaveLength(fakeRequests.length);
expect(
within(createGroupRow).getByRole("button", { name: "Approve" }),
).toBeVisible();
expect(
within(createGroupRow).getByRole("button", { name: "Reject" }),
).toBeVisible();
expect(screen.queryByText("Acceptable Use Policy")).not.toBeInTheDocument();
});

it("displays dialog when reject is clicked", async () => {
const user = userEvent.setup();
await act(async () => {
Expand All @@ -123,7 +162,7 @@ it("displays dialog when reject is clicked", async () => {
);
});
expect(
await screen.findByText("There are 2 request(s) awaiting approval"),
await screen.findByText(pendingRequestCountText),
).toBeVisible();

await act(async () => {
Expand All @@ -149,7 +188,7 @@ it("calls approve and filters list when approve is clicked", async () => {
);
});
expect(
await screen.findByText("There are 2 request(s) awaiting approval"),
await screen.findByText(pendingRequestCountText),
).toBeVisible();

await act(async () => {
Expand Down
39 changes: 39 additions & 0 deletions Hippo.Web/ClientApp/src/test/mockData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
PuppetUserRecord,
RequestModel,
AccountRequestDataModel,
GroupRequestDataModel,
RequestStatus,
GroupAccountModel
} from "../types";
Expand Down Expand Up @@ -153,6 +154,25 @@ export const fakeRequests: RequestModel[] = [
accessTypes: ["SshKey"],
} as AccountRequestDataModel,
},
{
id: 3,
requesterEmail: fakeUser.email,
requesterName: fakeUser.name,
action: "CreateGroup",
groupModel: {
id: 3,
name: "group3",
displayName: "Group 3",
admins: [fakeAdminGroupAccount],
data: {} as PuppetGroupRecord,
},
status: RequestStatus.PendingApproval,
cluster: "caesfarm",
data: {
name: "group3",
displayName: "Group 3",
} as GroupRequestDataModel,
},
];

const fakeCluster: ClusterModel = {
Expand Down Expand Up @@ -216,6 +236,25 @@ export const fakeGroupAdminAppContext: AppContextShape = {
featureFlags: fakeFeatureFlags,
};

export const fakeClusterAdminAppContextNoAccount: AppContextShape = {
antiForgeryToken: "fakeAntiForgeryToken",
user: {
detail: {
...fakeUser,
},
permissions: [
{
role: "ClusterAdmin",
cluster: "caesfarm",
},
],
},
accounts: [],
clusters: [fakeCluster],
openRequests: fakeRequests,
featureFlags: fakeFeatureFlags,
};

export const fakeSetContext = vi.fn();


Expand Down