Skip to content

Commit

Permalink
Add some business rule hooks.
Browse files Browse the repository at this point in the history
  • Loading branch information
tdilauro committed Aug 9, 2024
1 parent 3e0a053 commit cf985fd
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 0 deletions.
27 changes: 27 additions & 0 deletions src/businessRules/roleBasedAccess.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { useAppAdmin, useAppFeatureFlags } from "../context/appContext";

// Not all methods taking this type will use the specified properties.
// The type is here to ensure that the call site provides the right
// properties, in case the rules change in the future.
type HasLibraryKeyProps = {
library: string; // library "key" or "short name"
[key: string]: unknown;
};

// If the `reportsOnlyForSysadmins` feature flag is set, only system admins
// may request inventory reports.
export const useMayRequestInventoryReports = (
_: HasLibraryKeyProps
): boolean => {
const admin = useAppAdmin();
const onlyForSysAdmins = useAppFeatureFlags().reportsOnlyForSysadmins;
return !onlyForSysAdmins || admin.isSystemAdmin();
};

// Only system admins may view the collection statistics barchart.
export const useMayViewCollectionBarChart = (
_: HasLibraryKeyProps
): boolean => {
const admin = useAppAdmin();
return admin.isSystemAdmin();
};
158 changes: 158 additions & 0 deletions tests/jest/businessRules/roleBasedAccess.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { renderHook } from "@testing-library/react-hooks";
import { componentWithProviders } from "../testUtils/withProviders";
import { ContextProviderProps } from "../../../src/components/ContextProvider";
import { ConfigurationSettings, FeatureFlags } from "../../../src/interfaces";
import {
useMayRequestInventoryReports,
useMayViewCollectionBarChart,
} from "../../../src/businessRules/roleBasedAccess";

const setupWrapper = ({
roles,
featureFlags,
}: Partial<ConfigurationSettings>) => {
const contextProviderProps: ContextProviderProps = {
featureFlags,
roles,
email: "email",
csrfToken: "token",
};
return componentWithProviders({ contextProviderProps });
};

describe("Business rules for role-based access", () => {
const libraryMatch = "match";
const libraryMismatch = "mismatch";

describe("controls access to inventory reports", () => {
const testAccess = (
expectedResult: boolean,
config: Partial<ConfigurationSettings>
) => {
const wrapper = setupWrapper(config);
const { result } = renderHook(
() => useMayRequestInventoryReports({ library: libraryMatch }),
{ wrapper }
);
expect(result.current).toBe(expectedResult);
};

it("restricts access to only sysadmins, if the restriction feature flag is true", () => {
const featureFlags: FeatureFlags = { reportsOnlyForSysadmins: true };

testAccess(true, { roles: [{ role: "system" }], featureFlags });

testAccess(false, { roles: [{ role: "manager-all" }], featureFlags });
testAccess(false, { roles: [{ role: "librarian-all" }], featureFlags });

testAccess(false, {
roles: [{ role: "manager", library: libraryMatch }],
featureFlags,
});
testAccess(false, {
roles: [{ role: "manager", library: libraryMismatch }],
featureFlags,
});
testAccess(false, {
roles: [{ role: "librarian", library: libraryMatch }],
featureFlags,
});
testAccess(false, {
roles: [{ role: "librarian", library: libraryMismatch }],
featureFlags,
});
});

it("allows all users, if the restriction feature flag is is false", () => {
const featureFlags: FeatureFlags = { reportsOnlyForSysadmins: false };

testAccess(true, { roles: [{ role: "system" }], featureFlags });

testAccess(true, { roles: [{ role: "manager-all" }], featureFlags });
testAccess(true, { roles: [{ role: "librarian-all" }], featureFlags });

testAccess(true, {
roles: [{ role: "manager", library: libraryMatch }],
featureFlags,
});
testAccess(true, {
roles: [{ role: "manager", library: libraryMismatch }],
featureFlags,
});
testAccess(true, {
roles: [{ role: "librarian", library: libraryMatch }],
featureFlags,
});
testAccess(true, {
roles: [{ role: "librarian", library: libraryMismatch }],
featureFlags,
});
});

it("allows all users, if the restriction feature flag is not set", () => {
const featureFlags: FeatureFlags = {};

testAccess(true, { roles: [{ role: "system" }], featureFlags });

testAccess(true, { roles: [{ role: "manager-all" }], featureFlags });
testAccess(true, { roles: [{ role: "librarian-all" }], featureFlags });

testAccess(true, {
roles: [{ role: "manager", library: libraryMatch }],
featureFlags,
});
testAccess(true, {
roles: [{ role: "manager", library: libraryMismatch }],
featureFlags,
});
testAccess(true, {
roles: [{ role: "librarian", library: libraryMatch }],
featureFlags,
});
testAccess(true, {
roles: [{ role: "librarian", library: libraryMismatch }],
featureFlags,
});
});
});

describe("controls access to the collection statistics barchart", () => {
const testAccess = (
expectedResult: boolean,
config: Partial<ConfigurationSettings>
) => {
const wrapper = setupWrapper(config);
const { result } = renderHook(
() => useMayViewCollectionBarChart({ library: libraryMatch }),
{ wrapper }
);
expect(result.current).toBe(expectedResult);
};

it("restricts access to sysadmins", () => {
const featureFlags: FeatureFlags = {};

testAccess(true, { roles: [{ role: "system" }], featureFlags });

testAccess(false, { roles: [{ role: "manager-all" }], featureFlags });
testAccess(false, { roles: [{ role: "librarian-all" }], featureFlags });

testAccess(false, {
roles: [{ role: "manager", library: libraryMatch }],
featureFlags,
});
testAccess(false, {
roles: [{ role: "manager", library: libraryMismatch }],
featureFlags,
});
testAccess(false, {
roles: [{ role: "librarian", library: libraryMatch }],
featureFlags,
});
testAccess(false, {
roles: [{ role: "librarian", library: libraryMismatch }],
featureFlags,
});
});
});
});

0 comments on commit cf985fd

Please sign in to comment.