Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UIIN-2784: Set central tenant id in the request when Member tenant deletes a shared record #2416

Merged
merged 11 commits into from
Mar 25, 2024
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
## [10.0.1] (IN PROGRESS)

* Keep query and results list when switching Browse options. Refs UIIN-2802.
* Set central tenant id in the request when Member tenant deletes a shared record. Fixes UIIN-2784.

## [11.0.0](https://github.com/folio-org/ui-inventory/tree/v11.0.0) (2024-03-21)
[Full Changelog](https://github.com/folio-org/ui-inventory/compare/v10.0.11...v11.0.0)
Expand Down
20 changes: 7 additions & 13 deletions src/ViewInstance.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
isInstanceShadowCopy,
isMARCSource,
getLinkedAuthorityIds,
setRecordForDeletion,
} from './utils';
import {
CONSORTIUM_PREFIX,
Expand Down Expand Up @@ -169,14 +170,6 @@ class ViewInstance extends React.Component {
accumulate: true,
throwErrors: false,
},
setForDeletion: {
type: 'okapi',
throwErrors: false,
accumulate: true,
DELETE: {
path: 'inventory/instances/:{id}/mark-deleted',
},
},
authorities: {
type: 'okapi',
path: 'authority-storage/authorities',
Expand Down Expand Up @@ -587,15 +580,19 @@ class ViewInstance extends React.Component {

handleSetForDeletion = () => {
const {
mutator,
okapi,
isShared,
centralTenantId,
refetchInstance,
selectedInstance: {
title: instanceTitle,
id,
source,
},
} = this.props;
const tenantId = isShared && !isInstanceShadowCopy(source) ? centralTenantId : okapi.tenant;

mutator.setForDeletion.DELETE(id)
setRecordForDeletion(okapi, id, tenantId)
.then(async () => {
this.handleCloseSetForDeletionModal();

Expand Down Expand Up @@ -1207,9 +1204,6 @@ ViewInstance.propTypes = {
POST: PropTypes.func.isRequired,
GET: PropTypes.func.isRequired,
}).isRequired,
setForDeletion: PropTypes.shape({
DELETE: PropTypes.func.isRequired,
}).isRequired,
authorities: PropTypes.shape({
GET: PropTypes.func.isRequired,
}).isRequired,
Expand Down
15 changes: 12 additions & 3 deletions src/ViewInstance.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ const spyOncollapseAllSections = jest.spyOn(require('@folio/stripes/components')
const spyOnexpandAllSections = jest.spyOn(require('@folio/stripes/components'), 'expandAllSections');

const spyOnGetUserTenantsPermissions = jest.spyOn(utils, 'getUserTenantsPermissions');
const spyOnSetRecordForDeletion = jest.spyOn(utils, 'setRecordForDeletion');

const location = {
pathname: '/testPathName',
Expand Down Expand Up @@ -1117,20 +1118,28 @@ describe('ViewInstance', () => {
fireEvent.click(screen.getByText('Set record for deletion'));
fireEvent.click(screen.getByText('Confirm'));

expect(defaultProp.mutator.setForDeletion.DELETE).toHaveBeenCalledWith(defaultProp.selectedInstance.id);
expect(spyOnSetRecordForDeletion).toHaveBeenCalledWith(
{ tenant: defaultProp.okapi.tenant },
defaultProp.selectedInstance.id,
defaultProp.okapi.tenant,
);
expect(screen.queryByText(`${defaultProp.selectedInstance.title} has been set for deletion`)).toBeDefined();
});

describe('when there\'s an error', () => {
it('should throw an error with id of the instance and show error message', async () => {
defaultProp.mutator.setForDeletion.DELETE.mockRejectedValueOnce();
global.fetch.mockRejectedValueOnce({ ok: false });

renderViewInstance();

fireEvent.click(screen.getByText('Set record for deletion'));
fireEvent.click(screen.getByText('Confirm'));

expect(defaultProp.mutator.setForDeletion.DELETE).toHaveBeenCalledWith(defaultProp.selectedInstance.id);
expect(spyOnSetRecordForDeletion).toHaveBeenCalledWith(
{ tenant: defaultProp.okapi.tenant },
defaultProp.selectedInstance.id,
defaultProp.okapi.tenant,
);
expect(screen.queryByText(`${defaultProp.selectedInstance.title} was not set for deletion`)).toBeDefined();
});
});
Expand Down
24 changes: 24 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -886,3 +886,27 @@ export const clearStorage = () => {
removeItem(`${namespace}.${segment}.lastOpenRecord`);
});
};

export const setRecordForDeletion = async (okapi, id, tenantId) => {
const {
url,
token,
} = okapi;
const path = `${url}/inventory/instances/${id}/mark-deleted`;

const response = await fetch(path, {
method: 'DELETE',
headers: {
[OKAPI_TENANT_HEADER]: tenantId,
[CONTENT_TYPE_HEADER]: 'application/json',
...(token && { [OKAPI_TOKEN_HEADER]: token }),
},
credentials: 'include',
});

if (!response.ok) {
throw response;
}

return response;
};
71 changes: 70 additions & 1 deletion src/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,14 @@ import {
validateAlphaNumericField,
getQueryTemplate,
switchAffiliation,
setRecordForDeletion,
} from './utils';
import { browseModeOptions } from './constants';
import {
CONTENT_TYPE_HEADER,
OKAPI_TENANT_HEADER,
OKAPI_TOKEN_HEADER,
browseModeOptions,
} from './constants';

describe('validateRequiredField', () => {
const expectedResult = <FormattedMessage id="ui-inventory.hridHandling.validation.enterValue" />;
Expand Down Expand Up @@ -179,3 +185,66 @@ describe('switchAffiliation', () => {
});
});
});

describe('setRecordForDeletion', () => {
afterEach(() => {
global.fetch.mockClear();
});

afterAll(() => {
delete global.fetch;
});

const instanceId = 'testInstanceId';
const tenantId = 'testTenantId';
const okapi = {
token: 'token',
url: 'url/test',
};

describe('when the request was fulfilled successfuly', () => {
it('should return the appropriate response', () => {
global.fetch = jest.fn().mockReturnValue({ ok: true });

setRecordForDeletion(okapi, instanceId, tenantId);

expect(global.fetch).toHaveBeenCalledWith(
`${okapi.url}/inventory/instances/${instanceId}/mark-deleted`,
{
credentials: 'include',
headers: expect.objectContaining({
[OKAPI_TENANT_HEADER]: tenantId,
[OKAPI_TOKEN_HEADER]: okapi.token,
[CONTENT_TYPE_HEADER]: 'application/json',
}),
method: 'DELETE',
},
);

expect(global.fetch.mock.results[0].value.ok).toBe(true);
});
});

describe('when the request was fulfilled with an error', () => {
it('should the appropriate response', () => {
global.fetch = jest.fn().mockReturnValue({ ok: false });

setRecordForDeletion(okapi, instanceId, tenantId);

expect(global.fetch).toHaveBeenCalledWith(
`${okapi.url}/inventory/instances/${instanceId}/mark-deleted`,
{
credentials: 'include',
headers: expect.objectContaining({
[OKAPI_TENANT_HEADER]: tenantId,
[OKAPI_TOKEN_HEADER]: okapi.token,
[CONTENT_TYPE_HEADER]: 'application/json',
}),
method: 'DELETE',
},
);

expect(global.fetch.mock.results[0].value.ok).toBe(false);
});
});
});
Loading