21099 update filename validation with #
This commit is contained in:
@@ -1042,7 +1042,9 @@ export const RenderFileUpload = (field) => {
|
||||
});
|
||||
};
|
||||
|
||||
const [errorMessage, setErrorMessage] = useState(null);
|
||||
const [rejectedFiles, setRejectedFiles] = useState([]); // Store rejected files
|
||||
|
||||
const [completedUploadFiles, setCompletedUploadFiles] = useState(false);
|
||||
const [uploadCountMessage, setUploadCountMessage] = useState("");
|
||||
|
||||
@@ -1060,6 +1062,15 @@ export const RenderFileUpload = (field) => {
|
||||
"myrepresentations:fileupload-file-error-invalid-type-label"
|
||||
)}`;
|
||||
}
|
||||
|
||||
if (error.code === "filename-invalid-chars") {
|
||||
return (
|
||||
error.message ||
|
||||
`${file.name} ${t(
|
||||
"newappeal:new-appeal-fileupload-file-error-invalid-filename-label"
|
||||
)}`
|
||||
);
|
||||
}
|
||||
return `${file.name} ${t(
|
||||
"myrepresentations:fileupload-file-error-invalid-label"
|
||||
)}`;
|
||||
@@ -1076,6 +1087,44 @@ export const RenderFileUpload = (field) => {
|
||||
setRejectedFiles([]); // Clear any previously rejected file errorsss
|
||||
};
|
||||
|
||||
const FILENAME_ALLOWED = /^[A-Za-z0-9 ._\-()]+$/;
|
||||
|
||||
const validateFilename = (file, t) => {
|
||||
const name = file.name;
|
||||
|
||||
// block #
|
||||
if (name.includes("#")) {
|
||||
return {
|
||||
code: "filename-invalid-chars",
|
||||
message: `${name} ${t(
|
||||
"myrepresentations:fileupload-file-error-invalid-filename-label"
|
||||
)}`,
|
||||
};
|
||||
}
|
||||
|
||||
// broader blocklist (optional but recommended)
|
||||
if (!FILENAME_ALLOWED.test(name)) {
|
||||
return {
|
||||
code: "filename-invalid-chars",
|
||||
message: `${name} ${t(
|
||||
"myrepresentations:fileupload-file-error-invalid-filename-label"
|
||||
)}`,
|
||||
};
|
||||
}
|
||||
|
||||
// block characters < > : " / \ | ? *
|
||||
if (/[<>:"/\\|?*]/.test(name)) {
|
||||
return {
|
||||
code: "filename-invalid-chars",
|
||||
message: `${name} ${t(
|
||||
"myrepresentations:fileupload-file-error-invalid-filename-label"
|
||||
)}`,
|
||||
};
|
||||
}
|
||||
|
||||
return null; // valid
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dropzone
|
||||
@@ -1091,9 +1140,27 @@ export const RenderFileUpload = (field) => {
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
|
||||
[".xlsx"],
|
||||
}}
|
||||
onDrop={(filesToUpload, e) => {
|
||||
validator={(file) => validateFilename(file, t)}
|
||||
onDrop={(acceptedFiles, fileRejections, e) => {
|
||||
// build + display rejected messages (ALWAYS, even if some accepted)
|
||||
if (fileRejections?.length) {
|
||||
handleDropRejected(fileRejections);
|
||||
} else {
|
||||
// only clear rejections when nothing was rejected on this drop
|
||||
setRejectedFiles([]);
|
||||
setErrorMessage(null);
|
||||
}
|
||||
|
||||
// if nothing accepted, stop (prevents showing only "uploading" when all invalid)
|
||||
if (!acceptedFiles || acceptedFiles.length === 0) {
|
||||
setCompletedUploadFiles(true); // optional: depends on your UX
|
||||
setUploadCountMessage(0);
|
||||
return;
|
||||
}
|
||||
|
||||
setCompletedUploadFiles(false);
|
||||
const renamedAcceptedFiles = filesToUpload.map(
|
||||
|
||||
const renamedAcceptedFiles = acceptedFiles.map(
|
||||
(file) =>
|
||||
new File(
|
||||
[file],
|
||||
@@ -1115,7 +1182,16 @@ export const RenderFileUpload = (field) => {
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
field.input.onChange(renamedAcceptedFiles);
|
||||
|
||||
if (typeof field.setFileCount === "function") {
|
||||
field.setFileCount(
|
||||
(field.uploadCount || 0) +
|
||||
renamedAcceptedFiles.length
|
||||
);
|
||||
}
|
||||
|
||||
setUploadCountMessage(renamedAcceptedFiles.length);
|
||||
|
||||
uploadSingleFile(
|
||||
@@ -1196,8 +1272,6 @@ export const RenderFileUpload = (field) => {
|
||||
});
|
||||
});
|
||||
}}
|
||||
onDropRejected={handleDropRejected}
|
||||
onDropAccepted={handleDropAccepted}
|
||||
>
|
||||
{({ getRootProps, getInputProps }) => (
|
||||
<>
|
||||
@@ -1224,7 +1298,7 @@ export const RenderFileUpload = (field) => {
|
||||
</>
|
||||
)}
|
||||
</Dropzone>
|
||||
{rejectedFiles.length > 0 && completedUploadFiles == true && (
|
||||
{rejectedFiles.length > 0 && (
|
||||
<div
|
||||
style={{ color: "red", marginTop: "10px" }}
|
||||
className="govuk-body govuk-!-font-size-14 "
|
||||
|
||||
Reference in New Issue
Block a user