From c61075c2e3ec99a7868fb6fa96cb5bebccedceb7 Mon Sep 17 00:00:00 2001 From: etanb Date: Sun, 17 Nov 2024 23:52:31 -0800 Subject: [PATCH 1/5] Update README.md --- prime-router/docs/getting-started/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prime-router/docs/getting-started/README.md b/prime-router/docs/getting-started/README.md index 856c781608b..537800da32e 100644 --- a/prime-router/docs/getting-started/README.md +++ b/prime-router/docs/getting-started/README.md @@ -172,7 +172,7 @@ A `ctrl-c` will escape the running ReportStream instance. ## Debugging -`./gradlew quickrun` or `./gradlew run` will open a debug port on your locally running ReportStream instance. +`./gradlew quickRun` or `./gradlew run` will open a debug port on your locally running ReportStream instance. Connect your debugger remotely to port 5005. For profiling use the JMX port 9090. From aa88f3ea30bcfad648d0e8b1ad4b12ba09c254ab Mon Sep 17 00:00:00 2001 From: etanb Date: Mon, 18 Nov 2024 23:42:46 -0800 Subject: [PATCH 2/5] remove usage of downloadjs --- frontend-react/package.json | 2 - .../deliveries/daily-data/ReportLink.tsx | 45 ++++++------------- .../deliveries/daily-data/ReportsUtils.ts | 26 ++++++++--- frontend-react/yarn.lock | 16 ------- 4 files changed, 34 insertions(+), 55 deletions(-) diff --git a/frontend-react/package.json b/frontend-react/package.json index fad46aa994e..70b824c3f22 100644 --- a/frontend-react/package.json +++ b/frontend-react/package.json @@ -19,7 +19,6 @@ "date-fns": "^3.6.0", "date-fns-tz": "^3.2.0", "dompurify": "^3.1.7", - "downloadjs": "^1.4.7", "export-to-csv-fix-source-map": "^0.2.1", "focus-trap-react": "^10.3.0", "history": "^5.3.0", @@ -135,7 +134,6 @@ "@testing-library/user-event": "^14.5.2", "@types/dompurify": "^3.0.5", "@types/dotenv-flow": "^3.3.3", - "@types/downloadjs": "^1.4.6", "@types/eslint__js": "^8.42.3", "@types/github-slugger": "^1.3.0", "@types/html-to-text": "^9.0.4", diff --git a/frontend-react/src/pages/deliveries/daily-data/ReportLink.tsx b/frontend-react/src/pages/deliveries/daily-data/ReportLink.tsx index ea95e1b24cf..272d672a67d 100644 --- a/frontend-react/src/pages/deliveries/daily-data/ReportLink.tsx +++ b/frontend-react/src/pages/deliveries/daily-data/ReportLink.tsx @@ -1,7 +1,7 @@ import { Button, Icon } from "@trussworks/react-uswds"; -import download from "downloadjs"; import { PropsWithChildren } from "react"; +import { downloadReport } from "./ReportsUtils"; import config from "../../../config"; import useSessionContext from "../../../contexts/Session/useSessionContext"; import { isDateExpired } from "../../../utils/DateTimeUtils"; @@ -28,13 +28,7 @@ const formatFileType = (fileType: string) => { This element provides a download link on each row of the table and on the report details page */ -function ReportLink({ - reportId, - fileType, - reportExpires, - children, - button, -}: PropsWithChildren) { +function ReportLink({ reportId, fileType, reportExpires, children, button }: PropsWithChildren) { const { authState } = useSessionContext(); const { activeMembership } = useSessionContext(); const organization = activeMembership?.parsedName; @@ -50,15 +44,7 @@ function ReportLink({ }) .then((res) => res.json()) .then((report) => { - // The filename to use for the download should not contain blob folders if present - let filename = decodeURIComponent(report.fileName); - const filenameStartIndex = filename.lastIndexOf("/"); - if ( - filenameStartIndex >= 0 && - filename.length > filenameStartIndex + 1 - ) - filename = filename.substring(filenameStartIndex + 1); - download(report.content, filename, report.mimetype); + downloadReport(report); }); } }; @@ -73,21 +59,16 @@ function ReportLink({ } else { return ( <> - {fileType !== undefined && - !isDateExpired(reportExpires ?? "") && ( - - )} + {fileType !== undefined && !isDateExpired(reportExpires ?? "") && ( + + )} ); } diff --git a/frontend-react/src/pages/deliveries/daily-data/ReportsUtils.ts b/frontend-react/src/pages/deliveries/daily-data/ReportsUtils.ts index 7d5e64b9614..d4aa772ab00 100644 --- a/frontend-react/src/pages/deliveries/daily-data/ReportsUtils.ts +++ b/frontend-react/src/pages/deliveries/daily-data/ReportsUtils.ts @@ -1,12 +1,10 @@ import axios from "axios"; -import download from "downloadjs"; import config from "../../../config"; import { RSReportInterface } from "../../../utils/ReportUtils"; const { RS_API_URL } = config; -export const reportDetailURL = (id: string, base?: string) => - `${base ? base : RS_API_URL}/api/history/report/${id}`; +export const reportDetailURL = (id: string, base?: string) => `${base ? base : RS_API_URL}/api/history/report/${id}`; export const getReportAndDownload = ( reportId: string, @@ -31,9 +29,27 @@ export const getReportAndDownload = ( }; export const downloadReport = (report: RSReportInterface) => { + // Decode the file name from the report let filename = decodeURIComponent(report.fileName); + + // Extract the filename if it contains a path const filenameStartIndex = filename.lastIndexOf("/"); - if (filenameStartIndex >= 0 && filename.length > filenameStartIndex + 1) + if (filenameStartIndex >= 0 && filename.length > filenameStartIndex + 1) { filename = filename.substring(filenameStartIndex + 1); - return download(report.content, filename, report.mimeType); + } + + const blob = new Blob([report.content], { type: report.mimeType || "application/octet-stream" }); + + const url = URL.createObjectURL(blob); + + // Create a temporary anchor element to trigger the download + const a = document.createElement("a"); + a.href = url; + a.download = filename; + + // Append the anchor to the DOM, trigger the download, and clean up + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); }; diff --git a/frontend-react/yarn.lock b/frontend-react/yarn.lock index 36326ff0312..5f5f23f5c2e 100644 --- a/frontend-react/yarn.lock +++ b/frontend-react/yarn.lock @@ -2654,13 +2654,6 @@ __metadata: languageName: node linkType: hard -"@types/downloadjs@npm:^1.4.6": - version: 1.4.6 - resolution: "@types/downloadjs@npm:1.4.6" - checksum: 0e98425946c12315a7b9646edb75285bcc0fda2d59f9d296fa3bf9455ef62d6d73383c52ee86eec50e9b4cee6f9af9dba78c6fb56bc6444395b4ac4f76a86ec0 - languageName: node - linkType: hard - "@types/escodegen@npm:^0.0.6": version: 0.0.6 resolution: "@types/escodegen@npm:0.0.6" @@ -5146,13 +5139,6 @@ __metadata: languageName: node linkType: hard -"downloadjs@npm:^1.4.7": - version: 1.4.7 - resolution: "downloadjs@npm:1.4.7" - checksum: 4c546a28e7adcb1c290685f923add84e89582549f93502fa1b028194492522f716abb95a70f6ae464067a767e967806970d2a03e6262f8ccbcf3dd68e950d1da - languageName: node - linkType: hard - "eastasianwidth@npm:^0.2.0": version: 0.2.0 resolution: "eastasianwidth@npm:0.2.0" @@ -10365,7 +10351,6 @@ __metadata: "@trussworks/react-uswds": ^9.1.0 "@types/dompurify": ^3.0.5 "@types/dotenv-flow": ^3.3.3 - "@types/downloadjs": ^1.4.6 "@types/eslint__js": ^8.42.3 "@types/github-slugger": ^1.3.0 "@types/html-to-text": ^9.0.4 @@ -10392,7 +10377,6 @@ __metadata: date-fns-tz: ^3.2.0 dompurify: ^3.1.7 dotenv-flow: ^4.1.0 - downloadjs: ^1.4.7 eslint: 9.13.0 eslint-config-prettier: ^9.1.0 eslint-import-resolver-typescript: ^3.6.3 From d420f0b4bd6f99ae9d81669e713b4ade299da344 Mon Sep 17 00:00:00 2001 From: Arnej <118766341+arnejduranovic@users.noreply.github.com> Date: Wed, 20 Nov 2024 12:11:24 -0600 Subject: [PATCH 3/5] Update FHIRFunctions to base64 encode messages going to poison queue (#16611) --- .../src/main/kotlin/fhirengine/azure/FHIRFunctions.kt | 6 ++++-- prime-router/src/test/kotlin/azure/FHIRFunctionsTests.kt | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/prime-router/src/main/kotlin/fhirengine/azure/FHIRFunctions.kt b/prime-router/src/main/kotlin/fhirengine/azure/FHIRFunctions.kt index cd3e59e2d3d..8d10d783e17 100644 --- a/prime-router/src/main/kotlin/fhirengine/azure/FHIRFunctions.kt +++ b/prime-router/src/main/kotlin/fhirengine/azure/FHIRFunctions.kt @@ -34,6 +34,7 @@ import gov.cdc.prime.router.report.ReportService import org.apache.commons.lang3.StringUtils import org.apache.logging.log4j.kotlin.Logging import org.jooq.exception.DataAccessException +import java.util.Base64 class FHIRFunctions( private val workflowEngine: WorkflowEngine = WorkflowEngine(), @@ -204,7 +205,7 @@ class FHIRFunctions( } catch (ex: SubmissionSenderNotFound) { // This is a specific error case that can occur while handling a report via the new Submission service // In a situation that the sender is not found there is not enough information to record a report event - // and we want a poison queue message to be immediately added so that the configuration can be fixed + // so, we want a poison queue message to be immediately added so that the configuration can be fixed logger.error(ex) val tableEntity = Submission( ex.reportId.toString(), @@ -220,7 +221,8 @@ class FHIRFunctions( // that will not be resolved if the message is automatically retried // Instead, the error is recorded as an event and message is manually inserted into the poison queue val report = databaseAccess.fetchReportFile(messageContent.reportId) - val poisonQueueMessageId = queueAccess.sendMessage("${messageContent.messageQueueName}-poison", message) + val encodedMsg = Base64.getEncoder().encodeToString(message.toByteArray()) + val poisonQueueMessageId = queueAccess.sendMessage("${messageContent.messageQueueName}-poison", encodedMsg) fhirEngine.reportEventService.sendReportProcessingError( ReportStreamEventName.PIPELINE_EXCEPTION, report, diff --git a/prime-router/src/test/kotlin/azure/FHIRFunctionsTests.kt b/prime-router/src/test/kotlin/azure/FHIRFunctionsTests.kt index 6ccd26f0852..a7b7986874c 100644 --- a/prime-router/src/test/kotlin/azure/FHIRFunctionsTests.kt +++ b/prime-router/src/test/kotlin/azure/FHIRFunctionsTests.kt @@ -27,6 +27,7 @@ import org.jooq.tools.jdbc.MockResult import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows +import java.util.Base64 import java.util.UUID class FHIRFunctionsTests { @@ -98,7 +99,7 @@ class FHIRFunctionsTests { verify(exactly = 1) { QueueAccess.sendMessage( "${QueueMessage.elrConvertQueueName}-poison", - queueMessage + Base64.getEncoder().encodeToString(queueMessage.toByteArray()) ) mockReportEventService.sendReportProcessingError( ReportStreamEventName.PIPELINE_EXCEPTION, @@ -124,7 +125,7 @@ class FHIRFunctionsTests { verify(exactly = 0) { QueueAccess.sendMessage( "${QueueMessage.elrConvertQueueName}-poison", - queueMessage + Base64.getEncoder().encodeToString(queueMessage.toByteArray()) ) } } From f0972f32bd54c42c26b6e541f96bcae807a90840 Mon Sep 17 00:00:00 2001 From: matts <22215332+devopsmatt@users.noreply.github.com> Date: Wed, 20 Nov 2024 14:53:49 -0800 Subject: [PATCH 4/5] Update deploy_terraform.yml (#16601) re-enable TF deploys --- .github/workflows/deploy_terraform.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy_terraform.yml b/.github/workflows/deploy_terraform.yml index a2d837549a5..b2a44672fde 100644 --- a/.github/workflows/deploy_terraform.yml +++ b/.github/workflows/deploy_terraform.yml @@ -114,4 +114,4 @@ jobs: terraform validate terraform fmt -recursive terraform plan -out ${{ needs.pre_job.outputs.env_name }}-tf.plan - # terraform apply -input=false -no-color -lock-timeout=600s -auto-approve ${{ needs.pre_job.outputs.env_name }}-tf.plan + terraform apply -input=false -no-color -lock-timeout=600s -auto-approve ${{ needs.pre_job.outputs.env_name }}-tf.plan From 9258b5d66a7f565fff24093b376436496ba006f0 Mon Sep 17 00:00:00 2001 From: Arnej <118766341+arnejduranovic@users.noreply.github.com> Date: Wed, 20 Nov 2024 18:51:23 -0600 Subject: [PATCH 5/5] 16609 part 2 fix (#16616) Update FHIRFunctions to encode poison queue message in the case of SubmissionSenderNotFound --- .../src/main/kotlin/fhirengine/azure/FHIRFunctions.kt | 3 ++- .../kotlin/fhirengine/azure/FHIRConverterIntegrationTests.kt | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/prime-router/src/main/kotlin/fhirengine/azure/FHIRFunctions.kt b/prime-router/src/main/kotlin/fhirengine/azure/FHIRFunctions.kt index 8d10d783e17..0166b734662 100644 --- a/prime-router/src/main/kotlin/fhirengine/azure/FHIRFunctions.kt +++ b/prime-router/src/main/kotlin/fhirengine/azure/FHIRFunctions.kt @@ -214,7 +214,8 @@ class FHIRFunctions( actionLogger.errors.takeIf { it.isNotEmpty() }?.map { it.detail.message }?.toString() ) submissionTableService.insertSubmission(tableEntity) - queueAccess.sendMessage("${messageContent.messageQueueName}-poison", message) + val encodedMsg = Base64.getEncoder().encodeToString(message.toByteArray()) + queueAccess.sendMessage("${messageContent.messageQueueName}-poison", encodedMsg) return emptyList() } catch (ex: Exception) { // We're catching anything else that occurs because the most likely cause is a code or configuration error diff --git a/prime-router/src/test/kotlin/fhirengine/azure/FHIRConverterIntegrationTests.kt b/prime-router/src/test/kotlin/fhirengine/azure/FHIRConverterIntegrationTests.kt index a5a553442a5..e95fb3d5806 100644 --- a/prime-router/src/test/kotlin/fhirengine/azure/FHIRConverterIntegrationTests.kt +++ b/prime-router/src/test/kotlin/fhirengine/azure/FHIRConverterIntegrationTests.kt @@ -96,6 +96,7 @@ import tech.tablesaw.api.StringColumn import tech.tablesaw.api.Table import java.nio.charset.Charset import java.time.OffsetDateTime +import java.util.Base64 import java.util.UUID @Testcontainers @@ -334,8 +335,7 @@ class FHIRConverterIntegrationTests { verify(exactly = 1) { QueueAccess.sendMessage( "${QueueMessage.elrSubmissionConvertQueueName}-poison", - queueMessage - + Base64.getEncoder().encodeToString(queueMessage.toByteArray()) ) } }