From 5222342ea785e1ec032d60f27d49d8e7a70be358 Mon Sep 17 00:00:00 2001 From: aidynoJ Date: Mon, 4 Nov 2024 14:45:29 +0500 Subject: [PATCH 1/9] STCOR-905: Add userId parameter to useUserSelfTenantPermissions hook. --- CHANGELOG.md | 1 + src/hooks/useUserSelfTenantPermissions.js | 8 +++----- src/hooks/useUserTenantPermissionNames.js | 10 ++++------ src/hooks/useUserTenantPermissions.js | 7 ++++--- src/hooks/useUserTenantPermissions.test.js | 7 ++++++- 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72a09e5be..87da01c48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * Conditionally use `/users-keycloak/_self` endpoint when `users-keycloak` interface is present. Refs STCOR-835. * Wait longer before declaring a rotation request to be stale. Refs STCOR-895. * Send the stored central tenant name in the header on logout. Refs STCOR-900. +* Add userId parameter to useUserTenantPermissions hook. Refs STCOR-905. ## [10.2.0](https://github.com/folio-org/stripes-core/tree/v10.2.0) (2024-10-11) [Full Changelog](https://github.com/folio-org/stripes-core/compare/v10.1.1...v10.2.0) diff --git a/src/hooks/useUserSelfTenantPermissions.js b/src/hooks/useUserSelfTenantPermissions.js index 253784fc3..86098ba42 100644 --- a/src/hooks/useUserSelfTenantPermissions.js +++ b/src/hooks/useUserSelfTenantPermissions.js @@ -7,7 +7,7 @@ import useOkapiKy from '../useOkapiKy'; const INITIAL_DATA = []; const useUserSelfTenantPermissions = ( - { tenantId }, + { userId, tenantId }, options = {}, ) => { const stripes = useStripes(); @@ -19,15 +19,13 @@ const useUserSelfTenantPermissions = ( }); const [namespace] = useNamespace({ key: 'user-self-permissions' }); - const user = stripes.user.user; - const { isFetching, isFetched, isLoading, data, } = useQuery( - [namespace, user?.id, tenantId], + [namespace, userId, tenantId], ({ signal }) => { return api.get( 'users-keycloak/_self', @@ -35,7 +33,7 @@ const useUserSelfTenantPermissions = ( ).json(); }, { - enabled: Boolean(user?.id && tenantId) && stripes.hasInterface('users-keycloak'), + enabled: Boolean(userId && tenantId) && stripes.hasInterface('users-keycloak'), keepPreviousData: true, ...options, }, diff --git a/src/hooks/useUserTenantPermissionNames.js b/src/hooks/useUserTenantPermissionNames.js index 6ca306967..ee538da92 100644 --- a/src/hooks/useUserTenantPermissionNames.js +++ b/src/hooks/useUserTenantPermissionNames.js @@ -7,7 +7,7 @@ import useOkapiKy from '../useOkapiKy'; const INITIAL_DATA = []; const useUserTenantPermissionNames = ( - { tenantId }, + { userId, tenantId }, options = {}, ) => { const stripes = useStripes(); @@ -19,8 +19,6 @@ const useUserTenantPermissionNames = ( }); const [namespace] = useNamespace({ key: 'user-affiliation-permissions' }); - const user = stripes.user.user; - const searchParams = { full: 'true', indexField: 'userId', @@ -32,10 +30,10 @@ const useUserTenantPermissionNames = ( isLoading, data = {}, } = useQuery( - [namespace, user?.id, tenantId], + [namespace, userId, tenantId], ({ signal }) => { return api.get( - `perms/users/${user.id}/permissions`, + `perms/users/${userId}/permissions`, { searchParams, signal, @@ -43,7 +41,7 @@ const useUserTenantPermissionNames = ( ).json(); }, { - enabled: Boolean(user?.id && tenantId) && !stripes.hasInterface('roles'), + enabled: Boolean(userId && tenantId) && !stripes.hasInterface('roles'), keepPreviousData: true, ...options, }, diff --git a/src/hooks/useUserTenantPermissions.js b/src/hooks/useUserTenantPermissions.js index 35339b400..59c3e96fa 100644 --- a/src/hooks/useUserTenantPermissions.js +++ b/src/hooks/useUserTenantPermissions.js @@ -3,10 +3,11 @@ import useUserSelfTenantPermissions from './useUserSelfTenantPermissions'; import useUserTenantPermissionNames from './useUserTenantPermissionNames'; const useUserTenantPermissions = ( - { tenantId }, + { tenantId, userId }, options = {}, ) => { const stripes = useStripes(); + const stripesUser = stripes.user.user; const { isFetching: isPermissionsFetching, @@ -14,7 +15,7 @@ const useUserTenantPermissions = ( isLoading: isPermissionsLoading, userPermissions: permissionsData = {}, totalRecords: permissionsTotalRecords - } = useUserTenantPermissionNames({ tenantId }, options); + } = useUserTenantPermissionNames({ tenantId, userId: userId || stripesUser.id }, options); const { isFetching: isSelfPermissionsFetching, @@ -22,7 +23,7 @@ const useUserTenantPermissions = ( isLoading: isSelfPermissionsLoading, userPermissions:selfPermissionsData = {}, totalRecords: selfPermissionsTotalRecords - } = useUserSelfTenantPermissions({ tenantId }, options); + } = useUserSelfTenantPermissions({ tenantId, userId: userId || stripesUser.id }, options); const isFetching = stripes.hasInterface('roles') ? isSelfPermissionsFetching : isPermissionsFetching; const isFetched = stripes.hasInterface('roles') ? isSelfPermissionsFetched : isPermissionsFetched; diff --git a/src/hooks/useUserTenantPermissions.test.js b/src/hooks/useUserTenantPermissions.test.js index c9cf7b060..d65372d05 100644 --- a/src/hooks/useUserTenantPermissions.test.js +++ b/src/hooks/useUserTenantPermissions.test.js @@ -14,7 +14,12 @@ describe('useUserTenantPermissions', () => { beforeEach(() => { useStripes.mockReturnValue({ - hasInterface: jest.fn() + hasInterface: jest.fn(), + user:{ + user: { + id: 'userId' + } + } }); }); From 0883b607f8646c98e15591564c6fdbfe6822f12b Mon Sep 17 00:00:00 2001 From: aidynoJ Date: Thu, 7 Nov 2024 17:58:55 +0500 Subject: [PATCH 2/9] STCOR-905: expose 2 hooks, useUserTenantPermissions and useUserSelfTenantPermissions --- src/hooks/index.js | 3 +- src/hooks/useUserSelfTenantPermissions.js | 6 ++-- src/hooks/useUserTenantPermissions.js | 29 ++++++++-------- src/hooks/useUserTenantPermissions.test.js | 8 ++--- src/hooks/useUserTenantRoles.js | 39 ++++++++++++++++++++++ 5 files changed, 62 insertions(+), 23 deletions(-) create mode 100644 src/hooks/useUserTenantRoles.js diff --git a/src/hooks/index.js b/src/hooks/index.js index 8a889a1b9..c80c7656c 100644 --- a/src/hooks/index.js +++ b/src/hooks/index.js @@ -1 +1,2 @@ -export { default as useUserTenantPermissions } from './useUserTenantPermissions'; // eslint-disable-line import/prefer-default-export +export { default as useUserTenantPermissions } from './useUserTenantPermissions'; +export { default as useUserSelfTenantPermissions } from './useUserSelfTenantPermissions'; diff --git a/src/hooks/useUserSelfTenantPermissions.js b/src/hooks/useUserSelfTenantPermissions.js index 86098ba42..240f49470 100644 --- a/src/hooks/useUserSelfTenantPermissions.js +++ b/src/hooks/useUserSelfTenantPermissions.js @@ -7,7 +7,7 @@ import useOkapiKy from '../useOkapiKy'; const INITIAL_DATA = []; const useUserSelfTenantPermissions = ( - { userId, tenantId }, + { tenantId }, options = {}, ) => { const stripes = useStripes(); @@ -25,7 +25,7 @@ const useUserSelfTenantPermissions = ( isLoading, data, } = useQuery( - [namespace, userId, tenantId], + [namespace, tenantId], ({ signal }) => { return api.get( 'users-keycloak/_self', @@ -33,7 +33,7 @@ const useUserSelfTenantPermissions = ( ).json(); }, { - enabled: Boolean(userId && tenantId) && stripes.hasInterface('users-keycloak'), + enabled: Boolean(tenantId) && stripes.hasInterface('users-keycloak'), keepPreviousData: true, ...options, }, diff --git a/src/hooks/useUserTenantPermissions.js b/src/hooks/useUserTenantPermissions.js index 59c3e96fa..71b9004b9 100644 --- a/src/hooks/useUserTenantPermissions.js +++ b/src/hooks/useUserTenantPermissions.js @@ -1,35 +1,34 @@ import { useStripes } from '../StripesContext'; -import useUserSelfTenantPermissions from './useUserSelfTenantPermissions'; import useUserTenantPermissionNames from './useUserTenantPermissionNames'; +import useUserTenantRoles from './useUserTenantRoles'; const useUserTenantPermissions = ( { tenantId, userId }, options = {}, ) => { const stripes = useStripes(); - const stripesUser = stripes.user.user; const { isFetching: isPermissionsFetching, isFetched: isPermissionsFetched, isLoading: isPermissionsLoading, - userPermissions: permissionsData = {}, + userPermissions: permissionsData, totalRecords: permissionsTotalRecords - } = useUserTenantPermissionNames({ tenantId, userId: userId || stripesUser.id }, options); + } = useUserTenantPermissionNames({ tenantId, userId }, options); const { - isFetching: isSelfPermissionsFetching, - isFetched: isSelfPermissionsFetched, - isLoading: isSelfPermissionsLoading, - userPermissions:selfPermissionsData = {}, - totalRecords: selfPermissionsTotalRecords - } = useUserSelfTenantPermissions({ tenantId, userId: userId || stripesUser.id }, options); + isFetching: isRolesFetching, + isFetched: isRolesFetched, + isLoading: isRolesLoading, + userPermissions:userRolesData, + totalRecords: userRolesTotalRecords + } = useUserTenantRoles({ tenantId, userId }, options); - const isFetching = stripes.hasInterface('roles') ? isSelfPermissionsFetching : isPermissionsFetching; - const isFetched = stripes.hasInterface('roles') ? isSelfPermissionsFetched : isPermissionsFetched; - const isLoading = stripes.hasInterface('roles') ? isSelfPermissionsLoading : isPermissionsLoading; - const userPermissions = stripes.hasInterface('roles') ? selfPermissionsData : permissionsData; - const totalRecords = stripes.hasInterface('roles') ? selfPermissionsTotalRecords : permissionsTotalRecords; + const isFetching = stripes.hasInterface('roles') ? isRolesFetching : isPermissionsFetching; + const isFetched = stripes.hasInterface('roles') ? isRolesFetched : isPermissionsFetched; + const isLoading = stripes.hasInterface('roles') ? isRolesLoading : isPermissionsLoading; + const userPermissions = stripes.hasInterface('roles') ? userRolesData : permissionsData; + const totalRecords = stripes.hasInterface('roles') ? userRolesTotalRecords : permissionsTotalRecords; return ({ isFetching, diff --git a/src/hooks/useUserTenantPermissions.test.js b/src/hooks/useUserTenantPermissions.test.js index d65372d05..681af0cee 100644 --- a/src/hooks/useUserTenantPermissions.test.js +++ b/src/hooks/useUserTenantPermissions.test.js @@ -1,11 +1,11 @@ import { renderHook } from '@folio/jest-config-stripes/testing-library/react'; import { useStripes } from '../StripesContext'; -import useUserSelfTenantPermissions from './useUserSelfTenantPermissions'; import useUserTenantPermissionNames from './useUserTenantPermissionNames'; import useUserTenantPermissions from './useUserTenantPermissions'; +import useUserTenantRoles from './useUserTenantRoles'; jest.mock('../StripesContext'); -jest.mock('./useUserSelfTenantPermissions'); +jest.mock('./useUserTenantRoles'); jest.mock('./useUserTenantPermissionNames'); describe('useUserTenantPermissions', () => { @@ -26,7 +26,7 @@ describe('useUserTenantPermissions', () => { it('should return _self permissions data when "roles" interface is present', () => { useStripes().hasInterface.mockReturnValue(true); - useUserSelfTenantPermissions.mockReturnValue({ + useUserTenantRoles.mockReturnValue({ isFetching: true, isFetched: true, isLoading: true, @@ -56,7 +56,7 @@ describe('useUserTenantPermissions', () => { it('should return tenant permissions data when "roles" interface is NOT present', () => { useStripes().hasInterface.mockReturnValue(false); - useUserSelfTenantPermissions.mockReturnValue({ + useUserTenantRoles.mockReturnValue({ isFetching: true, isFetched: true, isLoading: true, diff --git a/src/hooks/useUserTenantRoles.js b/src/hooks/useUserTenantRoles.js new file mode 100644 index 000000000..63dbb36f2 --- /dev/null +++ b/src/hooks/useUserTenantRoles.js @@ -0,0 +1,39 @@ +import { useQuery } from 'react-query'; +import { useStripes } from '../StripesContext'; +import useOkapiKy from '../useOkapiKy'; +import { useNamespace } from '../components'; + +const INITIAL_DATA = []; + +function useUserTenantRoles({ userId, tenantId }, options) { + const stripes = useStripes(); + + const searchParams = { + limit: stripes.config.maxUnpagedResourceCount, + query: `userId==${userId}`, + }; + const ky = useOkapiKy(); + const api = ky.extend({ + hooks: { + beforeRequest: [(req) => req.headers.set('X-Okapi-Tenant', tenantId)] + } + }); + const [namespace] = useNamespace({ key: 'user-roles' }); + + const { data, isLoading, isFetched, isFetching } = useQuery([namespace, userId], () => { + return api.get( + 'roles/users', { searchParams }, + ) + .json(); + }, { enabled: !!userId && !!tenantId && stripes.hasInterface('roles'), ...options }); + + return { + isFetching, + isFetched, + isLoading, + userPermissions: data.roles || INITIAL_DATA, + totalRecords: data.totalRecords || 0 + }; +} + +export default useUserTenantRoles; From c7535fea66ed79b42aa6137b58c9700f1c8e89aa Mon Sep 17 00:00:00 2001 From: aidynoJ Date: Fri, 8 Nov 2024 18:44:59 +0500 Subject: [PATCH 3/9] coverage --- .../useUserSelfTenantPermissions.test.js | 6 -- src/hooks/useUserTenantRoles.js | 4 +- src/hooks/useUserTenantRoles.test.js | 76 +++++++++++++++++++ 3 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 src/hooks/useUserTenantRoles.test.js diff --git a/src/hooks/useUserSelfTenantPermissions.test.js b/src/hooks/useUserSelfTenantPermissions.test.js index e8604bab7..57808bdc1 100644 --- a/src/hooks/useUserSelfTenantPermissions.test.js +++ b/src/hooks/useUserSelfTenantPermissions.test.js @@ -14,11 +14,6 @@ jest.mock('../components', () => ({ })); jest.mock('../StripesContext', () => ({ useStripes: () => ({ - user: { - user: { - id: 'userId' - } - }, hasInterface: () => true }), })); @@ -58,7 +53,6 @@ describe('useUserSelfTenantPermissions', () => { it('should fetch user permissions for specified tenant', async () => { const options = { - userId: 'userId', tenantId: 'tenantId', }; const { result } = renderHook(() => useUserSelfTenantPermissions(options), { wrapper }); diff --git a/src/hooks/useUserTenantRoles.js b/src/hooks/useUserTenantRoles.js index 63dbb36f2..f74d51808 100644 --- a/src/hooks/useUserTenantRoles.js +++ b/src/hooks/useUserTenantRoles.js @@ -31,8 +31,8 @@ function useUserTenantRoles({ userId, tenantId }, options) { isFetching, isFetched, isLoading, - userPermissions: data.roles || INITIAL_DATA, - totalRecords: data.totalRecords || 0 + userPermissions: data?.roles || INITIAL_DATA, + totalRecords: data?.totalRecords || 0 }; } diff --git a/src/hooks/useUserTenantRoles.test.js b/src/hooks/useUserTenantRoles.test.js new file mode 100644 index 000000000..3a23fe023 --- /dev/null +++ b/src/hooks/useUserTenantRoles.test.js @@ -0,0 +1,76 @@ +import { renderHook, waitFor } from '@folio/jest-config-stripes/testing-library/react'; +import { + QueryClient, + QueryClientProvider, +} from 'react-query'; + +import useUserTenantRoles from './useUserTenantRoles'; +import useOkapiKy from '../useOkapiKy'; + +jest.mock('../useOkapiKy'); +jest.mock('../components', () => ({ + useNamespace: () => ([]), +})); +jest.mock('../StripesContext', () => ({ + useStripes: () => ({ + hasInterface: () => true, + config: { + maxUnpagedResourceCount: 2000 + } + }), +})); + +const queryClient = new QueryClient(); + +// eslint-disable-next-line react/prop-types +const wrapper = ({ children }) => ( + + {children} + +); + +const response = { + data: { + roles: ['role1', 'role2'], + totalRecords: 2, + } +}; + +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 roles for specified tenant', async () => { + const options = { + userId: 'superUserId', + tenantId: 'tenantId', + }; + const { result } = renderHook(() => useUserTenantRoles(options), { wrapper }); + + await waitFor(() => !result.current.isLoading); + + expect(setHeaderMock).toHaveBeenCalledWith('X-Okapi-Tenant', options.tenantId); + expect(getMock).toHaveBeenCalledWith('roles/users', { + searchParams: { + 'limit':2000, + query: 'userId==superUserId' + } + }); + }); +}); From 6083e50f8fd6a753c2ed13ce1eae45c1d411f04b Mon Sep 17 00:00:00 2001 From: aidynoJ Date: Mon, 11 Nov 2024 17:35:51 +0500 Subject: [PATCH 4/9] roles vs userRoles on response --- src/hooks/useUserTenantRoles.js | 2 +- src/hooks/useUserTenantRoles.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hooks/useUserTenantRoles.js b/src/hooks/useUserTenantRoles.js index f74d51808..d5cc09e0c 100644 --- a/src/hooks/useUserTenantRoles.js +++ b/src/hooks/useUserTenantRoles.js @@ -31,7 +31,7 @@ function useUserTenantRoles({ userId, tenantId }, options) { isFetching, isFetched, isLoading, - userPermissions: data?.roles || INITIAL_DATA, + userPermissions: data?.userRoles || INITIAL_DATA, totalRecords: data?.totalRecords || 0 }; } diff --git a/src/hooks/useUserTenantRoles.test.js b/src/hooks/useUserTenantRoles.test.js index 3a23fe023..03d891c81 100644 --- a/src/hooks/useUserTenantRoles.test.js +++ b/src/hooks/useUserTenantRoles.test.js @@ -31,7 +31,7 @@ const wrapper = ({ children }) => ( const response = { data: { - roles: ['role1', 'role2'], + userRoles: ['role1', 'role2'], totalRecords: 2, } }; From 62fe386a92c248417c063795acda68501d1b9502 Mon Sep 17 00:00:00 2001 From: aidynoJ Date: Wed, 13 Nov 2024 17:55:30 +0500 Subject: [PATCH 5/9] Remove unnecessary hooks, leave only useUserSelfTenantPermissions.js --- index.js | 2 +- src/hooks/index.js | 1 - src/hooks/useUserSelfTenantPermissions.js | 5 +- .../useUserSelfTenantPermissions.test.js | 2 +- src/hooks/useUserTenantPermissionNames.js | 59 ------------- .../useUserTenantPermissionNames.test.js | 72 ---------------- src/hooks/useUserTenantPermissions.js | 42 --------- src/hooks/useUserTenantPermissions.test.js | 85 ------------------- src/hooks/useUserTenantRoles.js | 39 --------- src/hooks/useUserTenantRoles.test.js | 76 ----------------- 10 files changed, 5 insertions(+), 378 deletions(-) delete mode 100644 src/hooks/useUserTenantPermissionNames.js delete mode 100644 src/hooks/useUserTenantPermissionNames.test.js delete mode 100644 src/hooks/useUserTenantPermissions.js delete mode 100644 src/hooks/useUserTenantPermissions.test.js delete mode 100644 src/hooks/useUserTenantRoles.js delete mode 100644 src/hooks/useUserTenantRoles.test.js diff --git a/index.js b/index.js index 67fd4d1d0..cb7a94d2c 100644 --- a/index.js +++ b/index.js @@ -40,7 +40,7 @@ export { useChunkedCQLFetch } from './src/queries'; export { getUserTenantsPermissions } from './src/queries'; /* Hooks */ -export { useUserTenantPermissions } from './src/hooks'; +export { useUserSelfTenantPermissions } from './src/hooks'; /* misc */ export { supportedLocales } from './src/loginServices'; diff --git a/src/hooks/index.js b/src/hooks/index.js index c80c7656c..70c0af475 100644 --- a/src/hooks/index.js +++ b/src/hooks/index.js @@ -1,2 +1 @@ -export { default as useUserTenantPermissions } from './useUserTenantPermissions'; export { default as useUserSelfTenantPermissions } from './useUserSelfTenantPermissions'; diff --git a/src/hooks/useUserSelfTenantPermissions.js b/src/hooks/useUserSelfTenantPermissions.js index 240f49470..4deadfcad 100644 --- a/src/hooks/useUserSelfTenantPermissions.js +++ b/src/hooks/useUserSelfTenantPermissions.js @@ -19,6 +19,8 @@ const useUserSelfTenantPermissions = ( }); const [namespace] = useNamespace({ key: 'user-self-permissions' }); + const permPath = stripes.hasInterface('users-keycloak') ? 'users-keycloak' : 'bl-users'; + const { isFetching, isFetched, @@ -28,12 +30,11 @@ const useUserSelfTenantPermissions = ( [namespace, tenantId], ({ signal }) => { return api.get( - 'users-keycloak/_self', + `${permPath}/_self?expandPermissions=true`, { signal }, ).json(); }, { - enabled: Boolean(tenantId) && stripes.hasInterface('users-keycloak'), keepPreviousData: true, ...options, }, diff --git a/src/hooks/useUserSelfTenantPermissions.test.js b/src/hooks/useUserSelfTenantPermissions.test.js index 57808bdc1..6429b691b 100644 --- a/src/hooks/useUserSelfTenantPermissions.test.js +++ b/src/hooks/useUserSelfTenantPermissions.test.js @@ -60,6 +60,6 @@ describe('useUserSelfTenantPermissions', () => { await waitFor(() => !result.current.isLoading); expect(setHeaderMock).toHaveBeenCalledWith('X-Okapi-Tenant', options.tenantId); - expect(getMock).toHaveBeenCalledWith('users-keycloak/_self', expect.objectContaining({})); + expect(getMock).toHaveBeenCalledWith('users-keycloak/_self?ex', expect.objectContaining({})); }); }); diff --git a/src/hooks/useUserTenantPermissionNames.js b/src/hooks/useUserTenantPermissionNames.js deleted file mode 100644 index ee538da92..000000000 --- a/src/hooks/useUserTenantPermissionNames.js +++ /dev/null @@ -1,59 +0,0 @@ -import { useQuery } from 'react-query'; - -import { useStripes } from '../StripesContext'; -import { useNamespace } from '../components'; -import useOkapiKy from '../useOkapiKy'; - -const INITIAL_DATA = []; - -const useUserTenantPermissionNames = ( - { userId, 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 searchParams = { - full: 'true', - indexField: 'userId', - }; - - const { - isFetching, - isFetched, - isLoading, - data = {}, - } = useQuery( - [namespace, userId, tenantId], - ({ signal }) => { - return api.get( - `perms/users/${userId}/permissions`, - { - searchParams, - signal, - }, - ).json(); - }, - { - enabled: Boolean(userId && tenantId) && !stripes.hasInterface('roles'), - keepPreviousData: true, - ...options, - }, - ); - - return ({ - isFetching, - isFetched, - isLoading, - userPermissions: data.permissionNames || INITIAL_DATA, - totalRecords: data.totalRecords, - }); -}; - -export default useUserTenantPermissionNames; diff --git a/src/hooks/useUserTenantPermissionNames.test.js b/src/hooks/useUserTenantPermissionNames.test.js deleted file mode 100644 index cc15aecda..000000000 --- a/src/hooks/useUserTenantPermissionNames.test.js +++ /dev/null @@ -1,72 +0,0 @@ -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 }) => ( - - {children} - -); - -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({})); - }); -}); diff --git a/src/hooks/useUserTenantPermissions.js b/src/hooks/useUserTenantPermissions.js deleted file mode 100644 index 71b9004b9..000000000 --- a/src/hooks/useUserTenantPermissions.js +++ /dev/null @@ -1,42 +0,0 @@ -import { useStripes } from '../StripesContext'; -import useUserTenantPermissionNames from './useUserTenantPermissionNames'; -import useUserTenantRoles from './useUserTenantRoles'; - -const useUserTenantPermissions = ( - { tenantId, userId }, - options = {}, -) => { - const stripes = useStripes(); - - const { - isFetching: isPermissionsFetching, - isFetched: isPermissionsFetched, - isLoading: isPermissionsLoading, - userPermissions: permissionsData, - totalRecords: permissionsTotalRecords - } = useUserTenantPermissionNames({ tenantId, userId }, options); - - const { - isFetching: isRolesFetching, - isFetched: isRolesFetched, - isLoading: isRolesLoading, - userPermissions:userRolesData, - totalRecords: userRolesTotalRecords - } = useUserTenantRoles({ tenantId, userId }, options); - - const isFetching = stripes.hasInterface('roles') ? isRolesFetching : isPermissionsFetching; - const isFetched = stripes.hasInterface('roles') ? isRolesFetched : isPermissionsFetched; - const isLoading = stripes.hasInterface('roles') ? isRolesLoading : isPermissionsLoading; - const userPermissions = stripes.hasInterface('roles') ? userRolesData : permissionsData; - const totalRecords = stripes.hasInterface('roles') ? userRolesTotalRecords : permissionsTotalRecords; - - return ({ - isFetching, - isFetched, - isLoading, - userPermissions, - totalRecords - }); -}; - -export default useUserTenantPermissions; diff --git a/src/hooks/useUserTenantPermissions.test.js b/src/hooks/useUserTenantPermissions.test.js deleted file mode 100644 index 681af0cee..000000000 --- a/src/hooks/useUserTenantPermissions.test.js +++ /dev/null @@ -1,85 +0,0 @@ -import { renderHook } from '@folio/jest-config-stripes/testing-library/react'; -import { useStripes } from '../StripesContext'; -import useUserTenantPermissionNames from './useUserTenantPermissionNames'; -import useUserTenantPermissions from './useUserTenantPermissions'; -import useUserTenantRoles from './useUserTenantRoles'; - -jest.mock('../StripesContext'); -jest.mock('./useUserTenantRoles'); -jest.mock('./useUserTenantPermissionNames'); - -describe('useUserTenantPermissions', () => { - const tenantId = 'tenant-id'; - const options = {}; - - beforeEach(() => { - useStripes.mockReturnValue({ - hasInterface: jest.fn(), - user:{ - user: { - id: 'userId' - } - } - }); - }); - - it('should return _self permissions data when "roles" interface is present', () => { - useStripes().hasInterface.mockReturnValue(true); - - useUserTenantRoles.mockReturnValue({ - isFetching: true, - isFetched: true, - isLoading: true, - userPermissions: ['self'], - totalRecords: 1 - }); - - useUserTenantPermissionNames.mockReturnValue({ - isFetching: false, - isFetched: false, - isLoading: false, - userPermissions: ['permission name'], - totalRecords: 1 - }); - - const { result } = renderHook(() => useUserTenantPermissions({ tenantId }, options)); - - expect(result.current).toStrictEqual({ - isFetching: true, - isFetched: true, - isLoading: true, - userPermissions: ['self'], - totalRecords: 1 - }); - }); - - it('should return tenant permissions data when "roles" interface is NOT present', () => { - useStripes().hasInterface.mockReturnValue(false); - - useUserTenantRoles.mockReturnValue({ - isFetching: true, - isFetched: true, - isLoading: true, - userPermissions: ['self'], - totalRecords: 1 - }); - - useUserTenantPermissionNames.mockReturnValue({ - isFetching: false, - isFetched: false, - isLoading: false, - userPermissions: ['permission name'], - totalRecords: 1 - }); - - const { result } = renderHook(() => useUserTenantPermissions({ tenantId }, options)); - - expect(result.current).toStrictEqual({ - isFetching: false, - isFetched: false, - isLoading: false, - userPermissions: ['permission name'], - totalRecords: 1 - }); - }); -}); diff --git a/src/hooks/useUserTenantRoles.js b/src/hooks/useUserTenantRoles.js deleted file mode 100644 index d5cc09e0c..000000000 --- a/src/hooks/useUserTenantRoles.js +++ /dev/null @@ -1,39 +0,0 @@ -import { useQuery } from 'react-query'; -import { useStripes } from '../StripesContext'; -import useOkapiKy from '../useOkapiKy'; -import { useNamespace } from '../components'; - -const INITIAL_DATA = []; - -function useUserTenantRoles({ userId, tenantId }, options) { - const stripes = useStripes(); - - const searchParams = { - limit: stripes.config.maxUnpagedResourceCount, - query: `userId==${userId}`, - }; - const ky = useOkapiKy(); - const api = ky.extend({ - hooks: { - beforeRequest: [(req) => req.headers.set('X-Okapi-Tenant', tenantId)] - } - }); - const [namespace] = useNamespace({ key: 'user-roles' }); - - const { data, isLoading, isFetched, isFetching } = useQuery([namespace, userId], () => { - return api.get( - 'roles/users', { searchParams }, - ) - .json(); - }, { enabled: !!userId && !!tenantId && stripes.hasInterface('roles'), ...options }); - - return { - isFetching, - isFetched, - isLoading, - userPermissions: data?.userRoles || INITIAL_DATA, - totalRecords: data?.totalRecords || 0 - }; -} - -export default useUserTenantRoles; diff --git a/src/hooks/useUserTenantRoles.test.js b/src/hooks/useUserTenantRoles.test.js deleted file mode 100644 index 03d891c81..000000000 --- a/src/hooks/useUserTenantRoles.test.js +++ /dev/null @@ -1,76 +0,0 @@ -import { renderHook, waitFor } from '@folio/jest-config-stripes/testing-library/react'; -import { - QueryClient, - QueryClientProvider, -} from 'react-query'; - -import useUserTenantRoles from './useUserTenantRoles'; -import useOkapiKy from '../useOkapiKy'; - -jest.mock('../useOkapiKy'); -jest.mock('../components', () => ({ - useNamespace: () => ([]), -})); -jest.mock('../StripesContext', () => ({ - useStripes: () => ({ - hasInterface: () => true, - config: { - maxUnpagedResourceCount: 2000 - } - }), -})); - -const queryClient = new QueryClient(); - -// eslint-disable-next-line react/prop-types -const wrapper = ({ children }) => ( - - {children} - -); - -const response = { - data: { - userRoles: ['role1', 'role2'], - totalRecords: 2, - } -}; - -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 roles for specified tenant', async () => { - const options = { - userId: 'superUserId', - tenantId: 'tenantId', - }; - const { result } = renderHook(() => useUserTenantRoles(options), { wrapper }); - - await waitFor(() => !result.current.isLoading); - - expect(setHeaderMock).toHaveBeenCalledWith('X-Okapi-Tenant', options.tenantId); - expect(getMock).toHaveBeenCalledWith('roles/users', { - searchParams: { - 'limit':2000, - query: 'userId==superUserId' - } - }); - }); -}); From ec708e30c04e7afd2d6c8599a1355a0b29462a8f Mon Sep 17 00:00:00 2001 From: aidynoJ Date: Wed, 13 Nov 2024 18:00:01 +0500 Subject: [PATCH 6/9] fix test --- src/hooks/useUserSelfTenantPermissions.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useUserSelfTenantPermissions.test.js b/src/hooks/useUserSelfTenantPermissions.test.js index 6429b691b..c2876a5dc 100644 --- a/src/hooks/useUserSelfTenantPermissions.test.js +++ b/src/hooks/useUserSelfTenantPermissions.test.js @@ -60,6 +60,6 @@ describe('useUserSelfTenantPermissions', () => { await waitFor(() => !result.current.isLoading); expect(setHeaderMock).toHaveBeenCalledWith('X-Okapi-Tenant', options.tenantId); - expect(getMock).toHaveBeenCalledWith('users-keycloak/_self?ex', expect.objectContaining({})); + expect(getMock).toHaveBeenCalledWith('users-keycloak/_self?expandPermissions=true', expect.objectContaining({})); }); }); From ed8eabcf6303065be4003ed74b4c79a306bec12d Mon Sep 17 00:00:00 2001 From: aidynoJ Date: Wed, 13 Nov 2024 18:15:35 +0500 Subject: [PATCH 7/9] changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87da01c48..1283ad170 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ * Conditionally use `/users-keycloak/_self` endpoint when `users-keycloak` interface is present. Refs STCOR-835. * Wait longer before declaring a rotation request to be stale. Refs STCOR-895. * Send the stored central tenant name in the header on logout. Refs STCOR-900. -* Add userId parameter to useUserTenantPermissions hook. Refs STCOR-905. +* Conditionally use `/users-keycloak/_self` endpoint when `users-keycloak` interface is present and `bl-users` if not in useUserSelfTenantPermissions. Refs STCOR-905. ## [10.2.0](https://github.com/folio-org/stripes-core/tree/v10.2.0) (2024-10-11) [Full Changelog](https://github.com/folio-org/stripes-core/compare/v10.1.1...v10.2.0) From 3acf9564fa40a3290d9584e6d428c8974a11dccd Mon Sep 17 00:00:00 2001 From: aidynoJ Date: Wed, 13 Nov 2024 18:19:34 +0500 Subject: [PATCH 8/9] rephrase changelog record --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1283ad170..8adbbf654 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ * Conditionally use `/users-keycloak/_self` endpoint when `users-keycloak` interface is present. Refs STCOR-835. * Wait longer before declaring a rotation request to be stale. Refs STCOR-895. * Send the stored central tenant name in the header on logout. Refs STCOR-900. -* Conditionally use `/users-keycloak/_self` endpoint when `users-keycloak` interface is present and `bl-users` if not in useUserSelfTenantPermissions. Refs STCOR-905. +* Use the `users-keycloak/_self` endpoint conditionally when the `users-keycloak` interface is present; otherwise, use `bl-users/_self` within `useUserSelfTenantPermissions`. Refs STCOR-905. ## [10.2.0](https://github.com/folio-org/stripes-core/tree/v10.2.0) (2024-10-11) [Full Changelog](https://github.com/folio-org/stripes-core/compare/v10.1.1...v10.2.0) From 1ba21b4fbc66cc7f9c577ed3f003958037c6b7b6 Mon Sep 17 00:00:00 2001 From: aidynoJ Date: Thu, 14 Nov 2024 17:27:17 +0500 Subject: [PATCH 9/9] rename to useUserTenantPermissions --- CHANGELOG.md | 2 +- index.js | 2 +- src/hooks/index.js | 2 +- ...SelfTenantPermissions.js => useUserTenantPermissions.js} | 4 ++-- ...Permissions.test.js => useUserTenantPermissions.test.js} | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) rename src/hooks/{useUserSelfTenantPermissions.js => useUserTenantPermissions.js} (92%) rename src/hooks/{useUserSelfTenantPermissions.test.js => useUserTenantPermissions.test.js} (87%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8adbbf654..1c3b82899 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ * Conditionally use `/users-keycloak/_self` endpoint when `users-keycloak` interface is present. Refs STCOR-835. * Wait longer before declaring a rotation request to be stale. Refs STCOR-895. * Send the stored central tenant name in the header on logout. Refs STCOR-900. -* Use the `users-keycloak/_self` endpoint conditionally when the `users-keycloak` interface is present; otherwise, use `bl-users/_self` within `useUserSelfTenantPermissions`. Refs STCOR-905. +* Use the `users-keycloak/_self` endpoint conditionally when the `users-keycloak` interface is present; otherwise, use `bl-users/_self` within `useUserTenantPermissions`. Refs STCOR-905. ## [10.2.0](https://github.com/folio-org/stripes-core/tree/v10.2.0) (2024-10-11) [Full Changelog](https://github.com/folio-org/stripes-core/compare/v10.1.1...v10.2.0) diff --git a/index.js b/index.js index cb7a94d2c..67fd4d1d0 100644 --- a/index.js +++ b/index.js @@ -40,7 +40,7 @@ export { useChunkedCQLFetch } from './src/queries'; export { getUserTenantsPermissions } from './src/queries'; /* Hooks */ -export { useUserSelfTenantPermissions } from './src/hooks'; +export { useUserTenantPermissions } from './src/hooks'; /* misc */ export { supportedLocales } from './src/loginServices'; diff --git a/src/hooks/index.js b/src/hooks/index.js index 70c0af475..8a889a1b9 100644 --- a/src/hooks/index.js +++ b/src/hooks/index.js @@ -1 +1 @@ -export { default as useUserSelfTenantPermissions } from './useUserSelfTenantPermissions'; +export { default as useUserTenantPermissions } from './useUserTenantPermissions'; // eslint-disable-line import/prefer-default-export diff --git a/src/hooks/useUserSelfTenantPermissions.js b/src/hooks/useUserTenantPermissions.js similarity index 92% rename from src/hooks/useUserSelfTenantPermissions.js rename to src/hooks/useUserTenantPermissions.js index 4deadfcad..91b5a503e 100644 --- a/src/hooks/useUserSelfTenantPermissions.js +++ b/src/hooks/useUserTenantPermissions.js @@ -6,7 +6,7 @@ import useOkapiKy from '../useOkapiKy'; const INITIAL_DATA = []; -const useUserSelfTenantPermissions = ( +const useUserTenantPermissions = ( { tenantId }, options = {}, ) => { @@ -49,4 +49,4 @@ const useUserSelfTenantPermissions = ( }); }; -export default useUserSelfTenantPermissions; +export default useUserTenantPermissions; diff --git a/src/hooks/useUserSelfTenantPermissions.test.js b/src/hooks/useUserTenantPermissions.test.js similarity index 87% rename from src/hooks/useUserSelfTenantPermissions.test.js rename to src/hooks/useUserTenantPermissions.test.js index c2876a5dc..18be2f44f 100644 --- a/src/hooks/useUserSelfTenantPermissions.test.js +++ b/src/hooks/useUserTenantPermissions.test.js @@ -5,7 +5,7 @@ import { } from 'react-query'; import permissions from 'fixtures/permissions'; -import useUserSelfTenantPermissions from './useUserSelfTenantPermissions'; +import useUserTenantPermissions from './useUserTenantPermissions'; import useOkapiKy from '../useOkapiKy'; jest.mock('../useOkapiKy'); @@ -31,7 +31,7 @@ const response = { permissions: { permissions }, }; -describe('useUserSelfTenantPermissions', () => { +describe('useUserTenantPermissions', () => { const getMock = jest.fn(() => ({ json: () => Promise.resolve(response), })); @@ -55,7 +55,7 @@ describe('useUserSelfTenantPermissions', () => { const options = { tenantId: 'tenantId', }; - const { result } = renderHook(() => useUserSelfTenantPermissions(options), { wrapper }); + const { result } = renderHook(() => useUserTenantPermissions(options), { wrapper }); await waitFor(() => !result.current.isLoading);