Skip to content

Commit

Permalink
refactor: [M3-7786] - Convert isRestrictedGlobalGrantType to hook
Browse files Browse the repository at this point in the history
  • Loading branch information
jaalah committed Feb 16, 2024
1 parent aa9899c commit fc7e5d7
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 68 deletions.
40 changes: 2 additions & 38 deletions packages/manager/src/features/Account/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { getStorage, setStorage } from 'src/utilities/storage';
import type {
GlobalGrantTypes,
GrantLevel,
Grants,
Profile,
Token,
UserType,
} from '@linode/api-v4';
Expand All @@ -18,17 +16,12 @@ interface GetRestrictedResourceText {
resourceType: GrantTypeMap;
}

interface GrantsProfileSchema {
grants: Grants | undefined;
profile: Profile | undefined;
}

interface AccountAccessGrant extends GrantsProfileSchema {
interface AccountAccessGrant {
globalGrantType: 'account_access';
permittedGrantLevel: GrantLevel;
}

interface NonAccountAccessGrant extends GrantsProfileSchema {
interface NonAccountAccessGrant {
globalGrantType: Exclude<GlobalGrantTypes, 'account_access'>;
permittedGrantLevel?: GrantLevel;
}
Expand Down Expand Up @@ -67,35 +60,6 @@ export const getAccessRestrictedText = (
} to request the necessary permission.`;
};

/**
* Determine whether the user has restricted access to a specific resource.
*
* @example
* // If account access does not equal 'read_write', the user has restricted access.
* isRestrictedGlobalGrantType({
* globalGrantType: 'account_access',
* permittedGrantLevel: 'read_write',
* grants,
* profile
* });
* // Returns: true
*/
export const isRestrictedGlobalGrantType = ({
globalGrantType,
grants,
permittedGrantLevel,
profile,
}: RestrictedGlobalGrantType): boolean => {
if (globalGrantType !== 'account_access') {
return Boolean(profile?.restricted) && !grants?.global[globalGrantType];
}

return (
Boolean(profile?.restricted) &&
grants?.global[globalGrantType] !== permittedGrantLevel
);
};

// TODO: Parent/Child: FOR MSW ONLY, REMOVE WHEN API IS READY
// ================================================================
// const mockExpiredTime =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,16 @@ import { Tag, TagsInput } from 'src/components/TagsInput/TagsInput';
import { TextField } from 'src/components/TextField';
import { Typography } from 'src/components/Typography';
import { FIREWALL_GET_STARTED_LINK } from 'src/constants';
import {
getRestrictedResourceText,
isRestrictedGlobalGrantType,
} from 'src/features/Account/utils';
import { getRestrictedResourceText } from 'src/features/Account/utils';
import { useFlags } from 'src/hooks/useFlags';
import { useRestrictedGlobalGrantCheck } from 'src/hooks/useRestrictedGlobalGrantCheck';
import {
reportAgreementSigningError,
useAccountAgreements,
useMutateAccountAgreements,
} from 'src/queries/accountAgreements';
import { useNodebalancerCreateMutation } from 'src/queries/nodebalancers';
import { useGrants, useProfile } from 'src/queries/profile';
import { useProfile } from 'src/queries/profile';
import { useRegionsQuery } from 'src/queries/regions';
import { sendCreateNodeBalancerEvent } from 'src/utilities/analytics';
import { getAPIErrorOrDefault } from 'src/utilities/errorUtils';
Expand Down Expand Up @@ -94,7 +92,6 @@ const defaultFieldsStates = {
const NodeBalancerCreate = () => {
const flags = useFlags();
const { data: agreements } = useAccountAgreements();
const { data: grants } = useGrants();
const { data: profile } = useProfile();
const { data: regions } = useRegionsQuery();

Expand Down Expand Up @@ -130,10 +127,8 @@ const NodeBalancerCreate = () => {
const theme = useTheme<Theme>();
const matchesSmDown = useMediaQuery(theme.breakpoints.down('md'));

const isRestricted = isRestrictedGlobalGrantType({
const isRestricted = useRestrictedGlobalGrantCheck({
globalGrantType: 'add_nodebalancers',
grants,
profile,
});

const addNodeBalancer = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,11 @@ import { TableHead } from 'src/components/TableHead';
import { TableRow } from 'src/components/TableRow';
import { TableSortCell } from 'src/components/TableSortCell/TableSortCell';
import { TransferDisplay } from 'src/components/TransferDisplay/TransferDisplay';
import {
getRestrictedResourceText,
isRestrictedGlobalGrantType,
} from 'src/features/Account/utils';
import { getRestrictedResourceText } from 'src/features/Account/utils';
import { useOrder } from 'src/hooks/useOrder';
import { usePagination } from 'src/hooks/usePagination';
import { useRestrictedGlobalGrantCheck } from 'src/hooks/useRestrictedGlobalGrantCheck';
import { useNodeBalancersQuery } from 'src/queries/nodebalancers';
import { useGrants, useProfile } from 'src/queries/profile';

import { NodeBalancerDeleteDialog } from '../NodeBalancerDeleteDialog';
import { NodeBalancerTableRow } from './NodeBalancerTableRow';
Expand All @@ -39,13 +36,8 @@ export const NodeBalancersLanding = () => {

const history = useHistory();
const pagination = usePagination(1, preferenceKey);
const { data: grants } = useGrants();
const { data: profile } = useProfile();

const isRestricted = isRestrictedGlobalGrantType({
const isRestricted = useRestrictedGlobalGrantCheck({
globalGrantType: 'add_nodebalancers',
grants,
profile,
});

const { handleOrderChange, order, orderBy } = useOrder(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,14 @@ import { DocumentTitleSegment } from 'src/components/DocumentTitle';
import { Link } from 'src/components/Link';
import { Placeholder } from 'src/components/Placeholder/Placeholder';
import { Typography } from 'src/components/Typography';
import {
getRestrictedResourceText,
isRestrictedGlobalGrantType,
} from 'src/features/Account/utils';
import { useGrants, useProfile } from 'src/queries/profile';
import { getRestrictedResourceText } from 'src/features/Account/utils';
import { useRestrictedGlobalGrantCheck } from 'src/hooks/useRestrictedGlobalGrantCheck';

export const NodeBalancerLandingEmptyState = () => {
const history = useHistory();
const { data: grants } = useGrants();
const { data: profile } = useProfile();

const isRestricted = isRestrictedGlobalGrantType({
const isRestricted = useRestrictedGlobalGrantCheck({
globalGrantType: 'add_nodebalancers',
grants,
profile,
});

return (
Expand Down
69 changes: 69 additions & 0 deletions packages/manager/src/hooks/useRestrictedGlobalGrantCheck.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { renderHook } from '@testing-library/react-hooks';

import { useRestrictedGlobalGrantCheck } from './useRestrictedGlobalGrantCheck';

const queryMocks = vi.hoisted(() => ({
useGrants: vi.fn().mockReturnValue({}),
useProfile: vi.fn().mockReturnValue({}),
}));

vi.mock('src/queries/profile', async () => {
const actual = await vi.importActual('src/queries/profile');
return {
...actual,
useGrants: queryMocks.useGrants,
useProfile: queryMocks.useProfile,
};
});

describe('useRestrictedGlobalGrantCheck', () => {
it('returns true for restricted access with non-permitted grant level', () => {
queryMocks.useGrants.mockReturnValue({
data: { global: { account_access: 'read_only' } },
});
queryMocks.useProfile.mockReturnValue({ data: { restricted: true } });

const { result } = renderHook(() =>
useRestrictedGlobalGrantCheck({
globalGrantType: 'account_access',
permittedGrantLevel: 'read_write',
})
);

expect(result.current).toBe(true);
});

it('returns false for unrestricted access with permitted grant level', () => {
queryMocks.useGrants.mockReturnValue({
data: { global: { account_access: 'read_write' } },
});
queryMocks.useProfile.mockReturnValue({ data: { restricted: false } });

const { result } = renderHook(() =>
useRestrictedGlobalGrantCheck({
globalGrantType: 'account_access',
permittedGrantLevel: 'read_write',
})
);

expect(result.current).toBe(false);
});

it('returns true for restricted access to non-account_access resource', () => {
queryMocks.useGrants.mockReturnValue({
data: { global: { add_linodes: false } },
});
queryMocks.useProfile.mockReturnValue({ data: { restricted: true } });

const { result } = renderHook(() =>
useRestrictedGlobalGrantCheck({
globalGrantType: 'add_linodes',
permittedGrantLevel: 'read_write', // This param is ignored for non-account_access types
})
);

expect(result.current).toBe(true);
});

// Add more tests as needed to cover different scenarios and edge cases
});
31 changes: 31 additions & 0 deletions packages/manager/src/hooks/useRestrictedGlobalGrantCheck.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useGrants, useProfile } from 'src/queries/profile';

import type { RestrictedGlobalGrantType } from 'src/features/Account/utils';

/**
* Determine whether the user has restricted access to a specific resource.
*
* @example
* // If account access does not equal 'read_write', the user has restricted access.
* useRestrictedGlobalGrantCheck({
* globalGrantType: 'account_access',
* permittedGrantLevel: 'read_write',
* });
* // Returns: true
*/
export const useRestrictedGlobalGrantCheck = ({
globalGrantType,
permittedGrantLevel,
}: RestrictedGlobalGrantType): boolean => {
const { data: grants } = useGrants();
const { data: profile } = useProfile();

if (globalGrantType !== 'account_access') {
return Boolean(profile?.restricted) && !grants?.global[globalGrantType];
}

return (
Boolean(profile?.restricted) &&
grants?.global[globalGrantType] !== permittedGrantLevel
);
};

0 comments on commit fc7e5d7

Please sign in to comment.