Skip to content

Commit

Permalink
STCOR-834: refactor useUserTenantPermissions to use _self endpoint pe…
Browse files Browse the repository at this point in the history
…rmissions instead of okapi permissions if roles interface is presented (#1491)

Refs STCOR-834.
  • Loading branch information
aidynoJ authored Jul 15, 2024
1 parent 8daa267 commit bec39d5
Show file tree
Hide file tree
Showing 6 changed files with 333 additions and 98 deletions.
51 changes: 51 additions & 0 deletions src/hooks/useUserSelfTenantPermissions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { useQuery } from 'react-query';

import { useStripes } from '../StripesContext';
import { useNamespace } from '../components';
import useOkapiKy from '../useOkapiKy';

const INITIAL_DATA = [];

const useUserSelfTenantPermissions = (
{ tenantId },
options = {},
) => {
const stripes = useStripes();
const ky = useOkapiKy();
const api = ky.extend({
hooks: {
beforeRequest: [(req) => req.headers.set('X-Okapi-Tenant', tenantId)]
}
});
const [namespace] = useNamespace({ key: 'user-self-permissions' });

const user = stripes.user.user;

const {
isFetching,
isLoading,
data,
} = useQuery(
[namespace, user?.id, tenantId],
({ signal }) => {
return api.get(
'users-keycloak/_self',
{ signal },
).json();
},
{
enabled: Boolean(user?.id && tenantId) && stripes.hasInterface('users-keycloak'),
keepPreviousData: true,
...options,
},
);

return ({
isFetching,
isLoading,
userPermissions: data?.permissions.permissions || INITIAL_DATA,
totalRecords: data?.permissions.permissions.length || 0,
});
};

export default useUserSelfTenantPermissions;
71 changes: 71 additions & 0 deletions src/hooks/useUserSelfTenantPermissions.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { renderHook, waitFor } from '@folio/jest-config-stripes/testing-library/react';
import {
QueryClient,
QueryClientProvider,
} from 'react-query';

import permissions from 'fixtures/permissions';
import useUserSelfTenantPermissions from './useUserSelfTenantPermissions';
import useOkapiKy from '../useOkapiKy';

jest.mock('../useOkapiKy');
jest.mock('../components', () => ({
useNamespace: () => ([]),
}));
jest.mock('../StripesContext', () => ({
useStripes: () => ({
user: {
user: {
id: 'userId'
}
},
hasInterface: () => true
}),
}));

const queryClient = new QueryClient();

// eslint-disable-next-line react/prop-types
const wrapper = ({ children }) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
);

const response = {
permissions: { permissions },
};

describe('useUserSelfTenantPermissions', () => {
const getMock = jest.fn(() => ({
json: () => Promise.resolve(response),
}));
const setHeaderMock = jest.fn();
const kyMock = {
extend: jest.fn(({ hooks: { beforeRequest } }) => {
beforeRequest.forEach(handler => handler({ headers: { set: setHeaderMock } }));

return {
get: getMock,
};
}),
};

beforeEach(() => {
getMock.mockClear();
useOkapiKy.mockClear().mockReturnValue(kyMock);
});

it('should fetch user permissions for specified tenant', async () => {
const options = {
userId: 'userId',
tenantId: 'tenantId',
};
const { result } = renderHook(() => useUserSelfTenantPermissions(options), { wrapper });

await waitFor(() => !result.current.isLoading);

expect(setHeaderMock).toHaveBeenCalledWith('X-Okapi-Tenant', options.tenantId);
expect(getMock).toHaveBeenCalledWith('users-keycloak/_self', expect.objectContaining({}));
});
});
59 changes: 59 additions & 0 deletions src/hooks/useUserTenantPermissionNames.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { useQuery } from 'react-query';

import { useStripes } from '../StripesContext';
import { useNamespace } from '../components';
import useOkapiKy from '../useOkapiKy';

const INITIAL_DATA = [];

const useUserTenantPermissionNames = (
{ tenantId },
options = {},
) => {
const stripes = useStripes();
const ky = useOkapiKy();
const api = ky.extend({
hooks: {
beforeRequest: [(req) => req.headers.set('X-Okapi-Tenant', tenantId)]
}
});
const [namespace] = useNamespace({ key: 'user-affiliation-permissions' });

const user = stripes.user.user;

const searchParams = {
full: 'true',
indexField: 'userId',
};

const {
isFetching,
isLoading,
data = {},
} = useQuery(
[namespace, user?.id, tenantId],
({ signal }) => {
return api.get(
`perms/users/${user.id}/permissions`,
{
searchParams,
signal,
},
).json();
},
{
enabled: Boolean(user?.id && tenantId) && !stripes.hasInterface('roles'),
keepPreviousData: true,
...options,
},
);

return ({
isFetching,
isLoading,
userPermissions: data.permissionNames || INITIAL_DATA,
totalRecords: data.totalRecords,
});
};

