Skip to content

Commit

Permalink
restrict save on invalid url n update test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
manvendra-s-rathore committed Apr 24, 2024
1 parent 0256ecd commit d21e191
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 21 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* Fix incorrect translation key having count-disagreements in Pay fees/fines modal in Fees/Fines Page. Refs UIU-1097.
* Trim input values and delete properties with empty string when user record save. Refs UIU-2049.
* Update username field validation to trim leading and trailing spaces. Refs UIU-3099.
* Handle invalid image URLs when uploading profile photo via External URL. Refs UIU-3080.

## [10.1.0](https://github.com/folio-org/ui-users/tree/v10.1.0) (2024-03-20)
[Full Changelog](https://github.com/folio-org/ui-users/compare/v10.0.4...v10.1.0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
TextField,
} from '@folio/stripes/components';
import { FormattedMessage } from 'react-intl';
import { isAValidURL } from '../../../../util';
import { isAValidURL, isAValidImageUrl } from '../../../../util';

const ExternalLinkModal = ({
open,
Expand All @@ -33,46 +33,37 @@ const ExternalLinkModal = ({
if (inputValue) {
setDisabled(previousInputValue.current === inputValue);
setExternalURLValidityError(null);
} else {
setDisabled(true);
}
}, [inputValue]);

const handleSave = () => {
onSave(inputValue);
const handleSave = async () => {
const isValidImgURL = await isAValidImageUrl(inputValue);
if (isValidImgURL) {
onSave(inputValue);
}
};

const handleInputChange = (e) => {
previousInputValue.current = inputValue;
setInputValue(e.target.value);
};

async function isValidImageUrl(url) {
try {
const response = await fetch(url);
if (response.ok) {
const contentType = response.headers.get('content-type');
return contentType && contentType.startsWith('image/');
} else {
return false;
}
} catch (e) {
return false;
}
}

const handleBlur = async () => {
if (!inputValue || !isAValidURL(inputValue)) {
setExternalURLValidityError(<FormattedMessage id="ui-users.information.profilePicture.externalLink.modal.externalURL.invalidURLErrorMessage" />);
setDisabled(true);
return;
}

const isValidImgURL = await isValidImageUrl(inputValue);
const isValidImgURL = await isAValidImageUrl(inputValue);
if (!isValidImgURL) {
setExternalURLValidityError(<FormattedMessage id="ui-users.information.profilePicture.externalLink.modal.externalURL.invalidImageURLErrorMessage" />);
setDisabled(true);
return;
}

setExternalURLValidityError(null);
setDisabled(false);
};

const renderModalFooter = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
} from '@folio/jest-config-stripes/testing-library/react';
import userEvent from '@folio/jest-config-stripes/testing-library/user-event';

import { isAValidURL } from '../../../../util';
import { isAValidURL, isAValidImageUrl } from '../../../../util';

import '../../../../../../test/jest/__mock__';

Expand Down Expand Up @@ -43,6 +43,7 @@ describe('ExternalLinkModal', () => {

beforeEach(() => {
isAValidURL.mockReset();
isAValidImageUrl.mockReset();
renderExternalLinkModal(props);
});

Expand All @@ -53,6 +54,7 @@ describe('ExternalLinkModal', () => {
expect(screen.getByText('ui-users.information.profilePicture.externalLink.modal.externalURL')).toBeInTheDocument();
});
it('should call onSave', async () => {
isAValidImageUrl.mockImplementationOnce(() => true);
const saveButton = screen.getByRole('button', { name: 'ui-users.save' });
const inputElement = screen.getByLabelText('ui-users.information.profilePicture.externalLink.modal.externalURL');

Expand Down
11 changes: 11 additions & 0 deletions src/components/util/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,14 @@ export const isAValidURL = (str) => {
return URL.canParse(str);
};

export const isAValidImageUrl = async (url) => {
try {
const response = await fetch(url);
if (!response.ok) return false;

const contentType = response.headers.get('content-type');
return contentType && contentType.startsWith('image/');
} catch (e) {
return false;
}
};

0 comments on commit d21e191

Please sign in to comment.