From 47619a31944b6d95d5f62cfe7e616013a6274666 Mon Sep 17 00:00:00 2001 From: Milos Despotovic Date: Thu, 30 May 2024 14:02:17 -0700 Subject: [PATCH 01/57] redlining.js changes from branch dev-AHMD-2646 --- web/src/components/FOI/Home/Redlining.js | 719 +++++++++++++++++++---- 1 file changed, 610 insertions(+), 109 deletions(-) diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index c3c4eca3a..9068d09bd 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -21,6 +21,7 @@ import IconButton from "@mui/material/IconButton"; import Switch from "@mui/material/Switch"; import Stack from "@mui/material/Stack"; import Typography from "@mui/material/Typography"; +import Grid from '@mui/material/Grid'; import { styled } from "@mui/material/styles"; import { fetchAnnotationsByPagination, @@ -72,6 +73,10 @@ import { getJoinedSections, isObjectNotEmpty, getValidObject, + constructPageFlags, + skipDocument, + skipDuplicateDocument, + skipNRDocument, constructPageFlags } from "./utils"; import { Edit, MultiSelectEdit } from "./Edit"; @@ -107,6 +112,8 @@ const Redlining = React.forwardRef( (state) => state.documents?.requestnumber ); + const allPublicBodies = useAppSelector((state) => state.documents?.allPublicBodies) + document.title = requestnumber + " - FOI Document Reviewer" const pageFlags = useAppSelector((state) => state.documents?.pageFlags); @@ -211,7 +218,7 @@ const Redlining = React.forwardRef( stopLoop = true; return false; //stop loop } else { - // artial Disclosure, Full Disclosure, Withheld in Full, Duplicate, Not Responsive + // Partial Disclosure, Full Disclosure, Withheld in Full, Duplicate, Not Responsive pageFlagArray = pageFlagInfo.pageflag?.filter((flag) => [ pageFlagTypes["Partial Disclosure"], @@ -268,7 +275,7 @@ const Redlining = React.forwardRef( const isValidRedlineDivisionDownload = (divisionid, divisionDocuments) => { let isvalid = false; - for (let divObj of divisionDocuments) { + for (let divObj of divisionDocuments) { if (divObj.divisionid == divisionid) { // enable the Redline for Sign off if a division has only Incompatable files if (divObj?.incompatableList?.length > 0) { @@ -279,8 +286,26 @@ const Redlining = React.forwardRef( else { for (let doc of divObj.documentlist) { for (const flagInfo of doc.pageFlag) { + if (modalFor == "consult") { + for (let consult of doc.consult) { + if (consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) { + if ( + (flagInfo.flagid !== pageFlagTypes["Consult"] && + flagInfo.flagid !== pageFlagTypes["Duplicate"] && flagInfo.flagid !== pageFlagTypes["Not Responsive"]) || + ( + (includeDuplicatePages && flagInfo.flagid === pageFlagTypes["Duplicate"]) || + (includeNRPages && flagInfo.flagid === pageFlagTypes["Not Responsive"]) + ) + ) { + if(isvalid == false) { + isvalid = true; + } + } + } + } + } // Added condition to handle Duplicate/NR clicked for Redline for Sign off Modal - if ( + else if ( (flagInfo.flagid != pageFlagTypes["Duplicate"] && flagInfo.flagid != pageFlagTypes["Not Responsive"]) || ( (includeDuplicatePages && flagInfo.flagid === pageFlagTypes["Duplicate"]) || @@ -296,6 +321,7 @@ const Redlining = React.forwardRef( } } } + console.log(divisionid, isvalid) return isvalid; }; @@ -312,16 +338,19 @@ const Redlining = React.forwardRef( } } setIsDisableNRDuplicate(isDisabled); - if (isDisabled) { - setIncludeNRPages(isDisabled) - setIncludeDuplicatePages(isDisabled); - } + setIncludeNRPages(isDisabled) + setIncludeDuplicatePages(isDisabled); } const [enableSavingRedline, setEnableSavingRedline] = useState(false); const [enableSavingOipcRedline, setEnableSavingOipcRedline] = useState(false) const [enableSavingFinal, setEnableSavingFinal] = useState(false); + const [enableSavingConsults, setEnableSavingConsults] = useState(false); + const [selectedPublicBodyIDs, setSelectedPublicBodyIDs] = useState([]); + const [documentPublicBodies, setDocumentPublicBodies] = useState([]); + const [consultApplyRedactions, setConsultApplyRedactions] = useState(false); + const [filteredComments, setFilteredComments] = useState({}); const [pagesRemoved, setPagesRemoved] = useState([]); @@ -434,6 +463,36 @@ const Redlining = React.forwardRef( menu.appendChild(redlineForSignOffBtn); + const consultPackageButton = document.createElement("button"); + consultPackageButton.textContent = "Consult Public Body"; + consultPackageButton.id = "consult_package"; + consultPackageButton.className = "consult_package"; + consultPackageButton.style.backgroundColor = "transparent"; + consultPackageButton.style.border = "none"; + consultPackageButton.style.padding = "8px 8px 8px 10px"; + consultPackageButton.style.cursor = "pointer"; + consultPackageButton.style.alignItems = "left"; + consultPackageButton.disabled = !enableSavingConsults; + consultPackageButton.onclick = () => { + // Save to s3 + setModalFor("consult"); + setModalTitle("Consult Public Body"); + setIncludeDuplicatePages(true); + setIncludeNRPages(true); + setModalMessage([ + "Are you sure want to create a consult? A PDF will be created for each public body selected and your web browser page will automatically refresh", +
, +
, + + Select one or more Ministry you wish to send the selected page(s) to for consult* + , + ]); + setModalButtonLabel("Create Consult"); + setRedlineModalOpen(true); + }; + + menu.appendChild(consultPackageButton); + const finalPackageBtn = document.createElement("button"); finalPackageBtn.textContent = "Final Package for Applicant"; finalPackageBtn.id = "final_package"; @@ -1601,6 +1660,12 @@ const Redlining = React.forwardRef( setEnableSavingFinal( _enableSavingRedline && requestStatus == RequestStates["Response"] ); + //consults validation + const publicBodyList = getPublicBodyList() + setDocumentPublicBodies(publicBodyList) + setEnableSavingConsults( + publicBodyList.length > 0 + ); if (_instance) { //oipc changes - begin const document = _instance.UI.iframeWindow.document; @@ -1621,6 +1686,8 @@ const Redlining = React.forwardRef( document.getElementById("final_package").disabled = !_enableSavingRedline || requestStatus !== RequestStates["Response"]; //oipc changes - end + // conults validation + document.getElementById("consult_package").disabled = !(publicBodyList.length > 0) } }; @@ -2376,6 +2443,7 @@ const Redlining = React.forwardRef( } ); } + setNewRedaction(null) } setEditAnnot(null); }; @@ -2682,23 +2750,58 @@ const Redlining = React.forwardRef( const getDivisionDocumentMappingForRedline = (divisions) => { let newDocList = []; - for (let div of divisions) { - let divDocList = documentList.filter((doc) => - doc.divisions.map((d) => d.divisionid).includes(div.divisionid) - ); - - // sort based on sortorder as the sortorder added based on the LastModified - divDocList = sortBySortOrder(divDocList); - - let incompatableList = incompatibleFiles.filter((doc) => - doc.divisions.map((d) => d.divisionid).includes(div.divisionid) - ); - newDocList.push({ - divisionid: div.divisionid, - divisionname: div.name, - documentlist: divDocList, - incompatableList: incompatableList, - }); + if (modalFor == "redline" || modalFor == "oipcreview") { + for (let div of divisions) { + let divDocList = documentList.filter((doc) => + doc.divisions.map((d) => d.divisionid).includes(div.divisionid) + ); + + // sort based on sortorder as the sortorder added based on the LastModified + divDocList = sortBySortOrder(divDocList); + + let incompatableList = incompatibleFiles.filter((doc) => + doc.divisions.map((d) => d.divisionid).includes(div.divisionid) + ); + newDocList.push({ + divisionid: div.divisionid, + divisionname: div.name, + documentlist: divDocList, + incompatableList: incompatableList, + }); + } + } else if (modalFor == "consult") { + // map documents to publicBodies (Divisions) for consults + for (let publicBodyId of divisions) { + let publicBodyDocList = []; + documentList.forEach((doc) => { + let programareaids = new Set(); + if (doc.consult && doc.consult.length) { + doc.consult.forEach((consult) => { + consult.programareaid.forEach((programareaid) => { + if (programareaid === publicBodyId) { + programareaids.add(programareaid); + } + }) + }); + } + for (let programareaid of programareaids) { + if (programareaid === publicBodyId) { + publicBodyDocList.push({...doc}) + } + } + }) + publicBodyDocList = sortBySortOrder(publicBodyDocList); + + let incompatableList = []; + + const publicBodyInfo = allPublicBodies.find((body) => body.programareaid === publicBodyId) + newDocList.push({ + divisionid: publicBodyId, + divisionname: publicBodyInfo.name, + documentlist: publicBodyDocList, + incompatableList: incompatableList, + }) + } } return newDocList; }; @@ -2725,6 +2828,8 @@ const Redlining = React.forwardRef( } // sort based on sortorder as the sortorder added based on the LastModified prepareRedlinePageMappingByRequest(sortBySortOrder(reqdocuments)); + } else if (modalFor == 'consult') { + prepareRedlinePageMappingByConsult(divisionDocuments); } else { prepareRedlinePageMappingByDivision(divisionDocuments); } @@ -2845,7 +2950,7 @@ const Redlining = React.forwardRef( let duplicateWatermarkPagesEachDiv = []; let NRWatermarksPages = {}; let NRWatermarksPagesEachDiv = []; - for (let divObj of divisionDocuments) { + for (let divObj of divisionDocuments) { divisionCount++; // sort based on sortorder as the sortorder added based on the LastModified for (let doc of sortBySortOrder(divObj.documentlist)) { @@ -2855,6 +2960,18 @@ const Redlining = React.forwardRef( let pageIndex = 1; //gather pages that need to be removed doc.pageFlag.sort((a, b) => a.page - b.page); //sort pageflag by page # + let skipDocumentPages = false; + let skipOnlyDuplicateDocument = false; + let skipOnlyNRDocument = false; + if (!includeDuplicatePages && !includeNRPages) { + skipDocumentPages = skipDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + else if (!includeDuplicatePages) { + skipOnlyDuplicateDocument = skipDuplicateDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + else if (!includeNRPages) { + skipOnlyNRDocument = skipNRDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } //if(isIgnoredDocument(doc, doc['pagecount'], divisionDocuments) == false) { for (const flagInfo of doc.pageFlag) { if (flagInfo.flagid !== pageFlagTypes["Consult"]) { // ignore consult flag to fix bug FOIMOD-3062 @@ -2868,10 +2985,11 @@ const Redlining = React.forwardRef( pagesToRemoveEachDoc.length; } else { pagesToRemoveEachDoc.push(flagInfo.page); - - pagesToRemove.push( - pageIndex + totalPageCountIncludeRemoved - ); + if (!skipDocumentPages && !skipOnlyDuplicateDocument) { + pagesToRemove.push( + pageIndex + totalPageCountIncludeRemoved + ); + } } } else if (flagInfo.flagid == pageFlagTypes["Not Responsive"]) { if(includeNRPages) { @@ -2883,10 +3001,11 @@ const Redlining = React.forwardRef( pagesToRemoveEachDoc.length; } else { pagesToRemoveEachDoc.push(flagInfo.page); - - pagesToRemove.push( - pageIndex + totalPageCountIncludeRemoved - ); + if (!skipDocumentPages && !skipOnlyNRDocument) { + pagesToRemove.push( + pageIndex + totalPageCountIncludeRemoved + ); + } } } else { if (flagInfo.flagid !== pageFlagTypes["Consult"]) { @@ -2905,7 +3024,9 @@ const Redlining = React.forwardRef( totalPageCount += Object.keys( pageMappings[doc.documentid] ).length; - totalPageCountIncludeRemoved += doc.pagecount; + if (!skipDocumentPages) { + totalPageCountIncludeRemoved += doc.pagecount; + } //} } @@ -2933,10 +3054,197 @@ const Redlining = React.forwardRef( }); } + const prepareRedlinePageMappingByConsult = (divisionDocuments) => { + let removepages = {}; + let pageMappings = {}; + let divPageMappings = {}; + let pagesToRemove = []; + let totalPageCount = 0; + let totalPageCountIncludeRemoved = 0; + let duplicateWatermarkPages = {}; + let duplicateWatermarkPagesEachDiv = []; + let NRWatermarksPages = {}; + let NRWatermarksPagesEachDiv = []; + for (let divObj of divisionDocuments) { + // sort based on sortorder as the sortorder added based on the LastModified + for (let doc of sortBySortOrder(divObj.documentlist)) { + if (doc.pagecount > 0) { + let pagesToRemoveEachDoc = []; + pageMappings[doc.documentid] = {}; + let pageIndex = 1; + //gather pages that need to be removed + doc.pageFlag.sort((a, b) => a.page - b.page); //sort pageflag by page # + let skipDocumentPages = false; + let skipOnlyDuplicateDocument = false; + let skipOnlyNRDocument = false; + if (!includeDuplicatePages && !includeNRPages) { + skipDocumentPages = skipDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + else if (!includeDuplicatePages) { + skipOnlyDuplicateDocument = skipDuplicateDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + else if (!includeNRPages) { + skipOnlyNRDocument = skipNRDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + + // for consults, go through all pages + for (const page of doc.pages) { + //find pageflags for this page + const pageFlagsOnPage = doc.pageFlag.filter((pageFlag) => { + return pageFlag.page === page; + }) + const notConsultPageFlagsOnPage = pageFlagsOnPage.filter((pageFlag) => { + return pageFlag.flagid !== pageFlagTypes["Consult"]; + }) + + // if the page has no pageflags, remove it + if (pageFlagsOnPage.length == 0) { + pagesToRemoveEachDoc.push(page); + if (!skipDocumentPages) { + pagesToRemove.push( + pageIndex + totalPageCountIncludeRemoved + ); + } + pageIndex ++; + } + + //differences in pagemapping for consults begin here + //for pages with only consult flags, remove if page doesn't belong to current consult body + if (pageFlagsOnPage.length > 0 && notConsultPageFlagsOnPage.length == 0) { + for (let flagInfo of pageFlagsOnPage) { + let hasConsult = false; + for (let consult of doc.consult) { + if (consult.page == flagInfo.page && consult.programareaid.includes(divObj.divisionid)) { + hasConsult = true; + break; + } + } + if (!hasConsult) { + if (!pagesToRemoveEachDoc.includes(flagInfo.page)) { + pagesToRemoveEachDoc.push(flagInfo.page); + if(!skipDocumentPages) { + delete pageMappings[doc.documentid][flagInfo.page]; + pagesToRemove.push(pageIndex + totalPageCountIncludeRemoved) + } + } + } + } + pageIndex ++; + } + + // if the page does have pageflags, process it + for (let flagInfo of notConsultPageFlagsOnPage) { + if (flagInfo.flagid == pageFlagTypes["Duplicate"]) { + if(includeDuplicatePages) { + duplicateWatermarkPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); + + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } else { + pagesToRemoveEachDoc.push(flagInfo.page); + if (!skipDocumentPages && !skipOnlyDuplicateDocument) { + pagesToRemove.push( + pageIndex + totalPageCountIncludeRemoved + ); + } + } + + } else if (flagInfo.flagid == pageFlagTypes["Not Responsive"]) { + if(includeNRPages) { + NRWatermarksPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); + + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } else { + pagesToRemoveEachDoc.push(flagInfo.page); + if (!skipDocumentPages && !skipOnlyNRDocument) { + pagesToRemove.push( + pageIndex + totalPageCountIncludeRemoved + ); + } + } + } else if (flagInfo.flagid == pageFlagTypes["In Progress"]) { + NRWatermarksPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); + + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } else { + if (flagInfo.flagid !== pageFlagTypes["Consult"]) { + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } + } + + // Check if the page has relevant consult flag, if not remove the page + let hasConsult = false; + for (let consult of doc.consult) { + if (consult.page == flagInfo.page && consult.programareaid.includes(divObj.divisionid)) { + hasConsult = true; + break; + } + } + if (!hasConsult) { + if (!pagesToRemoveEachDoc.includes(flagInfo.page)) { + pagesToRemoveEachDoc.push(flagInfo.page); + if(!skipDocumentPages) { + delete pageMappings[doc.documentid][flagInfo.page]; + pagesToRemove.push(pageIndex + totalPageCountIncludeRemoved) + } + } + } + if (flagInfo.flagid !== pageFlagTypes["Consult"]) { + pageIndex ++; + } + } + } + //End of pageMappingsByConsults + + totalPageCount += Object.keys( + pageMappings[doc.documentid] + ).length; + if (!skipDocumentPages) { + totalPageCountIncludeRemoved += doc.pagecount; + } + } + } + divPageMappings[divObj.divisionid] = pageMappings; + removepages[divObj.divisionid] = pagesToRemove; + duplicateWatermarkPages[divObj.divisionid] = duplicateWatermarkPagesEachDiv; + NRWatermarksPages[divObj.divisionid] = NRWatermarksPagesEachDiv; + pagesToRemove = []; + duplicateWatermarkPagesEachDiv = []; + NRWatermarksPagesEachDiv = []; + totalPageCount = 0; + totalPageCountIncludeRemoved = 0; + pageMappings = {} + } + + setRedlinepageMappings({ + 'divpagemappings': divPageMappings, + 'pagemapping': pageMappings, + 'pagestoremove': removepages + }); + setRedlineWatermarkPageMapping({ + 'duplicatewatermark': duplicateWatermarkPages, + 'NRwatermark': NRWatermarksPages + }); + } + const prepareRedlineIncompatibleMapping = (redlineAPIResponse) => { let divIncompatableMapping = {}; let incompatibleFiles = []; let divCounter = 0; + if (redlineAPIResponse.consultdocumentlist) { + redlineAPIResponse.divdocumentList = redlineAPIResponse.consultdocumentlist + } for (let divObj of redlineAPIResponse.divdocumentList) { divCounter++; @@ -2958,6 +3266,7 @@ const Redlining = React.forwardRef( }); incompatibleFiles = incompatibleFiles.concat(divIncompatableFiles); } + if (divObj.publicBody && !divObj.divisionid) divObj.divisionid = divObj.publicBody; if (redlineAPIResponse.issingleredlinepackage == "Y") { if (divCounter == redlineAPIResponse.divdocumentList.length) { incompatableObj["divisionid"] = "0"; @@ -3066,20 +3375,23 @@ const Redlining = React.forwardRef( let annotationManager = docInstance?.Core.annotationManager; let annotList = await annotationManager.importAnnotations(xfdfString); let sectionStamps = {}; - let annotationpagenumbers = annotationpagemapping(formattedAnnotationXML); - for (const annot of annotList) { - let parentRedaction = annot.getCustomData("parentRedaction"); - if (parentRedaction) { - if (annot.Subject == "Free Text") { - let parentRedactionId = parentRedaction.replace(/"/g, '"').replace(/\\/g, "") - let sections = getAnnotationSections(annot); - if (sections.some(item => item.section === 's. 14')) { + let annotationpagenumbers = annotationpagemapping(formattedAnnotationXML); + for (const annot of annotList) { + let parentRedaction = annot.getCustomData("parentRedaction"); + if (parentRedaction) { + if (annot.Subject == "Free Text") { + let parentRedactionId = parentRedaction.replace(/"/g, '"').replace(/\\/g, "") + let sections = getAnnotationSections(annot); + if (redlineCategory === "oipcreview" && sections.some(item => item.section === 's. 14')) { sectionStamps[parentRedactionId] = annotationpagenumbers[parentRedactionId]; - } + } + if (modalFor == "consult" && sections.some(item => item.section === 'NR')) { + sectionStamps[parentRedactionId] = annotationpagenumbers[parentRedactionId]; + } + } } } - } - return sectionStamps; + return sectionStamps; } const annotationpagemapping = (formattedAnnotationXML) => { @@ -3236,9 +3548,10 @@ const Redlining = React.forwardRef( } const cancelSaveRedlineDoc = () => { - setIncludeDuplicatePages(false); - setIncludeNRPages(false); + disableNRDuplicate(); + setSelectedPublicBodyIDs([]); setRedlineModalOpen(false); + setConsultApplyRedactions(false); }; const saveDoc = () => { @@ -3257,6 +3570,9 @@ const Redlining = React.forwardRef( case "responsepackage": saveResponsePackage(docViewer, annotManager, docInstance); break; + case "consult": + saveRedlineDocument(docInstance, modalFor); + break; default: } setIncludeDuplicatePages(false); @@ -3264,6 +3580,9 @@ const Redlining = React.forwardRef( }; const getzipredlinecategory = (layertype) => { + if (modalFor == "consult") { + return "consultpackage"; + } if (currentLayer.name.toLowerCase() === "oipc") { return layertype === "oipcreview" ? "oipcreviewredline" : "oipcredline"; } @@ -3272,6 +3591,34 @@ const Redlining = React.forwardRef( } /*Redline download & stitching code starts */ + const getPublicBodyList = () => { + let publicBodyIdList = []; + if (documentList?.length > 0) { + for (const doc of documentList) { + if ('pageFlag' in doc) { + for (let pageflag of doc['pageFlag']) { + if ('programareaid' in pageflag) { + for (let programareaid of pageflag['programareaid']) { + publicBodyIdList.push(programareaid) + } + } + } + } + } + const filteredPublicBodyIdList = [...new Set(publicBodyIdList)] + return getPublicBodyObjs(filteredPublicBodyIdList); + } + } + + const getPublicBodyObjs = (publicBodyIDList) => { + const publicBodies = []; + for (const publicBody of allPublicBodies) { + if (publicBodyIDList.includes(publicBody.programareaid)) { + publicBodies.push(publicBody); + } + } + return publicBodies; + } const saveRedlineDocument = async (_instance, layertype) => { toastId.current = toast(`Start saving redline...`, { @@ -3281,7 +3628,13 @@ const Redlining = React.forwardRef( }); const divisionFilesList = [...documentList, ...incompatibleFiles]; - const divisions = getDivisionsForSaveRedline(divisionFilesList); + let divisions; + if (modalFor == "consult") { + //Key consult logic, uses preexisting division reldine logic for consults + divisions = selectedPublicBodyIDs; + } else { + divisions = getDivisionsForSaveRedline(divisionFilesList); + } const divisionDocuments = getDivisionDocumentMappingForRedline(divisions); const documentids = documentList.map((obj) => obj.documentid); getFOIS3DocumentRedlinePreSignedUrl( @@ -3317,17 +3670,52 @@ const Redlining = React.forwardRef( for (let doc of div.documentlist) { docCount++; documentsObjArr.push(doc); - if (docCount == div.documentlist.length) { - if (pageMappedDocs != undefined) { - let divisionsdocpages = Object.values( + let skipDocumentPages = false; + let skipOnlyDuplicateDocument = false; + let skipOnlyNRDocument = false; + if (!includeDuplicatePages && !includeNRPages) { + skipDocumentPages = skipDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + else if (!includeDuplicatePages) { + skipOnlyDuplicateDocument = skipDuplicateDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + else if (!includeNRPages) { + skipOnlyNRDocument = skipNRDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + if (pageMappedDocs != undefined) { + let divisionsdocpages = []; + // for consults, no need to filter by division/consult + if (modalFor == "consult") { + Object.values( + pageMappedDocs.redlineDocIdLookup + ) + .forEach((obj) => { + divisionsdocpages = Object.values( + pageMappedDocs.redlineDocIdLookup + ) + .filter((obj) => { + return obj.docId == doc.documentid; + }) + .map((obj) => { + if (res.issingleredlinepackage == "Y" || (!skipDocumentPages && !skipOnlyDuplicateDocument && !skipOnlyNRDocument)) { + return obj.pageMappings; + } + }); + }) + } else { + divisionsdocpages = Object.values( pageMappedDocs.redlineDocIdLookup ) .filter((obj) => { - return obj.division.includes(div.divisionid); + return obj.division.includes(div.divisionid) && obj.docId == doc.documentid; }) .map((obj) => { - return obj.pageMappings; + if (res.issingleredlinepackage == "Y" || (!skipDocumentPages && !skipOnlyDuplicateDocument && !skipOnlyNRDocument)) { + return obj.pageMappings; + } }); + } + if (divisionsdocpages[0]) { divisionsdocpages.forEach(function (_arr) { _arr.forEach(function (value) { divisionstitchpages.push(value); @@ -3447,7 +3835,9 @@ const Redlining = React.forwardRef( // sort based on sortorder as the sortorder added based on the LastModified let sorteddocs = sortBySortOrder(alldocuments) for (const sorteddoc of sorteddocs) { + if (!sorteddocids.includes(sorteddoc['documentid'])) { sorteddocids.push(sorteddoc['documentid']); + } } return {"sorteddocuments": sorteddocids, "pkgdocuments": summarylist} @@ -3468,6 +3858,8 @@ const Redlining = React.forwardRef( for (const [key, value] of Object.entries(stitchlist)) { divCount++; let docCount = 0; + // added this vopy variable for validating the first document of a division with NR/Duplicate + let docCountCopy = 0; let division = key; let documentlist = stitchlist[key]; if (redlineSinglePkg == "N") { @@ -3483,27 +3875,47 @@ const Redlining = React.forwardRef( } if(documentlist.length > 0) { for (let doc of documentlist) { + let skipDocumentPages = false; + let skipOnlyDuplicateDocument = false; + let skipOnlyNRDocument = false; + if (!includeDuplicatePages && !includeNRPages) { + skipDocumentPages = skipDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + else if (!includeDuplicatePages) { + skipOnlyDuplicateDocument = skipDuplicateDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + else if (!includeNRPages) { + skipOnlyNRDocument = skipNRDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } await _instance.Core.createDocument(doc.s3path_load, { loadAsPDF: true, useDownloader: false, // Added to fix BLANK page issue - }).then(async (docObj) => { - applyRotations(docObj, doc.attributes.rotatedpages) + }).then(async (docObj) => { //if (isIgnoredDocument(doc, docObj.getPageCount(), divisionDocuments) == false) { + docCountCopy++; docCount++; - if (docCount == 1) { + if (docCountCopy == 1) { // Delete pages from the first document const deletedPages = getDeletedPagesBeforeStitching(doc.documentid); if (deletedPages.length > 0) { docObj.removePages(deletedPages); - } - stitchedDocObj = docObj; + } + if (!skipDocumentPages && !skipOnlyDuplicateDocument && !skipOnlyNRDocument) { + stitchedDocObj = docObj; + } + else { + docCountCopy--; + } + } else { - let pageIndexToInsert = stitchedDocObj?.getPageCount() + 1; - await stitchedDocObj.insertPages( - docObj, - doc.pages, - pageIndexToInsert - ); + if (stitchedDocObj && (!skipDocumentPages && !skipOnlyDuplicateDocument && !skipOnlyNRDocument)) { + let pageIndexToInsert = stitchedDocObj?.getPageCount() + 1; + await stitchedDocObj.insertPages( + docObj, + doc.pages, + pageIndexToInsert + ); + } } //} }); @@ -3700,11 +4112,44 @@ const Redlining = React.forwardRef( } }; + const applyRedactionsToRedlinesBySection = async (appliedSectionStamps, PDFNet, stitchObject) => { + let annotationManager = docInstance?.Core.annotationManager; + const rarr = []; + let rects = []; + for (const [key, value] of Object.entries(appliedSectionStamps)) { + let sectionAnnotation = annotationManager.getAnnotationById(key); + if (sectionAnnotation.Subject === "Redact") { + rects = rects.concat( + sectionAnnotation.getQuads().map((q) => { + return { + pageno: appliedSectionStamps[key], + recto: q.toRect(), + vpageno: sectionAnnotation.getPageNumber() + }; + }) + ); + } + } + for (const rect of rects) { + let height = docViewer.getPageHeight(rect.vpageno); + rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(rect.recto.x1,height-rect.recto.y1,rect.recto.x2,height-rect.recto.y2)), false, '')); + } + if (rarr.length > 0) { + const app = {}; + app.redaction_overlay = true; + app.border = false; + app.show_redacted_content_regions = false; + const doc = await stitchObject.getPDFDoc(); + await PDFNet.Redactor.redact(doc, rarr, app); + } + } + useEffect(() => { const StitchAndUploadDocument = async () => { const { PDFNet } = docInstance.Core; const downloadType = "pdf"; let currentDivisionCount = 0; + // keep track of the starting page number for consult packages const divisionCountForToast = Object.keys(redlineStitchObject).length; for (const [key, value] of Object.entries(redlineStitchObject)) { currentDivisionCount++; @@ -3722,7 +4167,7 @@ const Redlining = React.forwardRef( if (stitchObject == null) { triggerRedlineZipper( redlineIncompatabileMappings[divisionid], - redlineStitchInfo[divisionid]["s3path"], + null, // stitchObject == null then no stichedDocPath available divisionCountForToast, redlineSinglePackage ); @@ -3732,17 +4177,18 @@ const Redlining = React.forwardRef( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); - if(redlineCategory !== "oipcreview") { + if(redlineCategory !== "oipcreview" || modalFor == "consult") { await stampPageNumberRedline( - stitchObject, - PDFNet, - redlineStitchInfo[divisionid]["stitchpages"], - redlineSinglePackage + stitchObject, + PDFNet, + redlineStitchInfo[divisionid]["stitchpages"], + redlineSinglePackage ); } if ( redlinepageMappings["pagestoremove"][divisionid] && - redlinepageMappings["pagestoremove"][divisionid].length > 0 + redlinepageMappings["pagestoremove"][divisionid].length > 0 && + stitchObject?.getPageCount() > redlinepageMappings["pagestoremove"][divisionid].length ) { await stitchObject.removePages( redlinepageMappings["pagestoremove"][divisionid] @@ -3767,38 +4213,8 @@ const Redlining = React.forwardRef( //OIPC - Special Block (Redact S.14) : Begin if(redlineCategory === "oipcreview") { - const rarr = []; - let annotationManager = docInstance?.Core.annotationManager; let s14_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - let rects = []; - for (const [key, value] of Object.entries(s14_sectionStamps)) { - let s14annoation = annotationManager.getAnnotationById(key); - if ( s14annoation.Subject === "Redact") { - rects = rects.concat( - s14annoation.getQuads().map((q) => { - return { - pageno: s14_sectionStamps[key], - recto: q.toRect(), - vpageno: s14annoation.getPageNumber() - }; - }) - ); - } - - - } - for (const rect of rects) { - let height = docViewer.getPageHeight(rect.vpageno); - rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(rect.recto.x1,height-rect.recto.y1,rect.recto.x2,height-rect.recto.y2)), false, '')); - } - if (rarr.length > 0) { - const app = {}; - app.redaction_overlay = true; - app.border = false; - app.show_redacted_content_regions = false; - const doc = await stitchObject.getPDFDoc(); - await PDFNet.Redactor.redact(doc, rarr, app); - } + await applyRedactionsToRedlinesBySection(s14_sectionStamps, PDFNet, stitchObject); await stampPageNumberRedline( stitchObject, PDFNet, @@ -3807,8 +4223,15 @@ const Redlining = React.forwardRef( ); } //OIPC - Special Block : End - - + + //Consults - Redactions Block (Redact S.NR) : Start + if(modalFor == "consult") { + if (consultApplyRedactions) { + let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); + await applyRedactionsToRedlinesBySection(nr_sectionStamps, PDFNet, stitchObject); + } + } + //Consults - Redactions Block (Redact S.NR) : End stitchObject .getFileData({ @@ -3984,7 +4407,9 @@ const Redlining = React.forwardRef( let doc = documentViewer.getDocument(); await annotationManager.applyRedactions(); /**must apply redactions before removing pages*/ - await doc.removePages(pagesToRemove); + if (pagesToRemove.length > 0) { + await doc.removePages(pagesToRemove); + } const { PDFNet } = _instance.Core; PDFNet.initialize(); @@ -4095,7 +4520,9 @@ const Redlining = React.forwardRef( // sort based on sortorder as the sortorder added based on the LastModified let sorteddocs = sortBySortOrder(alldocuments) for (const sorteddoc of sorteddocs) { - sorteddocids.push(sorteddoc['documentid']); + if (!sorteddocids.includes(sorteddoc['documentid'])) { + sorteddocids.push(sorteddoc['documentid']); + } } return {"sorteddocuments": sorteddocids, "pkgdocuments": summarylist} } @@ -4163,6 +4590,24 @@ const Redlining = React.forwardRef( const handleIncludeDuplicantePages = (e) => { setIncludeDuplicatePages(e.target.checked); } + + const handleApplyRedactions = (e) => { + setConsultApplyRedactions(e.target.checked); + } + + const handleSelectedPublicBodies = (e) => { + const publicBodyId = parseInt(e.target.value); + if (selectedPublicBodyIDs.includes(publicBodyId)) { + setSelectedPublicBodyIDs((prev) => { + return [...prev.filter(id => id !== publicBodyId)] + }); + } + else { + setSelectedPublicBodyIDs((prev) => { + return [...prev, publicBodyId] + }); + } + } @@ -4288,7 +4733,7 @@ const Redlining = React.forwardRef( initHeight={300} minWidth={600} minHeight={250} - className={"state-change-dialog" + (modalFor == "redline"?" redline-modal":"")} + className={"state-change-dialog" + (modalFor === "redline" ? " redline-modal" : modalFor === "consult" ? " consult-modal" : "")} onRequestClose={cancelRedaction} isOpen={redlineModalOpen} > @@ -4306,7 +4751,7 @@ const Redlining = React.forwardRef( > {modalMessage}

- {modalFor == "redline" && <> + {modalFor === "redline" && <> } + {modalFor === "consult" && + <> + + {documentPublicBodies?.map((publicBody) => { + return (<> + + + + + ) + })} + +
+

More Options:

+ + +
+ + +
+ + + + }
- + + +

{modalTitle}

+ + Close + + +
+ + + + {modalMessage} + {isOverride && <> +

+ + + } +
+
+
+ + {!isOverride && + + } + {isOverride && + + } + + +
); } From e9dbd91979919a2ce43fdebd51444533868a6f7c Mon Sep 17 00:00:00 2001 From: Aparna Date: Mon, 10 Jun 2024 15:31:24 -0700 Subject: [PATCH 07/57] Removed debug codes and updated changes from code review --- api/reviewer_api/services/jobrecordservice.py | 7 +------ api/reviewer_api/services/radactionservice.py | 20 +++++-------------- web/src/components/FOI/Home/Redlining.js | 16 +++------------ 3 files changed, 9 insertions(+), 34 deletions(-) diff --git a/api/reviewer_api/services/jobrecordservice.py b/api/reviewer_api/services/jobrecordservice.py index 863a1e03b..09a74039e 100644 --- a/api/reviewer_api/services/jobrecordservice.py +++ b/api/reviewer_api/services/jobrecordservice.py @@ -141,13 +141,8 @@ def insertfeeoverridereason(self, message, pdfstitchjobid, userid): ) job = PDFStitchJobAttributes.insert(row) return job - - def __getpdfstitchjobattributesbyid(self, requestid): - job = PDFStitchJobAttributes().getpdfstitchjobattributesbyid(requestid) - return job def isbalancefeeoverrodforrequest(self, requestid): - pdfstitchjobattributes= self.__getpdfstitchjobattributesbyid(requestid) + pdfstitchjobattributes= PDFStitchJobAttributes().getpdfstitchjobattributesbyid(requestid) isbalancefeeoverrode= False if pdfstitchjobattributes is None or not pdfstitchjobattributes else True - #print("\nisbalancefeeoverrode:",isbalancefeeoverrode) return isbalancefeeoverrode diff --git a/api/reviewer_api/services/radactionservice.py b/api/reviewer_api/services/radactionservice.py index 27a3b9844..570145bfa 100644 --- a/api/reviewer_api/services/radactionservice.py +++ b/api/reviewer_api/services/radactionservice.py @@ -122,16 +122,12 @@ def triggerdownloadredlinefinalpackage(self, finalpackageschema, userinfo): job = jobrecordservice().insertpdfstitchjobstatus( _jobmessage, userinfo["userid"] ) - print("job:: ",job.message) - print("job-2:: ",job.identifier) if job.success: if finalpackageschema['pdfstitchjobattributes'] is not None: - feeoverridereason= finalpackageschema['pdfstitchjobattributes']['feeoverridereason'] - print("feeoverridereason:",feeoverridereason) - if feeoverridereason is not None and feeoverridereason != '': - feeoverridereasonresult= jobrecordservice().insertfeeoverridereason(finalpackageschema,job.identifier,userinfo["userid"]) - #print("feeoverridereasonresult:",feeoverridereasonresult) - #Add here the reason- comment text and a boolean + if 'feeoverridereason' in finalpackageschema['pdfstitchjobattributes']: + feeoverridereason= finalpackageschema['pdfstitchjobattributes']['feeoverridereason'] + if feeoverridereason is not None and feeoverridereason != '': + jobrecordservice().insertfeeoverridereason(finalpackageschema,job.identifier,userinfo["userid"]) _message = self.__preparemessageforsummaryservice( finalpackageschema, userinfo, job ) @@ -139,17 +135,12 @@ def triggerdownloadredlinefinalpackage(self, finalpackageschema, userinfo): # redline/final package download: prepare message for zipping service def __preparemessageforsummaryservice(self, messageschema, userinfo, job): + feeoverridereason= None pdf_stitch_job_attributes = to_json(messageschema['pdfstitchjobattributes']) - print("pdf_stitch_job_attributes:",pdf_stitch_job_attributes) if pdf_stitch_job_attributes is not None: feeoverridereason= json.loads(pdf_stitch_job_attributes).get("feeoverridereason", None) if feeoverridereason is not None and feeoverridereason != '': feeoverridereason= userinfo["firstname"]+" "+userinfo["lastname"]+" overrode balance outstanding warning for the following reason: "+feeoverridereason - print("feeoverridereason:",feeoverridereason) - else: - feeoverridereason= "" - else: - feeoverridereason= "" _message = { "jobid": job.identifier, "requestid": -1, @@ -167,7 +158,6 @@ def __preparemessageforsummaryservice(self, messageschema, userinfo, job): "redactionlayerid": json.dumps(messageschema["redactionlayerid"]), "feeoverridereason":feeoverridereason } - print("_message:",_message) return _message # redline/final package download: prepare message for zipping service diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 3fa98cb00..babf9df43 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -507,7 +507,6 @@ const Redlining = React.forwardRef( parent.appendChild(menu); menuBtn.onclick = async () => { - console.log("Menu button clicked"); if (menu.style.display == "flex") { menu.style.display = "none"; } else { @@ -3182,7 +3181,6 @@ const Redlining = React.forwardRef( }; const saveDoc = () => { - console.log("Inside saveDoc!") setIsOverride(false) setOutstandingBalanceModal(false) setRedlineModalOpen(false); @@ -3198,7 +3196,6 @@ const Redlining = React.forwardRef( saveRedlineDocument(docInstance, modalFor); break; case "responsepackage": - console.log("Inside responsepackage -- ", feeOverrideReason) saveResponsePackage(docViewer, annotManager, docInstance,feeOverrideReason); break; default: @@ -4032,9 +4029,9 @@ const Redlining = React.forwardRef( res.s3path_save, zipServiceMessage ); - // setTimeout(() => { - // window.location.reload(true); - // }, 3000); + setTimeout(() => { + window.location.reload(true); + }, 3000); }, (_err) => { console.log(_err); @@ -4153,13 +4150,6 @@ const Redlining = React.forwardRef( setIsOverride(true) } - // const saveOverrideReason = () => { - // console.log("Saved override reason!",feeOverrideReason) - // saveDoc("responsepackage") - // setIsOverride(false) - // setOutstandingBalanceModal(false) - // } - const handleOverrideReasonChange = (event) => { setFeeOverrideReason(event.target.value); }; From d32f10fdcd17d4c2ae1f72494819e9a388025725 Mon Sep 17 00:00:00 2001 From: Aparna Date: Tue, 11 Jun 2024 12:52:51 -0700 Subject: [PATCH 08/57] Merge issue -fix --- api/reviewer_api/resources/document.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/reviewer_api/resources/document.py b/api/reviewer_api/resources/document.py index 596204759..4163e45bc 100644 --- a/api/reviewer_api/resources/document.py +++ b/api/reviewer_api/resources/document.py @@ -107,8 +107,8 @@ def get(requestid): "validoipcreviewlayer": documentservice().validate_oipcreviewlayer(jsonobj, requestid), "balancefeeoverrodforrequest": balancefeeoverrodforrequest } - documentdivisionslist,result = documentservice().getdocuments(requestid, requestinfo["bcgovcode"]) - return json.dumps({"requeststatuslabel": "", "documents": result, "requestnumber":"", "requestinfo":requestinfo,"documentdivisions":documentdivisionslist}), 200 + result = documentservice().getdocuments(requestid, requestinfo["bcgovcode"]) + return json.dumps({"requeststatuslabel": "", "documents": result, "requestnumber":"", "requestinfo":requestinfo}), 200 except KeyError as error: return {'status': False, 'message': CUSTOM_KEYERROR_MESSAGE + str(error)}, 400 except BusinessException as exception: From daa67b7a51a2a8de1e61e0f1b570079356edc08b Mon Sep 17 00:00:00 2001 From: Aparna Date: Tue, 11 Jun 2024 21:53:08 -0700 Subject: [PATCH 09/57] Fetching & displaying balance due amount added --- api/reviewer_api/resources/document.py | 5 +++++ web/src/components/FOI/Home/Home.js | 3 +++ web/src/components/FOI/Home/Redlining.js | 4 ++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/api/reviewer_api/resources/document.py b/api/reviewer_api/resources/document.py index 4163e45bc..defc92d79 100644 --- a/api/reviewer_api/resources/document.py +++ b/api/reviewer_api/resources/document.py @@ -100,11 +100,16 @@ def get(requestid): response.raise_for_status() # get request status jsonobj = response.json() + print("jsonobj:", jsonobj) balancefeeoverrodforrequest = jobrecordservice().isbalancefeeoverrodforrequest(requestid) + outstandingbalance=0 + if 'cfrfee' in jsonobj and 'feedata' in jsonobj['cfrfee'] and "balanceDue" in jsonobj['cfrfee']['feedata']: + outstandingbalance= jsonobj['cfrfee']['feedata']["balanceDue"] requestinfo = { "bcgovcode": jsonobj["bcgovcode"], "requesttype": jsonobj["requestType"], "validoipcreviewlayer": documentservice().validate_oipcreviewlayer(jsonobj, requestid), + "outstandingbalance": outstandingbalance, "balancefeeoverrodforrequest": balancefeeoverrodforrequest } result = documentservice().getdocuments(requestid, requestinfo["bcgovcode"]) diff --git a/web/src/components/FOI/Home/Home.js b/web/src/components/FOI/Home/Home.js index bfe6697cb..f92749366 100644 --- a/web/src/components/FOI/Home/Home.js +++ b/web/src/components/FOI/Home/Home.js @@ -44,6 +44,7 @@ function Home() { const [isStitchingLoaded, setIsStitchingLoaded] = useState(false); const [warningModalOpen, setWarningModalOpen] = useState(false); const [isBalanceFeeOverrode , setIsBalanceFeeOverrode] = useState(false); + const [outstandingBalance, setOutstandingBalance]= useState(0) const redliningRef = useRef(); const selectorRef = useRef(); @@ -67,6 +68,7 @@ function Home() { fetchDocuments( parseInt(foiministryrequestid), async (data) => { + setOutstandingBalance(outstandingbalance) setIsBalanceFeeOverrode(data.requestinfo.balancefeeoverrodforrequest) const getFileExt = (filepath) => { const parts = filepath.split(".") @@ -278,6 +280,7 @@ function Home() { setWarningModalOpen={setWarningModalOpen} scrollLeftPanel={scrollLeftPanel} isBalanceFeeOverrode={isBalanceFeeOverrode} + outstandingBalance={outstandingBalance} /> ) // :
Loading
diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 7825224cc..e780c5b80 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -98,7 +98,8 @@ const Redlining = React.forwardRef( licenseKey, setWarningModalOpen, scrollLeftPanel, - isBalanceFeeOverrode + isBalanceFeeOverrode, + outstandingBalance }, ref ) => { @@ -195,7 +196,6 @@ const Redlining = React.forwardRef( const [enableRedactionPanel, setEnableRedactionPanel] = useState(false); const [clickRedactionPanel, setClickRedactionPanel] = useState(false); const [outstandingBalanceModal, setOutstandingBalanceModal] = useState(false); - const [outstandingBalance, setOutstandingBalance]= useState(1) const [isOverride, setIsOverride]= useState(false); const [feeOverrideReason, setFeeOverrideReason]= useState(""); From 1c0ea5ba2c121d473f4fe31bfe81ece2d79ed169 Mon Sep 17 00:00:00 2001 From: Aparna Date: Tue, 11 Jun 2024 22:10:45 -0700 Subject: [PATCH 10/57] Fix error with object --- web/src/components/FOI/Home/Home.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/FOI/Home/Home.js b/web/src/components/FOI/Home/Home.js index f92749366..bfab6e1b5 100644 --- a/web/src/components/FOI/Home/Home.js +++ b/web/src/components/FOI/Home/Home.js @@ -68,7 +68,7 @@ function Home() { fetchDocuments( parseInt(foiministryrequestid), async (data) => { - setOutstandingBalance(outstandingbalance) + setOutstandingBalance(data.requestinfo.outstandingbalance) setIsBalanceFeeOverrode(data.requestinfo.balancefeeoverrodforrequest) const getFileExt = (filepath) => { const parts = filepath.split(".") From b107a9226ce1b52240478b0dd9be889d965d8326 Mon Sep 17 00:00:00 2001 From: Aparna Date: Wed, 12 Jun 2024 09:31:28 -0700 Subject: [PATCH 11/57] String value conversion --- api/reviewer_api/resources/document.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/api/reviewer_api/resources/document.py b/api/reviewer_api/resources/document.py index defc92d79..0694375e6 100644 --- a/api/reviewer_api/resources/document.py +++ b/api/reviewer_api/resources/document.py @@ -102,9 +102,10 @@ def get(requestid): jsonobj = response.json() print("jsonobj:", jsonobj) balancefeeoverrodforrequest = jobrecordservice().isbalancefeeoverrodforrequest(requestid) - outstandingbalance=0 + outstandingbalance=0.0 if 'cfrfee' in jsonobj and 'feedata' in jsonobj['cfrfee'] and "balanceDue" in jsonobj['cfrfee']['feedata']: - outstandingbalance= jsonobj['cfrfee']['feedata']["balanceDue"] + outstandingbalancestr = jsonobj['cfrfee']['feedata']["balanceDue"] + outstandingbalance = float(outstandingbalancestr) requestinfo = { "bcgovcode": jsonobj["bcgovcode"], "requesttype": jsonobj["requestType"], From 3683264e39d5b59b241bb1ed89b519dd80e6ec19 Mon Sep 17 00:00:00 2001 From: Aparna Date: Wed, 12 Jun 2024 12:09:00 -0700 Subject: [PATCH 12/57] Debug code fixes --- api/reviewer_api/resources/document.py | 2 +- api/reviewer_api/resources/redaction.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/reviewer_api/resources/document.py b/api/reviewer_api/resources/document.py index 0694375e6..59087ef36 100644 --- a/api/reviewer_api/resources/document.py +++ b/api/reviewer_api/resources/document.py @@ -114,7 +114,7 @@ def get(requestid): "balancefeeoverrodforrequest": balancefeeoverrodforrequest } result = documentservice().getdocuments(requestid, requestinfo["bcgovcode"]) - return json.dumps({"requeststatuslabel": "", "documents": result, "requestnumber":"", "requestinfo":requestinfo}), 200 + return json.dumps({"requeststatuslabel": jsonobj["requeststatuslabel"], "documents": result, "requestnumber":jsonobj["axisRequestId"], "requestinfo":requestinfo}), 200 except KeyError as error: return {'status': False, 'message': CUSTOM_KEYERROR_MESSAGE + str(error)}, 400 except BusinessException as exception: diff --git a/api/reviewer_api/resources/redaction.py b/api/reviewer_api/resources/redaction.py index 694ffb87a..220cf62c5 100644 --- a/api/reviewer_api/resources/redaction.py +++ b/api/reviewer_api/resources/redaction.py @@ -230,7 +230,7 @@ class AnnotationMetadata(Resource): @staticmethod @TRACER.trace() @cross_origin(origins=allowedorigins()) - @auth.require + #@auth.require def get(ministryrequestid, redactionlayer): try: result = redactionservice().getannotationinfobyrequest(ministryrequestid, redactionlayer) From 495b25b75f103b0b5d5060007fa143ae9fbc539a Mon Sep 17 00:00:00 2001 From: Aparna Date: Wed, 12 Jun 2024 14:08:44 -0700 Subject: [PATCH 13/57] Missing field added in summary --- .../rstreamio/message/schemas/redactionsummary.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/computingservices/DocumentServices/rstreamio/message/schemas/redactionsummary.py b/computingservices/DocumentServices/rstreamio/message/schemas/redactionsummary.py index 979e4d18f..954d4ce33 100644 --- a/computingservices/DocumentServices/rstreamio/message/schemas/redactionsummary.py +++ b/computingservices/DocumentServices/rstreamio/message/schemas/redactionsummary.py @@ -30,7 +30,7 @@ def __init__(self, sorteddocuments, pkgdocuments) -> None: class RedactionSummaryMessage(object): def __init__(self, jobid, requestid, ministryrequestid, category, requestnumber, - bcgovcode, createdby, filestozip, finaloutput, attributes, summarydocuments ,redactionlayerid) -> None: + bcgovcode, createdby, filestozip, finaloutput, attributes, summarydocuments ,redactionlayerid, feeoverridereason) -> None: self.jobid = jobid self.requestid = requestid self.ministryrequestid = ministryrequestid @@ -43,6 +43,7 @@ def __init__(self, jobid, requestid, ministryrequestid, category, requestnumber, self.attributes = attributes self.summarydocuments = summarydocuments self.redactionlayerid = redactionlayerid + self.feeoverridereason = feeoverridereason def get_in_redactionsummary_msg(producer_json): From bf944019835caa5f75f29817594ee4c9e92d40c2 Mon Sep 17 00:00:00 2001 From: Aparna Date: Wed, 12 Jun 2024 15:31:11 -0700 Subject: [PATCH 14/57] Issue fixed in migration script --- api/migrations/versions/9d45ce57481e_.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/migrations/versions/9d45ce57481e_.py b/api/migrations/versions/9d45ce57481e_.py index 25bda2114..03e94fea5 100644 --- a/api/migrations/versions/9d45ce57481e_.py +++ b/api/migrations/versions/9d45ce57481e_.py @@ -19,7 +19,7 @@ def upgrade(): op.create_table('PDFStitchJobAttributes', sa.Column('attributesid', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('pdfstitchjobid', sa.Integer(), primary_key=True, autoincrement=True, nullable=False), + sa.Column('pdfstitchjobid', sa.Integer(), nullable=False), sa.Column('version', sa.Integer(), nullable=False), sa.Column('ministryrequestid', sa.Integer(), nullable=False), sa.Column('attributes', postgresql.JSON(astext_type=sa.Text()), nullable=False), From d1147aa4e6ff3ff40a488959860f6700a3f042c0 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Fri, 14 Jun 2024 16:23:33 -0700 Subject: [PATCH 15/57] small bug fixes added to this logic with Aparna to adjust redline creation --- api/reviewer_api/services/radactionservice.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/api/reviewer_api/services/radactionservice.py b/api/reviewer_api/services/radactionservice.py index 570145bfa..fe91d7620 100644 --- a/api/reviewer_api/services/radactionservice.py +++ b/api/reviewer_api/services/radactionservice.py @@ -123,7 +123,7 @@ def triggerdownloadredlinefinalpackage(self, finalpackageschema, userinfo): _jobmessage, userinfo["userid"] ) if job.success: - if finalpackageschema['pdfstitchjobattributes'] is not None: + if 'pdfstitchjobattributes' in finalpackageschema and finalpackageschema['pdfstitchjobattributes'] is not None: if 'feeoverridereason' in finalpackageschema['pdfstitchjobattributes']: feeoverridereason= finalpackageschema['pdfstitchjobattributes']['feeoverridereason'] if feeoverridereason is not None and feeoverridereason != '': @@ -135,8 +135,10 @@ def triggerdownloadredlinefinalpackage(self, finalpackageschema, userinfo): # redline/final package download: prepare message for zipping service def __preparemessageforsummaryservice(self, messageschema, userinfo, job): - feeoverridereason= None - pdf_stitch_job_attributes = to_json(messageschema['pdfstitchjobattributes']) + feeoverridereason= '' + pdf_stitch_job_attributes = None + if 'pdfstitchjobattributes' in messageschema: + pdf_stitch_job_attributes = to_json(messageschema['pdfstitchjobattributes']) if pdf_stitch_job_attributes is not None: feeoverridereason= json.loads(pdf_stitch_job_attributes).get("feeoverridereason", None) if feeoverridereason is not None and feeoverridereason != '': From bcc1f7ed1807d488111f1e09477c4d3264947704 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 19 Jun 2024 16:20:21 -0700 Subject: [PATCH 16/57] adjusted modal for consult to account for include redlines feature --- web/src/components/FOI/Home/Redlining.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 914489e66..6fba96220 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -353,6 +353,7 @@ const Redlining = React.forwardRef( const [selectedPublicBodyIDs, setSelectedPublicBodyIDs] = useState([]); const [documentPublicBodies, setDocumentPublicBodies] = useState([]); const [consultApplyRedactions, setConsultApplyRedactions] = useState(false); + const [consultApplyRedlines, setConsultApplyRedlines] = useState(false); const [filteredComments, setFilteredComments] = useState({}); const [pagesRemoved, setPagesRemoved] = useState([]); @@ -3585,6 +3586,7 @@ const Redlining = React.forwardRef( setRedlineModalOpen(false); setSelectedPublicBodyIDs([]); setConsultApplyRedactions(false); + setConsultApplyRedlines(false); } }; @@ -4637,6 +4639,9 @@ const Redlining = React.forwardRef( const handleApplyRedactions = (e) => { setConsultApplyRedactions(e.target.checked); } + const handleApplyRedlines = (e) => { + setConsultApplyRedlines(e.target.checked); + } const handleSelectedPublicBodies = (e) => { const publicBodyId = parseInt(e.target.value); @@ -4869,6 +4874,16 @@ const Redlining = React.forwardRef( />
+ + +
- + } From 40f4c5cf0b551904a2a3d7ccd240265a9394345e Mon Sep 17 00:00:00 2001 From: nkan-aot2 <156717133+nkan-aot2@users.noreply.github.com> Date: Mon, 24 Jun 2024 09:42:13 -0700 Subject: [PATCH 17/57] turn on sourcemap in test-marshal for debug --- web/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/Dockerfile b/web/Dockerfile index eaf8db1ea..b2d2af972 100644 --- a/web/Dockerfile +++ b/web/Dockerfile @@ -17,7 +17,7 @@ ARG REACT_APP_REDACTION_SELECT_LIMIT ENV NODE_ENV ${NODE_ENV} -ENV GENERATE_SOURCEMAP false +ENV GENERATE_SOURCEMAP true ENV REACT_APP_KEYCLOAK_CLIENT ${REACT_APP_KEYCLOAK_CLIENT} ENV REACT_APP_KEYCLOAK_URL_REALM ${REACT_APP_KEYCLOAK_URL_REALM} ENV REACT_APP_KEYCLOAK_URL ${REACT_APP_KEYCLOAK_URL} From 1954a44648799f9cf3aed04fe68c2e90dbdd1aef Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 3 Jul 2024 15:43:54 -0700 Subject: [PATCH 18/57] Consult Changes: 1. redline.js adjusted to fix redline package creation bug for single div packages (copied bug fix in dev/test) 2. Adjusted valid redline divison dl function for consults 3. Added new biz features (verbage changes, ability to exclude or incl. redlines) --- web/src/components/FOI/Home/ConsultModal.tsx | 4 +- web/src/components/FOI/Home/Redlining.js | 59 ++++++++++++++------ 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/web/src/components/FOI/Home/ConsultModal.tsx b/web/src/components/FOI/Home/ConsultModal.tsx index 0695226b9..9f1206104 100644 --- a/web/src/components/FOI/Home/ConsultModal.tsx +++ b/web/src/components/FOI/Home/ConsultModal.tsx @@ -100,7 +100,7 @@ const ConsultModal = ({ -
Select one or more Ministry you with the send the selected page(s) to for consult.
+
Select one or more public bodies you wish to consult with on the selected page(s).
{programAreaList.programareas?.map((programArea: any, index: number) => (
-
If you do not see the name of the Ministry you would like to send for consult above please type it below.
+
If you do not see the name of the public body you wish to consult with, please type it below.
flagId === pageFlagTypes["Duplicate"])) || (!includeNRPages && pageFlagsOnPage.some((flagId) => flagId === pageFlagTypes["Not Responsive"]))) { + isvalid = false; + } else { + isvalid = true; + } + } } } } @@ -484,11 +498,11 @@ const Redlining = React.forwardRef( setIncludeDuplicatePages(true); setIncludeNRPages(true); setModalMessage([ - "Are you sure want to create a consult? A PDF will be created for each public body selected and your web browser page will automatically refresh", + "Are you sure you want to create a consult package? A PDF will be created for each public body selected, and your web browser will automatically refresh after package creation.",
,
, - Select one or more Ministry you wish to send the selected page(s) to for consult* + Select one or more public bodies you wish to create a consult package for: , ]); setModalButtonLabel("Create Consult"); @@ -2850,7 +2864,7 @@ const Redlining = React.forwardRef( } // sort based on sortorder as the sortorder added based on the LastModified prepareRedlinePageMappingByRequest(sortBySortOrder(reqdocuments)); - } else if (modalFor == 'consult') { + } else if (modalFor == "consult") { prepareRedlinePageMappingByConsult(divisionDocuments); } else { prepareRedlinePageMappingByDivision(divisionDocuments); @@ -3041,7 +3055,7 @@ const Redlining = React.forwardRef( if (flagInfo.flagid !== pageFlagTypes["Consult"]) { pageIndex ++; } - } + } } //End of pageMappingsByDivisions totalPageCount += Object.keys( @@ -3052,7 +3066,7 @@ const Redlining = React.forwardRef( } //} } - + } divPageMappings[divObj.divisionid] = pageMappings; removepages[divObj.divisionid] = pagesToRemove; @@ -3829,7 +3843,7 @@ const Redlining = React.forwardRef( redactionlayerid: currentLayer.redactionlayerid }); - if(res.issingleredlinepackage == 'Y' || divisions.length == 1){ + if(res.issingleredlinepackage == 'Y'){ stitchSingleDivisionRedlineExport( _instance, divisionDocuments, @@ -3931,7 +3945,8 @@ const Redlining = React.forwardRef( await _instance.Core.createDocument(doc.s3path_load, { loadAsPDF: true, useDownloader: false, // Added to fix BLANK page issue - }).then(async (docObj) => { + }).then(async (docObj) => { + applyRotations(docObj, doc.attributes.rotatedpages) //if (isIgnoredDocument(doc, docObj.getPageCount(), divisionDocuments) == false) { docCountCopy++; docCount++; @@ -4055,13 +4070,11 @@ const Redlining = React.forwardRef( }).then(async (newDoc) => { applyRotations(newDoc, filerow.attributes.rotatedpages) docCount++; - setredlineDocCount(docCount); - if (isIgnoredDocument(filerow, newDoc, divisionDocuments) === false) { + // if (isIgnoredDocument(filerow, newDoc, divisionDocuments) === false) { if (filerow.stitchIndex === 1) { // Delete pages from the first document const deletedPages = getDeletedPagesBeforeStitching(filerow?.documentid); if (deletedPages.length > 0) { - setSkipDeletePages(true); await newDoc.removePages(deletedPages); } stitchedDocObj = newDoc; @@ -4080,7 +4093,7 @@ const Redlining = React.forwardRef( } ]) } - } + // } }); } catch (error) { console.error("An error occurred during create document:", error); @@ -4266,14 +4279,22 @@ const Redlining = React.forwardRef( } //OIPC - Special Block : End - //Consults - Redactions Block (Redact S.NR) : Start + //Consults - Redlines + Redactions (Redact S.NR) Block : Start if(modalFor == "consult") { + if (!consultApplyRedlines) { + const publicbodyAnnotList = xmlObj.getElementsByTagName('annots')[0]['children']; + const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { + return annot.name !== "freetext" && annot.name !== 'redact' + }); + xmlObj.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; + xfdfString = parser.toString(xmlObj); + } if (consultApplyRedactions) { let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); await applyRedactionsToRedlinesBySection(nr_sectionStamps, PDFNet, stitchObject); } } - //Consults - Redactions Block (Redact S.NR) : End + //Consults - Redlines + Redactions (Redact S.NR) Block : End stitchObject .getFileData({ @@ -4294,7 +4315,7 @@ const Redlining = React.forwardRef( (_res) => { // ######### call another process for zipping and generate download here ########## toast.update(toastId.current, { - render: `Redline PDF saved to Object Storage`, + render: `${modalFor == "consult" ? "Consult" : "Redline"} PDF saved to Object Storage`, type: "success", className: "file-upload-toast", isLoading: false, @@ -4641,6 +4662,9 @@ const Redlining = React.forwardRef( } const handleApplyRedlines = (e) => { setConsultApplyRedlines(e.target.checked); + if (consultApplyRedactions) { + setConsultApplyRedactions(false); + } } const handleSelectedPublicBodies = (e) => { @@ -4891,6 +4915,7 @@ const Redlining = React.forwardRef( id="redaction-checkbox" checked={consultApplyRedactions} onChange={handleApplyRedactions} + disabled={!consultApplyRedlines} /> From cd7291dd835f60995a229901b51922e6806ecef5 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Tue, 16 Jul 2024 13:08:15 -0700 Subject: [PATCH 19/57] Added richards bug fix (ticket 3299) to consults page mapping --- web/src/components/FOI/Home/Redlining.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 8429f54ab..39869fd2e 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -3061,7 +3061,7 @@ const Redlining = React.forwardRef( totalPageCount += Object.keys( pageMappings[doc.documentid] ).length; - if (!skipDocumentPages) { + if (!skipDocumentPages && !skipOnlyDuplicateDocument && !skipOnlyNRDocument) { totalPageCountIncludeRemoved += doc.pagecount; } //} @@ -3253,7 +3253,7 @@ const Redlining = React.forwardRef( totalPageCount += Object.keys( pageMappings[doc.documentid] ).length; - if (!skipDocumentPages) { + if (!skipDocumentPages && !skipOnlyDuplicateDocument && !skipOnlyNRDocument) { totalPageCountIncludeRemoved += doc.pagecount; } } From 48aecc93eabc4b326b0f6ca18716207a4b74671f Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 7 Aug 2024 16:42:32 -0700 Subject: [PATCH 20/57] Added consult code from PR 1001 / PR 1054 / PR 1036 for ticket 2646 to test-rook --- .../resources/foiflowmasterdata.py | 7 +- api/reviewer_api/utils/util.py | 2 + .../services/redactionsummaryservice.py | 3 + .../services/zippingservice.py | 2 +- web/public/stylesheets/webviewer.css | 5 + web/src/actions/actionConstants.ts | 1 + web/src/actions/documentActions.ts | 14 + .../services/docReviewerService.tsx | 3 +- web/src/apiManager/services/foiOSSService.tsx | 2 + web/src/components/FOI/App.scss | 4 + .../components/FOI/Home/ConfirmationModal.js | 65 ++- .../CreateResponsePDF/CreateResponsePDF.js | 39 ++ .../useSaveRedlineForSignOff.js | 451 +++++++++++++++--- web/src/components/FOI/Home/Redlining.js | 43 +- web/src/modules/documentReducer.ts | 5 +- 15 files changed, 583 insertions(+), 63 deletions(-) diff --git a/api/reviewer_api/resources/foiflowmasterdata.py b/api/reviewer_api/resources/foiflowmasterdata.py index b617d6746..2500357a7 100644 --- a/api/reviewer_api/resources/foiflowmasterdata.py +++ b/api/reviewer_api/resources/foiflowmasterdata.py @@ -200,6 +200,8 @@ def post(ministryrequestid, redactionlayer="redline", layertype="redline"): packagetype = "redline" if redactionlayer == "oipc": packagetype = "oipcreview" if layertype == "oipcreview" else "oipcredline" + if layertype == "consult": + packagetype = "consult" #check if is single redline package is_single_redline = is_single_redline_package(_bcgovcode, packagetype, requesttype) @@ -215,7 +217,10 @@ def post(ministryrequestid, redactionlayer="redline", layertype="redline"): filepath_put = "{0}/{2}/{1}/{0} - {2} - {1}.pdf".format( filepathlist[0], division_name, packagetype ) - + if packagetype == "consult": + filepath_put = "{0}/{2}/{2} - {1} - {0}.pdf".format( + filepathlist[0], division_name, packagetype + ) s3path_save = s3client.generate_presigned_url( ClientMethod="get_object", Params={ diff --git a/api/reviewer_api/utils/util.py b/api/reviewer_api/utils/util.py index 0a5f52954..796561c9f 100644 --- a/api/reviewer_api/utils/util.py +++ b/api/reviewer_api/utils/util.py @@ -137,6 +137,8 @@ def getbatchconfig(): return _begin, _size, _limit def is_single_redline_package(bcgovcode, packagetype, requesttype): + if packagetype == "consult": + return False if (packagetype == "oipcreview"): return True if REDLINE_SINGLE_PKG_MINISTRIES not in (None, ""): diff --git a/computingservices/DocumentServices/services/redactionsummaryservice.py b/computingservices/DocumentServices/services/redactionsummaryservice.py index fbf158207..701d096f1 100644 --- a/computingservices/DocumentServices/services/redactionsummaryservice.py +++ b/computingservices/DocumentServices/services/redactionsummaryservice.py @@ -13,6 +13,9 @@ class redactionsummaryservice(): def processmessage(self,incomingmessage): summaryfilestozip = [] message = get_in_redactionsummary_msg(incomingmessage) + #Condition to handle consults packaages (no summary files to be created) + if message.category == "consultpackage": + return summaryfilestozip try: pdfstitchjobactivity().recordjobstatus(message,3,"redactionsummarystarted") summarymsg = message.summarydocuments diff --git a/computingservices/DocumentServices/services/zippingservice.py b/computingservices/DocumentServices/services/zippingservice.py index c997af363..f29c000a5 100644 --- a/computingservices/DocumentServices/services/zippingservice.py +++ b/computingservices/DocumentServices/services/zippingservice.py @@ -14,7 +14,7 @@ def preparemessageforzipperservice(self,summaryfiles, message): if summaryfiles and len(summaryfiles) > 0: filestozip_list = json.loads(msgjson['filestozip'])+summaryfiles else: - filestozip_list = msgjson['filestozip'] + filestozip_list = json.loads(msgjson['filestozip']) print('filestozip_list: ', filestozip_list) msgjson['filestozip'] = self.to_json(filestozip_list) msgjson['attributes'] = self.to_json(msgjson['attributes']) diff --git a/web/public/stylesheets/webviewer.css b/web/public/stylesheets/webviewer.css index 9084bb2bc..bbf51b3c6 100644 --- a/web/public/stylesheets/webviewer.css +++ b/web/public/stylesheets/webviewer.css @@ -19,6 +19,11 @@ cursor: not-allowed !important; } +.consult_package:disabled { + color: #999999 !important; + cursor: not-allowed !important; +} + .file-upload-toast { .Toastify__toast-body { > div:last-child { diff --git a/web/src/actions/actionConstants.ts b/web/src/actions/actionConstants.ts index cbae36c3d..a93f87dce 100644 --- a/web/src/actions/actionConstants.ts +++ b/web/src/actions/actionConstants.ts @@ -20,6 +20,7 @@ const ACTION_CONSTANTS = { INC_REDACTION_LAYER: "INC_REDACTION_LAYER", SET_REQUEST_NUMBER:"SET_REQUEST_NUMBER", SET_DELETED_PAGES: "SET_DELETED_PAGES", + SET_PUBLIC_BODIES: "SET_PUBLIC_BODIES", FOI_PERSONAL_SECTIONS: "FOI_PERSONAL_SECTIONS", FOI_PERSONAL_PEOPLE: "FOI_PERSONAL_PEOPLE", FOI_PERSONAL_FILETYPES: "FOI_PERSONAL_FILETYPES", diff --git a/web/src/actions/documentActions.ts b/web/src/actions/documentActions.ts index da519f073..4bb4067a6 100644 --- a/web/src/actions/documentActions.ts +++ b/web/src/actions/documentActions.ts @@ -1,5 +1,13 @@ import ACTION_CONSTANTS from "./actionConstants"; +type PublicBody = { + bcgovcode: string, + iaocode: string, + name: string, + isactive: boolean, + type: string, + programareaid: number +} export const setRedactionInfo = (data: any) => (dispatch:any) =>{ dispatch({ @@ -8,6 +16,12 @@ export const setRedactionInfo = (data: any) => (dispatch:any) =>{ }) } +export const setPublicBodies = (data: PublicBody[]) => (dispatch:any) =>{ + dispatch({ + type:ACTION_CONSTANTS.SET_PUBLIC_BODIES, + payload:data + }) +} export const setIsPageLeftOff = (data: any) => (dispatch:any) =>{ dispatch({ diff --git a/web/src/apiManager/services/docReviewerService.tsx b/web/src/apiManager/services/docReviewerService.tsx index 823191efc..62b1d3898 100644 --- a/web/src/apiManager/services/docReviewerService.tsx +++ b/web/src/apiManager/services/docReviewerService.tsx @@ -4,7 +4,7 @@ import API from "../endpoints"; import UserService from "../../services/UserService"; import { setRedactionInfo, setIsPageLeftOff, setSections, setDocumentList, setRequestStatus, setRedactionLayers, incrementLayerCount, setRequestNumber, setRequestInfo, setDeletedPages, - setFOIPersonalSections, setFOIPersonalPeople, setFOIPersonalFiletypes, setFOIPersonalVolumes + setFOIPersonalSections, setFOIPersonalPeople, setFOIPersonalFiletypes, setFOIPersonalVolumes, setPublicBodies } from "../../actions/documentActions"; import { store } from "../../services/StoreService"; import { number } from "yargs"; @@ -295,6 +295,7 @@ export const fetchPageFlagsMasterData = ( .then((res:any) => { if (res.data || res.data === "") { callback(res.data); + store.dispatch(setPublicBodies(res.data.find((flag: any) => flag.name === 'Consult').programareas)); } else { throw new Error(); } diff --git a/web/src/apiManager/services/foiOSSService.tsx b/web/src/apiManager/services/foiOSSService.tsx index bb170b92a..82a79a962 100644 --- a/web/src/apiManager/services/foiOSSService.tsx +++ b/web/src/apiManager/services/foiOSSService.tsx @@ -59,6 +59,8 @@ export const getFOIS3DocumentRedlinePreSignedUrl = ( if (layertype === "oipcreview") { apiurl = apiurl + "/oipcreview" + } else if (layertype === "consult") { + apiurl = apiurl + "/consult" } else { apiurl = apiurl + "/" + layer } diff --git a/web/src/components/FOI/App.scss b/web/src/components/FOI/App.scss index f518f21da..11ebe19d8 100644 --- a/web/src/components/FOI/App.scss +++ b/web/src/components/FOI/App.scss @@ -221,6 +221,10 @@ li.modal-message-list-item { min-height: 350px !important; } +.consult-modal { + min-height: 500px !important; +} + .redline-checkmark { height:14px; width:14px; diff --git a/web/src/components/FOI/Home/ConfirmationModal.js b/web/src/components/FOI/Home/ConfirmationModal.js index 651cf6e8c..841093e3d 100644 --- a/web/src/components/FOI/Home/ConfirmationModal.js +++ b/web/src/components/FOI/Home/ConfirmationModal.js @@ -9,6 +9,7 @@ import DialogContentText from "@mui/material/DialogContentText"; import DialogTitle from "@mui/material/DialogTitle"; import CloseIcon from "@mui/icons-material/Close"; import IconButton from "@mui/material/IconButton"; +import Grid from '@mui/material/Grid'; //import type { ReactModalProps } from './types'; @@ -22,7 +23,12 @@ export const ConfirmationModal= ({ handleIncludeDuplicantePages, isDisableNRDuplicate, saveDoc, - modalData + modalData, + documentPublicBodies, + handleSelectedPublicBodies, + selectedPublicBodyIDs, + consultApplyRedactions, + handleApplyRedactions }) => { return ( @@ -31,7 +37,7 @@ export const ConfirmationModal= ({ initHeight={300} minWidth={600} minHeight={250} - className={"state-change-dialog" + (modalData?.modalFor == "redline"?" redline-modal":"")} + className={"state-change-dialog" + (modalData?.modalFor === "redline" ? " redline-modal" : modalData?.modalFor === "consult" ? " consult-modal" : "")} onRequestClose={cancelRedaction} isOpen={redlineModalOpen} > @@ -72,6 +78,61 @@ export const ConfirmationModal= ({ /> } + {modalData.modalFor === "consult" && + <> + + {documentPublicBodies?.map((publicBody) => { + return (<> + + + + + ) + })} + +
+

More Options:

+ + +
+ + +
+ + + } diff --git a/web/src/components/FOI/Home/CreateResponsePDF/CreateResponsePDF.js b/web/src/components/FOI/Home/CreateResponsePDF/CreateResponsePDF.js index e1d6feff3..f77d9b71a 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/CreateResponsePDF.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/CreateResponsePDF.js @@ -59,6 +59,21 @@ export const createFinalPackageSelection = (document, enableSave) => { return finalPackageBtn; }; +export const createConsultPackageSelection = (document, enableSave) => { + const consultPackageButton = document.createElement("button"); + consultPackageButton.textContent = "Consult Public Body"; + consultPackageButton.id = "consult_package"; + consultPackageButton.className = "consult_package"; + consultPackageButton.style.backgroundColor = "transparent"; + consultPackageButton.style.border = "none"; + consultPackageButton.style.padding = "8px 8px 8px 10px"; + consultPackageButton.style.cursor = "pointer"; + consultPackageButton.style.alignItems = "left"; + consultPackageButton.disabled = !enableSave; + + return consultPackageButton; +} + export const renderCustomButton = (document, menu) => { const menuBtn = document.createElement("button"); menuBtn.textContent = "Create Response PDF"; @@ -155,6 +170,30 @@ export const handleFinalPackageClick = ( setRedlineModalOpen(true); }; +export const handleConsultPackageClick = ( + updateModalData, + setRedlineModalOpen, + setIncludeDuplicatePages, + setIncludeNRPages +) => { + updateModalData({ + modalFor: "consult", + modalTitle: "Consult Public Body", + modalMessage: [ + "Are you sure you want to create a consult package? A PDF will be created for each public body selected, and your web browser will automatically refresh after package creation.", +
, +
, + + Select one or more public bodies you wish to create a consult package for: + , + ], + modalButtonLabel: "Create Consult" + }); + setIncludeDuplicatePages(true); + setIncludeNRPages(true); + setRedlineModalOpen(true); +} + export const isReadyForSignOff = (documentList, pageFlags) => { let pageFlagArray = []; let stopLoop = false; diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 8b81c5c90..1c5443ddf 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -34,6 +34,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { const requestnumber = useAppSelector( (state) => state.documents?.requestnumber ); + const allPublicBodies = useAppSelector((state) => state.documents?.allPublicBodies); const toastId = React.useRef(null); const { foiministryrequestid } = useParams(); @@ -67,6 +68,11 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { const [redlineCategory, setRedlineCategory] = useState(false); const [filteredComments, setFilteredComments] = useState({}); const [alreadyStitchedList, setAlreadyStitchedList] = useState([]); + const [enableSavingConsults, setEnableSavingConsults] = useState(false); + const [selectedPublicBodyIDs, setSelectedPublicBodyIDs] = useState([]); + const [documentPublicBodies, setDocumentPublicBodies] = useState([]); + const [consultApplyRedactions, setConsultApplyRedactions] = useState(false); + const requestInfo = useAppSelector((state) => state.documents?.requestinfo); const requestType = requestInfo?.requesttype ? requestInfo.requesttype : "public"; @@ -84,8 +90,26 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { else { for (let doc of divObj.documentlist) { for (const flagInfo of doc.pageFlag) { + if (modalFor == "consult") { + for (let consult of doc.consult) { + if (consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) { + if ( + ( + flagInfo.flagid !== pageFlagTypes["Duplicate"] && flagInfo.flagid !== pageFlagTypes["Not Responsive"]) || + ( + (includeDuplicatePages && flagInfo.flagid === pageFlagTypes["Duplicate"]) || + (includeNRPages && flagInfo.flagid === pageFlagTypes["Not Responsive"]) + ) + ) { + if(isvalid == false) { + isvalid = true; + } + } + } + } + } // Added condition to handle Duplicate/NR clicked for Redline for Sign off Modal - if ( + else if ( (flagInfo.flagid !== pageFlagTypes["Duplicate"] && flagInfo.flagid != pageFlagTypes["Not Responsive"]) || ( (includeDuplicatePages && flagInfo.flagid === pageFlagTypes["Duplicate"]) || @@ -153,21 +177,58 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { incompatibleFiles ) => { let newDocList = []; - for (let div of divisions) { - let divDocList = documentList?.filter((doc) => - doc.divisions.map((d) => d.divisionid).includes(div.divisionid) - ); - // sort based on sortorder as the sortorder added based on the LastModified - divDocList = sortBySortOrder(divDocList); - let incompatableList = incompatibleFiles.filter((doc) => - doc.divisions.map((d) => d.divisionid).includes(div.divisionid) - ); - newDocList.push({ - divisionid: div.divisionid, - divisionname: div.name, - documentlist: divDocList, - incompatableList: incompatableList, - }); + if (modalFor == "redline" || modalFor == "oipcreview") { + for (let div of divisions) { + let divDocList = documentList?.filter((doc) => + doc.divisions.map((d) => d.divisionid).includes(div.divisionid) + ); + + // sort based on sortorder as the sortorder added based on the LastModified + divDocList = sortBySortOrder(divDocList); + + let incompatableList = incompatibleFiles.filter((doc) => + doc.divisions.map((d) => d.divisionid).includes(div.divisionid) + ); + newDocList.push({ + divisionid: div.divisionid, + divisionname: div.name, + documentlist: divDocList, + incompatableList: incompatableList, + }); + } + } else if (modalFor == "consult") { + // map documents to publicBodies (Divisions) for consults + for (let publicBodyId of divisions) { + let publicBodyDocList = []; + documentList.forEach((doc) => { + let programareaids = new Set(); + if (doc.consult && doc.consult.length) { + doc.consult.forEach((consult) => { + consult.programareaid.forEach((programareaid) => { + if (programareaid === publicBodyId) { + programareaids.add(programareaid); + } + }) + }); + } + for (let programareaid of programareaids) { + if (programareaid === publicBodyId) { + publicBodyDocList.push({...doc}) + } + } + }) + publicBodyDocList = sortBySortOrder(publicBodyDocList); + + let incompatableList = []; + + const publicBodyInfo = allPublicBodies.find((body) => body.programareaid === publicBodyId) + newDocList.push({ + divisionid: publicBodyId, + divisionname: publicBodyInfo.name, + documentlist: publicBodyDocList, + incompatableList: incompatableList, + }) + } } return newDocList; }; @@ -185,6 +246,8 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } // sort based on sortorder as the sortorder added based on the LastModified prepareRedlinePageMappingByRequest(sortBySortOrder(reqdocuments), pageMappedDocs); + } else if (modalFor == "consult") { + prepareRedlinePageMappingByConsult(divisionDocuments); } else { prepareRedlinePageMappingByDivision(divisionDocuments); } @@ -414,11 +477,203 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }); } + const prepareRedlinePageMappingByConsult = (divisionDocuments) => { + let removepages = {}; + let pageMappings = {}; + let divPageMappings = {}; + let pagesToRemove = []; + let totalPageCount = 0; + let totalPageCountIncludeRemoved = 0; + let duplicateWatermarkPages = {}; + let duplicateWatermarkPagesEachDiv = []; + let NRWatermarksPages = {}; + let NRWatermarksPagesEachDiv = []; + for (let divObj of divisionDocuments) { + // sort based on sortorder as the sortorder added based on the LastModified + for (let doc of sortBySortOrder(divObj.documentlist)) { + if (doc.pagecount > 0) { + let pagesToRemoveEachDoc = []; + pageMappings[doc.documentid] = {}; + let pageIndex = 1; + //gather pages that need to be removed + doc.pageFlag.sort((a, b) => a.page - b.page); //sort pageflag by page # + let skipDocumentPages = false; + let skipOnlyDuplicateDocument = false; + let skipOnlyNRDocument = false; + if (!includeDuplicatePages && !includeNRPages) { + skipDocumentPages = skipDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + else if (!includeDuplicatePages) { + skipOnlyDuplicateDocument = skipDuplicateDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + else if (!includeNRPages) { + skipOnlyNRDocument = skipNRDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + + // for consults, go through all pages + for (const page of doc.pages) { + //find pageflags for this page + const pageFlagsOnPage = doc.pageFlag.filter((pageFlag) => { + return pageFlag.page === page; + }) + const notConsultPageFlagsOnPage = pageFlagsOnPage.filter((pageFlag) => { + return pageFlag.flagid !== pageFlagTypes["Consult"]; + }) + + // if the page has no pageflags, remove it + if (pageFlagsOnPage.length == 0) { + pagesToRemoveEachDoc.push(page); + if (!skipDocumentPages) { + pagesToRemove.push( + pageIndex + totalPageCountIncludeRemoved + ); + } + pageIndex ++; + } + + //differences in pagemapping for consults begin here + //for pages with only consult flags, remove if page doesn't belong to current consult body + if (pageFlagsOnPage.length > 0 && notConsultPageFlagsOnPage.length == 0) { + for (let flagInfo of pageFlagsOnPage) { + let hasConsult = false; + for (let consult of doc.consult) { + if (consult.page == flagInfo.page && consult.programareaid.includes(divObj.divisionid)) { + hasConsult = true; + break; + } + } + if (!hasConsult) { + if (!pagesToRemoveEachDoc.includes(flagInfo.page)) { + pagesToRemoveEachDoc.push(flagInfo.page); + if(!skipDocumentPages) { + delete pageMappings[doc.documentid][flagInfo.page]; + pagesToRemove.push(pageIndex + totalPageCountIncludeRemoved) + } + } + } else { + // add page as it will match the curent publicBody / division id + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } + } + pageIndex ++; + } + + // if the page does have pageflags, process it + for (let flagInfo of notConsultPageFlagsOnPage) { + if (flagInfo.flagid == pageFlagTypes["Duplicate"]) { + if(includeDuplicatePages) { + duplicateWatermarkPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); + + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } else { + pagesToRemoveEachDoc.push(flagInfo.page); + if (!skipDocumentPages && !skipOnlyDuplicateDocument) { + pagesToRemove.push( + pageIndex + totalPageCountIncludeRemoved + ); + } + } + + } else if (flagInfo.flagid == pageFlagTypes["Not Responsive"]) { + if(includeNRPages) { + NRWatermarksPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); + + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } else { + pagesToRemoveEachDoc.push(flagInfo.page); + if (!skipDocumentPages && !skipOnlyNRDocument) { + pagesToRemove.push( + pageIndex + totalPageCountIncludeRemoved + ); + } + } + } else if (flagInfo.flagid == pageFlagTypes["In Progress"]) { + NRWatermarksPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); + + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } else { + if (flagInfo.flagid !== pageFlagTypes["Consult"]) { + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } + } + + // Check if the page has relevant consult flag, if not remove the page + let hasConsult = false; + for (let consult of doc.consult) { + if (consult.page == flagInfo.page && consult.programareaid.includes(divObj.divisionid)) { + hasConsult = true; + break; + } + } + if (!hasConsult) { + if (!pagesToRemoveEachDoc.includes(flagInfo.page)) { + pagesToRemoveEachDoc.push(flagInfo.page); + if(!skipDocumentPages) { + delete pageMappings[doc.documentid][flagInfo.page]; + pagesToRemove.push(pageIndex + totalPageCountIncludeRemoved) + } + } + } + if (flagInfo.flagid !== pageFlagTypes["Consult"]) { + pageIndex ++; + } + } + } + //End of pageMappingsByConsults + + totalPageCount += Object.keys( + pageMappings[doc.documentid] + ).length; + if (!skipDocumentPages && !skipOnlyDuplicateDocument && !skipOnlyNRDocument) { + totalPageCountIncludeRemoved += doc.pagecount; + } + } + } + divPageMappings[divObj.divisionid] = pageMappings; + removepages[divObj.divisionid] = pagesToRemove; + duplicateWatermarkPages[divObj.divisionid] = duplicateWatermarkPagesEachDiv; + NRWatermarksPages[divObj.divisionid] = NRWatermarksPagesEachDiv; + pagesToRemove = []; + duplicateWatermarkPagesEachDiv = []; + NRWatermarksPagesEachDiv = []; + totalPageCount = 0; + totalPageCountIncludeRemoved = 0; + pageMappings = {} + } + + setRedlinepageMappings({ + 'divpagemappings': divPageMappings, + 'pagemapping': pageMappings, + 'pagestoremove': removepages + }); + setRedlineWatermarkPageMapping({ + 'duplicatewatermark': duplicateWatermarkPages, + 'NRwatermark': NRWatermarksPages + }); + } const prepareRedlineIncompatibleMapping = (redlineAPIResponse) => { let divIncompatableMapping = {}; let incompatibleFiles = []; let divCounter = 0; + if (redlineAPIResponse.consultdocumentlist) { + redlineAPIResponse.divdocumentList = redlineAPIResponse.consultdocumentlist + } for (let divObj of redlineAPIResponse.divdocumentList) { divCounter++; @@ -443,6 +698,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }); incompatibleFiles = incompatibleFiles.concat(divIncompatableFiles); } + if (divObj.publicBody && !divObj.divisionid) divObj.divisionid = divObj.publicBody; if (redlineAPIResponse.issingleredlinepackage == "Y") { if (divCounter == redlineAPIResponse.divdocumentList.length) { incompatableObj["divisionid"] = "0"; @@ -480,6 +736,9 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } }; const getzipredlinecategory = (layertype) => { + if (modalFor == "consult") { + return "consultpackage"; + } if (currentLayer.name.toLowerCase() === "oipc") { return layertype === "oipcreview" ? "oipcreviewredline" : "oipcredline"; } @@ -738,6 +997,33 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }); return sortedList; }; + const getPublicBodyList = (documentList) => { + let publicBodyIdList = []; + if (documentList?.length > 0) { + for (const doc of documentList) { + if ('pageFlag' in doc) { + for (let pageflag of doc['pageFlag']) { + if ('programareaid' in pageflag) { + for (let programareaid of pageflag['programareaid']) { + publicBodyIdList.push(programareaid) + } + } + } + } + } + const filteredPublicBodyIdList = [...new Set(publicBodyIdList)] + return getPublicBodyObjs(filteredPublicBodyIdList); + } + } + const getPublicBodyObjs = (publicBodyIDList) => { + const publicBodies = []; + for (const publicBody of allPublicBodies) { + if (publicBodyIDList.includes(publicBody.programareaid)) { + publicBodies.push(publicBody); + } + } + return publicBodies; + } const saveRedlineDocument = async ( @@ -755,7 +1041,13 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }); const divisionFilesList = [...documentList, ...incompatibleFiles]; - const divisions = getDivisionsForSaveRedline(divisionFilesList); + let divisions; + if (modalFor == "consult") { + //Key consult logic, uses preexisting division reldine logic for consults + divisions = selectedPublicBodyIDs; + } else { + divisions = getDivisionsForSaveRedline(divisionFilesList); + } const divisionDocuments = getDivisionDocumentMappingForRedline(divisions, documentList, incompatibleFiles); const documentids = documentList.map((obj) => obj.documentid); getFOIS3DocumentRedlinePreSignedUrl( @@ -805,9 +1097,29 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { skipOnlyNRDocument = skipNRDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); } if (pageMappedDocs != undefined) { - let divisionsdocpages = Object.values( - pageMappedDocs.redlineDocIdLookup - ) + let divisionsdocpages = []; + // for consults, no need to filter by division/consult + if (modalFor == "consult") { + Object.values( + pageMappedDocs.redlineDocIdLookup + ) + .forEach((obj) => { + divisionsdocpages = Object.values( + pageMappedDocs.redlineDocIdLookup + ) + .filter((obj) => { + return obj.docId == doc.documentid; + }) + .map((obj) => { + if (res.issingleredlinepackage == "Y" || (!skipDocumentPages && !skipOnlyDuplicateDocument && !skipOnlyNRDocument)) { + return obj.pageMappings; + } + }); + }) + } else { + divisionsdocpages = Object.values( + pageMappedDocs.redlineDocIdLookup + ) .filter((obj) => { return obj.division.includes(div.divisionid) && obj.docId == doc.documentid; }) @@ -816,6 +1128,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { return obj.pageMappings; } }); + } if (divisionsdocpages[0]) { divisionsdocpages.forEach(function (_arr) { _arr.forEach(function (value) { @@ -918,7 +1231,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { ); }; - const checkSavingRedline = (redlineReadyAndValid, instance) => { const validRedlineStatus = [ RequestStates["Records Review"], @@ -932,7 +1244,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { !redlineReadyAndValid || !validRedlineStatus; } }; - const checkSavingOIPCRedline = ( oipcRedlineReadyAndValid, instance, @@ -953,6 +1264,13 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { !readyForSignOff; } }; + const checkSavingConsults = (documentList) => { + const publicBodyList = getPublicBodyList(documentList); + setDocumentPublicBodies(publicBodyList); + setEnableSavingConsults( + publicBodyList.length > 0 + ); + } const triggerRedlineZipper = ( divObj, stitchedDocPath, @@ -1335,10 +1653,13 @@ const stampPageNumberRedline = async ( .replace(/"/g, '"') .replace(/\\/g, ""); let sections = getAnnotationSections(annot); - if (sections.some((item) => item.section === "s. 14")) { + if (redlineCategory === "oipcreview" && sections.some((item) => item.section === "s. 14")) { sectionStamps[parentRedactionId] = annotationpagenumbers[parentRedactionId]; } + if (modalFor == "consult" && sections.some(item => item.section === 'NR')) { + sectionStamps[parentRedactionId] = annotationpagenumbers[parentRedactionId]; + } } } } @@ -1391,6 +1712,37 @@ const stampPageNumberRedline = async ( } } }; + const applyRedactionsToRedlinesBySection = async (appliedSectionStamps, PDFNet, stitchObject) => { + let annotationManager = docInstance?.Core.annotationManager; + const rarr = []; + let rects = []; + for (const [key, value] of Object.entries(appliedSectionStamps)) { + let sectionAnnotation = annotationManager.getAnnotationById(key); + if (sectionAnnotation.Subject === "Redact") { + rects = rects.concat( + sectionAnnotation.getQuads().map((q) => { + return { + pageno: appliedSectionStamps[key], + recto: q.toRect(), + vpageno: sectionAnnotation.getPageNumber() + }; + }) + ); + } + } + for (const rect of rects) { + let height = docViewer.getPageHeight(rect.vpageno); + rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(rect.recto.x1,height-rect.recto.y1,rect.recto.x2,height-rect.recto.y2)), false, '')); + } + if (rarr.length > 0) { + const app = {}; + app.redaction_overlay = true; + app.border = false; + app.show_redacted_content_regions = false; + const doc = await stitchObject.getPDFDoc(); + await PDFNet.Redactor.redact(doc, rarr, app); + } + } //useEffects to keep docInstance and docViewer state up to date with Redlining.js useEffect(() => { @@ -1431,7 +1783,7 @@ const stampPageNumberRedline = async ( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); - if(redlineCategory !== "oipcreview") { + if(redlineCategory !== "oipcreview" || modalFor == "consult") { await stampPageNumberRedline( stitchObject, PDFNet, @@ -1471,38 +1823,8 @@ const stampPageNumberRedline = async ( //OIPC - Special Block (Redact S.14) : Begin if(redlineCategory === "oipcreview") { - const rarr = []; - let annotationManager = docInstance?.Core.annotationManager; let s14_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - let rects = []; - for (const [key, value] of Object.entries(s14_sectionStamps)) { - let s14annoation = annotationManager.getAnnotationById(key); - if ( s14annoation.Subject === "Redact") { - rects = rects.concat( - s14annoation.getQuads().map((q) => { - return { - pageno: s14_sectionStamps[key], - recto: q.toRect(), - vpageno: s14annoation.getPageNumber() - }; - }) - ); - } - - - } - for (const rect of rects) { - let height = docViewer.getPageHeight(rect.vpageno); - rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(rect.recto.x1,height-rect.recto.y1,rect.recto.x2,height-rect.recto.y2)), false, '')); - } - if (rarr.length > 0) { - const app = {}; - app.redaction_overlay = true; - app.border = false; - app.show_redacted_content_regions = false; - const doc = await stitchObject.getPDFDoc(); - await PDFNet.Redactor.redact(doc, rarr, app); - } + await applyRedactionsToRedlinesBySection(s14_sectionStamps, PDFNet, stitchObject); await stampPageNumberRedline( stitchObject, PDFNet, @@ -1510,7 +1832,17 @@ const stampPageNumberRedline = async ( isSingleRedlinePackage ); } - //OIPC - Special Block : End + //OIPC - Special Block : End + + //Consults - Redactions Block (Redact S.NR) : Start + if(modalFor == "consult") { + if (consultApplyRedactions) { + let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); + await applyRedactionsToRedlinesBySection(nr_sectionStamps, PDFNet, stitchObject); + } + } + //Consults - Redactions Block (Redact S.NR) : End + stitchObject .getFileData({ // saves the document with annotations in it @@ -1651,10 +1983,17 @@ const stampPageNumberRedline = async ( saveRedlineDocument, enableSavingOipcRedline, enableSavingRedline, + enableSavingConsults, checkSavingRedline, checkSavingOIPCRedline, + checkSavingConsults, setRedlineCategory, setFilteredComments, + setSelectedPublicBodyIDs, + setConsultApplyRedactions, + selectedPublicBodyIDs, + documentPublicBodies, + consultApplyRedactions, }; }; diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 8d9c010e6..8825547ed 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -52,10 +52,12 @@ import { createFinalPackageSelection, createOIPCForReviewSelection, createRedlineForSignOffSelection, - createResponsePDFMenu, + createResponsePDFMenu, + createConsultPackageSelection, handleFinalPackageClick, handleRedlineForOipcClick, handleRedlineForSignOffClick, + handleConsultPackageClick, renderCustomButton, isValidRedlineDownload, isReadyForSignOff } from "./CreateResponsePDF/CreateResponsePDF"; @@ -148,10 +150,17 @@ const Redlining = React.forwardRef( saveRedlineDocument, enableSavingOipcRedline, enableSavingRedline, + enableSavingConsults, checkSavingRedline, checkSavingOIPCRedline, + checkSavingConsults, setRedlineCategory, setFilteredComments, + setSelectedPublicBodyIDs, + setConsultApplyRedactions, + selectedPublicBodyIDs, + documentPublicBodies, + consultApplyRedactions } = useSaveRedlineForSignoff(docInstance, docViewer); const { saveResponsePackage, @@ -206,6 +215,7 @@ const Redlining = React.forwardRef( const redlineForSignOffBtn = createRedlineForSignOffSelection(document, enableSavingRedline); const redlineForOipcBtn = createOIPCForReviewSelection(document, enableSavingOipcRedline); const finalPackageBtn = createFinalPackageSelection(document, enableSavingFinal); + const consultPackageButton = createConsultPackageSelection(document, enableSavingConsults); redlineForOipcBtn.onclick = () => { handleRedlineForOipcClick(updateModalData, setRedlineModalOpen); }; @@ -215,9 +225,13 @@ const Redlining = React.forwardRef( finalPackageBtn.onclick = () => { handleFinalPackageClick(updateModalData, setRedlineModalOpen); }; + consultPackageButton.onClick = () => { + handleConsultPackageClick(updateModalData, setRedlineModalOpen, setIncludeDuplicatePages, setIncludeNRPages) + }; menu.appendChild(redlineForOipcBtn); menu.appendChild(redlineForSignOffBtn); menu.appendChild(finalPackageBtn); + menu.appendChild(consultPackageButton); parent.appendChild(menu); //Create render function to render custom Create Reseponse PDF button @@ -1320,6 +1334,7 @@ const Redlining = React.forwardRef( const validRedlineDownload = isValidRedlineDownload(pageFlags); const redlineReadyAndValid = readyForSignOff && validRedlineDownload; const oipcRedlineReadyAndValid = (validoipcreviewlayer === true && currentLayer.name.toLowerCase() === "oipc") && readyForSignOff; + checkSavingConsults(documentList); checkSavingRedline(redlineReadyAndValid, _instance); checkSavingOIPCRedline(oipcRedlineReadyAndValid, _instance, readyForSignOff); checkSavingFinalPackage(redlineReadyAndValid, _instance); @@ -2182,6 +2197,8 @@ const Redlining = React.forwardRef( const cancelSaveRedlineDoc = () => { disableNRDuplicate(); setRedlineModalOpen(false); + setSelectedPublicBodyIDs([]); + setConsultApplyRedactions(false); }; const handleIncludeNRPages = (e) => { @@ -2191,6 +2208,24 @@ const Redlining = React.forwardRef( const handleIncludeDuplicantePages = (e) => { setIncludeDuplicatePages(e.target.checked); }; + + const handleApplyRedactions = (e) => { + setConsultApplyRedactions(e.target.checked); + } + + const handleSelectedPublicBodies = (e) => { + const publicBodyId = parseInt(e.target.value); + if (selectedPublicBodyIDs.includes(publicBodyId)) { + setSelectedPublicBodyIDs((prev) => { + return [...prev.filter(id => id !== publicBodyId)] + }); + } + else { + setSelectedPublicBodyIDs((prev) => { + return [...prev, publicBodyId] + }); + } + } const saveDoc = () => { setRedlineModalOpen(false); @@ -2202,6 +2237,7 @@ const Redlining = React.forwardRef( switch (modalFor) { case "oipcreview": case "redline": + case "consult": saveRedlineDocument( docInstance, modalFor, @@ -2307,6 +2343,11 @@ const Redlining = React.forwardRef( isDisableNRDuplicate={isDisableNRDuplicate} saveDoc={saveDoc} modalData={modalData} + documentPublicBodies={documentPublicBodies} + handleSelectedPublicBodies={handleSelectedPublicBodies} + selectedPublicBodyIDs={selectedPublicBodyIDs} + consultApplyRedactions={consultApplyRedactions} + handleApplyRedactions={handleApplyRedactions} /> } {messageModalOpen && diff --git a/web/src/modules/documentReducer.ts b/web/src/modules/documentReducer.ts index 302df096f..be98b7a97 100644 --- a/web/src/modules/documentReducer.ts +++ b/web/src/modules/documentReducer.ts @@ -8,7 +8,8 @@ const initialState = { "description": "Redline", // "sortorder": 1, // "count": 0 - } + }, + allPublicBodies: [], } const documents = (state = initialState, action:any)=> { @@ -41,6 +42,8 @@ const documents = (state = initialState, action:any)=> { return {...state, redactionLayers: state.redactionLayers }; case ACTION_CONSTANTS.SET_DELETED_PAGES: return {...state, deletedDocPages: action.payload}; + case ACTION_CONSTANTS.SET_PUBLIC_BODIES: + return {...state, allPublicBodies: action.payload}; case ACTION_CONSTANTS.FOI_PERSONAL_SECTIONS: return { ...state, foiPersonalSections: action.payload }; case ACTION_CONSTANTS.FOI_PERSONAL_PEOPLE: From dbdbaaa8cb481a74c06e3277de21c7fd5a26a515 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 7 Aug 2024 17:18:45 -0700 Subject: [PATCH 21/57] Added consult code from PR 1036 for ticket 2646 to test-rook --- .../components/FOI/Home/ConfirmationModal.js | 17 +++++++-- web/src/components/FOI/Home/ConsultModal.tsx | 4 +-- .../useSaveRedlineForSignOff.js | 35 ++++++++++++++++--- web/src/components/FOI/Home/Redlining.js | 14 +++++++- 4 files changed, 60 insertions(+), 10 deletions(-) diff --git a/web/src/components/FOI/Home/ConfirmationModal.js b/web/src/components/FOI/Home/ConfirmationModal.js index 841093e3d..f25d82f68 100644 --- a/web/src/components/FOI/Home/ConfirmationModal.js +++ b/web/src/components/FOI/Home/ConfirmationModal.js @@ -28,7 +28,9 @@ export const ConfirmationModal= ({ handleSelectedPublicBodies, selectedPublicBodyIDs, consultApplyRedactions, - handleApplyRedactions + handleApplyRedactions, + consultApplyRedlines, + handleApplyRedlines }) => { return ( @@ -123,6 +125,16 @@ export const ConfirmationModal= ({ />
+ + +
- + } diff --git a/web/src/components/FOI/Home/ConsultModal.tsx b/web/src/components/FOI/Home/ConsultModal.tsx index 31da7b236..39ca4a0b9 100644 --- a/web/src/components/FOI/Home/ConsultModal.tsx +++ b/web/src/components/FOI/Home/ConsultModal.tsx @@ -100,7 +100,7 @@ const ConsultModal = ({ -
Select one or more Ministry you with the send the selected page(s) to for consult.
+
Select one or more public bodies you wish to consult with on the selected page(s).
{programAreaList.programareas?.map((programArea: any, index: number) => (
-
If you do not see the name of the Ministry you would like to send for consult above please type it below.
+
If you do not see the name of the public body you wish to consult with, please type it below.
{ const [selectedPublicBodyIDs, setSelectedPublicBodyIDs] = useState([]); const [documentPublicBodies, setDocumentPublicBodies] = useState([]); const [consultApplyRedactions, setConsultApplyRedactions] = useState(false); + const [consultApplyRedlines, setConsultApplyRedlines] = useState(false); const requestInfo = useAppSelector((state) => state.documents?.requestinfo); @@ -89,8 +90,18 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } else { for (let doc of divObj.documentlist) { + //page to pageFlag mappings logic for consults + const pagePageFlagMappings = {}; + for (let pageFlag of doc.pageFlag) { + if (pageFlag.page in pagePageFlagMappings) { + pagePageFlagMappings[pageFlag.page].push(pageFlag.flagid); + } else { + pagePageFlagMappings[pageFlag.page] = [pageFlag.flagid]; + } + } for (const flagInfo of doc.pageFlag) { if (modalFor == "consult") { + const pageFlagsOnPage = pagePageFlagMappings[flagInfo.page]; for (let consult of doc.consult) { if (consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) { if ( @@ -101,8 +112,12 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { (includeNRPages && flagInfo.flagid === pageFlagTypes["Not Responsive"]) ) ) { - if(isvalid == false) { - isvalid = true; + if(isvalid === false) { + if ((!includeDuplicatePages && pageFlagsOnPage.some((flagId) => flagId === pageFlagTypes["Duplicate"])) || (!includeNRPages && pageFlagsOnPage.some((flagId) => flagId === pageFlagTypes["Not Responsive"]))) { + isvalid = false; + } else { + isvalid = true; + } } } } @@ -1834,14 +1849,22 @@ const stampPageNumberRedline = async ( } //OIPC - Special Block : End - //Consults - Redactions Block (Redact S.NR) : Start + //Consults - Redlines + Redactions (Redact S.NR) Block : Start if(modalFor == "consult") { + if (!consultApplyRedlines) { + const publicbodyAnnotList = xmlObj.getElementsByTagName('annots')[0]['children']; + const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { + return annot.name !== "freetext" && annot.name !== 'redact' + }); + xmlObj.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; + xfdfString = parser.toString(xmlObj); + } if (consultApplyRedactions) { let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); await applyRedactionsToRedlinesBySection(nr_sectionStamps, PDFNet, stitchObject); } } - //Consults - Redactions Block (Redact S.NR) : End + //Consults - Redlines + Redactions (Redact S.NR) Block : End stitchObject .getFileData({ @@ -1862,7 +1885,7 @@ const stampPageNumberRedline = async ( (_res) => { // ######### call another process for zipping and generate download here ########## toast.update(toastId.current, { - render: `Redline PDF saved to Object Storage`, + render: `${modalFor == "consult" ? "Consult" : "Redline"} PDF saved to Object Storage`, type: "success", className: "file-upload-toast", isLoading: false, @@ -1994,6 +2017,8 @@ const stampPageNumberRedline = async ( selectedPublicBodyIDs, documentPublicBodies, consultApplyRedactions, + setConsultApplyRedlines, + consultApplyRedlines, }; }; diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 8825547ed..b3f0b4a85 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -160,7 +160,9 @@ const Redlining = React.forwardRef( setConsultApplyRedactions, selectedPublicBodyIDs, documentPublicBodies, - consultApplyRedactions + consultApplyRedactions, + setConsultApplyRedlines, + consultApplyRedlines, } = useSaveRedlineForSignoff(docInstance, docViewer); const { saveResponsePackage, @@ -2199,6 +2201,7 @@ const Redlining = React.forwardRef( setRedlineModalOpen(false); setSelectedPublicBodyIDs([]); setConsultApplyRedactions(false); + setConsultApplyRedlines(false); }; const handleIncludeNRPages = (e) => { @@ -2213,6 +2216,13 @@ const Redlining = React.forwardRef( setConsultApplyRedactions(e.target.checked); } + const handleApplyRedlines = (e) => { + setConsultApplyRedlines(e.target.checked); + if (consultApplyRedactions) { + setConsultApplyRedactions(false); + } + } + const handleSelectedPublicBodies = (e) => { const publicBodyId = parseInt(e.target.value); if (selectedPublicBodyIDs.includes(publicBodyId)) { @@ -2348,6 +2358,8 @@ const Redlining = React.forwardRef( selectedPublicBodyIDs={selectedPublicBodyIDs} consultApplyRedactions={consultApplyRedactions} handleApplyRedactions={handleApplyRedactions} + handleApplyRedlines={handleApplyRedlines} + consultApplyRedlines={consultApplyRedlines} /> } {messageModalOpen && From 3b581eabb83162ffa82745de6b87fb75f363d80c Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Thu, 8 Aug 2024 14:45:46 -0700 Subject: [PATCH 22/57] Added small changes to confirmation modal in merge of test-rook/marshal --- web/src/components/FOI/Home/ConfirmationModal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/FOI/Home/ConfirmationModal.js b/web/src/components/FOI/Home/ConfirmationModal.js index f25d82f68..41b6c66d0 100644 --- a/web/src/components/FOI/Home/ConfirmationModal.js +++ b/web/src/components/FOI/Home/ConfirmationModal.js @@ -80,7 +80,7 @@ export const ConfirmationModal= ({ /> } - {modalData.modalFor === "consult" && + {modalData?.modalFor === "consult" && <> {documentPublicBodies?.map((publicBody) => { From 70729724e74e87d98c4646b085d9379c043544be Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Fri, 9 Aug 2024 13:17:34 -0700 Subject: [PATCH 23/57] completed manual addition of consults to test-rook. WIP merge to test-marshal --- .../useSaveRedlineForSignOff.js | 30 +++++++++++-------- web/src/components/FOI/Home/Redlining.js | 5 ++-- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index e7a00b248..5c40ed071 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -100,7 +100,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } } for (const flagInfo of doc.pageFlag) { - if (modalFor == "consult") { + if (redlineCategory === "consult") { const pageFlagsOnPage = pagePageFlagMappings[flagInfo.page]; for (let consult of doc.consult) { if (consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) { @@ -192,7 +192,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { incompatibleFiles ) => { let newDocList = []; - if (modalFor == "redline" || modalFor == "oipcreview") { + if (redlineCategory === "redline" || redlineCategory === "oipcreview") { for (let div of divisions) { let divDocList = documentList?.filter((doc) => doc.divisions.map((d) => d.divisionid).includes(div.divisionid) @@ -211,7 +211,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { incompatableList: incompatableList, }); } - } else if (modalFor == "consult") { + } else if (redlineCategory === "consult") { // map documents to publicBodies (Divisions) for consults for (let publicBodyId of divisions) { let publicBodyDocList = []; @@ -261,7 +261,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } // sort based on sortorder as the sortorder added based on the LastModified prepareRedlinePageMappingByRequest(sortBySortOrder(reqdocuments), pageMappedDocs); - } else if (modalFor == "consult") { + } else if (redlineCategory === "consult") { prepareRedlinePageMappingByConsult(divisionDocuments); } else { prepareRedlinePageMappingByDivision(divisionDocuments); @@ -751,7 +751,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } }; const getzipredlinecategory = (layertype) => { - if (modalFor == "consult") { + if (redlineCategory === "consult") { return "consultpackage"; } if (currentLayer.name.toLowerCase() === "oipc") { @@ -1057,7 +1057,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { const divisionFilesList = [...documentList, ...incompatibleFiles]; let divisions; - if (modalFor == "consult") { + if (redlineCategory === "consult") { //Key consult logic, uses preexisting division reldine logic for consults divisions = selectedPublicBodyIDs; } else { @@ -1077,7 +1077,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }); setIsSingleRedlinePackage(res.issingleredlinepackage); let stitchDoc = {}; - + prepareRedlinePageMapping( res['divdocumentList'], res.issingleredlinepackage, @@ -1114,7 +1114,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { if (pageMappedDocs != undefined) { let divisionsdocpages = []; // for consults, no need to filter by division/consult - if (modalFor == "consult") { + if (redlineCategory === "consult") { Object.values( pageMappedDocs.redlineDocIdLookup ) @@ -1279,12 +1279,16 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { !readyForSignOff; } }; - const checkSavingConsults = (documentList) => { + const checkSavingConsults = (documentList, instance) => { const publicBodyList = getPublicBodyList(documentList); setDocumentPublicBodies(publicBodyList); setEnableSavingConsults( publicBodyList.length > 0 ); + if (instance) { + const document = instance.UI.iframeWindow.document; + document.getElementById("consult_package").disabled = !(publicBodyList.length > 0); + } } const triggerRedlineZipper = ( divObj, @@ -1672,7 +1676,7 @@ const stampPageNumberRedline = async ( sectionStamps[parentRedactionId] = annotationpagenumbers[parentRedactionId]; } - if (modalFor == "consult" && sections.some(item => item.section === 'NR')) { + if (redlineCategory === "consult" && sections.some(item => item.section === 'NR')) { sectionStamps[parentRedactionId] = annotationpagenumbers[parentRedactionId]; } } @@ -1798,7 +1802,7 @@ const stampPageNumberRedline = async ( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); - if(redlineCategory !== "oipcreview" || modalFor == "consult") { + if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { await stampPageNumberRedline( stitchObject, PDFNet, @@ -1850,7 +1854,7 @@ const stampPageNumberRedline = async ( //OIPC - Special Block : End //Consults - Redlines + Redactions (Redact S.NR) Block : Start - if(modalFor == "consult") { + if(redlineCategory === "consult") { if (!consultApplyRedlines) { const publicbodyAnnotList = xmlObj.getElementsByTagName('annots')[0]['children']; const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { @@ -1885,7 +1889,7 @@ const stampPageNumberRedline = async ( (_res) => { // ######### call another process for zipping and generate download here ########## toast.update(toastId.current, { - render: `${modalFor == "consult" ? "Consult" : "Redline"} PDF saved to Object Storage`, + render: `${redlineCategory === "consult" ? "Consult" : "Redline"} PDF saved to Object Storage`, type: "success", className: "file-upload-toast", isLoading: false, diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index b3f0b4a85..f2e6278b0 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -227,7 +227,7 @@ const Redlining = React.forwardRef( finalPackageBtn.onclick = () => { handleFinalPackageClick(updateModalData, setRedlineModalOpen); }; - consultPackageButton.onClick = () => { + consultPackageButton.onclick = () => { handleConsultPackageClick(updateModalData, setRedlineModalOpen, setIncludeDuplicatePages, setIncludeNRPages) }; menu.appendChild(redlineForOipcBtn); @@ -550,6 +550,7 @@ const Redlining = React.forwardRef( }, []); const updateModalData = (newModalData) => { + setRedlineCategory(newModalData.modalFor); setModalData(newModalData); }; @@ -1336,7 +1337,7 @@ const Redlining = React.forwardRef( const validRedlineDownload = isValidRedlineDownload(pageFlags); const redlineReadyAndValid = readyForSignOff && validRedlineDownload; const oipcRedlineReadyAndValid = (validoipcreviewlayer === true && currentLayer.name.toLowerCase() === "oipc") && readyForSignOff; - checkSavingConsults(documentList); + checkSavingConsults(documentList, _instance); checkSavingRedline(redlineReadyAndValid, _instance); checkSavingOIPCRedline(oipcRedlineReadyAndValid, _instance, readyForSignOff); checkSavingFinalPackage(redlineReadyAndValid, _instance); From 793160f72bffd31a2ab64235ef4ba2026972c548 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Mon, 12 Aug 2024 10:52:37 -0700 Subject: [PATCH 24/57] fixed small bug relating to data.documentdivisions --- web/src/components/FOI/Home/Home.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/FOI/Home/Home.js b/web/src/components/FOI/Home/Home.js index 5d394a647..c243be96c 100644 --- a/web/src/components/FOI/Home/Home.js +++ b/web/src/components/FOI/Home/Home.js @@ -71,7 +71,7 @@ function Home() { async (data) => { setOutstandingBalance(data.requestinfo.outstandingbalance) setIsBalanceFeeOverrode(data.requestinfo.balancefeeoverrodforrequest) - setDivisions(data.documentDivisions); + setDivisions(data.documentdivisions); const getFileExt = (filepath) => { const parts = filepath.split(".") const fileExt = parts.pop() From 5793726cc25421d7e3d65d73179550d735450895 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Mon, 12 Aug 2024 13:52:16 -0700 Subject: [PATCH 25/57] refactored feeoverride modal to its own component --- .../components/FOI/Home/FeeOverrideModal.jsx | 94 +++++++++++++++++++ web/src/components/FOI/Home/Redlining.js | 79 +++------------- 2 files changed, 106 insertions(+), 67 deletions(-) create mode 100644 web/src/components/FOI/Home/FeeOverrideModal.jsx diff --git a/web/src/components/FOI/Home/FeeOverrideModal.jsx b/web/src/components/FOI/Home/FeeOverrideModal.jsx new file mode 100644 index 000000000..db1341bbd --- /dev/null +++ b/web/src/components/FOI/Home/FeeOverrideModal.jsx @@ -0,0 +1,94 @@ +import ReactModal from "react-modal-resizable-draggable"; +import DialogActions from "@mui/material/DialogActions"; +import DialogContent from "@mui/material/DialogContent"; +import DialogContentText from "@mui/material/DialogContentText"; +import DialogTitle from "@mui/material/DialogTitle"; +import CloseIcon from "@mui/icons-material/Close"; +import IconButton from "@mui/material/IconButton"; + +const FeeOverrideModal = ({ + modalData, + cancelRedaction, + outstandingBalanceModal, + cancelSaveRedlineDoc, + isOverride, + feeOverrideReason, + handleOverrideReasonChange, + saveDoc, + overrideOutstandingBalance, +}) => { + return ( + <> + + +

{modalData?.modalTitle}

+ + Close + + +
+ + + + {modalData?.modalMessage} + {isOverride && ( + <> +
+
+ + + + )} +
+
+
+ + {!isOverride && ( + + )} + {isOverride && ( + + )} + + +
+ + ); +}; + +export default FeeOverrideModal; diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index a7530c4c6..e068d950d 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -66,14 +66,7 @@ import useSaveResponsePackage from "./CreateResponsePDF/useSaveResponsePackage"; import {ConfirmationModal} from "./ConfirmationModal"; import { FOIPPASectionsModal } from "./FOIPPASectionsModal"; import { NRWarningModal } from "./NRWarningModal"; - -import ReactModal from "react-modal-resizable-draggable"; -import DialogActions from "@mui/material/DialogActions"; -import DialogContent from "@mui/material/DialogContent"; -import DialogContentText from "@mui/material/DialogContentText"; -import DialogTitle from "@mui/material/DialogTitle"; -import CloseIcon from "@mui/icons-material/Close"; -import IconButton from "@mui/material/IconButton"; +import FeeOverrideModal from "./FeeOverrideModal"; const Redlining = React.forwardRef( ( @@ -101,8 +94,6 @@ const Redlining = React.forwardRef( (state) => state.documents?.requestnumber ); - const allPublicBodies = useAppSelector((state) => state.documents?.allPublicBodies) - document.title = requestnumber + " - FOI Document Reviewer" const redactionInfo = useSelector( @@ -2401,63 +2392,17 @@ const Redlining = React.forwardRef( modalData={modalData} /> } - - -

{modalData?.modalTitle}

- - Close - - -
- - - - {modalData?.modalMessage} - {isOverride && <> -

- - - } -
-
-
- - {!isOverride && - - } - {isOverride && - - } - - -
+
); } From 31a9060413d9f1eeb57653549d68eea140953267 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Mon, 12 Aug 2024 14:12:20 -0700 Subject: [PATCH 26/57] Small code clean --- .../useSaveRedlineForSignOff.js | 1 - .../components/FOI/Home/FeeOverrideModal.jsx | 130 +++++++++--------- 2 files changed, 63 insertions(+), 68 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 5c40ed071..849cc59fd 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -1091,7 +1091,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { let documentsObjArr = []; let divisionstitchpages = []; let divCount = 0; - console.log("RES:",res) for (let div of res.divdocumentList) { divCount++; let docCount = 0; diff --git a/web/src/components/FOI/Home/FeeOverrideModal.jsx b/web/src/components/FOI/Home/FeeOverrideModal.jsx index db1341bbd..a64862710 100644 --- a/web/src/components/FOI/Home/FeeOverrideModal.jsx +++ b/web/src/components/FOI/Home/FeeOverrideModal.jsx @@ -18,76 +18,72 @@ const FeeOverrideModal = ({ overrideOutstandingBalance, }) => { return ( - <> - - -

{modalData?.modalTitle}

- - Close - - -
- - - - {modalData?.modalMessage} - {isOverride && ( - <> -
-
- - - - )} -
-
-
- - {!isOverride && ( - - )} - {isOverride && ( - - )} + + +

{modalData?.modalTitle}

+ + Close + + +
+ + + + {modalData?.modalMessage} + {isOverride && ( + <> +
+
+ + + + )} +
+
+
+ + {!isOverride && ( + )} + {isOverride && ( + - -
- + )} + +
+
); }; From caf216dbcc48d995240380dd77b1f7a5e5f5944d Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Tue, 20 Aug 2024 15:03:55 -0700 Subject: [PATCH 27/57] bug fix involved with 10.1 release --- web/src/components/FOI/Home/utils.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/web/src/components/FOI/Home/utils.js b/web/src/components/FOI/Home/utils.js index fe926edf5..ef736a94f 100644 --- a/web/src/components/FOI/Home/utils.js +++ b/web/src/components/FOI/Home/utils.js @@ -783,6 +783,9 @@ export const skipNRDocument = (documentPageFlags, pagecount, pageFlagTypes) => { export const findNROrDuplicatePageFlag = (pageFlags, docObj, pageFlagTypes) => { const docPageFlags = pageFlags.find(pageFlagObj => pageFlagObj.documentid === docObj.docid); + if (!docPageFlags) { + return false; + } for (let pageFlag of docPageFlags.pageflag) { if ((pageFlag.page === docObj.page && pageFlag.flagid === pageFlagTypes["Duplicate"]) || (pageFlag.page === docObj.page && pageFlag.flagid === pageFlagTypes["Not Responsive"])) { return pageFlag; From 16d2db1985a53ddedf5df98ce96e5aac325c6723 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Thu, 29 Aug 2024 16:35:59 -0700 Subject: [PATCH 28/57] QA observation / bug fixes 2 and 3 fixed. WIP 1,4,5 observations --- api/reviewer_api/resources/foiflowmasterdata.py | 2 +- web/src/components/FOI/Home/ConfirmationModal.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api/reviewer_api/resources/foiflowmasterdata.py b/api/reviewer_api/resources/foiflowmasterdata.py index 7fe29a3ac..1d50eb851 100644 --- a/api/reviewer_api/resources/foiflowmasterdata.py +++ b/api/reviewer_api/resources/foiflowmasterdata.py @@ -219,7 +219,7 @@ def post(ministryrequestid, redactionlayer="redline", layertype="redline"): ) if packagetype == "consult": filepath_put = "{0}/{2}/{2} - {1} - {0}.pdf".format( - filepathlist[0], division_name, packagetype + filepathlist[0], division_name, 'Consult' ) s3path_save = s3client.generate_presigned_url( ClientMethod="get_object", diff --git a/web/src/components/FOI/Home/ConfirmationModal.js b/web/src/components/FOI/Home/ConfirmationModal.js index 41b6c66d0..add1e746b 100644 --- a/web/src/components/FOI/Home/ConfirmationModal.js +++ b/web/src/components/FOI/Home/ConfirmationModal.js @@ -91,12 +91,12 @@ export const ConfirmationModal= ({ type="checkbox" style={{ marginRight: 10 }} className="redline-checkmark" - id={`${publicBody.bcgovcode}-checkbox`} + id={`${publicBody.iaocode}-checkbox`} value={publicBody.programareaid} checked={selectedPublicBodyIDs.includes(publicBody.programareaid)} onClick={handleSelectedPublicBodies} /> - + ) })} From 16666949a0a2df2ab3592a49a384b78e24204c6b Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Tue, 3 Sep 2024 13:55:02 -0700 Subject: [PATCH 29/57] Obervation 5 issue from QA solved. Custom public body packages can now be created --- .../components/FOI/Home/ConfirmationModal.js | 6 +-- .../useSaveRedlineForSignOff.js | 51 +++++++++++++++---- web/src/components/FOI/Home/Redlining.js | 2 +- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/web/src/components/FOI/Home/ConfirmationModal.js b/web/src/components/FOI/Home/ConfirmationModal.js index add1e746b..ab49df08a 100644 --- a/web/src/components/FOI/Home/ConfirmationModal.js +++ b/web/src/components/FOI/Home/ConfirmationModal.js @@ -87,13 +87,13 @@ export const ConfirmationModal= ({ return (<> diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 849cc59fd..e604e39da 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -103,7 +103,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { if (redlineCategory === "consult") { const pageFlagsOnPage = pagePageFlagMappings[flagInfo.page]; for (let consult of doc.consult) { - if (consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) { + if ((consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) || (consult.page === flagInfo.page && consult.other.includes(divObj.divisionname))) { if ( ( flagInfo.flagid !== pageFlagTypes["Duplicate"] && flagInfo.flagid !== pageFlagTypes["Not Responsive"]) || @@ -212,7 +212,9 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }); } } else if (redlineCategory === "consult") { - // map documents to publicBodies (Divisions) for consults + // map documents to publicBodies and custom public bodies (treated as Divisions) for consults package. + // Consult Package logic will treat publicbodies (program areas + custom consults) as DIVISIONS and will incorporate the existing division mapping + redline logic to generate the consult package + console.log("DIV", divisions) for (let publicBodyId of divisions) { let publicBodyDocList = []; documentList.forEach((doc) => { @@ -225,6 +227,13 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } }) }); + for (let consult of doc.consult) { + for (let customPublicBody of consult.other) { + if (customPublicBody === publicBodyId) { + programareaids.add(customPublicBody); + } + } + } } for (let programareaid of programareaids) { if (programareaid === publicBodyId) { @@ -233,18 +242,22 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } }) publicBodyDocList = sortBySortOrder(publicBodyDocList); + console.log("sorteddoclist",publicBodyDocList ) let incompatableList = []; - const publicBodyInfo = allPublicBodies.find((body) => body.programareaid === publicBodyId) + // Custom public bodies/consults do not exist in allPublicBodies data (BE program area data) and are stored as simple strings with pageflag data (in other array attribute). + // Therefore, if publicBodyInfo cannot be found in allPublicBodies, the publicbody is a custom one and we will create its 'divison' data in the FE with a random unique id (date.now()), and its publicBodyID (which is its name as a string) for consult package creation purposes + const publicBodyInfo = allPublicBodies.find((body) => body.programareaid === publicBodyId); newDocList.push({ - divisionid: publicBodyId, - divisionname: publicBodyInfo.name, + divisionid: publicBodyInfo ? publicBodyInfo.programareaid : Date.now(), + divisionname: publicBodyInfo ? publicBodyInfo.name : publicBodyId, documentlist: publicBodyDocList, incompatableList: incompatableList, }) } } + console.log("newdoclist", newDocList) return newDocList; }; const prepareRedlinePageMapping = ( @@ -552,7 +565,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { for (let flagInfo of pageFlagsOnPage) { let hasConsult = false; for (let consult of doc.consult) { - if (consult.page == flagInfo.page && consult.programareaid.includes(divObj.divisionid)) { + if ((consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) || (consult.page === flagInfo.page && consult.other.includes(divObj.divisionname))) { hasConsult = true; break; } @@ -630,7 +643,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { // Check if the page has relevant consult flag, if not remove the page let hasConsult = false; for (let consult of doc.consult) { - if (consult.page == flagInfo.page && consult.programareaid.includes(divObj.divisionid)) { + if ((consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) || (consult.page === flagInfo.page && consult.other.includes(divObj.divisionname))) { hasConsult = true; break; } @@ -1020,23 +1033,39 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { for (let pageflag of doc['pageFlag']) { if ('programareaid' in pageflag) { for (let programareaid of pageflag['programareaid']) { - publicBodyIdList.push(programareaid) + publicBodyIdList.push(programareaid); + } + } + // Logic to include custom consults/public bodies as they are stored in another array (other) and not with programareaids + if ('other' in pageflag) { + for (let customPublicBody of pageflag['other']) { + publicBodyIdList.push(customPublicBody); } } } } } - const filteredPublicBodyIdList = [...new Set(publicBodyIdList)] + const filteredPublicBodyIdList = [...new Set(publicBodyIdList)]; return getPublicBodyObjs(filteredPublicBodyIdList); } } const getPublicBodyObjs = (publicBodyIDList) => { const publicBodies = []; - for (const publicBody of allPublicBodies) { - if (publicBodyIDList.includes(publicBody.programareaid)) { + for (let publicBodyId of publicBodyIDList) { + const publicBody = allPublicBodies.find(publicBody => publicBody.programareaid === publicBodyId); + if (publicBody) { publicBodies.push(publicBody); + } else { + // Custom public bodies/consults will not exist in allPublicBodies data (BE data for program areas) as they are not stored in the BE as programe areas (but rather as basic pageflags) + const customPublicBody = { + name: publicBodyId, + programareaid: null, + iaocode: publicBodyId + }; + publicBodies.push(customPublicBody); } } + console.log("pubbodies", publicBodies) return publicBodies; } diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 8d95c53fe..c31d2c62b 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -2241,7 +2241,7 @@ const Redlining = React.forwardRef( } const handleSelectedPublicBodies = (e) => { - const publicBodyId = parseInt(e.target.value); + let publicBodyId = !isNaN(parseInt(e.target.value)) ? parseInt(e.target.value) : e.target.value; if (selectedPublicBodyIDs.includes(publicBodyId)) { setSelectedPublicBodyIDs((prev) => { return [...prev.filter(id => id !== publicBodyId)] From 8afeec865a9393b28eb75d001320d59beb51c907 Mon Sep 17 00:00:00 2001 From: Aparna Date: Tue, 3 Sep 2024 16:33:18 -0700 Subject: [PATCH 30/57] FOIMOD-3073- Fees - Remaining Balance Check- Merge issues solved Test marshal - Feature not working due to Merge issues : resolved --- api/reviewer_api/schemas/finalpackage.py | 1 + .../CreateResponsePDF/CreateResponsePDF.js | 76 ++++++++++++------- .../useSaveResponsePackage.js | 5 +- web/src/components/FOI/Home/Redlining.js | 12 ++- 4 files changed, 63 insertions(+), 31 deletions(-) diff --git a/api/reviewer_api/schemas/finalpackage.py b/api/reviewer_api/schemas/finalpackage.py index 3f8b3be0b..a4500e585 100644 --- a/api/reviewer_api/schemas/finalpackage.py +++ b/api/reviewer_api/schemas/finalpackage.py @@ -57,3 +57,4 @@ class MCFFinalPackageSchema(Schema): ) summarydocuments = fields.Nested(MCFSummarySchema, allow_none=True) redactionlayerid = fields.Int(data_key="redactionlayerid", allow_none=False) + pdfstitchjobattributes = fields.Nested(FeeOverrideSchema, allow_none=True, many=False) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/CreateResponsePDF.js b/web/src/components/FOI/Home/CreateResponsePDF/CreateResponsePDF.js index f77d9b71a..5bbfa33e0 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/CreateResponsePDF.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/CreateResponsePDF.js @@ -139,35 +139,55 @@ export const handleRedlineForOipcClick = ( export const handleFinalPackageClick = ( updateModalData, - setRedlineModalOpen + setRedlineModalOpen, + outstandingBalance, + isBalanceFeeOverrode, + setOutstandingBalanceModal, + setIsOverride ) => { - updateModalData({ - modalFor: "responsepackage", - modalTitle: "Create Package for Applicant", - modalMessage: [ - "This should only be done when all redactions are finalized and ready to ", - - be - , - " sent to the ", - - Applicant - , - ". This will ", - - permanently - , - " apply the redactions and automatically create page stamps.", -
, -
, - - When you create the response package, your web browser page - will automatically refresh - , - ], - modalButtonLabel: "Create Applicant Package" - }); - setRedlineModalOpen(true); + + if(outstandingBalance > 0 && !isBalanceFeeOverrode){ + updateModalData({ + modalFor: "responsepackage", + modalTitle: "Create Package for Applicant", + modalMessage:[ + "There is an outstanding balance of fees, please cancel to resolve, or click override to proceed", + ], + modalButtonLabel: "Override" + }); + setOutstandingBalanceModal(true); + setIsOverride(false) + } + else{ + // Download + updateModalData({ + modalFor: "responsepackage", + modalTitle: "Create Package for Applicant", + modalMessage: [ + "This should only be done when all redactions are finalized and ready to ", + + be + , + " sent to the ", + + Applicant + , + ". This will ", + + permanently + , + " apply the redactions and automatically create page stamps.", +
, +
, + + When you create the response package, your web browser page + will automatically refresh + , + ], + modalButtonLabel: "Create Applicant Package" + }); + setRedlineModalOpen(true); + } }; export const handleConsultPackageClick = ( diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveResponsePackage.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveResponsePackage.js index 3a2a6a4c4..6b003abe3 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveResponsePackage.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveResponsePackage.js @@ -212,7 +212,8 @@ const useSaveResponsePackage = () => { _instance, documentList, pageMappedDocs, - pageFlags + pageFlags, + feeOverrideReason ) => { const downloadType = "pdf"; let zipServiceMessage = { @@ -223,6 +224,7 @@ const useSaveResponsePackage = () => { bcgovcode: "", summarydocuments: {} , redactionlayerid: currentLayer.redactionlayerid, + pdfstitchjobattributes:{"feeoverridereason":""} }; getResponsePackagePreSignedUrl( foiministryrequestid, @@ -232,6 +234,7 @@ const useSaveResponsePackage = () => { zipServiceMessage.requestnumber = res.requestnumber; zipServiceMessage.bcgovcode = res.bcgovcode; zipServiceMessage.summarydocuments= prepareresponseredlinesummarylist(documentList,zipServiceMessage.bcgovcode) + zipServiceMessage.pdfstitchjobattributes= {"feeoverridereason":feeOverrideReason} let annotList = annotationManager.getAnnotationsList(); annotationManager.ungroupAnnotations(annotList); /** remove duplicate and not responsive pages */ diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 8d95c53fe..ea2c110e8 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -233,7 +233,8 @@ const Redlining = React.forwardRef( handleRedlineForSignOffClick(updateModalData, setRedlineModalOpen); }; finalPackageBtn.onclick = () => { - handleFinalPackageClick(updateModalData, setRedlineModalOpen); + handleFinalPackageClick(updateModalData, setRedlineModalOpen, outstandingBalance, + isBalanceFeeOverrode,setOutstandingBalanceModal,setIsOverride); }; consultPackageButton.onclick = () => { handleConsultPackageClick(updateModalData, setRedlineModalOpen, setIncludeDuplicatePages, setIncludeNRPages) @@ -2219,6 +2220,12 @@ const Redlining = React.forwardRef( setSelectedPublicBodyIDs([]); setConsultApplyRedactions(false); setConsultApplyRedlines(false); + if(outstandingBalance > 0 && !isBalanceFeeOverrode){ + setOutstandingBalanceModal(false) + setIsOverride(false) + } + else + setRedlineModalOpen(false); }; const handleIncludeNRPages = (e) => { @@ -2283,7 +2290,8 @@ const Redlining = React.forwardRef( docInstance, documentList, pageMappedDocs, - pageFlags + pageFlags, + feeOverrideReason ); break; default: From c4f39764805fcbadf47e3ab8d69a46a328ccf4db Mon Sep 17 00:00:00 2001 From: Abin Antony Date: Wed, 4 Sep 2024 17:25:05 -0700 Subject: [PATCH 31/57] #FOIMOD-3439 TEst build to test-marshal for removing sensitive content --- .../ZippingServices/requirements.txt | Bin 760 -> 790 bytes .../ZippingServices/services/zipperservice.py | 29 ++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/computingservices/ZippingServices/requirements.txt b/computingservices/ZippingServices/requirements.txt index 6e93668753e3922077ce2411f35c45e150eb823a..a08f010df70dbc95af321746348195b932952cee 100644 GIT binary patch delta 38 pcmeytI*o0^4< Date: Mon, 9 Sep 2024 13:22:48 -0700 Subject: [PATCH 32/57] Adjusted redline creation process to fix bug where redactions were showing for NR consults when page rotated. Redline creation process for stitch and upload is now 1. apply redlines 2. remove pages 3. apply redactions (if any) 4. apply rotations 5. apply stamping 5. apply watermark. Previously it was 1. apply rotations, 2. apply reldines, 3. stamp pages 4. remove pages 5. apply watermakr 6. apply redactions --- .../useSaveRedlineForSignOff.js | 59 +++++++++++-------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index e604e39da..b3fb36f9d 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -214,7 +214,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } else if (redlineCategory === "consult") { // map documents to publicBodies and custom public bodies (treated as Divisions) for consults package. // Consult Package logic will treat publicbodies (program areas + custom consults) as DIVISIONS and will incorporate the existing division mapping + redline logic to generate the consult package - console.log("DIV", divisions) for (let publicBodyId of divisions) { let publicBodyDocList = []; documentList.forEach((doc) => { @@ -242,7 +241,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } }) publicBodyDocList = sortBySortOrder(publicBodyDocList); - console.log("sorteddoclist",publicBodyDocList ) let incompatableList = []; @@ -257,7 +255,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }) } } - console.log("newdoclist", newDocList) return newDocList; }; const prepareRedlinePageMapping = ( @@ -813,6 +810,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { let divCount = 0; const noofdivision = Object.keys(stitchlist).length; let stitchedDocObj = null; + setTotalStitchList(stitchlist) for (const [key, value] of Object.entries(stitchlist)) { divCount++; let docCount = 0; @@ -849,7 +847,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { loadAsPDF: true, useDownloader: false, // Added to fix BLANK page issue }).then(async (docObj) => { - applyRotations(docObj, doc.attributes.rotatedpages) + // applyRotations(docObj, doc.attributes.rotatedpages) //if (isIgnoredDocument(doc, docObj.getPageCount(), divisionDocuments) == false) { docCountCopy++; docCount++; @@ -1065,7 +1063,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { publicBodies.push(customPublicBody); } } - console.log("pubbodies", publicBodies) return publicBodies; } @@ -1349,7 +1346,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { includenrpages: includeNRPages, }; if (stitchedDocPath) { - console.log("stitchedDocPath:",stitchedDocPath) const stitchedDocPathArray = stitchedDocPath?.split("/"); let fileName = stitchedDocPathArray[stitchedDocPathArray.length - 1].split("?")[0]; @@ -1830,14 +1826,6 @@ const stampPageNumberRedline = async ( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); - if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { - await stampPageNumberRedline( - stitchObject, - PDFNet, - redlineStitchInfo[divisionid]["stitchpages"], - isSingleRedlinePackage - ); - } if ( redlinepageMappings["pagestoremove"][divisionid] && redlinepageMappings["pagestoremove"][divisionid].length > 0 && @@ -1847,14 +1835,6 @@ const stampPageNumberRedline = async ( redlinepageMappings["pagestoremove"][divisionid] ); } - if (redlineCategory === "redline") { - await addWatermarkToRedline( - stitchObject, - redlineWatermarkPageMapping, - key - ); - } - let string = await stitchObject.extractXFDF() let xmlObj = parser.parseFromString(string.xfdfString); @@ -1897,6 +1877,32 @@ const stampPageNumberRedline = async ( } } //Consults - Redlines + Redactions (Redact S.NR) Block : End + + // Rotate pages + for (const [key, value] of Object.entries(totalStitchList)) { + let documentlist = totalStitchList[key]; + if(documentlist.length > 0) { + for (let doc of documentlist) { + applyRotations(stitchObject, doc.attributes.rotatedpages) + } + } + } + // Stamp and apply watermark + if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { + await stampPageNumberRedline( + stitchObject, + PDFNet, + redlineStitchInfo[divisionid]["stitchpages"], + isSingleRedlinePackage + ); + } + if (redlineCategory === "redline" || redlineCategory === "consult") { + await addWatermarkToRedline( + stitchObject, + redlineWatermarkPageMapping, + key + ); + } stitchObject .getFileData({ @@ -1955,9 +1961,16 @@ const stampPageNumberRedline = async ( } } }; + + const applyRotations = (document, rotatedpages) => { + for (let page in rotatedpages) { + let existingrotation = document.getPageRotation(page); + let rotation = (rotatedpages[page] - existingrotation + 360) / 90; + document.rotatePages([page], rotation); + } + } useEffect(() => { - if ( redlineStitchObject && redlineDocumentAnnotations && From afe3817d40a6d15a7d074b2553cf45210366bf8d Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Tue, 10 Sep 2024 17:17:14 -0700 Subject: [PATCH 33/57] page rotation logic in redline adjusted / moved to end of redline creation (originally it was done before) to allow for redaactions to be applied (if any) before rotations. WIP code clean --- .../useSaveRedlineForSignOff.js | 172 +++++++++++------- 1 file changed, 111 insertions(+), 61 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index b3fb36f9d..44a0e61f8 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -214,6 +214,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } else if (redlineCategory === "consult") { // map documents to publicBodies and custom public bodies (treated as Divisions) for consults package. // Consult Package logic will treat publicbodies (program areas + custom consults) as DIVISIONS and will incorporate the existing division mapping + redline logic to generate the consult package + console.log("DIV", divisions) for (let publicBodyId of divisions) { let publicBodyDocList = []; documentList.forEach((doc) => { @@ -241,6 +242,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } }) publicBodyDocList = sortBySortOrder(publicBodyDocList); + console.log("sorteddoclist",publicBodyDocList ) let incompatableList = []; @@ -255,6 +257,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }) } } + console.log("newdoclist", newDocList) return newDocList; }; const prepareRedlinePageMapping = ( @@ -817,6 +820,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { // added this vopy variable for validating the first document of a division with NR/Duplicate let docCountCopy = 0; let division = key; + console.log("stitchlist", stitchlist) let documentlist = stitchlist[key]; if (redlineSinglePkg == "N") { toast.update(toastId.current, { @@ -1063,6 +1067,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { publicBodies.push(customPublicBody); } } + console.log("pubbodies", publicBodies) return publicBodies; } @@ -1369,7 +1374,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { if (divisionCountForToast === zipServiceMessage.attributes.length) { triggerDownloadRedlines(zipServiceMessage, (error) => { console.log(error); - window.location.reload(); + // window.location.reload(); }); } return zipServiceMessage; @@ -1775,6 +1780,30 @@ const stampPageNumberRedline = async ( } for (const rect of rects) { let height = docViewer.getPageHeight(rect.vpageno); + let x1 = rect.recto.x1 + let y1 = rect.recto.y1 + let x2 = rect.recto.x2 + let y2 = rect.recto.y2 + console.log("coords", x1,y1,x2,y2) + // const sectionAnnotation = rect.sectionAnnotation; + // // let quad = sectionAnnotation.getQuads()[0]; + // // let rect = new docInstance.Core.Math.Rect(quad.x1, quad.y3, quad.x2, quad.y2); + // const doc = docViewer.getDocument(); + // // const pageInfo = doc.getPageInfo(sectionAnnotation.PageNumber); + // // const pageMatrix = doc.getPageMatrix(sectionAnnotation.PageNumber); + // const pageRotation = doc.getPageRotation(sectionAnnotation.PageNumber); + // // _annot.FontSize = Math.min(parseInt(_redaction.FontSize), 9) + "pt"; + // sectionAnnotation.Rotation = 0; // reset rotation before resizing + // // _annot.fitText(pageInfo, pageMatrix, pageRotation); + // let annotrect = sectionAnnotation.getRect(); + // annotrect.x2 = Math.ceil(annotrect.x2); + // sectionAnnotation.setRect(annotrect); + // if (pageRotation === 180) { + // x1 = x2 - sectionAnnotation.Width + // y1 = y2 - sectionAnnotation.Height + // rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(x1,height-y1,x2,height-y2)), false, '')); + // sectionAnnotation.Rotation = pageRotation; + // } else { rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(rect.recto.x1,height-rect.recto.y1,rect.recto.x2,height-rect.recto.y2)), false, '')); } if (rarr.length > 0) { @@ -1796,6 +1825,7 @@ const stampPageNumberRedline = async ( }, [initDocViewer]); const StitchAndUploadDocument = async () => { + console.log("STITCH AND UPLOAD YE") const { PDFNet } = docInstance.Core; const downloadType = "pdf"; let currentDivisionCount = 0; @@ -1810,8 +1840,8 @@ const stampPageNumberRedline = async ( isLoading: true, autoClose: 5000, }); - let divisionid = key; + console.log("redlinepageMappings", redlinepageMappings) let stitchObject = redlineStitchObject[key]; if (stitchObject == null) { triggerRedlineZipper( @@ -1826,6 +1856,14 @@ const stampPageNumberRedline = async ( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); + if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { + await stampPageNumberRedline( + stitchObject, + PDFNet, + redlineStitchInfo[divisionid]["stitchpages"], + isSingleRedlinePackage + ); + } if ( redlinepageMappings["pagestoremove"][divisionid] && redlinepageMappings["pagestoremove"][divisionid].length > 0 && @@ -1835,6 +1873,14 @@ const stampPageNumberRedline = async ( redlinepageMappings["pagestoremove"][divisionid] ); } + if (redlineCategory === "redline") { // WATER MARK CONSULTS? + await addWatermarkToRedline( + stitchObject, + redlineWatermarkPageMapping, + key + ); + } + let string = await stitchObject.extractXFDF() let xmlObj = parser.parseFromString(string.xfdfString); @@ -1844,65 +1890,50 @@ const stampPageNumberRedline = async ( annotsObj[0].children = annotsObj[0].children.concat(annots.children) } else { xmlObj.children.push(annots) - } - + } let xfdfString = parser.toString(xmlObj); - - //OIPC - Special Block (Redact S.14) : Begin - if(redlineCategory === "oipcreview") { - let s14_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - await applyRedactionsToRedlinesBySection(s14_sectionStamps, PDFNet, stitchObject); - await stampPageNumberRedline( - stitchObject, - PDFNet, - redlineStitchInfo[divisionid]["stitchpages"], - isSingleRedlinePackage - ); - } - //OIPC - Special Block : End - - //Consults - Redlines + Redactions (Redact S.NR) Block : Start - if(redlineCategory === "consult") { - if (!consultApplyRedlines) { - const publicbodyAnnotList = xmlObj.getElementsByTagName('annots')[0]['children']; - const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { - return annot.name !== "freetext" && annot.name !== 'redact' - }); - xmlObj.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; - xfdfString = parser.toString(xmlObj); + + //Apply Redactions (if any) + //OIPC - Special Block (Redact S.14) : Begin + if(redlineCategory === "oipcreview") { + let s14_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); + await applyRedactionsToRedlinesBySection(s14_sectionStamps, PDFNet, stitchObject); + await stampPageNumberRedline( + stitchObject, + PDFNet, + redlineStitchInfo[divisionid]["stitchpages"], + isSingleRedlinePackage + ); } - if (consultApplyRedactions) { - let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - await applyRedactionsToRedlinesBySection(nr_sectionStamps, PDFNet, stitchObject); + //OIPC - Special Block : End + + //Consults - Redlines + Redactions (Redact S.NR) Block : Start + if(redlineCategory === "consult") { + if (!consultApplyRedlines) { + const publicbodyAnnotList = xmlObj.getElementsByTagName('annots')[0]['children']; + const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { + return annot.name !== "freetext" && annot.name !== 'redact' + }); + xmlObj.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; + xfdfString = parser.toString(xmlObj); + } + if (consultApplyRedactions) { + let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); + await applyRedactionsToRedlinesBySection(nr_sectionStamps, PDFNet, stitchObject); + } } - } - //Consults - Redlines + Redactions (Redact S.NR) Block : End - - // Rotate pages - for (const [key, value] of Object.entries(totalStitchList)) { - let documentlist = totalStitchList[key]; - if(documentlist.length > 0) { - for (let doc of documentlist) { - applyRotations(stitchObject, doc.attributes.rotatedpages) + //Consults - Redlines + Redactions (Redact S.NR) Block : End + + // Rotate pages + console.log("totalStithclist", totalStitchList) + for (const doc of totalStitchList[divisionid]) { + let documentlist = totalStitchList[divisionid]; + let divDocPageMappings = redlinepageMappings["divpagemappings"][divisionid]; + if(documentlist.length > 0) { + console.log("doc2", doc) + applyRotations(stitchObject, doc, divDocPageMappings); } } - } - // Stamp and apply watermark - if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { - await stampPageNumberRedline( - stitchObject, - PDFNet, - redlineStitchInfo[divisionid]["stitchpages"], - isSingleRedlinePackage - ); - } - if (redlineCategory === "redline" || redlineCategory === "consult") { - await addWatermarkToRedline( - stitchObject, - redlineWatermarkPageMapping, - key - ); - } stitchObject .getFileData({ @@ -1962,11 +1993,30 @@ const stampPageNumberRedline = async ( } }; - const applyRotations = (document, rotatedpages) => { - for (let page in rotatedpages) { - let existingrotation = document.getPageRotation(page); - let rotation = (rotatedpages[page] - existingrotation + 360) / 90; - document.rotatePages([page], rotation); + const applyRotations = (document, doc, divDocPageMappings) => { + const docPageMappings = divDocPageMappings[doc.documentid]; // {origPage: stitchedPage, origPage: stitchedPage} -> {2: 1, 3:2, 4:3} + const rotatedpages = doc.attributes.rotatedpages; // {origPage: rotation. origPage: rotations} -> {4: 180} + const rotatedStitchedPages = {}; + console.log("NEW LINE") + console.log("docPageMappings", docPageMappings) + console.log("rotatedObj", rotatedpages) + if (rotatedpages) { + for (let [originalPage, stitchedPage] of Object.entries(docPageMappings)) { + let rotation = rotatedpages[originalPage]; + console.log("BANG", stitchedPage, rotation) + if (rotation) { + rotatedStitchedPages[stitchedPage] = rotation; + } + } + console.log("NEW", rotatedStitchedPages) + for (let page in rotatedStitchedPages) { + let existingrotation = document.getPageRotation(page); + console.log("page", page, existingrotation) + console.log('rootatedpages', rotatedStitchedPages[page] ) + let rotation = (rotatedStitchedPages[page] - existingrotation + 360) / 90; + console.log("rotation", rotation) + document.rotatePages([page], rotation); + } } } From 3515db02886d6068eb3c6df8e10e6b65c959252a Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 11 Sep 2024 14:09:17 -0700 Subject: [PATCH 34/57] Moved redaction and apply rotation to pages after redline formatting in redline creation. New order for stith and upload for redlines is: 1. format redlines 2. apply redactions 3. rotate pages 4. stamp pages 5. remove pages 6. add watermarks --- .../useSaveRedlineForSignOff.js | 102 ++++++------------ 1 file changed, 31 insertions(+), 71 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 44a0e61f8..5abb51700 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -214,7 +214,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } else if (redlineCategory === "consult") { // map documents to publicBodies and custom public bodies (treated as Divisions) for consults package. // Consult Package logic will treat publicbodies (program areas + custom consults) as DIVISIONS and will incorporate the existing division mapping + redline logic to generate the consult package - console.log("DIV", divisions) for (let publicBodyId of divisions) { let publicBodyDocList = []; documentList.forEach((doc) => { @@ -242,7 +241,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } }) publicBodyDocList = sortBySortOrder(publicBodyDocList); - console.log("sorteddoclist",publicBodyDocList ) let incompatableList = []; @@ -257,7 +255,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }) } } - console.log("newdoclist", newDocList) return newDocList; }; const prepareRedlinePageMapping = ( @@ -820,7 +817,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { // added this vopy variable for validating the first document of a division with NR/Duplicate let docCountCopy = 0; let division = key; - console.log("stitchlist", stitchlist) let documentlist = stitchlist[key]; if (redlineSinglePkg == "N") { toast.update(toastId.current, { @@ -1067,7 +1063,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { publicBodies.push(customPublicBody); } } - console.log("pubbodies", publicBodies) return publicBodies; } @@ -1374,7 +1369,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { if (divisionCountForToast === zipServiceMessage.attributes.length) { triggerDownloadRedlines(zipServiceMessage, (error) => { console.log(error); - // window.location.reload(); + window.location.reload(); }); } return zipServiceMessage; @@ -1780,30 +1775,6 @@ const stampPageNumberRedline = async ( } for (const rect of rects) { let height = docViewer.getPageHeight(rect.vpageno); - let x1 = rect.recto.x1 - let y1 = rect.recto.y1 - let x2 = rect.recto.x2 - let y2 = rect.recto.y2 - console.log("coords", x1,y1,x2,y2) - // const sectionAnnotation = rect.sectionAnnotation; - // // let quad = sectionAnnotation.getQuads()[0]; - // // let rect = new docInstance.Core.Math.Rect(quad.x1, quad.y3, quad.x2, quad.y2); - // const doc = docViewer.getDocument(); - // // const pageInfo = doc.getPageInfo(sectionAnnotation.PageNumber); - // // const pageMatrix = doc.getPageMatrix(sectionAnnotation.PageNumber); - // const pageRotation = doc.getPageRotation(sectionAnnotation.PageNumber); - // // _annot.FontSize = Math.min(parseInt(_redaction.FontSize), 9) + "pt"; - // sectionAnnotation.Rotation = 0; // reset rotation before resizing - // // _annot.fitText(pageInfo, pageMatrix, pageRotation); - // let annotrect = sectionAnnotation.getRect(); - // annotrect.x2 = Math.ceil(annotrect.x2); - // sectionAnnotation.setRect(annotrect); - // if (pageRotation === 180) { - // x1 = x2 - sectionAnnotation.Width - // y1 = y2 - sectionAnnotation.Height - // rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(x1,height-y1,x2,height-y2)), false, '')); - // sectionAnnotation.Rotation = pageRotation; - // } else { rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(rect.recto.x1,height-rect.recto.y1,rect.recto.x2,height-rect.recto.y2)), false, '')); } if (rarr.length > 0) { @@ -1825,7 +1796,6 @@ const stampPageNumberRedline = async ( }, [initDocViewer]); const StitchAndUploadDocument = async () => { - console.log("STITCH AND UPLOAD YE") const { PDFNet } = docInstance.Core; const downloadType = "pdf"; let currentDivisionCount = 0; @@ -1841,7 +1811,6 @@ const stampPageNumberRedline = async ( autoClose: 5000, }); let divisionid = key; - console.log("redlinepageMappings", redlinepageMappings) let stitchObject = redlineStitchObject[key]; if (stitchObject == null) { triggerRedlineZipper( @@ -1856,41 +1825,18 @@ const stampPageNumberRedline = async ( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); - if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { - await stampPageNumberRedline( - stitchObject, - PDFNet, - redlineStitchInfo[divisionid]["stitchpages"], - isSingleRedlinePackage - ); - } - if ( - redlinepageMappings["pagestoremove"][divisionid] && - redlinepageMappings["pagestoremove"][divisionid].length > 0 && - stitchObject?.getPageCount() > redlinepageMappings["pagestoremove"][divisionid].length - ) { - await stitchObject.removePages( - redlinepageMappings["pagestoremove"][divisionid] - ); - } - if (redlineCategory === "redline") { // WATER MARK CONSULTS? - await addWatermarkToRedline( - stitchObject, - redlineWatermarkPageMapping, - key - ); - } - let string = await stitchObject.extractXFDF() + let string = await stitchObject.extractXFDF(); let xmlObj = parser.parseFromString(string.xfdfString); let annots = parser.parseFromString('' + formattedAnnotationXML + ''); - let annotsObj = xmlObj.getElementsByTagName('annots') + let annotsObj = xmlObj.getElementsByTagName('annots'); if (annotsObj.length > 0) { - annotsObj[0].children = annotsObj[0].children.concat(annots.children) + annotsObj[0].children = annotsObj[0].children.concat(annots.children); } else { - xmlObj.children.push(annots) + xmlObj.children.push(annots); } + let xfdfString = parser.toString(xmlObj); //Apply Redactions (if any) @@ -1906,7 +1852,6 @@ const stampPageNumberRedline = async ( ); } //OIPC - Special Block : End - //Consults - Redlines + Redactions (Redact S.NR) Block : Start if(redlineCategory === "consult") { if (!consultApplyRedlines) { @@ -1925,16 +1870,39 @@ const stampPageNumberRedline = async ( //Consults - Redlines + Redactions (Redact S.NR) Block : End // Rotate pages - console.log("totalStithclist", totalStitchList) for (const doc of totalStitchList[divisionid]) { let documentlist = totalStitchList[divisionid]; let divDocPageMappings = redlinepageMappings["divpagemappings"][divisionid]; if(documentlist.length > 0) { - console.log("doc2", doc) applyRotations(stitchObject, doc, divDocPageMappings); } } + if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { + await stampPageNumberRedline( + stitchObject, + PDFNet, + redlineStitchInfo[divisionid]["stitchpages"], + isSingleRedlinePackage + ); + } + if ( + redlinepageMappings["pagestoremove"][divisionid] && + redlinepageMappings["pagestoremove"][divisionid].length > 0 && + stitchObject?.getPageCount() > redlinepageMappings["pagestoremove"][divisionid].length + ) { + await stitchObject.removePages( + redlinepageMappings["pagestoremove"][divisionid] + ); + } + if (redlineCategory === "redline" || redlineCategory === "consult") { + await addWatermarkToRedline( + stitchObject, + redlineWatermarkPageMapping, + key + ); + } + stitchObject .getFileData({ // saves the document with annotations in it @@ -1997,24 +1965,16 @@ const stampPageNumberRedline = async ( const docPageMappings = divDocPageMappings[doc.documentid]; // {origPage: stitchedPage, origPage: stitchedPage} -> {2: 1, 3:2, 4:3} const rotatedpages = doc.attributes.rotatedpages; // {origPage: rotation. origPage: rotations} -> {4: 180} const rotatedStitchedPages = {}; - console.log("NEW LINE") - console.log("docPageMappings", docPageMappings) - console.log("rotatedObj", rotatedpages) if (rotatedpages) { for (let [originalPage, stitchedPage] of Object.entries(docPageMappings)) { let rotation = rotatedpages[originalPage]; - console.log("BANG", stitchedPage, rotation) if (rotation) { rotatedStitchedPages[stitchedPage] = rotation; } } - console.log("NEW", rotatedStitchedPages) for (let page in rotatedStitchedPages) { let existingrotation = document.getPageRotation(page); - console.log("page", page, existingrotation) - console.log('rootatedpages', rotatedStitchedPages[page] ) let rotation = (rotatedStitchedPages[page] - existingrotation + 360) / 90; - console.log("rotation", rotation) document.rotatePages([page], rotation); } } From f92bcc52cc502092999af8c47930a8f9f25e729c Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Thu, 12 Sep 2024 12:21:55 -0700 Subject: [PATCH 35/57] Adjust redline processing back to original order but with applyrotations happening after redactions + added watermark logic to consults --- .../useSaveRedlineForSignOff.js | 92 ++++++++++--------- 1 file changed, 51 insertions(+), 41 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 5abb51700..84ba7d3e7 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -590,12 +590,16 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { for (let flagInfo of notConsultPageFlagsOnPage) { if (flagInfo.flagid == pageFlagTypes["Duplicate"]) { if(includeDuplicatePages) { - duplicateWatermarkPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); + for (let consult of doc.consult) { + if ((consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) || (consult.page === flagInfo.page && consult.other.includes(divObj.divisionname))) { + duplicateWatermarkPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); - pageMappings[doc.documentid][flagInfo.page] = - pageIndex + - totalPageCount - - pagesToRemoveEachDoc.length; + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } + } } else { pagesToRemoveEachDoc.push(flagInfo.page); if (!skipDocumentPages && !skipOnlyDuplicateDocument) { @@ -607,12 +611,16 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } else if (flagInfo.flagid == pageFlagTypes["Not Responsive"]) { if(includeNRPages) { - NRWatermarksPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); + for (let consult of doc.consult) { + if ((consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) || (consult.page === flagInfo.page && consult.other.includes(divObj.divisionname))) { + NRWatermarksPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); - pageMappings[doc.documentid][flagInfo.page] = - pageIndex + - totalPageCount - - pagesToRemoveEachDoc.length; + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } + } } else { pagesToRemoveEachDoc.push(flagInfo.page); if (!skipDocumentPages && !skipOnlyNRDocument) { @@ -622,12 +630,16 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } } } else if (flagInfo.flagid == pageFlagTypes["In Progress"]) { - NRWatermarksPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); + for (let consult of doc.consult) { + if ((consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) || (consult.page === flagInfo.page && consult.other.includes(divObj.divisionname))) { + NRWatermarksPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); - pageMappings[doc.documentid][flagInfo.page] = - pageIndex + - totalPageCount - - pagesToRemoveEachDoc.length; + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } + } } else { if (flagInfo.flagid !== pageFlagTypes["Consult"]) { pageMappings[doc.documentid][flagInfo.page] = @@ -1825,9 +1837,32 @@ const stampPageNumberRedline = async ( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); + if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { + await stampPageNumberRedline( + stitchObject, + PDFNet, + redlineStitchInfo[divisionid]["stitchpages"], + isSingleRedlinePackage + ); + } + if ( + redlinepageMappings["pagestoremove"][divisionid] && + redlinepageMappings["pagestoremove"][divisionid].length > 0 && + stitchObject?.getPageCount() > redlinepageMappings["pagestoremove"][divisionid].length + ) { + await stitchObject.removePages( + redlinepageMappings["pagestoremove"][divisionid] + ); + } + if (redlineCategory === "redline" || redlineCategory === "consult") { + await addWatermarkToRedline( + stitchObject, + redlineWatermarkPageMapping, + key + ); + } let string = await stitchObject.extractXFDF(); - let xmlObj = parser.parseFromString(string.xfdfString); let annots = parser.parseFromString('' + formattedAnnotationXML + ''); let annotsObj = xmlObj.getElementsByTagName('annots'); @@ -1878,31 +1913,6 @@ const stampPageNumberRedline = async ( } } - if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { - await stampPageNumberRedline( - stitchObject, - PDFNet, - redlineStitchInfo[divisionid]["stitchpages"], - isSingleRedlinePackage - ); - } - if ( - redlinepageMappings["pagestoremove"][divisionid] && - redlinepageMappings["pagestoremove"][divisionid].length > 0 && - stitchObject?.getPageCount() > redlinepageMappings["pagestoremove"][divisionid].length - ) { - await stitchObject.removePages( - redlinepageMappings["pagestoremove"][divisionid] - ); - } - if (redlineCategory === "redline" || redlineCategory === "consult") { - await addWatermarkToRedline( - stitchObject, - redlineWatermarkPageMapping, - key - ); - } - stitchObject .getFileData({ // saves the document with annotations in it From d6b899ca35c8da2b3f6f68fb1073f08e1d44f844 Mon Sep 17 00:00:00 2001 From: Milos Despotovic Date: Wed, 18 Sep 2024 09:53:44 -0700 Subject: [PATCH 36/57] Disable button if there is no text --- web/src/components/FOI/Home/FeeOverrideModal.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/FOI/Home/FeeOverrideModal.jsx b/web/src/components/FOI/Home/FeeOverrideModal.jsx index a64862710..379a78a3d 100644 --- a/web/src/components/FOI/Home/FeeOverrideModal.jsx +++ b/web/src/components/FOI/Home/FeeOverrideModal.jsx @@ -72,7 +72,7 @@ const FeeOverrideModal = ({ )} {isOverride && ( - )} From 72132c89f2ee4fb7d11e5325642c98eb00633d35 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 25 Sep 2024 11:12:14 -0700 Subject: [PATCH 37/57] removed new test-marshal/consult code which moved rotation of pages to end of redline creation process --- .../useSaveRedlineForSignOff.js | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 682fb718d..035bb22fd 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -822,7 +822,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { let divCount = 0; const noofdivision = Object.keys(stitchlist).length; let stitchedDocObj = null; - setTotalStitchList(stitchlist) + // setTotalStitchList(stitchlist); //if you want to rotate pages at end of redline process for (const [key, value] of Object.entries(stitchlist)) { divCount++; let docCount = 0; @@ -859,7 +859,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { loadAsPDF: true, useDownloader: false, // Added to fix BLANK page issue }).then(async (docObj) => { - // applyRotations(docObj, doc.attributes.rotatedpages) + applyRotations(docObj, doc.attributes.rotatedpages) //if (isIgnoredDocument(doc, docObj.getPageCount(), divisionDocuments) == false) { docCountCopy++; docCount++; @@ -1905,14 +1905,14 @@ const stampPageNumberRedline = async ( } //Consults - Redlines + Redactions (Redact S.NR) Block : End - // Rotate pages - for (const doc of totalStitchList[divisionid]) { - let documentlist = totalStitchList[divisionid]; - let divDocPageMappings = redlinepageMappings["divpagemappings"][divisionid]; - if(documentlist.length > 0) { - applyRotations(stitchObject, doc, divDocPageMappings); - } - } + // Rotate pages - After all redline work is completed + // for (const doc of totalStitchList[divisionid]) { + // let documentlist = totalStitchList[divisionid]; + // let divDocPageMappings = redlinepageMappings["divpagemappings"][divisionid]; + // if(documentlist.length > 0) { + // applyRotations(stitchObject, doc, divDocPageMappings); + // } + // } stitchObject .getFileData({ @@ -1972,24 +1972,24 @@ const stampPageNumberRedline = async ( } }; - const applyRotations = (document, doc, divDocPageMappings) => { - const docPageMappings = divDocPageMappings[doc.documentid]; // {origPage: stitchedPage, origPage: stitchedPage} -> {2: 1, 3:2, 4:3} - const rotatedpages = doc.attributes.rotatedpages; // {origPage: rotation. origPage: rotations} -> {4: 180} - const rotatedStitchedPages = {}; - if (rotatedpages) { - for (let [originalPage, stitchedPage] of Object.entries(docPageMappings)) { - let rotation = rotatedpages[originalPage]; - if (rotation) { - rotatedStitchedPages[stitchedPage] = rotation; - } - } - for (let page in rotatedStitchedPages) { - let existingrotation = document.getPageRotation(page); - let rotation = (rotatedStitchedPages[page] - existingrotation + 360) / 90; - document.rotatePages([page], rotation); - } - } - } + // const applyRotations = (document, doc, divDocPageMappings) => { + // const docPageMappings = divDocPageMappings[doc.documentid]; // {origPage: stitchedPage, origPage: stitchedPage} -> {2: 1, 3:2, 4:3} + // const rotatedpages = doc.attributes.rotatedpages; // {origPage: rotation. origPage: rotations} -> {4: 180} + // const rotatedStitchedPages = {}; + // if (rotatedpages) { + // for (let [originalPage, stitchedPage] of Object.entries(docPageMappings)) { + // let rotation = rotatedpages[originalPage]; + // if (rotation) { + // rotatedStitchedPages[stitchedPage] = rotation; + // } + // } + // for (let page in rotatedStitchedPages) { + // let existingrotation = document.getPageRotation(page); + // let rotation = (rotatedStitchedPages[page] - existingrotation + 360) / 90; + // document.rotatePages([page], rotation); + // } + // } + // } useEffect(() => { if ( From 64ffcfab7e5cfddadfd8d8a5080fa2320566cbe3 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 25 Sep 2024 11:30:29 -0700 Subject: [PATCH 38/57] manually added dev-AS-oipc-section14-fix pr --- .../useSaveRedlineForSignOff.js | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 035bb22fd..0ab3b3a2d 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -1788,7 +1788,12 @@ const stampPageNumberRedline = async ( } for (const rect of rects) { let height = docViewer.getPageHeight(rect.vpageno); - rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(rect.recto.x1,height-rect.recto.y1,rect.recto.x2,height-rect.recto.y2)), false, '')); + let pageRotation = stitchObject?.getPageRotation(rect.pageno); + let pageWidth = docViewer.getPageWidth(rect.vpageno); + /**Fix for oipc redline displaying s.14 marked page content partially */ + let adjustedRect = await getAdjustedRedactionCoordinates(pageRotation, rect.recto, PDFNet,pageWidth, height); + //rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(rect.recto.x1,height-rect.recto.y1,rect.recto.x2,height-rect.recto.y2)), false, '')); + rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, adjustedRect, false, '')); } if (rarr.length > 0) { const app = {}; @@ -1990,6 +1995,34 @@ const stampPageNumberRedline = async ( // } // } // } + + const getAdjustedRedactionCoordinates = async(pageRotation, recto, PDFNet,pageWidth,pageHeight) => { + let x1 = recto.x1; + let y1 = recto.y1; + let x2 = recto.x2; + let y2 = recto.y2; + // Adjust Y-coordinates to account for the flipped Y-axis in PDF + y1 = pageHeight - y1; + y2 = pageHeight - y2; + // Adjust for page rotation (90, 180, 270 degrees) + switch (pageRotation) { + case 90: + [x1, y1] = [y1, x1]; + [x2, y2] = [y2, x2]; + break; + case 180: + x1 = pageWidth - x1; + y1 = pageHeight - y1; + x2 = pageWidth - x2; + y2 = pageHeight - y2; + break; + case 270: + [x1, y1] = [pageHeight - y1, x1]; + [x2, y2] = [pageHeight - y2, x2]; + break; + } + return await PDFNet.Rect.init(x1, y1, x2, y2); + } useEffect(() => { if ( From 24986ce9c324fb5dfdebb35e24fbfc9a889b67b0 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 25 Sep 2024 16:00:44 -0700 Subject: [PATCH 39/57] commented out applyrotations to redlines logic to reduce vunerability of data breaches (redlines for s.14 and NR not being applied to redline packages --- .../Home/CreateResponsePDF/useSaveRedlineForSignOff.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 0ab3b3a2d..e6b918c39 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -822,7 +822,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { let divCount = 0; const noofdivision = Object.keys(stitchlist).length; let stitchedDocObj = null; - // setTotalStitchList(stitchlist); //if you want to rotate pages at end of redline process + // setTotalStitchList(stitchlist); //if you want to applyrotations at end of redline process uncomment this for (const [key, value] of Object.entries(stitchlist)) { divCount++; let docCount = 0; @@ -859,7 +859,10 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { loadAsPDF: true, useDownloader: false, // Added to fix BLANK page issue }).then(async (docObj) => { - applyRotations(docObj, doc.attributes.rotatedpages) + + // NOTE: applying rotations to records/documents for redlines is turned off per biz. If uncommented, bugs related to redline redactions (s14, NR etc) not being applied and in turn data breachs can occur + // applyRotations(docObj, doc.attributes.rotatedpages) + //if (isIgnoredDocument(doc, docObj.getPageCount(), divisionDocuments) == false) { docCountCopy++; docCount++; @@ -1910,7 +1913,7 @@ const stampPageNumberRedline = async ( } //Consults - Redlines + Redactions (Redact S.NR) Block : End - // Rotate pages - After all redline work is completed + // Rotate pages - applyrotations after all redline processes (redline applying, stamping, removing pages etc) are completed // for (const doc of totalStitchList[divisionid]) { // let documentlist = totalStitchList[divisionid]; // let divDocPageMappings = redlinepageMappings["divpagemappings"][divisionid]; From fb90af65a44f7353759a55aa89f7db88ebcd1b26 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 25 Sep 2024 16:06:53 -0700 Subject: [PATCH 40/57] added additonal comments --- .../FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index e6b918c39..8eb1df5b1 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -822,7 +822,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { let divCount = 0; const noofdivision = Object.keys(stitchlist).length; let stitchedDocObj = null; - // setTotalStitchList(stitchlist); //if you want to applyrotations at end of redline process uncomment this + // setTotalStitchList(stitchlist); //if you want to the solution to applyrotations at end of redline process uncomment this for (const [key, value] of Object.entries(stitchlist)) { divCount++; let docCount = 0; @@ -1913,7 +1913,7 @@ const stampPageNumberRedline = async ( } //Consults - Redlines + Redactions (Redact S.NR) Block : End - // Rotate pages - applyrotations after all redline processes (redline applying, stamping, removing pages etc) are completed + // Rotate pages - applyrotations after all redline processes (redline applying, stamping, removing pages etc) are completed. This is a solution/option to apply the rotation of pages to redline pacakges (consults, oipc etc) without losing redactions and causing data breach of data that should be redacted. // for (const doc of totalStitchList[divisionid]) { // let documentlist = totalStitchList[divisionid]; // let divDocPageMappings = redlinepageMappings["divpagemappings"][divisionid]; @@ -1980,6 +1980,7 @@ const stampPageNumberRedline = async ( } }; + // This is a solution/option to apply the rotation of pages to redline pacakges (consults, oipc etc) without losing redactions and causing data breach of data that should be redacted. // const applyRotations = (document, doc, divDocPageMappings) => { // const docPageMappings = divDocPageMappings[doc.documentid]; // {origPage: stitchedPage, origPage: stitchedPage} -> {2: 1, 3:2, 4:3} // const rotatedpages = doc.attributes.rotatedpages; // {origPage: rotation. origPage: rotations} -> {4: 180} From 55b6cd469b62bc692eb33babf9c3d3c0b4abb0a6 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 25 Sep 2024 16:07:34 -0700 Subject: [PATCH 41/57] added additonal comments --- .../FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 8eb1df5b1..e98cd1b03 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -822,7 +822,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { let divCount = 0; const noofdivision = Object.keys(stitchlist).length; let stitchedDocObj = null; - // setTotalStitchList(stitchlist); //if you want to the solution to applyrotations at end of redline process uncomment this + // setTotalStitchList(stitchlist); //if you want to apply the solution to applyrotations at end of redline process uncomment this for (const [key, value] of Object.entries(stitchlist)) { divCount++; let docCount = 0; From 2df3cc485ab1731692c867165145e4e20029e336 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Tue, 15 Oct 2024 13:23:56 -0700 Subject: [PATCH 42/57] manual redline chnages for pr 1185 + 1183 --- .../useSaveRedlineForSignOff.js | 266 +++++++++++++----- 1 file changed, 192 insertions(+), 74 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index e98cd1b03..0335b8b39 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -861,7 +861,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }).then(async (docObj) => { // NOTE: applying rotations to records/documents for redlines is turned off per biz. If uncommented, bugs related to redline redactions (s14, NR etc) not being applied and in turn data breachs can occur - // applyRotations(docObj, doc.attributes.rotatedpages) + applyRotations(docObj, doc.attributes.rotatedpages) //if (isIgnoredDocument(doc, docObj.getPageCount(), divisionDocuments) == false) { docCountCopy++; @@ -1771,41 +1771,16 @@ const stampPageNumberRedline = async ( } } }; - const applyRedactionsToRedlinesBySection = async (appliedSectionStamps, PDFNet, stitchObject) => { + const applyRedactionsToRedlinesBySection = async (appliedSectionStamps) => { let annotationManager = docInstance?.Core.annotationManager; - const rarr = []; - let rects = []; + let annots = []; for (const [key, value] of Object.entries(appliedSectionStamps)) { let sectionAnnotation = annotationManager.getAnnotationById(key); - if (sectionAnnotation.Subject === "Redact") { - rects = rects.concat( - sectionAnnotation.getQuads().map((q) => { - return { - pageno: appliedSectionStamps[key], - recto: q.toRect(), - vpageno: sectionAnnotation.getPageNumber() - }; - }) - ); - } - } - for (const rect of rects) { - let height = docViewer.getPageHeight(rect.vpageno); - let pageRotation = stitchObject?.getPageRotation(rect.pageno); - let pageWidth = docViewer.getPageWidth(rect.vpageno); - /**Fix for oipc redline displaying s.14 marked page content partially */ - let adjustedRect = await getAdjustedRedactionCoordinates(pageRotation, rect.recto, PDFNet,pageWidth, height); - //rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(rect.recto.x1,height-rect.recto.y1,rect.recto.x2,height-rect.recto.y2)), false, '')); - rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, adjustedRect, false, '')); - } - if (rarr.length > 0) { - const app = {}; - app.redaction_overlay = true; - app.border = false; - app.show_redacted_content_regions = false; - const doc = await stitchObject.getPDFDoc(); - await PDFNet.Redactor.redact(doc, rarr, app); + if (sectionAnnotation.Subject === "Redact") { + annots.push(sectionAnnotation); + } } + await annotationManager.applyRedactions(annots); } //useEffects to keep docInstance and docViewer state up to date with Redlining.js @@ -1846,7 +1821,7 @@ const stampPageNumberRedline = async ( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); - if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { + if(redlineCategory !== "oipcreview" || redlineCategory !== "consult") { await stampPageNumberRedline( stitchObject, PDFNet, @@ -1872,6 +1847,8 @@ const stampPageNumberRedline = async ( } let string = await stitchObject.extractXFDF(); + + // for redline - formatted annots let xmlObj = parser.parseFromString(string.xfdfString); let annots = parser.parseFromString('' + formattedAnnotationXML + ''); let annotsObj = xmlObj.getElementsByTagName('annots'); @@ -1880,35 +1857,202 @@ const stampPageNumberRedline = async ( } else { xmlObj.children.push(annots); } - let xfdfString = parser.toString(xmlObj); + + // for oipc review + consults - re-apply annots after redaction - annots only no widgets/form fields + let xmlObj1 = parser.parseFromString(string.xfdfString); + xmlObj1.children = []; + xmlObj1.children.push(annots); + let xfdfString1 = parser.toString(xmlObj1); //Apply Redactions (if any) //OIPC - Special Block (Redact S.14) : Begin if(redlineCategory === "oipcreview") { let s14_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - await applyRedactionsToRedlinesBySection(s14_sectionStamps, PDFNet, stitchObject); - await stampPageNumberRedline( - stitchObject, - PDFNet, - redlineStitchInfo[divisionid]["stitchpages"], - isSingleRedlinePackage - ); + let doc = docViewer.getDocument(); + await applyRedactionsToRedlinesBySection(s14_sectionStamps); + /** apply redaction and save to s3 - newXfdfString is needed to display + * the freetext(section name) on downloaded file.*/ + doc + .getFileData({ + // export the document to arraybuffer + // xfdfString: xfdfString, + downloadType: downloadType, + flatten: true, + }) + .then(async (_data) => { + const _arr = new Uint8Array(_data); + const _blob = new Blob([_arr], { type: "application/pdf" }); + + await docInstance?.Core.createDocument(_data, { + loadAsPDF: true, + useDownloader: false, // Added to fix BLANK page issue + }).then( async (docObj) => { + + /**must apply redactions before removing pages*/ + if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { + await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); + } + + await stampPageNumberRedline( + docObj, + PDFNet, + redlineStitchInfo[divisionid]["stitchpages"], + isSingleRedlinePackage + ); + + docObj.getFileData({ + // saves the document with annotations in it + xfdfString: xfdfString1, + downloadType: downloadType, + flatten: true, + }) + .then(async (__data) => { + const __arr = new Uint8Array(__data); + const __blob = new Blob([__arr], { type: "application/pdf" }); + + saveFilesinS3( + { filepath: redlineStitchInfo[divisionid]["s3path"] }, + __blob, + (_res) => { + // ######### call another process for zipping and generate download here ########## + toast.update(toastId.current, { + render: `Redline PDF saved to Object Storage`, + type: "success", + className: "file-upload-toast", + isLoading: false, + autoClose: 3000, + hideProgressBar: true, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + closeButton: true, + }); + triggerRedlineZipper( + redlineIncompatabileMappings[divisionid], + redlineStitchInfo[divisionid]["s3path"], + divisionCountForToast, + isSingleRedlinePackage + ); + }, + (_err) => { + console.log(_err); + toast.update(toastId.current, { + render: "Failed to save redline pdf to Object Storage", + type: "error", + className: "file-upload-toast", + isLoading: false, + autoClose: 3000, + hideProgressBar: true, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + closeButton: true, + }); + } + ); + }); + }); + }); } //OIPC - Special Block : End //Consults - Redlines + Redactions (Redact S.NR) Block : Start if(redlineCategory === "consult") { if (!consultApplyRedlines) { - const publicbodyAnnotList = xmlObj.getElementsByTagName('annots')[0]['children']; + const publicbodyAnnotList = xmlObj1.getElementsByTagName('annots')[0]['children']; const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { return annot.name !== "freetext" && annot.name !== 'redact' }); - xmlObj.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; - xfdfString = parser.toString(xmlObj); + xmlObj1.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; + xfdfString1 = parser.toString(xmlObj1); } if (consultApplyRedactions) { let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - await applyRedactionsToRedlinesBySection(nr_sectionStamps, PDFNet, stitchObject); + let doc = docViewer.getDocument(); + await applyRedactionsToRedlinesBySection(nr_sectionStamps); + /** apply redaction and save to s3 - newXfdfString is needed to display + * the freetext(section name) on downloaded file.*/ + doc + .getFileData({ + // export the document to arraybuffer + // xfdfString: xfdfString, + downloadType: downloadType, + flatten: true, + }) + .then(async (_data) => { + const _arr = new Uint8Array(_data); + const _blob = new Blob([_arr], { type: "application/pdf" }); + + await docInstance?.Core.createDocument(_data, { + loadAsPDF: true, + useDownloader: false, // Added to fix BLANK page issue + }).then( async (docObj) => { + + /**must apply redactions before removing pages*/ + if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { + await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); + } + + await stampPageNumberRedline( + docObj, + PDFNet, + redlineStitchInfo[divisionid]["stitchpages"], + isSingleRedlinePackage + ); + + docObj.getFileData({ + // saves the document with annotations in it + xfdfString: xfdfString1, + downloadType: downloadType, + flatten: true, + }) + .then(async (__data) => { + const __arr = new Uint8Array(__data); + const __blob = new Blob([__arr], { type: "application/pdf" }); + + saveFilesinS3( + { filepath: redlineStitchInfo[divisionid]["s3path"] }, + __blob, + (_res) => { + // ######### call another process for zipping and generate download here ########## + toast.update(toastId.current, { + render: `Consult PDF saved to Object Storage`, + type: "success", + className: "file-upload-toast", + isLoading: false, + autoClose: 3000, + hideProgressBar: true, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + closeButton: true, + }); + triggerRedlineZipper( + redlineIncompatabileMappings[divisionid], + redlineStitchInfo[divisionid]["s3path"], + divisionCountForToast, + isSingleRedlinePackage + ); + }, + (_err) => { + console.log(_err); + toast.update(toastId.current, { + render: "Failed to save redline pdf to Object Storage", + type: "error", + className: "file-upload-toast", + isLoading: false, + autoClose: 3000, + hideProgressBar: true, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + closeButton: true, + }); + } + ); + }); + }); + }); } } //Consults - Redlines + Redactions (Redact S.NR) Block : End @@ -1922,6 +2066,7 @@ const stampPageNumberRedline = async ( // } // } + else { stitchObject .getFileData({ // saves the document with annotations in it @@ -1941,7 +2086,7 @@ const stampPageNumberRedline = async ( (_res) => { // ######### call another process for zipping and generate download here ########## toast.update(toastId.current, { - render: `${redlineCategory === "consult" ? "Consult" : "Redline"} PDF saved to Object Storage`, + render: `Redline PDF saved to Object Storage`, type: "success", className: "file-upload-toast", isLoading: false, @@ -1976,6 +2121,7 @@ const stampPageNumberRedline = async ( } ); }); + } } } }; @@ -1999,34 +2145,6 @@ const stampPageNumberRedline = async ( // } // } // } - - const getAdjustedRedactionCoordinates = async(pageRotation, recto, PDFNet,pageWidth,pageHeight) => { - let x1 = recto.x1; - let y1 = recto.y1; - let x2 = recto.x2; - let y2 = recto.y2; - // Adjust Y-coordinates to account for the flipped Y-axis in PDF - y1 = pageHeight - y1; - y2 = pageHeight - y2; - // Adjust for page rotation (90, 180, 270 degrees) - switch (pageRotation) { - case 90: - [x1, y1] = [y1, x1]; - [x2, y2] = [y2, x2]; - break; - case 180: - x1 = pageWidth - x1; - y1 = pageHeight - y1; - x2 = pageWidth - x2; - y2 = pageHeight - y2; - break; - case 270: - [x1, y1] = [pageHeight - y1, x1]; - [x2, y2] = [pageHeight - y2, x2]; - break; - } - return await PDFNet.Rect.init(x1, y1, x2, y2); - } useEffect(() => { if ( From 4186ccf53b118f8053d6383be3d38cb944b0c4e7 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 16 Oct 2024 10:30:03 -0700 Subject: [PATCH 43/57] adjustments to consults --- .../services/docReviewerService.tsx | 2 +- .../useSaveRedlineForSignOff.js | 169 +++++++++--------- 2 files changed, 88 insertions(+), 83 deletions(-) diff --git a/web/src/apiManager/services/docReviewerService.tsx b/web/src/apiManager/services/docReviewerService.tsx index 1e309edb3..7c1813378 100644 --- a/web/src/apiManager/services/docReviewerService.tsx +++ b/web/src/apiManager/services/docReviewerService.tsx @@ -36,7 +36,7 @@ export const fetchDocuments = ( store.dispatch(setRequestNumber(res.data.requestnumber) as any); store.dispatch(setRequestStatus(res.data.requeststatuslabel) as any); store.dispatch(setRequestInfo(res.data.requestinfo) as any); - callback(res.data); + callback(res.data.documents, res.data.documentdivisions, res.data.requestinfo); } else { throw new Error(); } diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 3dc642153..353a2933f 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -1838,7 +1838,7 @@ const stampPageNumberRedline = async ( redlinepageMappings["pagestoremove"][divisionid] ); } - if (redlineCategory === "redline" || redlineCategory === "consult") { + if (redlineCategory === "redline") { await addWatermarkToRedline( stitchObject, redlineWatermarkPageMapping, @@ -1957,6 +1957,7 @@ const stampPageNumberRedline = async ( //OIPC - Special Block : End //Consults - Redlines + Redactions (Redact S.NR) Block : Start if(redlineCategory === "consult") { + let doc = docViewer.getDocument(); if (!consultApplyRedlines) { const publicbodyAnnotList = xmlObj1.getElementsByTagName('annots')[0]['children']; const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { @@ -1967,92 +1968,96 @@ const stampPageNumberRedline = async ( } if (consultApplyRedactions) { let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - let doc = docViewer.getDocument(); await applyRedactionsToRedlinesBySection(nr_sectionStamps); - /** apply redaction and save to s3 - newXfdfString is needed to display - * the freetext(section name) on downloaded file.*/ - doc - .getFileData({ - // export the document to arraybuffer - // xfdfString: xfdfString, - downloadType: downloadType, - flatten: true, - }) - .then(async (_data) => { - const _arr = new Uint8Array(_data); - const _blob = new Blob([_arr], { type: "application/pdf" }); - - await docInstance?.Core.createDocument(_data, { - loadAsPDF: true, - useDownloader: false, // Added to fix BLANK page issue - }).then( async (docObj) => { - - /**must apply redactions before removing pages*/ - if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { - await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); - } + } + /** apply redaction and save to s3 - newXfdfString is needed to display + * the freetext(section name) on downloaded file.*/ + doc + .getFileData({ + // export the document to arraybuffer + // xfdfString: xfdfString, + downloadType: downloadType, + flatten: true, + }) + .then(async (_data) => { + const _arr = new Uint8Array(_data); + const _blob = new Blob([_arr], { type: "application/pdf" }); - await stampPageNumberRedline( - docObj, - PDFNet, - redlineStitchInfo[divisionid]["stitchpages"], - isSingleRedlinePackage - ); + await docInstance?.Core.createDocument(_data, { + loadAsPDF: true, + useDownloader: false, // Added to fix BLANK page issue + }).then( async (docObj) => { - docObj.getFileData({ - // saves the document with annotations in it - xfdfString: xfdfString1, - downloadType: downloadType, - flatten: true, - }) - .then(async (__data) => { - const __arr = new Uint8Array(__data); - const __blob = new Blob([__arr], { type: "application/pdf" }); - - saveFilesinS3( - { filepath: redlineStitchInfo[divisionid]["s3path"] }, - __blob, - (_res) => { - // ######### call another process for zipping and generate download here ########## - toast.update(toastId.current, { - render: `Consult PDF saved to Object Storage`, - type: "success", - className: "file-upload-toast", - isLoading: false, - autoClose: 3000, - hideProgressBar: true, - closeOnClick: true, - pauseOnHover: true, - draggable: true, - closeButton: true, - }); - triggerRedlineZipper( - redlineIncompatabileMappings[divisionid], - redlineStitchInfo[divisionid]["s3path"], - divisionCountForToast, - isSingleRedlinePackage - ); - }, - (_err) => { - console.log(_err); - toast.update(toastId.current, { - render: "Failed to save redline pdf to Object Storage", - type: "error", - className: "file-upload-toast", - isLoading: false, - autoClose: 3000, - hideProgressBar: true, - closeOnClick: true, - pauseOnHover: true, - draggable: true, - closeButton: true, - }); - } - ); - }); + /**must apply redactions before removing pages*/ + if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { + await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); + } + + await stampPageNumberRedline( + docObj, + PDFNet, + redlineStitchInfo[divisionid]["stitchpages"], + isSingleRedlinePackage + ); + await addWatermarkToRedline( + docObj, + redlineWatermarkPageMapping, + key + ); + + docObj.getFileData({ + // saves the document with annotations in it + xfdfString: xfdfString1, + downloadType: downloadType, + flatten: true, + }) + .then(async (__data) => { + const __arr = new Uint8Array(__data); + const __blob = new Blob([__arr], { type: "application/pdf" }); + + saveFilesinS3( + { filepath: redlineStitchInfo[divisionid]["s3path"] }, + __blob, + (_res) => { + // ######### call another process for zipping and generate download here ########## + toast.update(toastId.current, { + render: `Consult PDF saved to Object Storage`, + type: "success", + className: "file-upload-toast", + isLoading: false, + autoClose: 3000, + hideProgressBar: true, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + closeButton: true, + }); + triggerRedlineZipper( + redlineIncompatabileMappings[divisionid], + redlineStitchInfo[divisionid]["s3path"], + divisionCountForToast, + isSingleRedlinePackage + ); + }, + (_err) => { + console.log(_err); + toast.update(toastId.current, { + render: "Failed to save redline pdf to Object Storage", + type: "error", + className: "file-upload-toast", + isLoading: false, + autoClose: 3000, + hideProgressBar: true, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + closeButton: true, + }); + } + ); }); }); - } + }); } //Consults - Redlines + Redactions (Redact S.NR) Block : End From 1c04c01daf6ccf3456c7bf6ba603f325129ca15a Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 16 Oct 2024 13:53:24 -0700 Subject: [PATCH 44/57] adjusted consults logic back to test-marshal / original code --- .../useSaveRedlineForSignOff.js | 216 ++++++++---------- 1 file changed, 95 insertions(+), 121 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 353a2933f..5960a7621 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -861,7 +861,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }).then(async (docObj) => { // NOTE: applying rotations to records/documents for redlines is turned off per biz. If uncommented, bugs related to redline redactions (s14, NR etc) not being applied and in turn data breachs can occur - applyRotations(docObj, doc.attributes.rotatedpages) + // applyRotations(docObj, doc.attributes.rotatedpages) //if (isIgnoredDocument(doc, docObj.getPageCount(), divisionDocuments) == false) { docCountCopy++; @@ -1771,7 +1771,7 @@ const stampPageNumberRedline = async ( } } }; - const applyRedactionsToRedlinesBySection = async (appliedSectionStamps) => { + const applyS14RedactionsToRedlinesBySection = async (appliedSectionStamps) => { let annotationManager = docInstance?.Core.annotationManager; let annots = []; for (const [key, value] of Object.entries(appliedSectionStamps)) { @@ -1782,6 +1782,42 @@ const stampPageNumberRedline = async ( } await annotationManager.applyRedactions(annots); } + const applyNRRedactionsToRedlinesBySection = async (appliedSectionStamps, PDFNet, stitchObject) => { + let annotationManager = docInstance?.Core.annotationManager; + const rarr = []; + let rects = []; + for (const [key, value] of Object.entries(appliedSectionStamps)) { + let sectionAnnotation = annotationManager.getAnnotationById(key); + if (sectionAnnotation.Subject === "Redact") { + rects = rects.concat( + sectionAnnotation.getQuads().map((q) => { + return { + pageno: appliedSectionStamps[key], + recto: q.toRect(), + vpageno: sectionAnnotation.getPageNumber() + }; + }) + ); + } + } + for (const rect of rects) { + let height = docViewer.getPageHeight(rect.vpageno); + let pageRotation = stitchObject?.getPageRotation(rect.pageno); + let pageWidth = docViewer.getPageWidth(rect.vpageno); + /**Fix for consults redline displaying NR marked page content partially */ + let adjustedRect = await getAdjustedRedactionCoordinates(pageRotation, rect.recto, PDFNet,pageWidth, height); + //rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(rect.recto.x1,height-rect.recto.y1,rect.recto.x2,height-rect.recto.y2)), false, '')); + rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, adjustedRect, false, '')); + } + if (rarr.length > 0) { + const app = {}; + app.redaction_overlay = true; + app.border = false; + app.show_redacted_content_regions = false; + const doc = await stitchObject.getPDFDoc(); + await PDFNet.Redactor.redact(doc, rarr, app); + } + } //useEffects to keep docInstance and docViewer state up to date with Redlining.js useEffect(() => { @@ -1821,7 +1857,7 @@ const stampPageNumberRedline = async ( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); - if(redlineCategory !== "oipcreview" || redlineCategory !== "consult") { + if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { await stampPageNumberRedline( stitchObject, PDFNet, @@ -1838,7 +1874,7 @@ const stampPageNumberRedline = async ( redlinepageMappings["pagestoremove"][divisionid] ); } - if (redlineCategory === "redline") { + if (redlineCategory === "redline" || redlineCategory === "consult") { await addWatermarkToRedline( stitchObject, redlineWatermarkPageMapping, @@ -1848,7 +1884,7 @@ const stampPageNumberRedline = async ( let string = await stitchObject.extractXFDF(); - // for redline - formatted annots + // for redline + consults - formatted annots let xmlObj = parser.parseFromString(string.xfdfString); let annots = parser.parseFromString('' + formattedAnnotationXML + ''); let annotsObj = xmlObj.getElementsByTagName('annots'); @@ -1870,7 +1906,7 @@ const stampPageNumberRedline = async ( if(redlineCategory === "oipcreview") { let s14_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); let doc = docViewer.getDocument(); - await applyRedactionsToRedlinesBySection(s14_sectionStamps); + await applyS14RedactionsToRedlinesBySection(s14_sectionStamps); /** apply redaction and save to s3 - newXfdfString is needed to display * the freetext(section name) on downloaded file.*/ doc @@ -1955,122 +1991,32 @@ const stampPageNumberRedline = async ( }); } //OIPC - Special Block : End - //Consults - Redlines + Redactions (Redact S.NR) Block : Start - if(redlineCategory === "consult") { - let doc = docViewer.getDocument(); - if (!consultApplyRedlines) { - const publicbodyAnnotList = xmlObj1.getElementsByTagName('annots')[0]['children']; - const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { - return annot.name !== "freetext" && annot.name !== 'redact' - }); - xmlObj1.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; - xfdfString1 = parser.toString(xmlObj1); - } - if (consultApplyRedactions) { - let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - await applyRedactionsToRedlinesBySection(nr_sectionStamps); - } - /** apply redaction and save to s3 - newXfdfString is needed to display - * the freetext(section name) on downloaded file.*/ - doc - .getFileData({ - // export the document to arraybuffer - // xfdfString: xfdfString, - downloadType: downloadType, - flatten: true, - }) - .then(async (_data) => { - const _arr = new Uint8Array(_data); - const _blob = new Blob([_arr], { type: "application/pdf" }); - - await docInstance?.Core.createDocument(_data, { - loadAsPDF: true, - useDownloader: false, // Added to fix BLANK page issue - }).then( async (docObj) => { - - /**must apply redactions before removing pages*/ - if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { - await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); - } - - await stampPageNumberRedline( - docObj, - PDFNet, - redlineStitchInfo[divisionid]["stitchpages"], - isSingleRedlinePackage - ); - await addWatermarkToRedline( - docObj, - redlineWatermarkPageMapping, - key - ); - - docObj.getFileData({ - // saves the document with annotations in it - xfdfString: xfdfString1, - downloadType: downloadType, - flatten: true, - }) - .then(async (__data) => { - const __arr = new Uint8Array(__data); - const __blob = new Blob([__arr], { type: "application/pdf" }); - - saveFilesinS3( - { filepath: redlineStitchInfo[divisionid]["s3path"] }, - __blob, - (_res) => { - // ######### call another process for zipping and generate download here ########## - toast.update(toastId.current, { - render: `Consult PDF saved to Object Storage`, - type: "success", - className: "file-upload-toast", - isLoading: false, - autoClose: 3000, - hideProgressBar: true, - closeOnClick: true, - pauseOnHover: true, - draggable: true, - closeButton: true, - }); - triggerRedlineZipper( - redlineIncompatabileMappings[divisionid], - redlineStitchInfo[divisionid]["s3path"], - divisionCountForToast, - isSingleRedlinePackage - ); - }, - (_err) => { - console.log(_err); - toast.update(toastId.current, { - render: "Failed to save redline pdf to Object Storage", - type: "error", - className: "file-upload-toast", - isLoading: false, - autoClose: 3000, - hideProgressBar: true, - closeOnClick: true, - pauseOnHover: true, - draggable: true, - closeButton: true, - }); - } - ); - }); - }); + else { + //Consults - Redlines + Redactions (Redact S.NR) Block : Start + if(redlineCategory === "consult") { + if (!consultApplyRedlines) { + const publicbodyAnnotList = xmlObj.getElementsByTagName('annots')[0]['children']; + const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { + return annot.name !== "freetext" && annot.name !== 'redact' }); + xmlObj.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; + xfdfString = parser.toString(xmlObj); } - //Consults - Redlines + Redactions (Redact S.NR) Block : End - - // Rotate pages - applyrotations after all redline processes (redline applying, stamping, removing pages etc) are completed. This is a solution/option to apply the rotation of pages to redline pacakges (consults, oipc etc) without losing redactions and causing data breach of data that should be redacted. - // for (const doc of totalStitchList[divisionid]) { - // let documentlist = totalStitchList[divisionid]; - // let divDocPageMappings = redlinepageMappings["divpagemappings"][divisionid]; - // if(documentlist.length > 0) { - // applyRotations(stitchObject, doc, divDocPageMappings); - // } - // } - - else { + if (consultApplyRedactions) { + let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); + await applyNRRedactionsToRedlinesBySection(nr_sectionStamps, PDFNet, stitchObject); + } + } + //Consults - Redlines + Redactions (Redact S.NR) Block : End + + // Rotate pages - applyrotations after all redline processes (redline applying, stamping, removing pages etc) are completed. This is a solution/option to apply the rotation of pages to redline pacakges (consults, oipc etc) without losing redactions and causing data breach of data that should be redacted. + // for (const doc of totalStitchList[divisionid]) { + // let documentlist = totalStitchList[divisionid]; + // let divDocPageMappings = redlinepageMappings["divpagemappings"][divisionid]; + // if(documentlist.length > 0) { + // applyRotations(stitchObject, doc, divDocPageMappings); + // } + // } stitchObject .getFileData({ // saves the document with annotations in it @@ -2090,7 +2036,7 @@ const stampPageNumberRedline = async ( (_res) => { // ######### call another process for zipping and generate download here ########## toast.update(toastId.current, { - render: `Redline PDF saved to Object Storage`, + render: `${redlineCategory === "consult" ? "Consult" : "Redline"} PDF saved to Object Storage`, type: "success", className: "file-upload-toast", isLoading: false, @@ -2149,6 +2095,34 @@ const stampPageNumberRedline = async ( // } // } // } + + const getAdjustedRedactionCoordinates = async(pageRotation, recto, PDFNet,pageWidth,pageHeight) => { + let x1 = recto.x1; + let y1 = recto.y1; + let x2 = recto.x2; + let y2 = recto.y2; + // Adjust Y-coordinates to account for the flipped Y-axis in PDF + y1 = pageHeight - y1; + y2 = pageHeight - y2; + // Adjust for page rotation (90, 180, 270 degrees) + switch (pageRotation) { + case 90: + [x1, y1] = [y1, x1]; + [x2, y2] = [y2, x2]; + break; + case 180: + x1 = pageWidth - x1; + y1 = pageHeight - y1; + x2 = pageWidth - x2; + y2 = pageHeight - y2; + break; + case 270: + [x1, y1] = [pageHeight - y1, x1]; + [x2, y2] = [pageHeight - y2, x2]; + break; + } + return await PDFNet.Rect.init(x1, y1, x2, y2); + } useEffect(() => { if ( From 4076e86d18d8c4c96d800cd77c1e35c790ac6fec Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 16 Oct 2024 14:49:52 -0700 Subject: [PATCH 45/57] re-added new oipc logic to consults --- .../useSaveRedlineForSignOff.js | 227 ++++++++++-------- 1 file changed, 131 insertions(+), 96 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 5960a7621..37979dddb 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -861,7 +861,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }).then(async (docObj) => { // NOTE: applying rotations to records/documents for redlines is turned off per biz. If uncommented, bugs related to redline redactions (s14, NR etc) not being applied and in turn data breachs can occur - // applyRotations(docObj, doc.attributes.rotatedpages) + applyRotations(docObj, doc.attributes.rotatedpages) //if (isIgnoredDocument(doc, docObj.getPageCount(), divisionDocuments) == false) { docCountCopy++; @@ -1385,7 +1385,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { if (divisionCountForToast === zipServiceMessage.attributes.length) { triggerDownloadRedlines(zipServiceMessage, (error) => { console.log(error); - window.location.reload(); + // window.location.reload(); }); } return zipServiceMessage; @@ -1771,7 +1771,7 @@ const stampPageNumberRedline = async ( } } }; - const applyS14RedactionsToRedlinesBySection = async (appliedSectionStamps) => { + const applyRedactionsToRedlinesBySection = async (appliedSectionStamps) => { let annotationManager = docInstance?.Core.annotationManager; let annots = []; for (const [key, value] of Object.entries(appliedSectionStamps)) { @@ -1782,42 +1782,6 @@ const stampPageNumberRedline = async ( } await annotationManager.applyRedactions(annots); } - const applyNRRedactionsToRedlinesBySection = async (appliedSectionStamps, PDFNet, stitchObject) => { - let annotationManager = docInstance?.Core.annotationManager; - const rarr = []; - let rects = []; - for (const [key, value] of Object.entries(appliedSectionStamps)) { - let sectionAnnotation = annotationManager.getAnnotationById(key); - if (sectionAnnotation.Subject === "Redact") { - rects = rects.concat( - sectionAnnotation.getQuads().map((q) => { - return { - pageno: appliedSectionStamps[key], - recto: q.toRect(), - vpageno: sectionAnnotation.getPageNumber() - }; - }) - ); - } - } - for (const rect of rects) { - let height = docViewer.getPageHeight(rect.vpageno); - let pageRotation = stitchObject?.getPageRotation(rect.pageno); - let pageWidth = docViewer.getPageWidth(rect.vpageno); - /**Fix for consults redline displaying NR marked page content partially */ - let adjustedRect = await getAdjustedRedactionCoordinates(pageRotation, rect.recto, PDFNet,pageWidth, height); - //rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(rect.recto.x1,height-rect.recto.y1,rect.recto.x2,height-rect.recto.y2)), false, '')); - rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, adjustedRect, false, '')); - } - if (rarr.length > 0) { - const app = {}; - app.redaction_overlay = true; - app.border = false; - app.show_redacted_content_regions = false; - const doc = await stitchObject.getPDFDoc(); - await PDFNet.Redactor.redact(doc, rarr, app); - } - } //useEffects to keep docInstance and docViewer state up to date with Redlining.js useEffect(() => { @@ -1857,7 +1821,7 @@ const stampPageNumberRedline = async ( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); - if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { + if(redlineCategory !== "oipcreview" || redlineCategory !== "consult") { await stampPageNumberRedline( stitchObject, PDFNet, @@ -1870,11 +1834,12 @@ const stampPageNumberRedline = async ( redlinepageMappings["pagestoremove"][divisionid].length > 0 && stitchObject?.getPageCount() > redlinepageMappings["pagestoremove"][divisionid].length ) { + console.log("REDLINE REMOVE", redlinepageMappings["pagestoremove"][divisionid]) await stitchObject.removePages( redlinepageMappings["pagestoremove"][divisionid] ); } - if (redlineCategory === "redline" || redlineCategory === "consult") { + if (redlineCategory === "redline") { await addWatermarkToRedline( stitchObject, redlineWatermarkPageMapping, @@ -1884,7 +1849,7 @@ const stampPageNumberRedline = async ( let string = await stitchObject.extractXFDF(); - // for redline + consults - formatted annots + // for redline - formatted annots let xmlObj = parser.parseFromString(string.xfdfString); let annots = parser.parseFromString('' + formattedAnnotationXML + ''); let annotsObj = xmlObj.getElementsByTagName('annots'); @@ -1906,7 +1871,8 @@ const stampPageNumberRedline = async ( if(redlineCategory === "oipcreview") { let s14_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); let doc = docViewer.getDocument(); - await applyS14RedactionsToRedlinesBySection(s14_sectionStamps); + await applyRedactionsToRedlinesBySection(s14_sectionStamps); + console.log("s14_sectionStamps", s14_sectionStamps) /** apply redaction and save to s3 - newXfdfString is needed to display * the freetext(section name) on downloaded file.*/ doc @@ -1991,32 +1957,129 @@ const stampPageNumberRedline = async ( }); } //OIPC - Special Block : End - else { - //Consults - Redlines + Redactions (Redact S.NR) Block : Start - if(redlineCategory === "consult") { - if (!consultApplyRedlines) { - const publicbodyAnnotList = xmlObj.getElementsByTagName('annots')[0]['children']; - const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { - return annot.name !== "freetext" && annot.name !== 'redact' + //Consults - Redlines + Redactions (Redact S.NR) Block : Start + if(redlineCategory === "consult") { + let doc = docViewer.getDocument(); + if (!consultApplyRedlines) { + const publicbodyAnnotList = xmlObj1.getElementsByTagName('annots')[0]['children']; + console.log("publicbodyAnnotList", publicbodyAnnotList) + const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { + return annot.name !== "freetext" && annot.name !== 'redact' + }); + console.log("filteredPublicbodyAnnotList", filteredPublicbodyAnnotList) + xmlObj1.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; + xfdfString1 = parser.toString(xmlObj1); + } + if (consultApplyRedactions) { + let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); + console.log("nr_sectionStamps", nr_sectionStamps) + await applyRedactionsToRedlinesBySection(nr_sectionStamps); + } + /** apply redaction and save to s3 - newXfdfString is needed to display + * the freetext(section name) on downloaded file.*/ + doc + .getFileData({ + // export the document to arraybuffer + // xfdfString: xfdfString, + downloadType: downloadType, + flatten: true, + }) + .then(async (_data) => { + const _arr = new Uint8Array(_data); + const _blob = new Blob([_arr], { type: "application/pdf" }); + + //LOOP HERE + // loop through each of the divisons/consults that exist, in the loop remove the pages that belong to other divisions find those pages to remove. which pages belong to other divisons + + await docInstance?.Core.createDocument(_data, { + loadAsPDF: true, + useDownloader: false, // Added to fix BLANK page issue + }).then( async (docObj) => { + + /**must apply redactions before removing pages*/ + console.log("CONSULT REMOVE", redlinepageMappings["pagestoremove"][divisionid]) + if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { + await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); + } + + await stampPageNumberRedline( + docObj, + PDFNet, + redlineStitchInfo[divisionid]["stitchpages"], + isSingleRedlinePackage + ); + // await addWatermarkToRedline( + // docObj, + // redlineWatermarkPageMapping, + // key + // ); + + docObj.getFileData({ + // saves the document with annotations in it + xfdfString: xfdfString1, + downloadType: downloadType, + flatten: true, + }) + .then(async (__data) => { + const __arr = new Uint8Array(__data); + const __blob = new Blob([__arr], { type: "application/pdf" }); + + saveFilesinS3( + { filepath: redlineStitchInfo[divisionid]["s3path"] }, + __blob, + (_res) => { + // ######### call another process for zipping and generate download here ########## + toast.update(toastId.current, { + render: `Consult PDF saved to Object Storage`, + type: "success", + className: "file-upload-toast", + isLoading: false, + autoClose: 3000, + hideProgressBar: true, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + closeButton: true, + }); + triggerRedlineZipper( + redlineIncompatabileMappings[divisionid], + redlineStitchInfo[divisionid]["s3path"], + divisionCountForToast, + isSingleRedlinePackage + ); + }, + (_err) => { + console.log(_err); + toast.update(toastId.current, { + render: "Failed to save redline pdf to Object Storage", + type: "error", + className: "file-upload-toast", + isLoading: false, + autoClose: 3000, + hideProgressBar: true, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + closeButton: true, + }); + } + ); + }); + }); }); - xmlObj.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; - xfdfString = parser.toString(xmlObj); - } - if (consultApplyRedactions) { - let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - await applyNRRedactionsToRedlinesBySection(nr_sectionStamps, PDFNet, stitchObject); } - } - //Consults - Redlines + Redactions (Redact S.NR) Block : End - - // Rotate pages - applyrotations after all redline processes (redline applying, stamping, removing pages etc) are completed. This is a solution/option to apply the rotation of pages to redline pacakges (consults, oipc etc) without losing redactions and causing data breach of data that should be redacted. - // for (const doc of totalStitchList[divisionid]) { - // let documentlist = totalStitchList[divisionid]; - // let divDocPageMappings = redlinepageMappings["divpagemappings"][divisionid]; - // if(documentlist.length > 0) { - // applyRotations(stitchObject, doc, divDocPageMappings); - // } - // } + //Consults - Redlines + Redactions (Redact S.NR) Block : End + + // Rotate pages - applyrotations after all redline processes (redline applying, stamping, removing pages etc) are completed. This is a solution/option to apply the rotation of pages to redline pacakges (consults, oipc etc) without losing redactions and causing data breach of data that should be redacted. + // for (const doc of totalStitchList[divisionid]) { + // let documentlist = totalStitchList[divisionid]; + // let divDocPageMappings = redlinepageMappings["divpagemappings"][divisionid]; + // if(documentlist.length > 0) { + // applyRotations(stitchObject, doc, divDocPageMappings); + // } + // } + + else { stitchObject .getFileData({ // saves the document with annotations in it @@ -2036,7 +2099,7 @@ const stampPageNumberRedline = async ( (_res) => { // ######### call another process for zipping and generate download here ########## toast.update(toastId.current, { - render: `${redlineCategory === "consult" ? "Consult" : "Redline"} PDF saved to Object Storage`, + render: `Redline PDF saved to Object Storage`, type: "success", className: "file-upload-toast", isLoading: false, @@ -2095,34 +2158,6 @@ const stampPageNumberRedline = async ( // } // } // } - - const getAdjustedRedactionCoordinates = async(pageRotation, recto, PDFNet,pageWidth,pageHeight) => { - let x1 = recto.x1; - let y1 = recto.y1; - let x2 = recto.x2; - let y2 = recto.y2; - // Adjust Y-coordinates to account for the flipped Y-axis in PDF - y1 = pageHeight - y1; - y2 = pageHeight - y2; - // Adjust for page rotation (90, 180, 270 degrees) - switch (pageRotation) { - case 90: - [x1, y1] = [y1, x1]; - [x2, y2] = [y2, x2]; - break; - case 180: - x1 = pageWidth - x1; - y1 = pageHeight - y1; - x2 = pageWidth - x2; - y2 = pageHeight - y2; - break; - case 270: - [x1, y1] = [pageHeight - y1, x1]; - [x2, y2] = [pageHeight - y2, x2]; - break; - } - return await PDFNet.Rect.init(x1, y1, x2, y2); - } useEffect(() => { if ( From 99d932a842f4c36f33b8e00da0ec5cec32f7d396 Mon Sep 17 00:00:00 2001 From: Richard Qi Date: Thu, 17 Oct 2024 14:07:06 -0700 Subject: [PATCH 46/57] remove pages from other division --- .../useSaveRedlineForSignOff.js | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 37979dddb..82b3ff638 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -1796,6 +1796,30 @@ const stampPageNumberRedline = async ( const downloadType = "pdf"; let currentDivisionCount = 0; const divisionCountForToast = Object.keys(redlineStitchObject).length; + + let pagesOfEachDivisions = {}; + let pagesOfOtherDivisions = {}; + //get page numbers of each division + Object.keys(redlineStitchInfo).forEach((_div) => { + pagesOfEachDivisions[_div] = []; + redlineStitchInfo[_div]["stitchpages"].forEach((pageinfo) => { + pagesOfEachDivisions[_div].push(pageinfo["stitchedPageNo"]); + }); + }); + + //get page numbers that not belongs to the division + for (const [key, value] of Object.entries(pagesOfEachDivisions)) { + pagesOfOtherDivisions[key] = []; + for(const [_div, _pageNumbers] of Object.entries(pagesOfEachDivisions)) { + if(_div !== key) { + pagesOfOtherDivisions[key] = [...new Set([...pagesOfOtherDivisions[key], ..._pageNumbers])]; + } + } + } + for(const [_div, _pageNumbers] of Object.entries(pagesOfEachDivisions)) { + pagesOfOtherDivisions[_div] = pagesOfOtherDivisions[_div].filter((_pageNum) => {return !_pageNumbers.includes(_pageNum)}) + } + for (const [key, value] of Object.entries(redlineStitchObject)) { currentDivisionCount++; toast.update(toastId.current, { @@ -1995,6 +2019,9 @@ const stampPageNumberRedline = async ( loadAsPDF: true, useDownloader: false, // Added to fix BLANK page issue }).then( async (docObj) => { + if (pagesOfOtherDivisions[key].length > 0) { + await docObj.removePages(pagesOfOtherDivisions[key]); + } /**must apply redactions before removing pages*/ console.log("CONSULT REMOVE", redlinepageMappings["pagestoremove"][divisionid]) From bb7528fdf7b52ca8f4e60d92c36d13b4ab7e70f1 Mon Sep 17 00:00:00 2001 From: Richard Qi Date: Thu, 17 Oct 2024 15:17:12 -0700 Subject: [PATCH 47/57] bug fix --- .../useSaveRedlineForSignOff.js | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 82b3ff638..3aea348ed 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -1798,7 +1798,7 @@ const stampPageNumberRedline = async ( const divisionCountForToast = Object.keys(redlineStitchObject).length; let pagesOfEachDivisions = {}; - let pagesOfOtherDivisions = {}; + // let pagesOfOtherDivisions = {}; //get page numbers of each division Object.keys(redlineStitchInfo).forEach((_div) => { pagesOfEachDivisions[_div] = []; @@ -1806,19 +1806,7 @@ const stampPageNumberRedline = async ( pagesOfEachDivisions[_div].push(pageinfo["stitchedPageNo"]); }); }); - - //get page numbers that not belongs to the division - for (const [key, value] of Object.entries(pagesOfEachDivisions)) { - pagesOfOtherDivisions[key] = []; - for(const [_div, _pageNumbers] of Object.entries(pagesOfEachDivisions)) { - if(_div !== key) { - pagesOfOtherDivisions[key] = [...new Set([...pagesOfOtherDivisions[key], ..._pageNumbers])]; - } - } - } - for(const [_div, _pageNumbers] of Object.entries(pagesOfEachDivisions)) { - pagesOfOtherDivisions[_div] = pagesOfOtherDivisions[_div].filter((_pageNum) => {return !_pageNumbers.includes(_pageNum)}) - } + console.log("pagesOfEachDivisions: ", pagesOfEachDivisions); for (const [key, value] of Object.entries(redlineStitchObject)) { currentDivisionCount++; @@ -2019,8 +2007,15 @@ const stampPageNumberRedline = async ( loadAsPDF: true, useDownloader: false, // Added to fix BLANK page issue }).then( async (docObj) => { - if (pagesOfOtherDivisions[key].length > 0) { - await docObj.removePages(pagesOfOtherDivisions[key]); + + let pagesNotBelongsToThisDivision = []; + for(let i=1; i <= docObj.getPageCount(); i++) { + if(!pagesOfEachDivisions[key].includes(i)) + pagesNotBelongsToThisDivision.push(i); + } + + if(pagesNotBelongsToThisDivision.length > 0) { + await docObj.removePages(pagesNotBelongsToThisDivision); } /**must apply redactions before removing pages*/ From 11007c246c9f7aaa27dec098e318fd8d9b813c46 Mon Sep 17 00:00:00 2001 From: Richard Qi Date: Thu, 17 Oct 2024 16:04:33 -0700 Subject: [PATCH 48/57] fix page stamp issue --- .../useSaveRedlineForSignOff.js | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 3aea348ed..dae1b431b 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -1846,7 +1846,6 @@ const stampPageNumberRedline = async ( redlinepageMappings["pagestoremove"][divisionid].length > 0 && stitchObject?.getPageCount() > redlinepageMappings["pagestoremove"][divisionid].length ) { - console.log("REDLINE REMOVE", redlinepageMappings["pagestoremove"][divisionid]) await stitchObject.removePages( redlinepageMappings["pagestoremove"][divisionid] ); @@ -1884,7 +1883,7 @@ const stampPageNumberRedline = async ( let s14_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); let doc = docViewer.getDocument(); await applyRedactionsToRedlinesBySection(s14_sectionStamps); - console.log("s14_sectionStamps", s14_sectionStamps) + // console.log("s14_sectionStamps", s14_sectionStamps) /** apply redaction and save to s3 - newXfdfString is needed to display * the freetext(section name) on downloaded file.*/ doc @@ -1974,17 +1973,17 @@ const stampPageNumberRedline = async ( let doc = docViewer.getDocument(); if (!consultApplyRedlines) { const publicbodyAnnotList = xmlObj1.getElementsByTagName('annots')[0]['children']; - console.log("publicbodyAnnotList", publicbodyAnnotList) + // console.log("publicbodyAnnotList", publicbodyAnnotList) const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { return annot.name !== "freetext" && annot.name !== 'redact' }); - console.log("filteredPublicbodyAnnotList", filteredPublicbodyAnnotList) + // console.log("filteredPublicbodyAnnotList", filteredPublicbodyAnnotList) xmlObj1.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; xfdfString1 = parser.toString(xmlObj1); } if (consultApplyRedactions) { let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - console.log("nr_sectionStamps", nr_sectionStamps) + // console.log("nr_sectionStamps", nr_sectionStamps) await applyRedactionsToRedlinesBySection(nr_sectionStamps); } /** apply redaction and save to s3 - newXfdfString is needed to display @@ -2018,18 +2017,18 @@ const stampPageNumberRedline = async ( await docObj.removePages(pagesNotBelongsToThisDivision); } - /**must apply redactions before removing pages*/ - console.log("CONSULT REMOVE", redlinepageMappings["pagestoremove"][divisionid]) - if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { - await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); - } - await stampPageNumberRedline( docObj, PDFNet, redlineStitchInfo[divisionid]["stitchpages"], isSingleRedlinePackage ); + + /**must apply redactions before removing pages*/ + if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { + await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); + } + // await addWatermarkToRedline( // docObj, // redlineWatermarkPageMapping, From b9bb65ced5b527c07dd21454375dcec6b825c4d1 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Fri, 18 Oct 2024 11:29:55 -0700 Subject: [PATCH 49/57] code clean --- .../useSaveRedlineForSignOff.js | 87 ++++++++----------- 1 file changed, 34 insertions(+), 53 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index dae1b431b..aec22a58b 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -90,7 +90,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } else { for (let doc of divObj.documentlist) { - //page to pageFlag mappings logic for consults + //page to pageFlag mappings logic used for consults const pagePageFlagMappings = {}; for (let pageFlag of doc.pageFlag) { if (pageFlag.page in pagePageFlagMappings) { @@ -822,7 +822,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { let divCount = 0; const noofdivision = Object.keys(stitchlist).length; let stitchedDocObj = null; - // setTotalStitchList(stitchlist); //if you want to apply the solution to applyrotations at end of redline process uncomment this for (const [key, value] of Object.entries(stitchlist)) { divCount++; let docCount = 0; @@ -859,10 +858,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { loadAsPDF: true, useDownloader: false, // Added to fix BLANK page issue }).then(async (docObj) => { - - // NOTE: applying rotations to records/documents for redlines is turned off per biz. If uncommented, bugs related to redline redactions (s14, NR etc) not being applied and in turn data breachs can occur - applyRotations(docObj, doc.attributes.rotatedpages) - + applyRotations(docObj, doc.attributes.rotatedpages); //if (isIgnoredDocument(doc, docObj.getPageCount(), divisionDocuments) == false) { docCountCopy++; docCount++; @@ -1385,7 +1381,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { if (divisionCountForToast === zipServiceMessage.attributes.length) { triggerDownloadRedlines(zipServiceMessage, (error) => { console.log(error); - // window.location.reload(); + window.location.reload(); }); } return zipServiceMessage; @@ -1797,8 +1793,8 @@ const stampPageNumberRedline = async ( let currentDivisionCount = 0; const divisionCountForToast = Object.keys(redlineStitchObject).length; + //Consult Package page removal logic let pagesOfEachDivisions = {}; - // let pagesOfOtherDivisions = {}; //get page numbers of each division Object.keys(redlineStitchInfo).forEach((_div) => { pagesOfEachDivisions[_div] = []; @@ -1806,7 +1802,6 @@ const stampPageNumberRedline = async ( pagesOfEachDivisions[_div].push(pageinfo["stitchedPageNo"]); }); }); - console.log("pagesOfEachDivisions: ", pagesOfEachDivisions); for (const [key, value] of Object.entries(redlineStitchObject)) { currentDivisionCount++; @@ -1850,7 +1845,7 @@ const stampPageNumberRedline = async ( redlinepageMappings["pagestoremove"][divisionid] ); } - if (redlineCategory === "redline") { + if (redlineCategory !== "oipcreview" || redlineCategory !== "consult") { await addWatermarkToRedline( stitchObject, redlineWatermarkPageMapping, @@ -1883,7 +1878,6 @@ const stampPageNumberRedline = async ( let s14_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); let doc = docViewer.getDocument(); await applyRedactionsToRedlinesBySection(s14_sectionStamps); - // console.log("s14_sectionStamps", s14_sectionStamps) /** apply redaction and save to s3 - newXfdfString is needed to display * the freetext(section name) on downloaded file.*/ doc @@ -1973,17 +1967,14 @@ const stampPageNumberRedline = async ( let doc = docViewer.getDocument(); if (!consultApplyRedlines) { const publicbodyAnnotList = xmlObj1.getElementsByTagName('annots')[0]['children']; - // console.log("publicbodyAnnotList", publicbodyAnnotList) const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { return annot.name !== "freetext" && annot.name !== 'redact' }); - // console.log("filteredPublicbodyAnnotList", filteredPublicbodyAnnotList) xmlObj1.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; xfdfString1 = parser.toString(xmlObj1); } if (consultApplyRedactions) { let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - // console.log("nr_sectionStamps", nr_sectionStamps) await applyRedactionsToRedlinesBySection(nr_sectionStamps); } /** apply redaction and save to s3 - newXfdfString is needed to display @@ -1999,14 +1990,12 @@ const stampPageNumberRedline = async ( const _arr = new Uint8Array(_data); const _blob = new Blob([_arr], { type: "application/pdf" }); - //LOOP HERE - // loop through each of the divisons/consults that exist, in the loop remove the pages that belong to other divisions find those pages to remove. which pages belong to other divisons - await docInstance?.Core.createDocument(_data, { loadAsPDF: true, useDownloader: false, // Added to fix BLANK page issue }).then( async (docObj) => { + // Consult Pacakge page removal of pages that are not in this division let pagesNotBelongsToThisDivision = []; for(let i=1; i <= docObj.getPageCount(); i++) { if(!pagesOfEachDivisions[key].includes(i)) @@ -2024,17 +2013,12 @@ const stampPageNumberRedline = async ( isSingleRedlinePackage ); + //Consult Pacakge page removal of NR and DUPE /**must apply redactions before removing pages*/ if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); } - // await addWatermarkToRedline( - // docObj, - // redlineWatermarkPageMapping, - // key - // ); - docObj.getFileData({ // saves the document with annotations in it xfdfString: xfdfString1, @@ -2090,16 +2074,6 @@ const stampPageNumberRedline = async ( }); } //Consults - Redlines + Redactions (Redact S.NR) Block : End - - // Rotate pages - applyrotations after all redline processes (redline applying, stamping, removing pages etc) are completed. This is a solution/option to apply the rotation of pages to redline pacakges (consults, oipc etc) without losing redactions and causing data breach of data that should be redacted. - // for (const doc of totalStitchList[divisionid]) { - // let documentlist = totalStitchList[divisionid]; - // let divDocPageMappings = redlinepageMappings["divpagemappings"][divisionid]; - // if(documentlist.length > 0) { - // applyRotations(stitchObject, doc, divDocPageMappings); - // } - // } - else { stitchObject .getFileData({ @@ -2160,25 +2134,33 @@ const stampPageNumberRedline = async ( } }; - // This is a solution/option to apply the rotation of pages to redline pacakges (consults, oipc etc) without losing redactions and causing data breach of data that should be redacted. - // const applyRotations = (document, doc, divDocPageMappings) => { - // const docPageMappings = divDocPageMappings[doc.documentid]; // {origPage: stitchedPage, origPage: stitchedPage} -> {2: 1, 3:2, 4:3} - // const rotatedpages = doc.attributes.rotatedpages; // {origPage: rotation. origPage: rotations} -> {4: 180} - // const rotatedStitchedPages = {}; - // if (rotatedpages) { - // for (let [originalPage, stitchedPage] of Object.entries(docPageMappings)) { - // let rotation = rotatedpages[originalPage]; - // if (rotation) { - // rotatedStitchedPages[stitchedPage] = rotation; - // } - // } - // for (let page in rotatedStitchedPages) { - // let existingrotation = document.getPageRotation(page); - // let rotation = (rotatedStitchedPages[page] - existingrotation + 360) / 90; - // document.rotatePages([page], rotation); - // } - // } - // } + const getAdjustedRedactionCoordinates = async(pageRotation, recto, PDFNet,pageWidth,pageHeight) => { + let x1 = recto.x1; + let y1 = recto.y1; + let x2 = recto.x2; + let y2 = recto.y2; + // Adjust Y-coordinates to account for the flipped Y-axis in PDF + y1 = pageHeight - y1; + y2 = pageHeight - y2; + // Adjust for page rotation (90, 180, 270 degrees) + switch (pageRotation) { + case 90: + [x1, y1] = [y1, x1]; + [x2, y2] = [y2, x2]; + break; + case 180: + x1 = pageWidth - x1; + y1 = pageHeight - y1; + x2 = pageWidth - x2; + y2 = pageHeight - y2; + break; + case 270: + [x1, y1] = [pageHeight - y1, x1]; + [x2, y2] = [pageHeight - y2, x2]; + break; + } + return await PDFNet.Rect.init(x1, y1, x2, y2); + } useEffect(() => { if ( @@ -2191,7 +2173,6 @@ const stampPageNumberRedline = async ( } }, [redlineDocumentAnnotations, redlineStitchObject, redlineStitchInfo]); - useEffect(() => { if ( pdftronDocObjectsForRedline?.length > 0 && From d125a46bd202edb38fa5a4f2a39f3be7ba58d525 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Fri, 18 Oct 2024 14:45:48 -0700 Subject: [PATCH 50/57] Consults + NR/DUPE client watermark fix --- .../FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js | 1 - web/src/components/FOI/Home/Redlining.js | 7 ++++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index aec22a58b..0e045b243 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -74,7 +74,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { const [consultApplyRedactions, setConsultApplyRedactions] = useState(false); const [consultApplyRedlines, setConsultApplyRedlines] = useState(false); - const requestInfo = useAppSelector((state) => state.documents?.requestinfo); const requestType = requestInfo?.requesttype ? requestInfo.requesttype : "public"; diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 5cb7a3384..311b43eff 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -1374,8 +1374,9 @@ const Redlining = React.forwardRef( // Hence being able to leverage those properties let originalPage = pageMappedDocs['stitchedPageLookup'][pageNumber] let doc = pageFlags.find(d => d.documentid === originalPage.docid); - let pageFlag = doc?.pageflag?.find(f => f.page === originalPage.page); - if (pageFlag?.flagid === pageFlagTypes["Duplicate"]) { + let pageFlagsOnPage = doc?.pageflag?.filter(f => f.page === originalPage.page); + let NrOrDupeFlag = pageFlagsOnPage.find(pageFlagItem => pageFlagItem.flagid === pageFlagTypes["Duplicate"] || pageFlagItem.flagid === pageFlagTypes["Not Responsive"]); + if (NrOrDupeFlag?.flagid === pageFlagTypes["Duplicate"]) { ctx.fillStyle = "#ff0000"; ctx.font = "20pt Arial"; ctx.globalAlpha = 0.4; @@ -1387,7 +1388,7 @@ const Redlining = React.forwardRef( ctx.restore(); } - if (pageFlag?.flagid === pageFlagTypes["Not Responsive"]) { + if (NrOrDupeFlag?.flagid === pageFlagTypes["Not Responsive"]) { ctx.fillStyle = "#ff0000"; ctx.font = "20pt Arial"; ctx.globalAlpha = 0.4; From 758d02bb47baabdd1414aeb2a63b09be28a0ff2e Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Mon, 21 Oct 2024 13:03:08 -0700 Subject: [PATCH 51/57] final consult changes --- .../useSaveRedlineForSignOff.js | 27 +++---------------- web/src/components/FOI/Home/utils.js | 3 +++ 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 0e045b243..59506f118 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -508,10 +508,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { let pagesToRemove = []; let totalPageCount = 0; let totalPageCountIncludeRemoved = 0; - let duplicateWatermarkPages = {}; - let duplicateWatermarkPagesEachDiv = []; - let NRWatermarksPages = {}; - let NRWatermarksPagesEachDiv = []; for (let divObj of divisionDocuments) { // sort based on sortorder as the sortorder added based on the LastModified for (let doc of sortBySortOrder(divObj.documentlist)) { @@ -591,8 +587,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { if(includeDuplicatePages) { for (let consult of doc.consult) { if ((consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) || (consult.page === flagInfo.page && consult.other.includes(divObj.divisionname))) { - duplicateWatermarkPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); - pageMappings[doc.documentid][flagInfo.page] = pageIndex + totalPageCount - @@ -612,8 +606,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { if(includeNRPages) { for (let consult of doc.consult) { if ((consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) || (consult.page === flagInfo.page && consult.other.includes(divObj.divisionname))) { - NRWatermarksPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); - pageMappings[doc.documentid][flagInfo.page] = pageIndex + totalPageCount - @@ -631,8 +623,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } else if (flagInfo.flagid == pageFlagTypes["In Progress"]) { for (let consult of doc.consult) { if ((consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) || (consult.page === flagInfo.page && consult.other.includes(divObj.divisionname))) { - NRWatermarksPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); - pageMappings[doc.documentid][flagInfo.page] = pageIndex + totalPageCount - @@ -682,11 +672,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } divPageMappings[divObj.divisionid] = pageMappings; removepages[divObj.divisionid] = pagesToRemove; - duplicateWatermarkPages[divObj.divisionid] = duplicateWatermarkPagesEachDiv; - NRWatermarksPages[divObj.divisionid] = NRWatermarksPagesEachDiv; pagesToRemove = []; - duplicateWatermarkPagesEachDiv = []; - NRWatermarksPagesEachDiv = []; totalPageCount = 0; totalPageCountIncludeRemoved = 0; pageMappings = {} @@ -697,10 +683,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { 'pagemapping': pageMappings, 'pagestoremove': removepages }); - setRedlineWatermarkPageMapping({ - 'duplicatewatermark': duplicateWatermarkPages, - 'NRwatermark': NRWatermarksPages - }); } const prepareRedlineIncompatibleMapping = (redlineAPIResponse) => { @@ -1194,9 +1176,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { ); } } - // if (docCount == div.documentlist.length) { - - // } } } if ( @@ -1827,7 +1806,7 @@ const stampPageNumberRedline = async ( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); - if(redlineCategory !== "oipcreview" || redlineCategory !== "consult") { + if (redlineCategory !== "oipcreview" || redlineCategory !== "consult") { await stampPageNumberRedline( stitchObject, PDFNet, @@ -1994,7 +1973,7 @@ const stampPageNumberRedline = async ( useDownloader: false, // Added to fix BLANK page issue }).then( async (docObj) => { - // Consult Pacakge page removal of pages that are not in this division + // Consult Pacakge page removal of pages that are not in this division (will leave consult/division specific pages in docObj to be removed by redlinepagemappings pagestoremove below) let pagesNotBelongsToThisDivision = []; for(let i=1; i <= docObj.getPageCount(); i++) { if(!pagesOfEachDivisions[key].includes(i)) @@ -2012,7 +1991,7 @@ const stampPageNumberRedline = async ( isSingleRedlinePackage ); - //Consult Pacakge page removal of NR and DUPE + //Consult Pacakge page removal of pages/documents associated with divison/consult /**must apply redactions before removing pages*/ if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); diff --git a/web/src/components/FOI/Home/utils.js b/web/src/components/FOI/Home/utils.js index ef736a94f..fa910f68f 100644 --- a/web/src/components/FOI/Home/utils.js +++ b/web/src/components/FOI/Home/utils.js @@ -517,6 +517,9 @@ const constructPageFlagsForAddOrEdit = ( pageFlags ) => { let pagesToUpdate = {}; + if (annotationsInfo.section === undefined) { + return getValidObject(pagesToUpdate); // non redaction annotations do not need page flags automatically applied + } const foundBlank = ["", " "].includes(annotationsInfo.section); const foundNR = annotationsInfo.section == "NR"; // section with a valid number found From 2043295e762e4ba7cfef3ef73900f903a684027a Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Mon, 21 Oct 2024 15:10:52 -0700 Subject: [PATCH 52/57] final redline changes for consults with new oipc logic --- .../useSaveRedlineForSignOff.js | 192 +++++++++--------- 1 file changed, 99 insertions(+), 93 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 59506f118..fbd52e3e9 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -1745,17 +1745,6 @@ const stampPageNumberRedline = async ( } } }; - const applyRedactionsToRedlinesBySection = async (appliedSectionStamps) => { - let annotationManager = docInstance?.Core.annotationManager; - let annots = []; - for (const [key, value] of Object.entries(appliedSectionStamps)) { - let sectionAnnotation = annotationManager.getAnnotationById(key); - if (sectionAnnotation.Subject === "Redact") { - annots.push(sectionAnnotation); - } - } - await annotationManager.applyRedactions(annots); - } //useEffects to keep docInstance and docViewer state up to date with Redlining.js useEffect(() => { @@ -1806,14 +1795,13 @@ const stampPageNumberRedline = async ( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); - if (redlineCategory !== "oipcreview" || redlineCategory !== "consult") { + if (redlineCategory === "redline") { await stampPageNumberRedline( stitchObject, PDFNet, redlineStitchInfo[divisionid]["stitchpages"], isSingleRedlinePackage ); - } if ( redlinepageMappings["pagestoremove"][divisionid] && redlinepageMappings["pagestoremove"][divisionid].length > 0 && @@ -1823,7 +1811,6 @@ const stampPageNumberRedline = async ( redlinepageMappings["pagestoremove"][divisionid] ); } - if (redlineCategory !== "oipcreview" || redlineCategory !== "consult") { await addWatermarkToRedline( stitchObject, redlineWatermarkPageMapping, @@ -1853,95 +1840,106 @@ const stampPageNumberRedline = async ( //Apply Redactions (if any) //OIPC - Special Block (Redact S.14) : Begin if(redlineCategory === "oipcreview") { + let annotationManager = docInstance?.Core.annotationManager; let s14_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); + let s14annots = []; + for (const [key, value] of Object.entries(s14_sectionStamps)) { + let s14annoation = annotationManager.getAnnotationById(key); + if ( s14annoation.Subject === "Redact") { + s14annots.push(s14annoation); + } + } + let doc = docViewer.getDocument(); - await applyRedactionsToRedlinesBySection(s14_sectionStamps); + await annotationManager.applyRedactions(s14annots); + /** apply redaction and save to s3 - newXfdfString is needed to display * the freetext(section name) on downloaded file.*/ doc - .getFileData({ - // export the document to arraybuffer - // xfdfString: xfdfString, - downloadType: downloadType, - flatten: true, - }) - .then(async (_data) => { - const _arr = new Uint8Array(_data); - const _blob = new Blob([_arr], { type: "application/pdf" }); - - await docInstance?.Core.createDocument(_data, { - loadAsPDF: true, - useDownloader: false, // Added to fix BLANK page issue - }).then( async (docObj) => { - - /**must apply redactions before removing pages*/ - if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { - await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); - } - await stampPageNumberRedline( - docObj, - PDFNet, - redlineStitchInfo[divisionid]["stitchpages"], - isSingleRedlinePackage - ); - - docObj.getFileData({ - // saves the document with annotations in it - xfdfString: xfdfString1, - downloadType: downloadType, - flatten: true, - }) - .then(async (__data) => { - const __arr = new Uint8Array(__data); - const __blob = new Blob([__arr], { type: "application/pdf" }); - - saveFilesinS3( - { filepath: redlineStitchInfo[divisionid]["s3path"] }, - __blob, - (_res) => { - // ######### call another process for zipping and generate download here ########## - toast.update(toastId.current, { - render: `Redline PDF saved to Object Storage`, - type: "success", - className: "file-upload-toast", - isLoading: false, - autoClose: 3000, - hideProgressBar: true, - closeOnClick: true, - pauseOnHover: true, - draggable: true, - closeButton: true, - }); - triggerRedlineZipper( - redlineIncompatabileMappings[divisionid], - redlineStitchInfo[divisionid]["s3path"], - divisionCountForToast, - isSingleRedlinePackage - ); - }, - (_err) => { - console.log(_err); - toast.update(toastId.current, { - render: "Failed to save redline pdf to Object Storage", - type: "error", - className: "file-upload-toast", - isLoading: false, - autoClose: 3000, - hideProgressBar: true, - closeOnClick: true, - pauseOnHover: true, - draggable: true, - closeButton: true, - }); - } + .getFileData({ + // export the document to arraybuffer + // xfdfString: xfdfString, + downloadType: downloadType, + flatten: true, + }) + .then(async (_data) => { + const _arr = new Uint8Array(_data); + const _blob = new Blob([_arr], { type: "application/pdf" }); + + await docInstance?.Core.createDocument(_data, { + loadAsPDF: true, + useDownloader: false, // Added to fix BLANK page issue + }).then( async (docObj) => { + + /**must apply redactions before removing pages*/ + if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { + await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); + } + + await stampPageNumberRedline( + docObj, + PDFNet, + redlineStitchInfo[divisionid]["stitchpages"], + isSingleRedlinePackage ); + + docObj.getFileData({ + // saves the document with annotations in it + xfdfString: xfdfString1, + downloadType: downloadType, + flatten: true, + }) + .then(async (__data) => { + const __arr = new Uint8Array(__data); + const __blob = new Blob([__arr], { type: "application/pdf" }); + + saveFilesinS3( + { filepath: redlineStitchInfo[divisionid]["s3path"] }, + __blob, + (_res) => { + // ######### call another process for zipping and generate download here ########## + toast.update(toastId.current, { + render: `Redline PDF saved to Object Storage`, + type: "success", + className: "file-upload-toast", + isLoading: false, + autoClose: 3000, + hideProgressBar: true, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + closeButton: true, + }); + triggerRedlineZipper( + redlineIncompatabileMappings[divisionid], + redlineStitchInfo[divisionid]["s3path"], + divisionCountForToast, + isSingleRedlinePackage + ); + }, + (_err) => { + console.log(_err); + toast.update(toastId.current, { + render: "Failed to save redline pdf to Object Storage", + type: "error", + className: "file-upload-toast", + isLoading: false, + autoClose: 3000, + hideProgressBar: true, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + closeButton: true, + }); + } + ); + }); }); }); - }); } //OIPC - Special Block : End //Consults - Redlines + Redactions (Redact S.NR) Block : Start - if(redlineCategory === "consult") { + else if (redlineCategory === "consult") { let doc = docViewer.getDocument(); if (!consultApplyRedlines) { const publicbodyAnnotList = xmlObj1.getElementsByTagName('annots')[0]['children']; @@ -1952,8 +1950,16 @@ const stampPageNumberRedline = async ( xfdfString1 = parser.toString(xmlObj1); } if (consultApplyRedactions) { + let annotationManager = docInstance?.Core.annotationManager; let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - await applyRedactionsToRedlinesBySection(nr_sectionStamps); + let nrAnnots = []; + for (const [key, value] of Object.entries(nr_sectionStamps)) { + let nrAnnotation = annotationManager.getAnnotationById(key); + if (nrAnnotation.Subject === "Redact") { + nrAnnots.push(nrAnnotation); + } + } + await annotationManager.applyRedactions(nrAnnots); } /** apply redaction and save to s3 - newXfdfString is needed to display * the freetext(section name) on downloaded file.*/ From a6112ed346496391e5634e2da808d320ee686de7 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Mon, 21 Oct 2024 15:55:20 -0700 Subject: [PATCH 53/57] small code clean (spaces) --- .../CreateResponsePDF/useSaveRedlineForSignOff.js | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index fbd52e3e9..65f90de2c 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -383,7 +383,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }); }; - const prepareRedlinePageMappingByDivision = (divisionDocuments) => { let removepages = {}; let pageMappings = {}; @@ -763,7 +762,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { return "redline"; }; - const prepareredlinesummarylist = (stitchDocuments) => { let summarylist = []; let alldocuments = []; @@ -871,7 +869,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { if (docCount == documentlist.length && redlineSinglePkg == "N" ) { requestStitchObject[division] = stitchedDocObj; } - } } else { if (incompatableList[division]["incompatibleFiles"].length > 0) { @@ -890,12 +887,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } }; - - - - - - const stitchSingleDivisionRedlineExport = async ( _instance, divisionDocuments, @@ -1058,7 +1049,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { return publicBodies; } - const saveRedlineDocument = async ( _instance, layertype, @@ -2242,4 +2232,4 @@ const stampPageNumberRedline = async ( }; }; -export default useSaveRedlineForSignoff; +export default useSaveRedlineForSignoff; \ No newline at end of file From a48d2c85a594dd05c0c648eb2f9a4338031ff294 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 23 Oct 2024 16:10:08 -0700 Subject: [PATCH 54/57] bug fix test-marshal for consults merge made on oct 21 --- web/src/components/FOI/Home/Redlining.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 311b43eff..8b4d80b3e 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -1375,7 +1375,7 @@ const Redlining = React.forwardRef( let originalPage = pageMappedDocs['stitchedPageLookup'][pageNumber] let doc = pageFlags.find(d => d.documentid === originalPage.docid); let pageFlagsOnPage = doc?.pageflag?.filter(f => f.page === originalPage.page); - let NrOrDupeFlag = pageFlagsOnPage.find(pageFlagItem => pageFlagItem.flagid === pageFlagTypes["Duplicate"] || pageFlagItem.flagid === pageFlagTypes["Not Responsive"]); + let NrOrDupeFlag = pageFlagsOnPage?.find(pageFlagItem => pageFlagItem.flagid === pageFlagTypes["Duplicate"] || pageFlagItem.flagid === pageFlagTypes["Not Responsive"]); if (NrOrDupeFlag?.flagid === pageFlagTypes["Duplicate"]) { ctx.fillStyle = "#ff0000"; ctx.font = "20pt Arial"; From 2eaecbfc8d8264057d0e1ed54e7c3992d6152019 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Mon, 28 Oct 2024 14:48:18 -0700 Subject: [PATCH 55/57] small wording/messaging changes realted to consults + addedd missed fee-overriding changes(ticket 3073) when main was merged to test-marshal --- .../models/redlineresponsenotificationmessage.py | 2 +- .../ZippingServices/models/zipperproducermessage.py | 2 +- web/src/components/FOI/Home/ConfirmationModal.js | 2 +- .../FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/computingservices/ZippingServices/models/redlineresponsenotificationmessage.py b/computingservices/ZippingServices/models/redlineresponsenotificationmessage.py index ccb851933..cc562164f 100644 --- a/computingservices/ZippingServices/models/redlineresponsenotificationmessage.py +++ b/computingservices/ZippingServices/models/redlineresponsenotificationmessage.py @@ -1,5 +1,5 @@ class redlineresponsenotificationmessage(object): - def __init__(self, ministryrequestid, serviceid, errorflag, createdby,feeoverridereason) -> None: + def __init__(self, ministryrequestid, serviceid, errorflag, createdby,feeoverridereason="") -> None: self.ministryrequestid = ministryrequestid self.serviceid = serviceid self.errorflag = errorflag diff --git a/computingservices/ZippingServices/models/zipperproducermessage.py b/computingservices/ZippingServices/models/zipperproducermessage.py index 73b4b795c..41b175753 100644 --- a/computingservices/ZippingServices/models/zipperproducermessage.py +++ b/computingservices/ZippingServices/models/zipperproducermessage.py @@ -1,5 +1,5 @@ class zipperproducermessage(object): - def __init__(self,jobid,requestid,category,requestnumber,bcgovcode,createdby,ministryrequestid,filestozip,finaloutput,attributes,feeoverridereason,summarydocuments=None,redactionlayerid=None,foldername=None) -> None: + def __init__(self,jobid,requestid,category,requestnumber,bcgovcode,createdby,ministryrequestid,filestozip,finaloutput,attributes,feeoverridereason=None,summarydocuments=None,redactionlayerid=None,foldername=None) -> None: self.jobid = jobid self.requestid = requestid self.category=category diff --git a/web/src/components/FOI/Home/ConfirmationModal.js b/web/src/components/FOI/Home/ConfirmationModal.js index ab49df08a..b44a05762 100644 --- a/web/src/components/FOI/Home/ConfirmationModal.js +++ b/web/src/components/FOI/Home/ConfirmationModal.js @@ -133,7 +133,7 @@ export const ConfirmationModal= ({ checked={consultApplyRedlines} onChange={handleApplyRedlines} /> - +
Date: Tue, 29 Oct 2024 11:13:23 -0700 Subject: [PATCH 56/57] observation fixes for 11.0 (adjusted LSB in docreivewer enums + added disabled option or create consult button --- api/reviewer_api/utils/enums.py | 3 ++- web/src/components/FOI/Home/ConfirmationModal.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/api/reviewer_api/utils/enums.py b/api/reviewer_api/utils/enums.py index 23e99fb1a..00f5682b1 100644 --- a/api/reviewer_api/utils/enums.py +++ b/api/reviewer_api/utils/enums.py @@ -74,7 +74,8 @@ class MinistryTeamWithKeycloackGroup(Enum): ECC = "ECC Ministry Team" JED = "JED Ministry Team" COR = "COR Ministry Team" - HSG = "HSG Ministry Team" + HSG = "HSG Ministry Team", + LSB = "LSB Ministry Team" @staticmethod def list(): diff --git a/web/src/components/FOI/Home/ConfirmationModal.js b/web/src/components/FOI/Home/ConfirmationModal.js index b44a05762..89280c3dc 100644 --- a/web/src/components/FOI/Home/ConfirmationModal.js +++ b/web/src/components/FOI/Home/ConfirmationModal.js @@ -150,7 +150,7 @@ export const ConfirmationModal= ({
-