export default useUserTenantPermissionNames;
72 changes: 72 additions & 0 deletions src/hooks/useUserTenantPermissionNames.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { renderHook, waitFor } from '@folio/jest-config-stripes/testing-library/react';
import {
QueryClient,
QueryClientProvider,
} from 'react-query';

import permissions from 'fixtures/permissions';
import useUserTenantPermissionNames from './useUserTenantPermissionNames';
import useOkapiKy from '../useOkapiKy';

jest.mock('../useOkapiKy');
jest.mock('../components', () => ({
useNamespace: () => ([]),
}));
jest.mock('../StripesContext', () => ({
useStripes: () => ({
user: {
user: {
id: 'userId'
}
},
hasInterface: () => false
}),
}));

const queryClient = new QueryClient();

// eslint-disable-next-line react/prop-types
const wrapper = ({ children }) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
);

const response = {
permissionNames: permissions,
totalRecords: permissions.length,
};

describe('useUserTenantPermissionNames', () => {
const getMock = jest.fn(() => ({
json: () => Promise.resolve(response),
}));
const setHeaderMock = jest.fn();
const kyMock = {
extend: jest.fn(({ hooks: { beforeRequest } }) => {
beforeRequest.forEach(handler => handler({ headers: { set: setHeaderMock } }));

return {
get: getMock,
};
}),
};

beforeEach(() => {
getMock.mockClear();
useOkapiKy.mockClear().mockReturnValue(kyMock);
});

it('should fetch user permissions for specified tenant', async () => {
const options = {
userId: 'userId',
tenantId: 'tenantId',
};
const { result } = renderHook(() => useUserTenantPermissionNames(options), { wrapper });

await waitFor(() => !result.current.isLoading);

expect(setHeaderMock).toHaveBeenCalledWith('X-Okapi-Tenant', options.tenantId);
expect(getMock).toHaveBeenCalledWith(`perms/users/${options.userId}/permissions`, expect.objectContaining({}));
});
});
61 changes: 20 additions & 41 deletions src/hooks/useUserTenantPermissions.js
Original file line number Diff line number Diff line change
@@ -1,58 +1,37 @@
import { useQuery } from 'react-query';

import { useStripes } from '../StripesContext';
import { useNamespace } from '../components';
import useOkapiKy from '../useOkapiKy';

const INITIAL_DATA = [];
import useUserSelfTenantPermissions from './useUserSelfTenantPermissions';
import useUserTenantPermissionNames from './useUserTenantPermissionNames';

const useUserTenantPermissions = (
{ tenantId },
options = {},
) => {
const stripes = useStripes();
const ky = useOkapiKy();
const api = ky.extend({
hooks: {
beforeRequest: [(req) => req.headers.set('X-Okapi-Tenant', tenantId)]
}
});
const [namespace] = useNamespace({ key: 'user-affiliation-permissions' });

const user = stripes.user.user;

const searchParams = {
full: 'true',
indexField: 'userId',
};
const {
isFetching: isPermissionsFetching,
isLoading: isPermissionsLoading,
userPermissions: permissionsData = {},
totalRecords: permissionsTotalRecords
} = useUserTenantPermissionNames({ tenantId }, options);

const {
isFetching,
isLoading,
data = {},
} = useQuery(
[namespace, user?.id, tenantId],
({ signal }) => {
return api.get(
`perms/users/${user.id}/permissions`,
{
searchParams,
signal,
},
).json();
},
{
enabled: Boolean(user?.id && tenantId),
keepPreviousData: true,
...options,
},
);
isFetching: isSelfPermissionsFetching,
isLoading: isSelfPermissionsLoading,
userPermissions:selfPermissionsData = {},
totalRecords: selfPermissionsTotalRecords
} = useUserSelfTenantPermissions({ tenantId }, options);

const isFetching = stripes.hasInterface('roles') ? isSelfPermissionsFetching : isPermissionsFetching;
const isLoading = stripes.hasInterface('roles') ? isSelfPermissionsLoading : isPermissionsLoading;
const userPermissions = stripes.hasInterface('roles') ? selfPermissionsData : permissionsData;
const totalRecords = stripes.hasInterface('roles') ? selfPermissionsTotalRecords : permissionsTotalRecords;

return ({
isFetching,
isLoading,
userPermissions: data.permissionNames || INITIAL_DATA,
totalRecords: data.totalRecords,
userPermissions,
totalRecords
});
};

Expand Down
Loading

0 comments on commit bec39d5

Please sign in to comment.