From acca8cdae3522394b1d9a1735b11ca7d94ed6076 Mon Sep 17 00:00:00 2001 From: Cody Seibert Date: Mon, 15 Jul 2024 15:50:40 -0400 Subject: [PATCH 01/30] initial work on typeorm --- package-lock.json | 579 ++++++++++++++++-- package.json | 5 +- tsconfig.json | 31 +- web-api/src/app.ts | 1 + web-api/src/data-source.ts | 17 + web-api/src/persistence/repository/Message.ts | 81 +++ 6 files changed, 627 insertions(+), 87 deletions(-) create mode 100644 web-api/src/data-source.ts create mode 100644 web-api/src/persistence/repository/Message.ts diff --git a/package-lock.json b/package-lock.json index da6a12e0462..d40836ec97a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -77,6 +77,7 @@ "parse-full-name": "1.2.6", "pdf-lib": "1.17.1", "pdfjs-dist": "2.16.105", + "pg": "^8.12.0", "process": "0.11.10", "promise-retry": "2.0.1", "pug": "3.0.3", @@ -90,11 +91,13 @@ "react-quill": "2.0.0", "react-responsive": "10.0.0", "react-select": "5.8.0", + "reflect-metadata": "^0.2.2", "riot-route": "3.1.4", "sanitize-filename": "1.6.3", "servor": "4.0.2", "supports-color": "9.4.0", "tmp": "0.2.3", + "typeorm": "^0.3.20", "util": "0.12.5", "uuid": "10.0.0", "websocket": "1.0.35", @@ -117,7 +120,7 @@ "@types/jest": "29.5.12", "@types/lodash": "4.17.6", "@types/luxon": "3.4.2", - "@types/node": "20.14.10", + "@types/node": "^20.14.10", "@types/promise-retry": "1.1.6", "@types/react": "18.3.3", "@types/react-dom": "18.3.0", @@ -9075,7 +9078,7 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, + "devOptional": true, "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -9087,7 +9090,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, + "devOptional": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -10747,7 +10750,6 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -10764,7 +10766,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, "engines": { "node": ">=12" }, @@ -10776,7 +10777,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, "engines": { "node": ">=12" }, @@ -10788,7 +10788,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -10805,7 +10804,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -10820,7 +10818,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -12929,7 +12926,6 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, "optional": true, "engines": { "node": ">=14" @@ -14050,6 +14046,11 @@ "node": ">= 16" } }, + "node_modules/@sqltools/formatter": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz", + "integrity": "sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==" + }, "node_modules/@szmarczak/http-timer": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", @@ -14817,13 +14818,13 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node14": { "version": "14.1.2", @@ -15778,7 +15779,7 @@ "version": "8.12.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", - "dev": true, + "devOptional": true, "bin": { "acorn": "bin/acorn" }, @@ -15819,7 +15820,7 @@ "version": "8.3.3", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", - "dev": true, + "devOptional": true, "dependencies": { "acorn": "^8.11.0" }, @@ -15985,7 +15986,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -16008,6 +16008,11 @@ "integrity": "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg==", "dev": true }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -16027,6 +16032,14 @@ "integrity": "sha512-gkco+qxENJV+8vFcDiiFhuoSvRXb2a/QPqpSoWhVz829VNJfOTnELbBmPmNKFxf3xdNnw4DWCkzkDaavcX/1YQ==", "dev": true }, + "node_modules/app-root-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz", + "integrity": "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==", + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", @@ -16082,7 +16095,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "devOptional": true }, "node_modules/argparse": { "version": "2.0.1", @@ -17860,7 +17873,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -18693,6 +18705,105 @@ "node": ">=8" } }, + "node_modules/cli-highlight": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", + "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", + "dependencies": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "bin": { + "highlight": "bin/highlight" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" + } + }, + "node_modules/cli-highlight/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cli-highlight/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cli-highlight/node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" + }, + "node_modules/cli-highlight/node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/cli-highlight/node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "node_modules/cli-highlight/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-highlight/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cli-highlight/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "engines": { + "node": ">=10" + } + }, "node_modules/cli-progress": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz", @@ -18766,7 +18877,6 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -18910,7 +19020,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -19303,7 +19412,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true + "devOptional": true }, "node_modules/create-serve": { "version": "1.0.1", @@ -19318,7 +19427,6 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -20638,7 +20746,6 @@ "version": "16.4.5", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", - "dev": true, "engines": { "node": ">=12" }, @@ -20714,8 +20821,7 @@ "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, "node_modules/ecc-jsbn": { "version": "0.1.2", @@ -20817,8 +20923,7 @@ "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, "node_modules/emojis-list": { "version": "3.0.0", @@ -21475,7 +21580,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "dev": true, "engines": { "node": ">=6" } @@ -23138,7 +23242,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", - "dev": true, "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -23154,7 +23257,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, "engines": { "node": ">=14" }, @@ -23441,7 +23543,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -23912,7 +24013,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -24017,6 +24117,14 @@ "integrity": "sha512-F9QO0+ZI8r1VZudxw21bD/U5pb2Y9LZY3TsnVqCPaijvw5mIhH5jsH29acLPijl5fECfD8FetJtgX8GN5YPM9Q==", "dev": true }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "engines": { + "node": "*" + } + }, "node_modules/hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -25452,8 +25560,7 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/isobject": { "version": "3.0.1", @@ -25589,7 +25696,6 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -28681,7 +28787,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "devOptional": true }, "node_modules/make-fetch-happen": { "version": "13.0.1", @@ -28969,7 +29075,6 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -28993,7 +29098,6 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, "engines": { "node": ">=16 || 14 >=14.17" } @@ -29316,6 +29420,16 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, "node_modules/nan": { "version": "2.20.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz", @@ -30635,8 +30749,7 @@ "node_modules/package-json-from-dist": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", - "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", - "dev": true + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==" }, "node_modules/pacote": { "version": "17.0.7", @@ -30826,7 +30939,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "engines": { "node": ">=8" } @@ -30840,7 +30952,6 @@ "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -30855,8 +30966,7 @@ "node_modules/path-scurry/node_modules/lru-cache": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" }, "node_modules/path-to-regexp": { "version": "0.1.7", @@ -30948,6 +31058,43 @@ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", "dev": true }, + "node_modules/pg": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.12.0.tgz", + "integrity": "sha512-A+LHUSnwnxrnL/tZ+OLfqR1SxLN3c/pgDztZ47Rpbsd4jUytsTtwQo/TLPRzPJMp/1pbhYVhH9cuSZLAajNfjQ==", + "dependencies": { + "pg-connection-string": "^2.6.4", + "pg-pool": "^3.6.2", + "pg-protocol": "^1.6.1", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.4.tgz", + "integrity": "sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==" + }, "node_modules/pg-int8": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", @@ -30964,6 +31111,14 @@ "node": ">=4" } }, + "node_modules/pg-pool": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.2.tgz", + "integrity": "sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==", + "peerDependencies": { + "pg": ">=8.0" + } + }, "node_modules/pg-protocol": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.1.tgz", @@ -30986,6 +31141,64 @@ "node": ">=10" } }, + "node_modules/pg/node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pg/node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/pg/node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pg/node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pg/node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dependencies": { + "split2": "^4.1.0" + } + }, "node_modules/pica": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/pica/-/pica-9.0.1.tgz", @@ -33555,6 +33768,11 @@ "esprima": "~4.0.0" } }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==" + }, "node_modules/reflect.getprototypeof": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", @@ -33694,7 +33912,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -34489,7 +34706,6 @@ "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dev": true, "dependencies": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -34519,7 +34735,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -34531,7 +34746,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "engines": { "node": ">=8" } @@ -34921,7 +35135,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "dev": true, "engines": { "node": ">= 10.x" } @@ -35154,7 +35367,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -35167,8 +35379,7 @@ "node_modules/string-width-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/string-width/node_modules/emoji-regex": { "version": "8.0.0", @@ -35308,7 +35519,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -36423,6 +36633,25 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/thread-stream": { "version": "0.15.2", "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-0.15.2.tgz", @@ -36770,7 +36999,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, + "devOptional": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -36813,19 +37042,19 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true + "devOptional": true }, "node_modules/ts-node/node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true + "devOptional": true }, "node_modules/ts-node/node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.3.1" } @@ -37138,11 +37367,229 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typeorm": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.20.tgz", + "integrity": "sha512-sJ0T08dV5eoZroaq9uPKBoNcGslHBR4E4y+EBHs//SiGbblGe7IeduP/IH4ddCcj0qp3PHwDwGnuvqEAnKlq/Q==", + "dependencies": { + "@sqltools/formatter": "^1.2.5", + "app-root-path": "^3.1.0", + "buffer": "^6.0.3", + "chalk": "^4.1.2", + "cli-highlight": "^2.1.11", + "dayjs": "^1.11.9", + "debug": "^4.3.4", + "dotenv": "^16.0.3", + "glob": "^10.3.10", + "mkdirp": "^2.1.3", + "reflect-metadata": "^0.2.1", + "sha.js": "^2.4.11", + "tslib": "^2.5.0", + "uuid": "^9.0.0", + "yargs": "^17.6.2" + }, + "bin": { + "typeorm": "cli.js", + "typeorm-ts-node-commonjs": "cli-ts-node-commonjs.js", + "typeorm-ts-node-esm": "cli-ts-node-esm.js" + }, + "engines": { + "node": ">=16.13.0" + }, + "funding": { + "url": "https://opencollective.com/typeorm" + }, + "peerDependencies": { + "@google-cloud/spanner": "^5.18.0", + "@sap/hana-client": "^2.12.25", + "better-sqlite3": "^7.1.2 || ^8.0.0 || ^9.0.0", + "hdb-pool": "^0.1.6", + "ioredis": "^5.0.4", + "mongodb": "^5.8.0", + "mssql": "^9.1.1 || ^10.0.1", + "mysql2": "^2.2.5 || ^3.0.1", + "oracledb": "^6.3.0", + "pg": "^8.5.1", + "pg-native": "^3.0.0", + "pg-query-stream": "^4.0.0", + "redis": "^3.1.1 || ^4.0.0", + "sql.js": "^1.4.0", + "sqlite3": "^5.0.3", + "ts-node": "^10.7.0", + "typeorm-aurora-data-api-driver": "^2.0.0" + }, + "peerDependenciesMeta": { + "@google-cloud/spanner": { + "optional": true + }, + "@sap/hana-client": { + "optional": true + }, + "better-sqlite3": { + "optional": true + }, + "hdb-pool": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "mongodb": { + "optional": true + }, + "mssql": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "oracledb": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-native": { + "optional": true + }, + "pg-query-stream": { + "optional": true + }, + "redis": { + "optional": true + }, + "sql.js": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "ts-node": { + "optional": true + }, + "typeorm-aurora-data-api-driver": { + "optional": true + } + } + }, + "node_modules/typeorm/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/typeorm/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/typeorm/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typeorm/node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/typeorm/node_modules/mkdirp": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz", + "integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typeorm/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/typeorm/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/typescript": { "version": "5.4.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", - "dev": true, + "devOptional": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -37507,7 +37954,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true + "devOptional": true }, "node_modules/v8-to-istanbul": { "version": "9.3.0", @@ -37859,7 +38306,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -38086,7 +38532,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -38104,7 +38549,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -38200,11 +38644,18 @@ "node": ">=0.4.0" } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, "engines": { "node": ">=10" } @@ -38258,7 +38709,6 @@ "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -38276,7 +38726,6 @@ "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, "engines": { "node": ">=12" } @@ -38313,7 +38762,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, + "devOptional": true, "engines": { "node": ">=6" } diff --git a/package.json b/package.json index f5bbaa518bb..d02cbef4fb1 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "parse-full-name": "1.2.6", "pdf-lib": "1.17.1", "pdfjs-dist": "2.16.105", + "pg": "^8.12.0", "process": "0.11.10", "promise-retry": "2.0.1", "pug": "3.0.3", @@ -89,11 +90,13 @@ "react-quill": "2.0.0", "react-responsive": "10.0.0", "react-select": "5.8.0", + "reflect-metadata": "^0.2.2", "riot-route": "3.1.4", "sanitize-filename": "1.6.3", "servor": "4.0.2", "supports-color": "9.4.0", "tmp": "0.2.3", + "typeorm": "^0.3.20", "util": "0.12.5", "uuid": "10.0.0", "websocket": "1.0.35", @@ -259,7 +262,7 @@ "@types/jest": "29.5.12", "@types/lodash": "4.17.6", "@types/luxon": "3.4.2", - "@types/node": "20.14.10", + "@types/node": "^20.14.10", "@types/promise-retry": "1.1.6", "@types/react": "18.3.3", "@types/react-dom": "18.3.0", diff --git a/tsconfig.json b/tsconfig.json index c92e74a28dc..91c96c88344 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,41 +3,30 @@ "module": "commonjs", "allowJs": false, "noImplicitAny": false, + "lib": ["es5", "es6"], "removeComments": true, "preserveConstEnums": true, "esModuleInterop": true, "inlineSourceMap": true, "resolveJsonModule": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, "skipLibCheck": true, - "typeRoots": [ - "./node_modules/@types", - "./types" - ], - "types": [ - "jest", - "node" - ], + "typeRoots": ["./node_modules/@types", "./types"], + "types": ["jest", "node"], "target": "es6", "jsx": "react", "strict": true, "baseUrl": "./", "paths": { - "@web-client/*": [ - "web-client/src/*" - ], - "@web-api/*": [ - "web-api/src/*" - ], - "@shared/*": [ - "shared/src/*" - ] + "@web-client/*": ["web-client/src/*"], + "@web-api/*": ["web-api/src/*"], + "@shared/*": ["shared/src/*"] } }, "ts-node": { "files": true, - "require": [ - "tsconfig-paths/register" - ] + "require": ["tsconfig-paths/register"] }, "include": ["./**/*.ts", "./**/*.tsx"], "exclude": [ @@ -51,4 +40,4 @@ "./cypress-smoketests-readonly-public.config.ts", "./cypress-public.config.ts" ] -} \ No newline at end of file +} diff --git a/web-api/src/app.ts b/web-api/src/app.ts index 36823c11bee..88e2f2d704a 100644 --- a/web-api/src/app.ts +++ b/web-api/src/app.ts @@ -1,4 +1,5 @@ /* eslint-disable max-lines */ +import 'reflect-metadata'; import { addCaseToTrialSessionLambda } from './lambdas/trialSessions/addCaseToTrialSessionLambda'; import { addConsolidatedCaseLambda } from './lambdas/cases/addConsolidatedCaseLambda'; import { addCoversheetLambda } from './lambdas/documents/addCoversheetLambda'; diff --git a/web-api/src/data-source.ts b/web-api/src/data-source.ts new file mode 100644 index 00000000000..8903b40c8d7 --- /dev/null +++ b/web-api/src/data-source.ts @@ -0,0 +1,17 @@ +import 'reflect-metadata'; +import { DataSource } from 'typeorm'; +import { Message } from './persistence/repository/Message'; + +export const AppDataSource = new DataSource({ + database: 'postgres', + entities: [Message], + host: 'localhost', + logging: false, + migrations: [], + password: 'example', + port: 5432, + subscribers: [], + synchronize: true, + type: 'postgres', + username: 'postgres', +}); diff --git a/web-api/src/persistence/repository/Message.ts b/web-api/src/persistence/repository/Message.ts new file mode 100644 index 00000000000..a872011dd42 --- /dev/null +++ b/web-api/src/persistence/repository/Message.ts @@ -0,0 +1,81 @@ +import { Column, Entity, PrimaryColumn, PrimaryGeneratedColumn } from 'typeorm'; + +@Entity() +export class Message { + @Column('jsonb', { nullable: true }) + attachments?: { + documentId: string; + }[]; + + @Column() + caseStatus: string; + + @Column() + caseTitle: string; + + @Column({ nullable: true }) + completedAt?: string; + + @Column({ nullable: true }) + completedBy?: string; + + @Column({ nullable: true }) + completedBySection?: string; + + @Column({ nullable: true }) + completedByUserId?: string; + + @Column({ nullable: true }) + completedMessage?: string; + + @Column() + createdAt: string; + + @Column() + docketNumber: string; + + @Column() + docketNumberWithSuffix: string; + + @Column() + from: string; + + @Column() + fromSection: string; + + @Column() + fromUserId: string; + + @Column() + isCompleted: boolean; + + @Column() + isRead: boolean; + + @Column() + isRepliedTo: boolean; + + @Column({ nullable: true }) + leadDocketNumber?: string; + + @Column() + message: string; + + @PrimaryColumn() + messageId: string; + + @Column() + parentMessageId: string; + + @Column() + subject: string; + + @Column() + to: string; + + @Column() + toSection: string; + + @Column() + toUserId: string; +} From e63c8d2976f991438d8fe2d1c5b8558a500fd7eb Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Mon, 15 Jul 2024 16:44:12 -0600 Subject: [PATCH 02/30] 10391: setup postgres + type orm --- package-lock.json | 151 +++++++++++++++--- package.json | 9 +- postgres/__tmp_notes.md | 29 ++++ {web-api/src => postgres}/data-source.ts | 7 +- postgres/docker-compose.yaml | 16 ++ postgres/migrations/1721075669958-Message.ts | 15 ++ postgres/seed/seed.ts | 83 ++++++++++ web-api/docker-compose.yaml | 16 ++ .../dynamo/messages/createMessage.ts | 20 ++- .../dynamo/messages/getMessageById.ts | 20 +-- .../messages/getMessageThreadByParentId.ts | 31 ++-- .../messages/getMessagesByDocketNumber.ts | 30 ++-- .../messages/markMessageThreadRepliedTo.ts | 33 ++-- .../dynamo/messages/setMessageAsRead.ts | 25 +-- .../dynamo/messages/updateMessage.ts | 35 ++-- .../getCompletedSectionInboxMessages.ts | 48 ++---- .../messages/getCompletedUserInboxMessages.ts | 53 +++--- .../messages/getSectionInboxMessages.ts | 47 +++--- .../messages/getSectionOutboxMessages.ts | 44 ++--- .../messages/getUserInboxMessages.ts | 62 +++---- .../messages/getUserOutboxMessages.ts | 54 +++---- web-api/src/persistence/repository/Message.ts | 38 ++--- 22 files changed, 534 insertions(+), 332 deletions(-) create mode 100644 postgres/__tmp_notes.md rename {web-api/src => postgres}/data-source.ts (58%) create mode 100644 postgres/docker-compose.yaml create mode 100644 postgres/migrations/1721075669958-Message.ts create mode 100644 postgres/seed/seed.ts create mode 100644 web-api/docker-compose.yaml diff --git a/package-lock.json b/package-lock.json index d40836ec97a..7b6169e3e62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -98,6 +98,7 @@ "supports-color": "9.4.0", "tmp": "0.2.3", "typeorm": "^0.3.20", + "typeorm-extension": "^3.5.1", "util": "0.12.5", "uuid": "10.0.0", "websocket": "1.0.35", @@ -10554,7 +10555,6 @@ "version": "8.4.1", "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.4.1.tgz", "integrity": "sha512-XQ3cU+Q8Uqmrbf2e0cIC/QN43sTBSC8KF12u29Mb47tWrt2hAgBXSgpZMj4Ao8Uk0iJcU99QsOCaIL8934obCg==", - "dev": true, "funding": [ { "type": "opencollective", @@ -11564,7 +11564,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -11577,7 +11576,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, "engines": { "node": ">= 8" } @@ -11586,7 +11584,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -17881,7 +17878,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, "dependencies": { "fill-range": "^7.1.1" }, @@ -19129,6 +19125,14 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, + "node_modules/consola": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", + "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -20359,6 +20363,11 @@ "minimalistic-assert": "^1.0.0" } }, + "node_modules/destr": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.3.tgz", + "integrity": "sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==" + }, "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -20823,6 +20832,11 @@ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, + "node_modules/ebec": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ebec/-/ebec-2.3.0.tgz", + "integrity": "sha512-bt+0tSL7223VU3PSVi0vtNLZ8pO1AfWolcPPMk2a/a5H+o/ZU9ky0n3A0zhrR4qzJTN61uPsGIO4ShhOukdzxA==" + }, "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -21080,6 +21094,17 @@ "node": ">=6" } }, + "node_modules/envix": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/envix/-/envix-1.5.0.tgz", + "integrity": "sha512-IOxTKT+tffjxgvX2O5nq6enbkv6kBQ/QdMy18bZWo0P0rKPvsRp2/EypIPwTvJfnmk3VdOlq/KcRSZCswefM/w==", + "dependencies": { + "std-env": "^3.7.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/err-code": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", @@ -22829,7 +22854,6 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -22914,7 +22938,6 @@ "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, "dependencies": { "reusify": "^1.0.4" } @@ -23110,7 +23133,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -23186,6 +23208,14 @@ "node": ">=8" } }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "bin": { + "flat": "cli.js" + } + }, "node_modules/flat-cache": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", @@ -23695,7 +23725,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -25134,7 +25163,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -25186,7 +25214,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -25262,7 +25289,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "engines": { "node": ">=0.12.0" } @@ -27087,7 +27113,6 @@ "version": "1.21.6", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", - "dev": true, "bin": { "jiti": "bin/jiti.js" } @@ -28486,6 +28511,19 @@ "node": ">=8" } }, + "node_modules/locter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/locter/-/locter-2.1.0.tgz", + "integrity": "sha512-QUPPtb6CQ3hOacDZq2kc6KMzYn9z6r9B2RtFJTBD9nqxmyQJVYnTNZNqY6Z5NcJfwsGEgJLddnfFpofg7EJMDg==", + "dependencies": { + "destr": "^2.0.3", + "ebec": "^2.3.0", + "fast-glob": "^3.3.2", + "flat": "^5.0.2", + "jiti": "^1.21.0", + "yaml": "^2.4.1" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -28726,6 +28764,14 @@ "loose-envify": "cli.js" } }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dependencies": { + "tslib": "^2.0.3" + } + }, "node_modules/lowercase-keys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", @@ -28960,7 +29006,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, "engines": { "node": ">= 8" } @@ -28982,7 +29027,6 @@ "version": "4.0.7", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", - "dev": true, "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -29542,6 +29586,15 @@ "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==", "dev": true }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, "node_modules/node-cache": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", @@ -30893,6 +30946,15 @@ "node": ">= 0.8" } }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/passthrough-counter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/passthrough-counter/-/passthrough-counter-1.0.0.tgz", @@ -31219,7 +31281,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "engines": { "node": ">=8.6" }, @@ -33168,7 +33229,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, "funding": [ { "type": "github", @@ -33322,6 +33382,23 @@ "node": ">= 0.6" } }, + "node_modules/rapiq": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/rapiq/-/rapiq-0.9.0.tgz", + "integrity": "sha512-k4oT4RarFBrlLMJ49xUTeQpa/us0uU4I70D/UEnK3FWQ4GENzei01rEQAmvPKAIzACo4NMW+YcYJ7EVfSa7EFg==", + "dependencies": { + "ebec": "^1.1.0", + "smob": "^1.4.0" + } + }, + "node_modules/rapiq/node_modules/ebec": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ebec/-/ebec-1.1.1.tgz", + "integrity": "sha512-JZ1vcvPQtR+8LGbZmbjG21IxLQq/v47iheJqn2F6yB2CgnGfn8ZVg3myHrf3buIZS8UCwQK0jOSIb3oHX7aH8g==", + "dependencies": { + "smob": "^1.4.0" + } + }, "node_modules/raw-body": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", @@ -34111,7 +34188,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -34176,7 +34252,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -34988,6 +35063,11 @@ "npm": ">= 3.0.0" } }, + "node_modules/smob": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", + "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==" + }, "node_modules/socket.io-client": { "version": "4.7.5", "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz", @@ -35250,6 +35330,11 @@ "node": ">= 0.8" } }, + "node_modules/std-env": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", + "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==" + }, "node_modules/stop-iteration-iterator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", @@ -36764,7 +36849,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -37472,6 +37556,32 @@ } } }, + "node_modules/typeorm-extension": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/typeorm-extension/-/typeorm-extension-3.5.1.tgz", + "integrity": "sha512-gykF1eBattSIt+F0+134c+j+AFODYCb/6uIjmFCNzAoc63UW5j7d25JnzDah10viWnDi99BY03UUIxRcQWcR+w==", + "dependencies": { + "@faker-js/faker": "^8.4.1", + "consola": "^3.2.3", + "envix": "^1.5.0", + "locter": "^2.1.0", + "pascal-case": "^3.1.2", + "rapiq": "^0.9.0", + "reflect-metadata": "^0.2.2", + "smob": "^1.5.0", + "yargs": "^17.7.2" + }, + "bin": { + "typeorm-extension": "bin/cli.cjs", + "typeorm-extension-esm": "bin/cli.mjs" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "typeorm": "~0.3.0" + } + }, "node_modules/typeorm/node_modules/buffer": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", @@ -38678,7 +38788,6 @@ "version": "2.4.5", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", "integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==", - "dev": true, "bin": { "yaml": "bin.mjs" }, diff --git a/package.json b/package.json index d02cbef4fb1..9ed8d75a7da 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,8 @@ "servor": "4.0.2", "supports-color": "9.4.0", "tmp": "0.2.3", - "typeorm": "^0.3.20", + "typeorm": "0.3.20", + "typeorm-extension": "3.5.1", "util": "0.12.5", "uuid": "10.0.0", "websocket": "1.0.35", @@ -238,7 +239,11 @@ "test:watch": "jest --watch .*test\\.js$", "verify-authorizers": "./scripts/circleci/verify-authorizers.sh", "verify-private-elasticsearch": "./scripts/circleci/verify-private-elasticsearch.sh", - "visualize-bundle": "esbuild-visualizer --metadata ./metadata.json && open stats.html" + "visualize-bundle": "esbuild-visualizer --metadata ./metadata.json && open stats.html", + "typeorm:migrations:migrate": "npx typeorm-ts-node-commonjs migration:run -d postgres/data-source.ts", + "typeorm:migrations:revert": "npx typeorm-ts-node-commonjs migration:revert -d postgres/data-source.ts", + "typeorm:migrations:generate": "npx typeorm-ts-node-commonjs migration:generate ${MIGRATION_NAME} -d postgres/data-source.ts", + "typeorm:seed": "npx ts-node ./postgres/seed.ts" }, "overrides": { "axios": "$axios", diff --git a/postgres/__tmp_notes.md b/postgres/__tmp_notes.md new file mode 100644 index 00000000000..43582789cd3 --- /dev/null +++ b/postgres/__tmp_notes.md @@ -0,0 +1,29 @@ + +# Things done + +- Migrations +- Seeding via Script +- Message CRUD (Note: Not all functions are properly mapped over to Flexion Entities) +- Package scripts: + "typeorm:migrations:migrate" + "typeorm:migrations:revert" + "typeorm:migrations:generate" (this will probably need to be converted to script) + "typeorm:seed" +- Log in and view dashboard (load inbox) for docketclerk on localhost + +# Questions + +- How to handle null, as we were expecting undefined before, ex: message.leadDocketNumber: null will fail validation unless we override it? + - Custom repository method? + - Custom mapping utility function for each OR transformToNull wrapper function, etc, etc? + +# Stuff to consider + +- Transactions?? + +# Things to do + +- Figure out overall organization of implementation +- ... ??? + + diff --git a/web-api/src/data-source.ts b/postgres/data-source.ts similarity index 58% rename from web-api/src/data-source.ts rename to postgres/data-source.ts index 8903b40c8d7..6aec00431d9 100644 --- a/web-api/src/data-source.ts +++ b/postgres/data-source.ts @@ -1,13 +1,13 @@ import 'reflect-metadata'; import { DataSource } from 'typeorm'; -import { Message } from './persistence/repository/Message'; +import { Message } from '../web-api/src/persistence/repository/Message'; export const AppDataSource = new DataSource({ database: 'postgres', entities: [Message], host: 'localhost', logging: false, - migrations: [], + migrations: ['migrations/*.ts'], password: 'example', port: 5432, subscribers: [], @@ -15,3 +15,6 @@ export const AppDataSource = new DataSource({ type: 'postgres', username: 'postgres', }); + +const dataSource = AppDataSource.initialize().then(() => AppDataSource); +export const getDataSource = () => dataSource; diff --git a/postgres/docker-compose.yaml b/postgres/docker-compose.yaml new file mode 100644 index 00000000000..6c1af9f5360 --- /dev/null +++ b/postgres/docker-compose.yaml @@ -0,0 +1,16 @@ +version: '3.9' +services: + message-service: + image: postgres + restart: always + container_name: message-service + ports: + - 5432:5432 + environment: + POSTGRES_PASSWORD: example + PGDATA: /data/postgres + volumes: + - postgres:/data/postgres + +volumes: + postgres: diff --git a/postgres/migrations/1721075669958-Message.ts b/postgres/migrations/1721075669958-Message.ts new file mode 100644 index 00000000000..155c05262ac --- /dev/null +++ b/postgres/migrations/1721075669958-Message.ts @@ -0,0 +1,15 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class Message1721075669958 implements MigrationInterface { + name = 'Message1721075669958'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'CREATE TABLE "message" ("attachments" jsonb, "caseStatus" character varying NOT NULL, "caseTitle" character varying NOT NULL, "completedAt" character varying, "completedBy" character varying, "completedBySection" character varying, "completedByUserId" character varying, "completedMessage" character varying, "createdAt" character varying NOT NULL, "docketNumber" character varying NOT NULL, "docketNumberWithSuffix" character varying NOT NULL, "from" character varying NOT NULL, "fromSection" character varying NOT NULL, "fromUserId" character varying NOT NULL, "isCompleted" boolean NOT NULL, "isRead" boolean NOT NULL, "isRepliedTo" boolean NOT NULL, "leadDocketNumber" character varying, "message" character varying NOT NULL, "messageId" character varying NOT NULL, "parentMessageId" character varying NOT NULL, "subject" character varying NOT NULL, "to" character varying NOT NULL, "toSection" character varying NOT NULL, "toUserId" character varying NOT NULL, CONSTRAINT "PK_b664c8ae63d634326ce5896cecc" PRIMARY KEY ("messageId"))', + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('DROP TABLE "message"'); + } +} diff --git a/postgres/seed/seed.ts b/postgres/seed/seed.ts new file mode 100644 index 00000000000..535ac9aa962 --- /dev/null +++ b/postgres/seed/seed.ts @@ -0,0 +1,83 @@ +import { Message } from '../../web-api/src/persistence/repository/Message'; +import { getDataSource } from '../data-source'; + +async function main() { + const appDataSource = await getDataSource(); + const messageRepository = appDataSource.getRepository(Message); + const messages = [ + { + attachments: [], + caseStatus: 'General Docket - Not at Issue', + caseTitle: 'Bill Burr', + createdAt: new Date('2020-06-05T18:02:25.280Z').toISOString(), + docketNumber: '105-20', + docketNumberWithSuffix: '105-20L', + from: 'Test Petitionsclerk', + fromSection: 'petitions', + fromUserId: '3805d1ab-18d0-43ec-bafb-654e83405416', + isCompleted: false, + isRead: false, + isRepliedTo: false, + message: 'hello!', + messageId: 'eb0a139a-8951-4de1-8b83-f02a27504105', + parentMessageId: 'eb0a139a-8951-4de1-8b83-f02a27504105', + subject: 'message to myself', + to: 'Test Petitionsclerk', + toSection: 'petitions', + toUserId: '3805d1ab-18d0-43ec-bafb-654e83405416', + }, + { + attachments: [ + { + documentId: '4796a931-14fb-43e6-948f-d2b67ce4c1cb', + }, + ], + caseStatus: 'Calendared', + caseTitle: 'Reuben Blair', + createdAt: new Date('2023-06-02T21:15:50.105Z').toISOString(), + docketNumber: '103-20', + docketNumberWithSuffix: '103-20L', + from: 'Test Admissions Clerk', + fromSection: 'admissions', + fromUserId: '9d7d63b7-d7a5-4905-ba89-ef71bf30057f', + isCompleted: false, + isRead: false, + isRepliedTo: false, + message: 'Could you please review this?', + messageId: '1d4c1fd9-5265-4e46-894f-b8426d3a6836', + parentMessageId: '1d4c1fd9-5265-4e46-894f-b8426d3a6836', + subject: 'Administrative Record', + to: 'Test Petitionsclerk', + toSection: 'petitions', + toUserId: '3805d1ab-18d0-43ec-bafb-654e83405416', + }, + { + attachments: [ + { + documentId: '8ed9bad9-db58-43c8-b03f-c2e3ad92995f', + }, + ], + caseStatus: 'New', + caseTitle: 'Mufutau Wade', + createdAt: new Date('2020-08-18T18:07:36.333Z').toISOString(), + docketNumber: '104-19', + docketNumberWithSuffix: '104-19', + from: 'Test Docketclerk', + fromSection: 'docket', + fromUserId: '1805d1ab-18d0-43ec-bafb-654e83405416', + isCompleted: false, + isRead: false, + isRepliedTo: false, + message: 'Test message with deleted document.', + messageId: '2d1191d3-4597-454a-a2b2-84e267ccf01e', + parentMessageId: '2d1191d3-4597-454a-a2b2-84e267ccf01e', + subject: 'Order', + to: 'Test Docketclerk', + toSection: 'docket', + toUserId: '1805d1ab-18d0-43ec-bafb-654e83405416', + }, + ]; + await messageRepository.save(messages); +} + +main().catch(console.error); diff --git a/web-api/docker-compose.yaml b/web-api/docker-compose.yaml new file mode 100644 index 00000000000..6c1af9f5360 --- /dev/null +++ b/web-api/docker-compose.yaml @@ -0,0 +1,16 @@ +version: '3.9' +services: + message-service: + image: postgres + restart: always + container_name: message-service + ports: + - 5432:5432 + environment: + POSTGRES_PASSWORD: example + PGDATA: /data/postgres + volumes: + - postgres:/data/postgres + +volumes: + postgres: diff --git a/web-api/src/persistence/dynamo/messages/createMessage.ts b/web-api/src/persistence/dynamo/messages/createMessage.ts index 9eaf7115953..b59648a5ac4 100644 --- a/web-api/src/persistence/dynamo/messages/createMessage.ts +++ b/web-api/src/persistence/dynamo/messages/createMessage.ts @@ -1,5 +1,6 @@ +import { AppDataSource } from '@web-api/data-source'; +import { Message } from '@web-api/persistence/repository/Message'; import { RawMessage } from '@shared/business/entities/Message'; -import { put } from '../../dynamodbClientService'; /** * createMessage @@ -9,19 +10,16 @@ import { put } from '../../dynamodbClientService'; * @param {object} providers.message the message data * @returns {object} the created message */ -export const createMessage = ({ +export const createMessage = async ({ applicationContext, message, }: { applicationContext: IApplicationContext; message: RawMessage; -}) => - put({ - Item: { - ...message, - gsi1pk: `message|${message.parentMessageId}`, - pk: `case|${message.docketNumber}`, - sk: `message|${message.messageId}`, - }, - applicationContext, +}) => { + const messageRepository = AppDataSource.getRepository(Message); + + return await messageRepository.save({ + ...message, }); +}; diff --git a/web-api/src/persistence/dynamo/messages/getMessageById.ts b/web-api/src/persistence/dynamo/messages/getMessageById.ts index 2d0d0161106..2dc5ef34927 100644 --- a/web-api/src/persistence/dynamo/messages/getMessageById.ts +++ b/web-api/src/persistence/dynamo/messages/getMessageById.ts @@ -1,4 +1,5 @@ -import { get } from '../../dynamodbClientService'; +import { Message } from '@web-api/persistence/repository/Message'; +import { getDataSource } from '@web-api/data-source'; /** * getMessageById @@ -9,7 +10,7 @@ import { get } from '../../dynamodbClientService'; * @param {string} providers.messageId the id of the message * @returns {object} the message */ -export const getMessageById = ({ +export const getMessageById = async ({ applicationContext, docketNumber, messageId, @@ -17,11 +18,12 @@ export const getMessageById = ({ applicationContext: IApplicationContext; docketNumber: string; messageId: string; -}) => - get({ - Key: { - pk: `case|${docketNumber}`, - sk: `message|${messageId}`, - }, - applicationContext, +}) => { + const appDataSource = await getDataSource(); + const messageRepository = appDataSource.getRepository(Message); + const message = await messageRepository.findOne({ + where: { messageId }, }); + + return message; +}; diff --git a/web-api/src/persistence/dynamo/messages/getMessageThreadByParentId.ts b/web-api/src/persistence/dynamo/messages/getMessageThreadByParentId.ts index c71889802fd..6db462349ee 100644 --- a/web-api/src/persistence/dynamo/messages/getMessageThreadByParentId.ts +++ b/web-api/src/persistence/dynamo/messages/getMessageThreadByParentId.ts @@ -1,4 +1,6 @@ -import { query } from '../../dynamodbClientService'; +import { AppDataSource } from '@web-api/data-source'; +import { Message } from '@web-api/persistence/repository/Message'; +import { Message as MessageEntity } from '@shared/business/entities/Message'; /** * getMessageThreadByParentId @@ -8,21 +10,26 @@ import { query } from '../../dynamodbClientService'; * @param {string} providers.parentMessageId the id of the parent message * @returns {object} the created message */ -export const getMessageThreadByParentId = ({ +export const getMessageThreadByParentId = async ({ applicationContext, parentMessageId, }: { applicationContext: IApplicationContext; parentMessageId: string; -}) => - query({ - ExpressionAttributeNames: { - '#gsi1pk': 'gsi1pk', - }, - ExpressionAttributeValues: { - ':gsi1pk': `message|${parentMessageId}`, +}) => { + const messageRepository = AppDataSource.getRepository(Message); + + const messages = await messageRepository.find({ + where: { + parentMessageId, }, - IndexName: 'gsi1', - KeyConditionExpression: '#gsi1pk = :gsi1pk', - applicationContext, }); + + return messages.map( + result => + new MessageEntity( + { ...result, createdAt: result.createdAt?.toISOString() }, + { applicationContext }, + ), + ); +}; diff --git a/web-api/src/persistence/dynamo/messages/getMessagesByDocketNumber.ts b/web-api/src/persistence/dynamo/messages/getMessagesByDocketNumber.ts index 86dbd260062..c1ef357f99d 100644 --- a/web-api/src/persistence/dynamo/messages/getMessagesByDocketNumber.ts +++ b/web-api/src/persistence/dynamo/messages/getMessagesByDocketNumber.ts @@ -1,4 +1,5 @@ -import { query } from '../../dynamodbClientService'; +import { AppDataSource } from '@web-api/data-source'; +import { Message } from '@web-api/persistence/repository/Message'; /** * getMessagesByDocketNumber @@ -6,24 +7,21 @@ import { query } from '../../dynamodbClientService'; * @param {object} providers the providers object * @param {object} providers.applicationContext the application context * @param {string} providers.docketNumber the docket number of the case - * @returns {object} the created message + * @returns {object} the messages */ -export const getMessagesByDocketNumber = ({ +export const getMessagesByDocketNumber = async ({ applicationContext, docketNumber, }: { applicationContext: IApplicationContext; docketNumber: string; -}) => - query({ - ExpressionAttributeNames: { - '#pk': 'pk', - '#sk': 'sk', - }, - ExpressionAttributeValues: { - ':pk': `case|${docketNumber}`, - ':prefix': 'message|', - }, - KeyConditionExpression: '#pk = :pk and begins_with(#sk, :prefix)', - applicationContext, - }); +}) => { + const messageRepository = AppDataSource.getRepository(Message); + + const results = await messageRepository + .createQueryBuilder('message') + .where('message.docketNumber = :docketNumber', { docketNumber }) + .getMany(); + + return results; +}; diff --git a/web-api/src/persistence/dynamo/messages/markMessageThreadRepliedTo.ts b/web-api/src/persistence/dynamo/messages/markMessageThreadRepliedTo.ts index 6aed24660fc..1697163475b 100644 --- a/web-api/src/persistence/dynamo/messages/markMessageThreadRepliedTo.ts +++ b/web-api/src/persistence/dynamo/messages/markMessageThreadRepliedTo.ts @@ -1,13 +1,14 @@ +import { AppDataSource } from '@web-api/data-source'; +import { Message } from '@web-api/persistence/repository/Message'; import { getMessageThreadByParentId } from './getMessageThreadByParentId'; -import { update } from '../../dynamodbClientService'; /** * markMessageThreadRepliedTo * * @param {object} providers the providers object * @param {object} providers.applicationContext the application context - * @param {string} providers.messageId the id of the message to update - * @returns {object} the created message + * @param {string} providers.parentMessageId the id of the parent message to update + * @returns {object} the updated messages */ export const markMessageThreadRepliedTo = async ({ applicationContext, @@ -22,23 +23,15 @@ export const markMessageThreadRepliedTo = async ({ }); if (messages.length) { - const updateMessage = async message => { - return await update({ - ExpressionAttributeNames: { - '#isRepliedTo': 'isRepliedTo', - }, - ExpressionAttributeValues: { - ':isRepliedTo': true, - }, - Key: { - pk: `case|${message.docketNumber}`, - sk: `message|${message.messageId}`, - }, - UpdateExpression: 'SET #isRepliedTo = :isRepliedTo', - applicationContext, - }); - }; + const messageRepository = AppDataSource.getRepository(Message); - await Promise.all(messages.map(updateMessage)); + await Promise.all( + messages.map(async message => { + await messageRepository.update( + { messageId: message.messageId }, + { isRepliedTo: true }, + ); + }), + ); } }; diff --git a/web-api/src/persistence/dynamo/messages/setMessageAsRead.ts b/web-api/src/persistence/dynamo/messages/setMessageAsRead.ts index bfcc1ef3745..9d181e623a5 100644 --- a/web-api/src/persistence/dynamo/messages/setMessageAsRead.ts +++ b/web-api/src/persistence/dynamo/messages/setMessageAsRead.ts @@ -1,6 +1,7 @@ -import { update } from '../../dynamodbClientService'; +import { AppDataSource } from '@web-api/data-source'; +import { Message } from '@web-api/persistence/repository/Message'; -export const setMessageAsRead = ({ +export const setMessageAsRead = async ({ applicationContext, docketNumber, messageId, @@ -8,18 +9,8 @@ export const setMessageAsRead = ({ applicationContext: IApplicationContext; messageId: string; docketNumber: string; -}) => - update({ - ExpressionAttributeNames: { - '#isRead': 'isRead', - }, - ExpressionAttributeValues: { - ':isRead': true, - }, - Key: { - pk: `case|${docketNumber}`, - sk: `message|${messageId}`, - }, - UpdateExpression: 'SET #isRead = :isRead', - applicationContext, - }); +}) => { + const messageRepository = AppDataSource.getRepository(Message); + + await messageRepository.update({ docketNumber, messageId }, { isRead: true }); +}; diff --git a/web-api/src/persistence/dynamo/messages/updateMessage.ts b/web-api/src/persistence/dynamo/messages/updateMessage.ts index 9efc7b0b9a1..b4de56193ca 100644 --- a/web-api/src/persistence/dynamo/messages/updateMessage.ts +++ b/web-api/src/persistence/dynamo/messages/updateMessage.ts @@ -1,5 +1,6 @@ +import { AppDataSource } from '@web-api/data-source'; +import { Message } from '@web-api/persistence/repository/Message'; import { RawMessage } from '@shared/business/entities/Message'; -import { put } from '../../dynamodbClientService'; /** * updateMessage @@ -7,21 +8,31 @@ import { put } from '../../dynamodbClientService'; * @param {object} providers the providers object * @param {object} providers.applicationContext the application context * @param {object} providers.message the message data - * @returns {object} the created message + * @returns {object} the updated message */ -export const updateMessage = ({ +export const updateMessage = async ({ applicationContext, message, }: { applicationContext: IApplicationContext; message: RawMessage; -}) => - put({ - Item: { - ...message, - gsi1pk: `message|${message.parentMessageId}`, - pk: `case|${message.docketNumber}`, - sk: `message|${message.messageId}`, - }, - applicationContext, +}) => { + const messageRepository = AppDataSource.getRepository(Message); + + const existingMessage = await messageRepository.findOne({ + where: { messageId: message.messageId }, }); + + if (existingMessage) { + const updatedMessage = { + ...existingMessage, + ...message, + }; + + await messageRepository.save(updatedMessage); + + return updatedMessage; + } else { + throw new Error(`Message with id ${message.messageId} not found`); + } +}; diff --git a/web-api/src/persistence/elasticsearch/messages/getCompletedSectionInboxMessages.ts b/web-api/src/persistence/elasticsearch/messages/getCompletedSectionInboxMessages.ts index 21c3ea054f4..637d3323f81 100644 --- a/web-api/src/persistence/elasticsearch/messages/getCompletedSectionInboxMessages.ts +++ b/web-api/src/persistence/elasticsearch/messages/getCompletedSectionInboxMessages.ts @@ -1,45 +1,25 @@ -import { GET_PARENT_CASE } from '../helpers/searchClauses'; -import { calculateISODate } from '../../../../../shared/src/business/utilities/DateHandler'; -import { search } from '../searchClient'; +import { AppDataSource } from '@web-api/data-source'; +import { Message } from '@web-api/persistence/repository/Message'; +import { calculateISODate } from '@shared/business/utilities/DateHandler'; export const getCompletedSectionInboxMessages = async ({ applicationContext, section, +}: { + applicationContext: IApplicationContext; + section: string; }) => { const filterDate = calculateISODate({ howMuch: -7 }); - const query = { - body: { - query: { - bool: { - must: [ - { - term: { 'completedBySection.S': section }, - }, - { - term: { 'isCompleted.BOOL': true }, - }, - { - range: { - 'completedAt.S': { - format: 'strict_date_time', // ISO-8601 time stamp - gte: filterDate, - }, - }, - }, - GET_PARENT_CASE, - ], - }, - }, - size: 5000, - }, - index: 'efcms-message', - }; + const messageRepository = AppDataSource.getRepository(Message); - const { results } = await search({ - applicationContext, - searchParameters: query, - }); + const results = await messageRepository + .createQueryBuilder('message') + .where('message.completedBySection = :section', { section }) + .andWhere('message.isCompleted = :isCompleted', { isCompleted: true }) + .andWhere('message.completedAt >= :filterDate', { filterDate }) + .limit(5000) + .getMany(); return results; }; diff --git a/web-api/src/persistence/elasticsearch/messages/getCompletedUserInboxMessages.ts b/web-api/src/persistence/elasticsearch/messages/getCompletedUserInboxMessages.ts index d6a6f115de5..500e1d2217b 100644 --- a/web-api/src/persistence/elasticsearch/messages/getCompletedUserInboxMessages.ts +++ b/web-api/src/persistence/elasticsearch/messages/getCompletedUserInboxMessages.ts @@ -1,45 +1,28 @@ -import { GET_PARENT_CASE } from '../helpers/searchClauses'; -import { calculateISODate } from '../../../../../shared/src/business/utilities/DateHandler'; -import { search } from '../searchClient'; +import { AppDataSource } from '@web-api/data-source'; +import { Message } from '@shared/business/entities/Message'; +import { calculateISODate } from '@shared/business/utilities/DateHandler'; +import { Message as messageRepo } from '@web-api/persistence/repository/Message'; export const getCompletedUserInboxMessages = async ({ applicationContext, userId, +}: { + applicationContext: IApplicationContext; + userId: string; }) => { const filterDate = calculateISODate({ howMuch: -7 }); - const query = { - body: { - query: { - bool: { - must: [ - { - term: { 'completedByUserId.S': userId }, - }, - { - term: { 'isCompleted.BOOL': true }, - }, - { - range: { - 'completedAt.S': { - format: 'strict_date_time', // ISO-8601 time stamp - gte: filterDate, - }, - }, - }, - GET_PARENT_CASE, - ], - }, - }, - size: 5000, - }, - index: 'efcms-message', - }; + const messageRepository = AppDataSource.getRepository(messageRepo); - const { results } = await search({ - applicationContext, - searchParameters: query, - }); + const messages = await messageRepository + .createQueryBuilder('message') + .where('message.completedByUserId = :userId', { userId }) + .andWhere('message.isCompleted = :isCompleted', { isCompleted: true }) + .andWhere('message.completedAt >= :filterDate', { filterDate }) + .limit(5000) + .getMany(); - return results; + return messages.map( + message => new Message({ ...message }, { applicationContext }), + ); }; diff --git a/web-api/src/persistence/elasticsearch/messages/getSectionInboxMessages.ts b/web-api/src/persistence/elasticsearch/messages/getSectionInboxMessages.ts index 35825c0c21f..bc08d56582b 100644 --- a/web-api/src/persistence/elasticsearch/messages/getSectionInboxMessages.ts +++ b/web-api/src/persistence/elasticsearch/messages/getSectionInboxMessages.ts @@ -1,40 +1,29 @@ -import { GET_PARENT_CASE } from '../helpers/searchClauses'; -import { search } from '../searchClient'; +import { AppDataSource } from '@web-api/data-source'; +import { Message } from '@shared/business/entities/Message'; +import { Message as messageRepo } from '@web-api/persistence/repository/Message'; export const getSectionInboxMessages = async ({ applicationContext, section, +}: { + applicationContext: IApplicationContext; + section: string; }) => { applicationContext.logger.info('getSectionInboxMessages start'); - const query = { - body: { - query: { - bool: { - must: [ - { - term: { 'toSection.S': section }, - }, - { - term: { 'isRepliedTo.BOOL': false }, - }, - { - match: { 'isCompleted.BOOL': false }, - }, - GET_PARENT_CASE, - ], - }, - }, - size: 5000, - }, - index: 'efcms-message', - }; - const { results } = await search({ - applicationContext, - searchParameters: query, - }); + const messageRepository = AppDataSource.getRepository(messageRepo); + + const messages = await messageRepository + .createQueryBuilder('message') + .where('message.toSection = :section', { section }) + .andWhere('message.isRepliedTo = :isRepliedTo', { isRepliedTo: false }) + .andWhere('message.isCompleted = :isCompleted', { isCompleted: false }) + .limit(5000) + .getMany(); applicationContext.logger.info('getSectionInboxMessages end'); - return results; + return messages.map( + message => new Message({ ...message }, { applicationContext }), + ); }; diff --git a/web-api/src/persistence/elasticsearch/messages/getSectionOutboxMessages.ts b/web-api/src/persistence/elasticsearch/messages/getSectionOutboxMessages.ts index 01db990ba7d..562c0f1fda0 100644 --- a/web-api/src/persistence/elasticsearch/messages/getSectionOutboxMessages.ts +++ b/web-api/src/persistence/elasticsearch/messages/getSectionOutboxMessages.ts @@ -1,42 +1,24 @@ -import { GET_PARENT_CASE } from '../helpers/searchClauses'; -import { calculateISODate } from '../../../../../shared/src/business/utilities/DateHandler'; -import { search } from '../searchClient'; +import { AppDataSource } from '@web-api/data-source'; +import { Message } from '@web-api/persistence/repository/Message'; +import { calculateISODate } from '@shared/business/utilities/DateHandler'; export const getSectionOutboxMessages = async ({ applicationContext, section, +}: { + applicationContext: IApplicationContext; + section: string; }) => { const filterDate = calculateISODate({ howMuch: -7 }); - const query = { - body: { - query: { - bool: { - must: [ - { - term: { 'fromSection.S': section }, - }, - { - range: { - 'createdAt.S': { - format: 'strict_date_time', // ISO-8601 time stamp - gte: filterDate, - }, - }, - }, - GET_PARENT_CASE, - ], - }, - }, - size: 5000, - }, - index: 'efcms-message', - }; + const messageRepository = AppDataSource.getRepository(Message); - const { results } = await search({ - applicationContext, - searchParameters: query, - }); + const results = await messageRepository + .createQueryBuilder('message') + .where('message.fromSection = :section', { section }) + .andWhere('message.createdAt >= :filterDate', { filterDate }) + .limit(5000) + .getMany(); return results; }; diff --git a/web-api/src/persistence/elasticsearch/messages/getUserInboxMessages.ts b/web-api/src/persistence/elasticsearch/messages/getUserInboxMessages.ts index 52a1e3fc4d9..e9168ea40b1 100644 --- a/web-api/src/persistence/elasticsearch/messages/getUserInboxMessages.ts +++ b/web-api/src/persistence/elasticsearch/messages/getUserInboxMessages.ts @@ -1,38 +1,42 @@ -import { GET_PARENT_CASE } from '../helpers/searchClauses'; -import { search } from '../searchClient'; +import { AppDataSource } from '@web-api/data-source'; +import { Message } from '@shared/business/entities/Message'; +import { Message as messageRepo } from '@web-api/persistence/repository/Message'; -export const getUserInboxMessages = async ({ applicationContext, userId }) => { +export const getUserInboxMessages = async ({ + applicationContext, + userId, +}: { + applicationContext: IApplicationContext; + userId: string; +}) => { applicationContext.logger.info('getUserInboxMessages start'); - const query = { - body: { - query: { - bool: { - must: [ - { - term: { 'toUserId.S': userId }, - }, - { - term: { 'isRepliedTo.BOOL': false }, - }, - { - term: { 'isCompleted.BOOL': false }, - }, - GET_PARENT_CASE, - ], - }, - }, - size: 5000, - }, - index: 'efcms-message', - }; + const messageRepository = AppDataSource.getRepository(messageRepo); - const { results } = await search({ - applicationContext, - searchParameters: query, + const messages = await messageRepository.find({ + take: 5000, + where: { + isCompleted: false, + isRepliedTo: false, + toUserId: userId, + }, }); applicationContext.logger.info('getUserInboxMessages end'); - return results; + console.log('messages', messages); + + return messages.map( + message => + new Message( + { + ...message, + leadDocketNumber: + message.leadDocketNumber === null + ? undefined + : message.leadDocketNumber, + }, + { applicationContext }, + ), + ); }; diff --git a/web-api/src/persistence/elasticsearch/messages/getUserOutboxMessages.ts b/web-api/src/persistence/elasticsearch/messages/getUserOutboxMessages.ts index de210078d90..844ec744f05 100644 --- a/web-api/src/persistence/elasticsearch/messages/getUserOutboxMessages.ts +++ b/web-api/src/persistence/elasticsearch/messages/getUserOutboxMessages.ts @@ -1,39 +1,27 @@ -import { GET_PARENT_CASE } from '../helpers/searchClauses'; -import { calculateISODate } from '../../../../../shared/src/business/utilities/DateHandler'; -import { search } from '../searchClient'; +import { AppDataSource } from '@web-api/data-source'; +import { Message } from '@shared/business/entities/Message'; +import { calculateISODate } from '@shared/business/utilities/DateHandler'; +import { Message as messageRepo } from '@web-api/persistence/repository/Message'; -export const getUserOutboxMessages = async ({ applicationContext, userId }) => { +export const getUserOutboxMessages = async ({ + applicationContext, + userId, +}: { + applicationContext: IApplicationContext; + userId: string; +}) => { const filterDate = calculateISODate({ howMuch: -7 }); - const query = { - body: { - query: { - bool: { - must: [ - { - term: { 'fromUserId.S': userId }, - }, - { - range: { - 'createdAt.S': { - format: 'strict_date_time', // ISO-8601 time stamp - gte: filterDate, - }, - }, - }, - GET_PARENT_CASE, - ], - }, - }, - size: 5000, - }, - index: 'efcms-message', - }; + const messageRepository = AppDataSource.getRepository(messageRepo); - const { results } = await search({ - applicationContext, - searchParameters: query, - }); + const messages = await messageRepository + .createQueryBuilder('message') + .where('message.fromUserId = :userId', { userId }) + .andWhere('message.createdAt >= :filterDate', { filterDate }) + .limit(5000) + .getMany(); - return results; + return messages.map( + message => new Message({ ...message }, { applicationContext }), + ); }; diff --git a/web-api/src/persistence/repository/Message.ts b/web-api/src/persistence/repository/Message.ts index a872011dd42..71c3623541e 100644 --- a/web-api/src/persistence/repository/Message.ts +++ b/web-api/src/persistence/repository/Message.ts @@ -1,4 +1,4 @@ -import { Column, Entity, PrimaryColumn, PrimaryGeneratedColumn } from 'typeorm'; +import { Column, Entity, PrimaryColumn } from 'typeorm'; @Entity() export class Message { @@ -8,10 +8,10 @@ export class Message { }[]; @Column() - caseStatus: string; + caseStatus!: string; @Column() - caseTitle: string; + caseTitle!: string; @Column({ nullable: true }) completedAt?: string; @@ -29,53 +29,53 @@ export class Message { completedMessage?: string; @Column() - createdAt: string; + createdAt!: string; @Column() - docketNumber: string; + docketNumber!: string; @Column() - docketNumberWithSuffix: string; + docketNumberWithSuffix!: string; @Column() - from: string; + from!: string; @Column() - fromSection: string; + fromSection!: string; @Column() - fromUserId: string; + fromUserId!: string; @Column() - isCompleted: boolean; + isCompleted!: boolean; @Column() - isRead: boolean; + isRead!: boolean; @Column() - isRepliedTo: boolean; + isRepliedTo!: boolean; @Column({ nullable: true }) leadDocketNumber?: string; @Column() - message: string; + message!: string; @PrimaryColumn() - messageId: string; + messageId!: string; @Column() - parentMessageId: string; + parentMessageId!: string; @Column() - subject: string; + subject!: string; @Column() - to: string; + to!: string; @Column() - toSection: string; + toSection!: string; @Column() - toUserId: string; + toUserId!: string; } From abc60de9839fc4bf2c548e1a314f579af918514d Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Tue, 16 Jul 2024 08:21:58 -0600 Subject: [PATCH 03/30] 10391: move data-source --- web-api/src/data-source.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 web-api/src/data-source.ts diff --git a/web-api/src/data-source.ts b/web-api/src/data-source.ts new file mode 100644 index 00000000000..888cbd7ba46 --- /dev/null +++ b/web-api/src/data-source.ts @@ -0,0 +1,20 @@ +import 'reflect-metadata'; +import { DataSource } from 'typeorm'; +import { Message } from './persistence/repository/Message'; + +export const AppDataSource = new DataSource({ + database: 'postgres', + entities: [Message], + host: 'localhost', + logging: false, + migrations: ['migrations/*.ts'], + password: 'example', + port: 5432, + subscribers: [], + synchronize: true, + type: 'postgres', + username: 'postgres', +}); + +const dataSource = AppDataSource.initialize().then(() => AppDataSource); +export const getDataSource = () => dataSource; From 94b7995d27b5c61afe35844a0cfe6d86bde3a93d Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Tue, 16 Jul 2024 08:22:39 -0600 Subject: [PATCH 04/30] 10391: move data-source --- postgres/data-source.ts | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 postgres/data-source.ts diff --git a/postgres/data-source.ts b/postgres/data-source.ts deleted file mode 100644 index 6aec00431d9..00000000000 --- a/postgres/data-source.ts +++ /dev/null @@ -1,20 +0,0 @@ -import 'reflect-metadata'; -import { DataSource } from 'typeorm'; -import { Message } from '../web-api/src/persistence/repository/Message'; - -export const AppDataSource = new DataSource({ - database: 'postgres', - entities: [Message], - host: 'localhost', - logging: false, - migrations: ['migrations/*.ts'], - password: 'example', - port: 5432, - subscribers: [], - synchronize: true, - type: 'postgres', - username: 'postgres', -}); - -const dataSource = AppDataSource.initialize().then(() => AppDataSource); -export const getDataSource = () => dataSource; From d050765ba0973ec92589b2d353968c18dc356e2b Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Tue, 16 Jul 2024 08:33:56 -0600 Subject: [PATCH 05/30] 10391: move data-source --- package.json | 8 ++++---- postgres/seed/seed.ts | 2 +- web-api/src/data-source.ts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 9ed8d75a7da..4fb796f19c2 100644 --- a/package.json +++ b/package.json @@ -240,10 +240,10 @@ "verify-authorizers": "./scripts/circleci/verify-authorizers.sh", "verify-private-elasticsearch": "./scripts/circleci/verify-private-elasticsearch.sh", "visualize-bundle": "esbuild-visualizer --metadata ./metadata.json && open stats.html", - "typeorm:migrations:migrate": "npx typeorm-ts-node-commonjs migration:run -d postgres/data-source.ts", - "typeorm:migrations:revert": "npx typeorm-ts-node-commonjs migration:revert -d postgres/data-source.ts", - "typeorm:migrations:generate": "npx typeorm-ts-node-commonjs migration:generate ${MIGRATION_NAME} -d postgres/data-source.ts", - "typeorm:seed": "npx ts-node ./postgres/seed.ts" + "typeorm:migrations:migrate": "npx typeorm-ts-node-commonjs migration:run -d web-api/src/data-source.ts", + "typeorm:migrations:revert": "npx typeorm-ts-node-commonjs migration:revert -d web-api/src/data-source.ts", + "typeorm:migrations:generate": "npx typeorm-ts-node-commonjs migration:generate ${MIGRATION_NAME} -d web-api/src/data-source.ts", + "typeorm:seed": "npx ts-node postgres/seed/seed.ts" }, "overrides": { "axios": "$axios", diff --git a/postgres/seed/seed.ts b/postgres/seed/seed.ts index 535ac9aa962..0a98414d7d1 100644 --- a/postgres/seed/seed.ts +++ b/postgres/seed/seed.ts @@ -1,5 +1,5 @@ import { Message } from '../../web-api/src/persistence/repository/Message'; -import { getDataSource } from '../data-source'; +import { getDataSource } from '../../web-api/src/data-source'; async function main() { const appDataSource = await getDataSource(); diff --git a/web-api/src/data-source.ts b/web-api/src/data-source.ts index 888cbd7ba46..85ea6e6a3da 100644 --- a/web-api/src/data-source.ts +++ b/web-api/src/data-source.ts @@ -7,7 +7,7 @@ export const AppDataSource = new DataSource({ entities: [Message], host: 'localhost', logging: false, - migrations: ['migrations/*.ts'], + migrations: ['postgres/migrations/*.ts'], password: 'example', port: 5432, subscribers: [], From 4a5e80a7637b86a7b76615b3655a25f5e619d774 Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Tue, 16 Jul 2024 09:07:41 -0600 Subject: [PATCH 06/30] 10391: Add transformNullToUndefined helpers + wrap additional returns as Message types --- postgres/helpers/transformNullToUndefined.ts | 8 ++++++++ .../messages/getCompletedSectionInboxMessages.ts | 13 +++++++++---- .../messages/getCompletedUserInboxMessages.ts | 4 +++- .../messages/getSectionInboxMessages.ts | 4 +++- .../messages/getSectionOutboxMessages.ts | 13 +++++++++---- .../elasticsearch/messages/getUserInboxMessages.ts | 14 ++------------ .../messages/getUserOutboxMessages.ts | 4 +++- 7 files changed, 37 insertions(+), 23 deletions(-) create mode 100644 postgres/helpers/transformNullToUndefined.ts diff --git a/postgres/helpers/transformNullToUndefined.ts b/postgres/helpers/transformNullToUndefined.ts new file mode 100644 index 00000000000..274135813d4 --- /dev/null +++ b/postgres/helpers/transformNullToUndefined.ts @@ -0,0 +1,8 @@ +export const transformNullToUndefined = data => { + for (const [key, item] of Object.entries(data)) { + if (item === null) { + delete data[key]; + } + } + return data; +}; diff --git a/web-api/src/persistence/elasticsearch/messages/getCompletedSectionInboxMessages.ts b/web-api/src/persistence/elasticsearch/messages/getCompletedSectionInboxMessages.ts index 637d3323f81..4f51e4e875e 100644 --- a/web-api/src/persistence/elasticsearch/messages/getCompletedSectionInboxMessages.ts +++ b/web-api/src/persistence/elasticsearch/messages/getCompletedSectionInboxMessages.ts @@ -1,6 +1,8 @@ import { AppDataSource } from '@web-api/data-source'; -import { Message } from '@web-api/persistence/repository/Message'; +import { Message } from '@shared/business/entities/Message'; import { calculateISODate } from '@shared/business/utilities/DateHandler'; +import { Message as messageRepo } from '@web-api/persistence/repository/Message'; +import { transformNullToUndefined } from 'postgres/helpers/transformNullToUndefined'; export const getCompletedSectionInboxMessages = async ({ applicationContext, @@ -11,9 +13,9 @@ export const getCompletedSectionInboxMessages = async ({ }) => { const filterDate = calculateISODate({ howMuch: -7 }); - const messageRepository = AppDataSource.getRepository(Message); + const messageRepository = AppDataSource.getRepository(messageRepo); - const results = await messageRepository + const messages = await messageRepository .createQueryBuilder('message') .where('message.completedBySection = :section', { section }) .andWhere('message.isCompleted = :isCompleted', { isCompleted: true }) @@ -21,5 +23,8 @@ export const getCompletedSectionInboxMessages = async ({ .limit(5000) .getMany(); - return results; + return messages.map( + message => + new Message(transformNullToUndefined(message), { applicationContext }), + ); }; diff --git a/web-api/src/persistence/elasticsearch/messages/getCompletedUserInboxMessages.ts b/web-api/src/persistence/elasticsearch/messages/getCompletedUserInboxMessages.ts index 500e1d2217b..7ca50a13459 100644 --- a/web-api/src/persistence/elasticsearch/messages/getCompletedUserInboxMessages.ts +++ b/web-api/src/persistence/elasticsearch/messages/getCompletedUserInboxMessages.ts @@ -2,6 +2,7 @@ import { AppDataSource } from '@web-api/data-source'; import { Message } from '@shared/business/entities/Message'; import { calculateISODate } from '@shared/business/utilities/DateHandler'; import { Message as messageRepo } from '@web-api/persistence/repository/Message'; +import { transformNullToUndefined } from 'postgres/helpers/transformNullToUndefined'; export const getCompletedUserInboxMessages = async ({ applicationContext, @@ -23,6 +24,7 @@ export const getCompletedUserInboxMessages = async ({ .getMany(); return messages.map( - message => new Message({ ...message }, { applicationContext }), + message => + new Message(transformNullToUndefined(message), { applicationContext }), ); }; diff --git a/web-api/src/persistence/elasticsearch/messages/getSectionInboxMessages.ts b/web-api/src/persistence/elasticsearch/messages/getSectionInboxMessages.ts index bc08d56582b..2f039b886a8 100644 --- a/web-api/src/persistence/elasticsearch/messages/getSectionInboxMessages.ts +++ b/web-api/src/persistence/elasticsearch/messages/getSectionInboxMessages.ts @@ -1,6 +1,7 @@ import { AppDataSource } from '@web-api/data-source'; import { Message } from '@shared/business/entities/Message'; import { Message as messageRepo } from '@web-api/persistence/repository/Message'; +import { transformNullToUndefined } from 'postgres/helpers/transformNullToUndefined'; export const getSectionInboxMessages = async ({ applicationContext, @@ -24,6 +25,7 @@ export const getSectionInboxMessages = async ({ applicationContext.logger.info('getSectionInboxMessages end'); return messages.map( - message => new Message({ ...message }, { applicationContext }), + message => + new Message(transformNullToUndefined(message), { applicationContext }), ); }; diff --git a/web-api/src/persistence/elasticsearch/messages/getSectionOutboxMessages.ts b/web-api/src/persistence/elasticsearch/messages/getSectionOutboxMessages.ts index 562c0f1fda0..b491a11018c 100644 --- a/web-api/src/persistence/elasticsearch/messages/getSectionOutboxMessages.ts +++ b/web-api/src/persistence/elasticsearch/messages/getSectionOutboxMessages.ts @@ -1,6 +1,8 @@ import { AppDataSource } from '@web-api/data-source'; -import { Message } from '@web-api/persistence/repository/Message'; +import { Message } from '@shared/business/entities/Message'; import { calculateISODate } from '@shared/business/utilities/DateHandler'; +import { Message as messageRepo } from '@web-api/persistence/repository/Message'; +import { transformNullToUndefined } from 'postgres/helpers/transformNullToUndefined'; export const getSectionOutboxMessages = async ({ applicationContext, @@ -11,14 +13,17 @@ export const getSectionOutboxMessages = async ({ }) => { const filterDate = calculateISODate({ howMuch: -7 }); - const messageRepository = AppDataSource.getRepository(Message); + const messageRepository = AppDataSource.getRepository(messageRepo); - const results = await messageRepository + const messages = await messageRepository .createQueryBuilder('message') .where('message.fromSection = :section', { section }) .andWhere('message.createdAt >= :filterDate', { filterDate }) .limit(5000) .getMany(); - return results; + return messages.map( + message => + new Message(transformNullToUndefined(message), { applicationContext }), + ); }; diff --git a/web-api/src/persistence/elasticsearch/messages/getUserInboxMessages.ts b/web-api/src/persistence/elasticsearch/messages/getUserInboxMessages.ts index e9168ea40b1..d4b4660d855 100644 --- a/web-api/src/persistence/elasticsearch/messages/getUserInboxMessages.ts +++ b/web-api/src/persistence/elasticsearch/messages/getUserInboxMessages.ts @@ -1,6 +1,7 @@ import { AppDataSource } from '@web-api/data-source'; import { Message } from '@shared/business/entities/Message'; import { Message as messageRepo } from '@web-api/persistence/repository/Message'; +import { transformNullToUndefined } from 'postgres/helpers/transformNullToUndefined'; export const getUserInboxMessages = async ({ applicationContext, @@ -24,19 +25,8 @@ export const getUserInboxMessages = async ({ applicationContext.logger.info('getUserInboxMessages end'); - console.log('messages', messages); - return messages.map( message => - new Message( - { - ...message, - leadDocketNumber: - message.leadDocketNumber === null - ? undefined - : message.leadDocketNumber, - }, - { applicationContext }, - ), + new Message(transformNullToUndefined(message), { applicationContext }), ); }; diff --git a/web-api/src/persistence/elasticsearch/messages/getUserOutboxMessages.ts b/web-api/src/persistence/elasticsearch/messages/getUserOutboxMessages.ts index 844ec744f05..133af419605 100644 --- a/web-api/src/persistence/elasticsearch/messages/getUserOutboxMessages.ts +++ b/web-api/src/persistence/elasticsearch/messages/getUserOutboxMessages.ts @@ -2,6 +2,7 @@ import { AppDataSource } from '@web-api/data-source'; import { Message } from '@shared/business/entities/Message'; import { calculateISODate } from '@shared/business/utilities/DateHandler'; import { Message as messageRepo } from '@web-api/persistence/repository/Message'; +import { transformNullToUndefined } from 'postgres/helpers/transformNullToUndefined'; export const getUserOutboxMessages = async ({ applicationContext, @@ -22,6 +23,7 @@ export const getUserOutboxMessages = async ({ .getMany(); return messages.map( - message => new Message({ ...message }, { applicationContext }), + message => + new Message(transformNullToUndefined(message), { applicationContext }), ); }; From 6dfcd6f35a72ccd64a9539610be1645cb14d358b Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Tue, 16 Jul 2024 10:05:30 -0600 Subject: [PATCH 07/30] 10391: remove tests + fix mappings --- postgres/__tmp_notes.md | 4 ++ .../messages/getMessageThreadByParentId.ts | 11 ++--- .../messages/getMessagesByDocketNumber.ts | 13 ++++-- .../getCompletedSectionInboxMessages.test.ts | 19 --------- .../getCompletedUserInboxMessages.test.ts | 18 --------- .../messages/getSectionInboxMessages.test.ts | 40 ------------------- .../messages/getSectionOutboxMessages.test.ts | 19 --------- .../messages/getUserInboxMessages.test.ts | 39 ------------------ .../messages/getUserOutboxMessages.test.ts | 18 --------- 9 files changed, 19 insertions(+), 162 deletions(-) delete mode 100644 web-api/src/persistence/elasticsearch/messages/getCompletedSectionInboxMessages.test.ts delete mode 100644 web-api/src/persistence/elasticsearch/messages/getCompletedUserInboxMessages.test.ts delete mode 100644 web-api/src/persistence/elasticsearch/messages/getSectionInboxMessages.test.ts delete mode 100644 web-api/src/persistence/elasticsearch/messages/getSectionOutboxMessages.test.ts delete mode 100644 web-api/src/persistence/elasticsearch/messages/getUserInboxMessages.test.ts delete mode 100644 web-api/src/persistence/elasticsearch/messages/getUserOutboxMessages.test.ts diff --git a/postgres/__tmp_notes.md b/postgres/__tmp_notes.md index 43582789cd3..fa68558f525 100644 --- a/postgres/__tmp_notes.md +++ b/postgres/__tmp_notes.md @@ -16,6 +16,9 @@ - How to handle null, as we were expecting undefined before, ex: message.leadDocketNumber: null will fail validation unless we override it? - Custom repository method? - Custom mapping utility function for each OR transformToNull wrapper function, etc, etc? +- Unit Tests + - Ignore DB Folders +- CI/CD # Stuff to consider @@ -24,6 +27,7 @@ # Things to do - Figure out overall organization of implementation +- How to define Indexes? - ... ??? diff --git a/web-api/src/persistence/dynamo/messages/getMessageThreadByParentId.ts b/web-api/src/persistence/dynamo/messages/getMessageThreadByParentId.ts index 6db462349ee..f71766ffbe3 100644 --- a/web-api/src/persistence/dynamo/messages/getMessageThreadByParentId.ts +++ b/web-api/src/persistence/dynamo/messages/getMessageThreadByParentId.ts @@ -1,6 +1,7 @@ import { AppDataSource } from '@web-api/data-source'; -import { Message } from '@web-api/persistence/repository/Message'; -import { Message as MessageEntity } from '@shared/business/entities/Message'; +import { Message } from '@shared/business/entities/Message'; +import { Message as messageRepo } from '@web-api/persistence/repository/Message'; +import { transformNullToUndefined } from 'postgres/helpers/transformNullToUndefined'; /** * getMessageThreadByParentId @@ -17,7 +18,7 @@ export const getMessageThreadByParentId = async ({ applicationContext: IApplicationContext; parentMessageId: string; }) => { - const messageRepository = AppDataSource.getRepository(Message); + const messageRepository = AppDataSource.getRepository(messageRepo); const messages = await messageRepository.find({ where: { @@ -27,8 +28,8 @@ export const getMessageThreadByParentId = async ({ return messages.map( result => - new MessageEntity( - { ...result, createdAt: result.createdAt?.toISOString() }, + new Message( + transformNullToUndefined({ ...result, createdAt: result.createdAt }), { applicationContext }, ), ); diff --git a/web-api/src/persistence/dynamo/messages/getMessagesByDocketNumber.ts b/web-api/src/persistence/dynamo/messages/getMessagesByDocketNumber.ts index c1ef357f99d..59930430f3b 100644 --- a/web-api/src/persistence/dynamo/messages/getMessagesByDocketNumber.ts +++ b/web-api/src/persistence/dynamo/messages/getMessagesByDocketNumber.ts @@ -1,5 +1,7 @@ import { AppDataSource } from '@web-api/data-source'; -import { Message } from '@web-api/persistence/repository/Message'; +import { Message } from '@shared/business/entities/Message'; +import { Message as messageRepo } from '@web-api/persistence/repository/Message'; +import { transformNullToUndefined } from 'postgres/helpers/transformNullToUndefined'; /** * getMessagesByDocketNumber @@ -16,12 +18,15 @@ export const getMessagesByDocketNumber = async ({ applicationContext: IApplicationContext; docketNumber: string; }) => { - const messageRepository = AppDataSource.getRepository(Message); + const messageRepository = AppDataSource.getRepository(messageRepo); - const results = await messageRepository + const messages = await messageRepository .createQueryBuilder('message') .where('message.docketNumber = :docketNumber', { docketNumber }) .getMany(); - return results; + return messages.map( + message => + new Message(transformNullToUndefined(message), { applicationContext }), + ); }; diff --git a/web-api/src/persistence/elasticsearch/messages/getCompletedSectionInboxMessages.test.ts b/web-api/src/persistence/elasticsearch/messages/getCompletedSectionInboxMessages.test.ts deleted file mode 100644 index 906465e1664..00000000000 --- a/web-api/src/persistence/elasticsearch/messages/getCompletedSectionInboxMessages.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { applicationContext } from '../../../../../shared/src/business/test/createTestApplicationContext'; -import { getCompletedSectionInboxMessages } from './getCompletedSectionInboxMessages'; -jest.mock('../searchClient'); -import { PETITIONS_SECTION } from '../../../../../shared/src/business/entities/EntityConstants'; -import { search } from '../searchClient'; - -describe('getCompletedSectionInboxMessages', () => { - it('should return results from the search client', async () => { - search.mockReturnValue({ results: ['some', 'matches'], total: 0 }); - - const results = await getCompletedSectionInboxMessages({ - applicationContext, - section: PETITIONS_SECTION, - }); - - expect(search).toHaveBeenCalledTimes(1); - expect(results).toMatchObject(['some', 'matches']); - }); -}); diff --git a/web-api/src/persistence/elasticsearch/messages/getCompletedUserInboxMessages.test.ts b/web-api/src/persistence/elasticsearch/messages/getCompletedUserInboxMessages.test.ts deleted file mode 100644 index 24b4d0e62a0..00000000000 --- a/web-api/src/persistence/elasticsearch/messages/getCompletedUserInboxMessages.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { applicationContext } from '../../../../../shared/src/business/test/createTestApplicationContext'; -import { getCompletedUserInboxMessages } from './getCompletedUserInboxMessages'; -jest.mock('../searchClient'); -import { search } from '../searchClient'; - -describe('getCompletedUserInboxMessages', () => { - it('should return results from the search client', async () => { - search.mockReturnValue({ results: ['some', 'matches'], total: 0 }); - - const results = await getCompletedUserInboxMessages({ - applicationContext, - userId: 'f5d68c53-af31-484d-803b-da22c4d03357', - }); - - expect(search).toHaveBeenCalledTimes(1); - expect(results).toMatchObject(['some', 'matches']); - }); -}); diff --git a/web-api/src/persistence/elasticsearch/messages/getSectionInboxMessages.test.ts b/web-api/src/persistence/elasticsearch/messages/getSectionInboxMessages.test.ts deleted file mode 100644 index c849f23006d..00000000000 --- a/web-api/src/persistence/elasticsearch/messages/getSectionInboxMessages.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { applicationContext } from '../../../../../shared/src/business/test/createTestApplicationContext'; -import { getSectionInboxMessages } from './getSectionInboxMessages'; -jest.mock('../searchClient'); -import { PETITIONS_SECTION } from '../../../../../shared/src/business/entities/EntityConstants'; -import { search } from '../searchClient'; - -describe('getSectionInboxMessages', () => { - it('should return results from the search client', async () => { - search.mockReturnValue({ results: ['some', 'matches'], total: 0 }); - - const results = await getSectionInboxMessages({ - applicationContext, - section: PETITIONS_SECTION, - }); - - expect(search).toHaveBeenCalledTimes(1); - expect(results).toMatchObject(['some', 'matches']); - }); - - it('should filter out completed messages', async () => { - search.mockReturnValue({ results: ['some', 'matches'], total: 0 }); - - await getSectionInboxMessages({ - applicationContext, - section: PETITIONS_SECTION, - }); - - expect( - search.mock.calls[0][0].searchParameters.body.query.bool.must, - ).toEqual( - expect.arrayContaining([ - { - match: { - 'isCompleted.BOOL': false, - }, - }, - ]), - ); - }); -}); diff --git a/web-api/src/persistence/elasticsearch/messages/getSectionOutboxMessages.test.ts b/web-api/src/persistence/elasticsearch/messages/getSectionOutboxMessages.test.ts deleted file mode 100644 index 4ef3c720fdc..00000000000 --- a/web-api/src/persistence/elasticsearch/messages/getSectionOutboxMessages.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { applicationContext } from '../../../../../shared/src/business/test/createTestApplicationContext'; -import { getSectionOutboxMessages } from './getSectionOutboxMessages'; -jest.mock('../searchClient'); -import { PETITIONS_SECTION } from '../../../../../shared/src/business/entities/EntityConstants'; -import { search } from '../searchClient'; - -describe('getSectionOutboxMessages', () => { - it('should return results from the search client', async () => { - search.mockReturnValue({ results: ['some', 'matches'], total: 0 }); - - const results = await getSectionOutboxMessages({ - applicationContext, - section: PETITIONS_SECTION, - }); - - expect(search).toHaveBeenCalledTimes(1); - expect(results).toMatchObject(['some', 'matches']); - }); -}); diff --git a/web-api/src/persistence/elasticsearch/messages/getUserInboxMessages.test.ts b/web-api/src/persistence/elasticsearch/messages/getUserInboxMessages.test.ts deleted file mode 100644 index ffd186e2334..00000000000 --- a/web-api/src/persistence/elasticsearch/messages/getUserInboxMessages.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { applicationContext } from '../../../../../shared/src/business/test/createTestApplicationContext'; -import { getUserInboxMessages } from './getUserInboxMessages'; -jest.mock('../searchClient'); -import { search } from '../searchClient'; - -describe('getUserInboxMessages', () => { - it('should return results from the search client', async () => { - search.mockReturnValue({ results: ['some', 'matches'], total: 0 }); - - const results = await getUserInboxMessages({ - applicationContext, - userId: 'f5d68c53-af31-484d-803b-da22c4d03357', - }); - - expect(search).toHaveBeenCalledTimes(1); - expect(results).toMatchObject(['some', 'matches']); - }); - - it('should filter out completed messages', async () => { - search.mockReturnValue({ results: ['some', 'matches'], total: 0 }); - - await getUserInboxMessages({ - applicationContext, - userId: 'f5d68c53-af31-484d-803b-da22c4d03357', - }); - - expect( - search.mock.calls[0][0].searchParameters.body.query.bool.must, - ).toEqual( - expect.arrayContaining([ - { - term: { - 'isCompleted.BOOL': false, - }, - }, - ]), - ); - }); -}); diff --git a/web-api/src/persistence/elasticsearch/messages/getUserOutboxMessages.test.ts b/web-api/src/persistence/elasticsearch/messages/getUserOutboxMessages.test.ts deleted file mode 100644 index 4343fd4cc34..00000000000 --- a/web-api/src/persistence/elasticsearch/messages/getUserOutboxMessages.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { applicationContext } from '../../../../../shared/src/business/test/createTestApplicationContext'; -import { getUserOutboxMessages } from './getUserOutboxMessages'; -jest.mock('../searchClient'); -import { search } from '../searchClient'; - -describe('getUserOutboxMessages', () => { - it('should return results from the search client', async () => { - search.mockReturnValue({ results: ['some', 'matches'], total: 0 }); - - const results = await getUserOutboxMessages({ - applicationContext, - userId: '318de3b3-1625-4638-98a3-c67ab1b17be7', - }); - - expect(search).toHaveBeenCalledTimes(1); - expect(results).toMatchObject(['some', 'matches']); - }); -}); From 8d40cd69e687781afa4e6c0023e2575801344d03 Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Tue, 16 Jul 2024 10:13:20 -0600 Subject: [PATCH 08/30] 10391: Add postgres to cypress --- .github/workflows/e2e-cypress.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/workflows/e2e-cypress.yml b/.github/workflows/e2e-cypress.yml index f23ccd75870..ba13f8175ae 100644 --- a/.github/workflows/e2e-cypress.yml +++ b/.github/workflows/e2e-cypress.yml @@ -16,6 +16,18 @@ jobs: CI: true CI_NODE_TOTAL: ${{ matrix.ci_node_total }} CI_NODE_INDEX: ${{ matrix.ci_node_index }} + services: + postgres: + image: postgres + env: + POSTGRES_PASSWORD: example + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -30,6 +42,9 @@ jobs: with: port: 8000 cors: '*' + - name: Seed Postgres + run: | + npm run typeorm:seed - name: Collect Workflow Telemetry uses: runforesight/workflow-telemetry-action@v2 with: From 95fff42a504978db841209bc732170043a91e95b Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Tue, 16 Jul 2024 11:31:08 -0600 Subject: [PATCH 09/30] 10391: wip add case --- .../migrations/1721149262326-AddCaseTable.ts | 27 +++++++ postgres/seed/seed.ts | 22 ++++++ shared/src/business/entities/Message.ts | 4 ++ .../caseStatusWithTrialInformation.ts | 9 ++- .../getInboxMessagesForUserInteractor.ts | 8 ++- web-api/src/data-source.ts | 3 +- .../dynamo/messages/createMessage.test.ts | 41 ----------- .../dynamo/messages/getMessageById.test.ts | 35 --------- .../getMessageThreadByParentId.test.ts | 35 --------- .../getMessagesByDocketNumber.test.ts | 35 --------- .../markMessageThreadRepliedTo.test.ts | 71 ------------------- .../dynamo/messages/setMessageAsRead.test.ts | 25 ------- .../dynamo/messages/updateMessage.test.ts | 45 ------------ .../messages/getUserInboxMessages.ts | 18 +++-- web-api/src/persistence/repository/Case.ts | 17 +++++ web-api/src/persistence/repository/Message.ts | 6 +- 16 files changed, 102 insertions(+), 299 deletions(-) create mode 100644 postgres/migrations/1721149262326-AddCaseTable.ts delete mode 100644 web-api/src/persistence/dynamo/messages/createMessage.test.ts delete mode 100644 web-api/src/persistence/dynamo/messages/getMessageById.test.ts delete mode 100644 web-api/src/persistence/dynamo/messages/getMessageThreadByParentId.test.ts delete mode 100644 web-api/src/persistence/dynamo/messages/getMessagesByDocketNumber.test.ts delete mode 100644 web-api/src/persistence/dynamo/messages/markMessageThreadRepliedTo.test.ts delete mode 100644 web-api/src/persistence/dynamo/messages/setMessageAsRead.test.ts delete mode 100644 web-api/src/persistence/dynamo/messages/updateMessage.test.ts create mode 100644 web-api/src/persistence/repository/Case.ts diff --git a/postgres/migrations/1721149262326-AddCaseTable.ts b/postgres/migrations/1721149262326-AddCaseTable.ts new file mode 100644 index 00000000000..8064639503a --- /dev/null +++ b/postgres/migrations/1721149262326-AddCaseTable.ts @@ -0,0 +1,27 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class AddCaseTable1721149262326 implements MigrationInterface { + name = 'AddCaseTable1721149262326'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'CREATE TABLE "case" ("docketNumber" character varying NOT NULL, "trialLocation" character varying, "trialDate" character varying, CONSTRAINT "PK_22bea6459f33e75269daee9bb49" PRIMARY KEY ("docketNumber"))', + ); + await queryRunner.query( + 'ALTER TABLE "message" ADD "caseDocketNumber" character varying', + ); + await queryRunner.query( + 'ALTER TABLE "message" ADD CONSTRAINT "FK_2dad987847361722fd55a8c19fa" FOREIGN KEY ("caseDocketNumber") REFERENCES "case"("docketNumber") ON DELETE NO ACTION ON UPDATE NO ACTION', + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "message" DROP CONSTRAINT "FK_2dad987847361722fd55a8c19fa"', + ); + await queryRunner.query( + 'ALTER TABLE "message" DROP COLUMN "caseDocketNumber"', + ); + await queryRunner.query('DROP TABLE "case"'); + } +} diff --git a/postgres/seed/seed.ts b/postgres/seed/seed.ts index 0a98414d7d1..61a3011bfa3 100644 --- a/postgres/seed/seed.ts +++ b/postgres/seed/seed.ts @@ -1,3 +1,4 @@ +import { Case } from '@web-api/persistence/repository/Case'; import { Message } from '../../web-api/src/persistence/repository/Message'; import { getDataSource } from '../../web-api/src/data-source'; @@ -78,6 +79,27 @@ async function main() { }, ]; await messageRepository.save(messages); + + const caseRepository = appDataSource.getRepository(Case); + const cases = [ + { + docketNumber: '105-20', + trialDate: new Date('2021-03-18T18:07:36.333Z').toISOString(), + trialLocation: 'Detroit, Michigan', + }, + { + docketNumber: '103-20', + trialDate: new Date('2023-04-18T18:07:36.333Z').toISOString(), + trialLocation: 'Denver, Colorado', + }, + { + docketNumber: '104-19', + trialDate: new Date('2022-05-18T18:07:36.333Z').toISOString(), + trialLocation: 'Chicago, Illinois', + }, + ]; + + await caseRepository.save(cases); } main().catch(console.error); diff --git a/shared/src/business/entities/Message.ts b/shared/src/business/entities/Message.ts index bcf723f5fbc..61f4ede9ac2 100644 --- a/shared/src/business/entities/Message.ts +++ b/shared/src/business/entities/Message.ts @@ -32,6 +32,8 @@ export class Message extends JoiValidationEntity { public to: string; public toSection: string; public toUserId: string; + public trialLocation?: string; + public trialDate?: string; constructor(rawMessage, { applicationContext }) { super('Message'); @@ -67,6 +69,8 @@ export class Message extends JoiValidationEntity { this.to = rawMessage.to; this.toSection = rawMessage.toSection; this.toUserId = rawMessage.toUserId; + this.trialDate = rawMessage.trialDate; + this.trialLocation = rawMessage.trialLocation; } static VALIDATION_RULES = { diff --git a/shared/src/business/utilities/caseStatusWithTrialInformation.ts b/shared/src/business/utilities/caseStatusWithTrialInformation.ts index c4046ce727e..c19d8c2db16 100644 --- a/shared/src/business/utilities/caseStatusWithTrialInformation.ts +++ b/shared/src/business/utilities/caseStatusWithTrialInformation.ts @@ -18,9 +18,12 @@ export function caseStatusWithTrialInformation({ return caseStatus; } - const formattedTrialDate = applicationContext - .getUtilities() - .formatDateString(trialDate, 'MM/dd/yy'); + const formattedTrialDate = trialDate + ? applicationContext.getUtilities().formatDateString(trialDate, 'MM/dd/yy') + : 'NA'; + + console.log('trialDate', trialDate); + console.log('trialLocation', trialLocation); const formattedTrialLocation = trialLocation === TRIAL_SESSION_SCOPE_TYPES.standaloneRemote diff --git a/web-api/src/business/useCases/messages/getInboxMessagesForUserInteractor.ts b/web-api/src/business/useCases/messages/getInboxMessagesForUserInteractor.ts index 4d68bcd0f3c..3101302daf3 100644 --- a/web-api/src/business/useCases/messages/getInboxMessagesForUserInteractor.ts +++ b/web-api/src/business/useCases/messages/getInboxMessagesForUserInteractor.ts @@ -31,7 +31,9 @@ export const getInboxMessagesForUserInteractor = async ( userId, }); - return MessageResult.validateRawCollection(messages, { - applicationContext, - }); + // return MessageResult.validateRawCollection(messages, { + // applicationContext, + // }); + + return messages; }; diff --git a/web-api/src/data-source.ts b/web-api/src/data-source.ts index 85ea6e6a3da..62e7dd50905 100644 --- a/web-api/src/data-source.ts +++ b/web-api/src/data-source.ts @@ -1,10 +1,11 @@ import 'reflect-metadata'; +import { Case } from '@web-api/persistence/repository/Case'; import { DataSource } from 'typeorm'; import { Message } from './persistence/repository/Message'; export const AppDataSource = new DataSource({ database: 'postgres', - entities: [Message], + entities: [Message, Case], host: 'localhost', logging: false, migrations: ['postgres/migrations/*.ts'], diff --git a/web-api/src/persistence/dynamo/messages/createMessage.test.ts b/web-api/src/persistence/dynamo/messages/createMessage.test.ts deleted file mode 100644 index 2e39ca05fc9..00000000000 --- a/web-api/src/persistence/dynamo/messages/createMessage.test.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { PETITIONS_SECTION } from '../../../../../shared/src/business/entities/EntityConstants'; -import { RawMessage } from '@shared/business/entities/Message'; -import { applicationContext } from '../../../../../shared/src/business/test/createTestApplicationContext'; -import { createMessage } from './createMessage'; -import { put } from '../../dynamodbClientService'; - -jest.mock('../../dynamodbClientService', () => ({ - put: jest.fn(), -})); - -const mockMessage = { - createdAt: '2019-03-01T21:40:46.415Z', - docketNumber: '123-20', - from: 'Test Petitionsclerk', - fromSection: PETITIONS_SECTION, - fromUserId: '4791e892-14ee-4ab1-8468-0c942ec379d2', - message: 'hey there', - messageId: 'a10d6855-f3ee-4c11-861c-c7f11cba4dff', - parentMessageId: '31687a1e-3640-42cd-8e7e-a8e6df39ce9a', - subject: 'hello', - to: 'Test Petitionsclerk2', - toSection: PETITIONS_SECTION, - toUserId: '449b916e-3362-4a5d-bf56-b2b94ba29c12', -} as RawMessage; - -describe('createMessage', () => { - it('attempts to persist the message record', async () => { - await createMessage({ - applicationContext, - message: mockMessage, - }); - - expect((put as jest.Mock).mock.calls.length).toEqual(1); - expect((put as jest.Mock).mock.calls[0][0].Item).toMatchObject({ - gsi1pk: `message|${mockMessage.parentMessageId}`, - pk: 'case|123-20', - sk: `message|${mockMessage.messageId}`, - ...mockMessage, - }); - }); -}); diff --git a/web-api/src/persistence/dynamo/messages/getMessageById.test.ts b/web-api/src/persistence/dynamo/messages/getMessageById.test.ts deleted file mode 100644 index e184d66d3a8..00000000000 --- a/web-api/src/persistence/dynamo/messages/getMessageById.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { applicationContext } from '../../../../../shared/src/business/test/createTestApplicationContext'; -import { get } from '../../dynamodbClientService'; -import { getMessageById } from './getMessageById'; - -const mockDocketNumber = '101-20'; -const mockMessageId = '445e9644-1f8f-4778-9582-6eafc15f1de4'; - -jest.mock('../../dynamodbClientService', () => ({ - get: jest.fn().mockReturnValue({ - docketNumber: '101-20', - messageId: '445e9644-1f8f-4778-9582-6eafc15f1de4', - }), -})); - -describe('getMessageById', () => { - it('should return the message retrieved from persistence using docket number and message id', async () => { - const returnedMessage = await getMessageById({ - applicationContext, - docketNumber: mockDocketNumber, - messageId: mockMessageId, - }); - - expect((get as jest.Mock).mock.calls[0][0]).toMatchObject({ - Key: { - pk: `case|${mockDocketNumber}`, - sk: `message|${mockMessageId}`, - }, - }); - - expect(returnedMessage).toEqual({ - docketNumber: '101-20', - messageId: '445e9644-1f8f-4778-9582-6eafc15f1de4', - }); - }); -}); diff --git a/web-api/src/persistence/dynamo/messages/getMessageThreadByParentId.test.ts b/web-api/src/persistence/dynamo/messages/getMessageThreadByParentId.test.ts deleted file mode 100644 index 3bcaf7a7bdb..00000000000 --- a/web-api/src/persistence/dynamo/messages/getMessageThreadByParentId.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { PETITIONS_SECTION } from '../../../../../shared/src/business/entities/EntityConstants'; -import { applicationContext } from '../../../../../shared/src/business/test/createTestApplicationContext'; -import { getMessageThreadByParentId } from './getMessageThreadByParentId'; - -const mockMessage = { - createdAt: '2019-03-01T21:40:46.415Z', - docketNumber: '101-20', - from: 'Test Petitionsclerk', - fromSection: PETITIONS_SECTION, - fromUserId: '4791e892-14ee-4ab1-8468-0c942ec379d2', - message: 'hey there', - messageId: 'a10d6855-f3ee-4c11-861c-c7f11cba4dff', - subject: 'hello', - to: 'Test Petitionsclerk2', - toSection: PETITIONS_SECTION, - toUserId: '449b916e-3362-4a5d-bf56-b2b94ba29c12', -}; - -describe('getMessageThreadByParentId', () => { - beforeAll(() => { - applicationContext.environment.stage = 'dev'; - applicationContext - .getDocumentClient() - .query.mockResolvedValue({ Items: [mockMessage] }); - }); - - it('retrieves the message from persistence', async () => { - const retrievedMessage = await getMessageThreadByParentId({ - applicationContext, - parentMessageId: mockMessage.messageId, - }); - - expect(retrievedMessage).toEqual([mockMessage]); - }); -}); diff --git a/web-api/src/persistence/dynamo/messages/getMessagesByDocketNumber.test.ts b/web-api/src/persistence/dynamo/messages/getMessagesByDocketNumber.test.ts deleted file mode 100644 index 7f1e1e19020..00000000000 --- a/web-api/src/persistence/dynamo/messages/getMessagesByDocketNumber.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { PETITIONS_SECTION } from '../../../../../shared/src/business/entities/EntityConstants'; -import { applicationContext } from '../../../../../shared/src/business/test/createTestApplicationContext'; -import { getMessagesByDocketNumber } from './getMessagesByDocketNumber'; - -const mockMessage = { - createdAt: '2019-03-01T21:40:46.415Z', - docketNumber: '123-20', - from: 'Test Petitionsclerk', - fromSection: PETITIONS_SECTION, - fromUserId: '4791e892-14ee-4ab1-8468-0c942ec379d2', - message: 'hey there', - messageId: 'a10d6855-f3ee-4c11-861c-c7f11cba4dff', - subject: 'hello', - to: 'Test Petitionsclerk2', - toSection: PETITIONS_SECTION, - toUserId: '449b916e-3362-4a5d-bf56-b2b94ba29c12', -}; - -describe('getMessagesByDocketNumber', () => { - beforeAll(() => { - applicationContext.environment.stage = 'dev'; - applicationContext - .getDocumentClient() - .query.mockResolvedValueOnce({ Items: [mockMessage] }); - }); - - it('retrieves the message from persistence', async () => { - const retrievedMessage = await getMessagesByDocketNumber({ - applicationContext, - docketNumber: mockMessage.docketNumber, - }); - - expect(retrievedMessage).toEqual([mockMessage]); - }); -}); diff --git a/web-api/src/persistence/dynamo/messages/markMessageThreadRepliedTo.test.ts b/web-api/src/persistence/dynamo/messages/markMessageThreadRepliedTo.test.ts deleted file mode 100644 index 2cd64f46d1e..00000000000 --- a/web-api/src/persistence/dynamo/messages/markMessageThreadRepliedTo.test.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { applicationContext } from '../../../../../shared/src/business/test/createTestApplicationContext'; -import { markMessageThreadRepliedTo } from './markMessageThreadRepliedTo'; - -describe('markMessageThreadRepliedTo', () => { - const DOCKET_NUMBER = '123-20'; - - beforeAll(() => { - applicationContext.environment.stage = 'dev'; - applicationContext.getDocumentClient().update.mockResolvedValue(null); - applicationContext.getDocumentClient().query.mockResolvedValueOnce({ - Items: [ - { - docketNumber: DOCKET_NUMBER, - gsi1pk: 'message|28de1ba1-8518-4a7d-8075-4291eea569c7', - messageId: '28de1ba1-8518-4a7d-8075-4291eea569c7', - pk: `case|${DOCKET_NUMBER}`, - sk: 'message|28de1ba1-8518-4a7d-8075-4291eea569c7', - }, - { - docketNumber: DOCKET_NUMBER, - gsi1pk: 'message|28de1ba1-8518-4a7d-8075-4291eea569c7', - messageId: 'badc2bf0-cc82-4fd1-9a61-d1a8937a4f1b', - pk: `case|${DOCKET_NUMBER}`, - sk: 'message|badc2bf0-cc82-4fd1-9a61-d1a8937a4f1b', - }, - ], - }); - }); - - it('attempts to update the message records', async () => { - await markMessageThreadRepliedTo({ - applicationContext, - parentMessageId: '0c0de040-1dfd-4be8-937a-d6aefdfcd71d', - }); - - expect( - applicationContext.getDocumentClient().update.mock.calls.length, - ).toEqual(2); - expect( - applicationContext.getDocumentClient().update.mock.calls[0][0], - ).toMatchObject({ - Key: { - pk: `case|${DOCKET_NUMBER}`, - sk: 'message|28de1ba1-8518-4a7d-8075-4291eea569c7', - }, - }); - expect( - applicationContext.getDocumentClient().update.mock.calls[1][0], - ).toMatchObject({ - Key: { - pk: `case|${DOCKET_NUMBER}`, - sk: 'message|badc2bf0-cc82-4fd1-9a61-d1a8937a4f1b', - }, - }); - }); - - it("doesn't update messages if there are none found", async () => { - applicationContext - .getDocumentClient() - .query.mockResolvedValue({ Items: [] }); - - await markMessageThreadRepliedTo({ - applicationContext, - parentMessageId: '0c0de040-1dfd-4be8-937a-d6aefdfcd71d', - }); - - expect( - applicationContext.getDocumentClient().update.mock.calls.length, - ).toEqual(0); - }); -}); diff --git a/web-api/src/persistence/dynamo/messages/setMessageAsRead.test.ts b/web-api/src/persistence/dynamo/messages/setMessageAsRead.test.ts deleted file mode 100644 index 0af36da4f81..00000000000 --- a/web-api/src/persistence/dynamo/messages/setMessageAsRead.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { applicationContext } from '../../../../../shared/src/business/test/createTestApplicationContext'; -import { setMessageAsRead } from './setMessageAsRead'; - -describe('setMessageAsRead', () => { - beforeAll(() => { - applicationContext.getDocumentClient().update.mockResolvedValue(true); - }); - - it('invokes the persistence for setting a message as read', async () => { - await setMessageAsRead({ - applicationContext, - docketNumber: '123-45', - messageId: '15adf875-8c3c-4e94-91e9-a4c1bff51291', - }); - - expect( - applicationContext.getDocumentClient().update.mock.calls[0][0], - ).toMatchObject({ - Key: { - pk: 'case|123-45', - sk: 'message|15adf875-8c3c-4e94-91e9-a4c1bff51291', - }, - }); - }); -}); diff --git a/web-api/src/persistence/dynamo/messages/updateMessage.test.ts b/web-api/src/persistence/dynamo/messages/updateMessage.test.ts deleted file mode 100644 index 4c8cdbe4472..00000000000 --- a/web-api/src/persistence/dynamo/messages/updateMessage.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { PETITIONS_SECTION } from '../../../../../shared/src/business/entities/EntityConstants'; -import { RawMessage } from '@shared/business/entities/Message'; -import { applicationContext } from '../../../../../shared/src/business/test/createTestApplicationContext'; -import { updateMessage } from './updateMessage'; - -const mockMessage = { - createdAt: '2019-03-01T21:40:46.415Z', - docketNumber: '101-20', - from: 'Test Petitionsclerk', - fromSection: PETITIONS_SECTION, - fromUserId: '4791e892-14ee-4ab1-8468-0c942ec379d2', - message: 'hey there', - messageId: 'a10d6855-f3ee-4c11-861c-c7f11cba4dff', - parentMessageId: '31687a1e-3640-42cd-8e7e-a8e6df39ce9a', - subject: 'hello', - to: 'Test Petitionsclerk2', - toSection: PETITIONS_SECTION, - toUserId: '449b916e-3362-4a5d-bf56-b2b94ba29c12', -} as RawMessage; - -describe('updateMessage', () => { - beforeAll(() => { - applicationContext.environment.stage = 'dev'; - applicationContext.getDocumentClient().put.mockResolvedValue(null); - }); - - it('attempts to persist the message record', async () => { - await updateMessage({ - applicationContext, - message: mockMessage, - }); - - expect( - applicationContext.getDocumentClient().put.mock.calls.length, - ).toEqual(1); - expect( - applicationContext.getDocumentClient().put.mock.calls[0][0].Item, - ).toMatchObject({ - gsi1pk: `message|${mockMessage.parentMessageId}`, - pk: `case|${mockMessage.docketNumber}`, - sk: `message|${mockMessage.messageId}`, - ...mockMessage, - }); - }); -}); diff --git a/web-api/src/persistence/elasticsearch/messages/getUserInboxMessages.ts b/web-api/src/persistence/elasticsearch/messages/getUserInboxMessages.ts index d4b4660d855..12a0668c161 100644 --- a/web-api/src/persistence/elasticsearch/messages/getUserInboxMessages.ts +++ b/web-api/src/persistence/elasticsearch/messages/getUserInboxMessages.ts @@ -1,5 +1,6 @@ import { AppDataSource } from '@web-api/data-source'; -import { Message } from '@shared/business/entities/Message'; +import { Case } from '@web-api/persistence/repository/Case'; +import { MessageResult } from '@shared/business/entities/MessageResult'; import { Message as messageRepo } from '@web-api/persistence/repository/Message'; import { transformNullToUndefined } from 'postgres/helpers/transformNullToUndefined'; @@ -15,6 +16,7 @@ export const getUserInboxMessages = async ({ const messageRepository = AppDataSource.getRepository(messageRepo); const messages = await messageRepository.find({ + relations: { case: true }, take: 5000, where: { isCompleted: false, @@ -25,8 +27,16 @@ export const getUserInboxMessages = async ({ applicationContext.logger.info('getUserInboxMessages end'); - return messages.map( - message => - new Message(transformNullToUndefined(message), { applicationContext }), + return messages.map(message => + new MessageResult( + transformNullToUndefined({ + ...message, + // trialDate: message.case?.trialDate, + // trialLocation: message.case?.trialLocation, + }), + { + applicationContext, + }, + ).validate(), ); }; diff --git a/web-api/src/persistence/repository/Case.ts b/web-api/src/persistence/repository/Case.ts new file mode 100644 index 00000000000..d07dc9a0351 --- /dev/null +++ b/web-api/src/persistence/repository/Case.ts @@ -0,0 +1,17 @@ +import { Column, Entity, OneToMany, PrimaryColumn } from 'typeorm'; +import { Message } from '@web-api/persistence/repository/Message'; + +@Entity() +export class Case { + @PrimaryColumn() + docketNumber!: string; + + @Column({ nullable: true }) + trialLocation?: string; + + @Column({ nullable: true }) + trialDate?: string; + + @OneToMany(() => Message, message => message.docketNumber) + messages?: Message[]; +} diff --git a/web-api/src/persistence/repository/Message.ts b/web-api/src/persistence/repository/Message.ts index 71c3623541e..e81cc6fc05c 100644 --- a/web-api/src/persistence/repository/Message.ts +++ b/web-api/src/persistence/repository/Message.ts @@ -1,4 +1,5 @@ -import { Column, Entity, PrimaryColumn } from 'typeorm'; +import { Case } from '@web-api/persistence/repository/Case'; +import { Column, Entity, ManyToOne, PrimaryColumn } from 'typeorm'; @Entity() export class Message { @@ -78,4 +79,7 @@ export class Message { @Column() toUserId!: string; + + @ManyToOne(() => Case, item => item.docketNumber) + case!: Case; } From 815fa63e0762bd6a8b46a104653c43356e6a5950 Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Tue, 16 Jul 2024 14:12:18 -0600 Subject: [PATCH 10/30] 10391: wip fix cypress integration tests --- .../utilities/caseStatusWithTrialInformation.ts | 14 +++++++------- .../messages/getInboxMessagesForUserInteractor.ts | 5 ----- .../elasticsearch/messages/getUserInboxMessages.ts | 5 ++--- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/shared/src/business/utilities/caseStatusWithTrialInformation.ts b/shared/src/business/utilities/caseStatusWithTrialInformation.ts index c19d8c2db16..d3cd6339d1a 100644 --- a/shared/src/business/utilities/caseStatusWithTrialInformation.ts +++ b/shared/src/business/utilities/caseStatusWithTrialInformation.ts @@ -22,13 +22,13 @@ export function caseStatusWithTrialInformation({ ? applicationContext.getUtilities().formatDateString(trialDate, 'MM/dd/yy') : 'NA'; - console.log('trialDate', trialDate); - console.log('trialLocation', trialLocation); - - const formattedTrialLocation = - trialLocation === TRIAL_SESSION_SCOPE_TYPES.standaloneRemote - ? TRIAL_SESSION_SCOPE_TYPES.standaloneRemote - : applicationContext.getUtilities().abbreviateState(trialLocation); + let formattedTrialLocation = ''; + if (trialLocation) { + formattedTrialLocation = + trialLocation === TRIAL_SESSION_SCOPE_TYPES.standaloneRemote + ? TRIAL_SESSION_SCOPE_TYPES.standaloneRemote + : applicationContext.getUtilities().abbreviateState(trialLocation); + } return `${caseStatus} - ${formattedTrialDate} ${formattedTrialLocation}`; } diff --git a/web-api/src/business/useCases/messages/getInboxMessagesForUserInteractor.ts b/web-api/src/business/useCases/messages/getInboxMessagesForUserInteractor.ts index 3101302daf3..0e6528c9886 100644 --- a/web-api/src/business/useCases/messages/getInboxMessagesForUserInteractor.ts +++ b/web-api/src/business/useCases/messages/getInboxMessagesForUserInteractor.ts @@ -1,4 +1,3 @@ -import { MessageResult } from '../../../../../shared/src/business/entities/MessageResult'; import { ROLE_PERMISSIONS, isAuthorized, @@ -31,9 +30,5 @@ export const getInboxMessagesForUserInteractor = async ( userId, }); - // return MessageResult.validateRawCollection(messages, { - // applicationContext, - // }); - return messages; }; diff --git a/web-api/src/persistence/elasticsearch/messages/getUserInboxMessages.ts b/web-api/src/persistence/elasticsearch/messages/getUserInboxMessages.ts index 12a0668c161..96da98a097c 100644 --- a/web-api/src/persistence/elasticsearch/messages/getUserInboxMessages.ts +++ b/web-api/src/persistence/elasticsearch/messages/getUserInboxMessages.ts @@ -1,5 +1,4 @@ import { AppDataSource } from '@web-api/data-source'; -import { Case } from '@web-api/persistence/repository/Case'; import { MessageResult } from '@shared/business/entities/MessageResult'; import { Message as messageRepo } from '@web-api/persistence/repository/Message'; import { transformNullToUndefined } from 'postgres/helpers/transformNullToUndefined'; @@ -31,8 +30,8 @@ export const getUserInboxMessages = async ({ new MessageResult( transformNullToUndefined({ ...message, - // trialDate: message.case?.trialDate, - // trialLocation: message.case?.trialLocation, + trialDate: message.case?.trialDate, + trialLocation: message.case?.trialLocation, }), { applicationContext, From aac5993bc68385b37f0a7fb4216f9485c14e9042 Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Tue, 16 Jul 2024 14:14:56 -0600 Subject: [PATCH 11/30] 10391: wip try to fix e2e cypress so runs --- .github/workflows/e2e-cypress.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/e2e-cypress.yml b/.github/workflows/e2e-cypress.yml index ba13f8175ae..4f6bffd2939 100644 --- a/.github/workflows/e2e-cypress.yml +++ b/.github/workflows/e2e-cypress.yml @@ -42,15 +42,15 @@ jobs: with: port: 8000 cors: '*' - - name: Seed Postgres - run: | - npm run typeorm:seed - name: Collect Workflow Telemetry uses: runforesight/workflow-telemetry-action@v2 with: comment_on_pr: false - name: Install Node Dependencies run: npm ci + - name: Seed Postgres + run: | + npm run typeorm:seed - name: Run E2E Cypress run: | mkdir -p /tmp/cypress/ From 852352df9547987a7eccf630f6ade84e3a709ae9 Mon Sep 17 00:00:00 2001 From: Cody Seibert Date: Tue, 16 Jul 2024 17:39:50 -0400 Subject: [PATCH 12/30] adding a joincolumn on the messages --- 1721165468631-JoinColumnMessages.ts | 29 +++++++++++++ package-lock.json | 4 +- package.json | 1 + postgres/seed/seed.ts | 42 +++++++++---------- .../messages/createMessage.ts | 0 .../getCompletedSectionInboxMessages.ts | 0 .../messages/getCompletedUserInboxMessages.ts | 0 .../messages/getMessageById.ts | 0 .../messages/getMessageThreadByParentId.ts | 0 .../messages/getMessagesByDocketNumber.ts | 0 .../messages/getSectionInboxMessages.ts | 0 .../messages/getSectionOutboxMessages.ts | 0 .../messages/getUserInboxMessages.ts | 0 .../messages/getUserOutboxMessages.ts | 0 .../messages/markMessageThreadRepliedTo.ts | 0 .../messages/setMessageAsRead.ts | 0 .../messages/updateMessage.ts | 0 web-api/src/persistence/repository/Message.ts | 3 +- 18 files changed, 55 insertions(+), 24 deletions(-) create mode 100644 1721165468631-JoinColumnMessages.ts rename web-api/src/persistence/{dynamo => postgres}/messages/createMessage.ts (100%) rename web-api/src/persistence/{elasticsearch => postgres}/messages/getCompletedSectionInboxMessages.ts (100%) rename web-api/src/persistence/{elasticsearch => postgres}/messages/getCompletedUserInboxMessages.ts (100%) rename web-api/src/persistence/{dynamo => postgres}/messages/getMessageById.ts (100%) rename web-api/src/persistence/{dynamo => postgres}/messages/getMessageThreadByParentId.ts (100%) rename web-api/src/persistence/{dynamo => postgres}/messages/getMessagesByDocketNumber.ts (100%) rename web-api/src/persistence/{elasticsearch => postgres}/messages/getSectionInboxMessages.ts (100%) rename web-api/src/persistence/{elasticsearch => postgres}/messages/getSectionOutboxMessages.ts (100%) rename web-api/src/persistence/{elasticsearch => postgres}/messages/getUserInboxMessages.ts (100%) rename web-api/src/persistence/{elasticsearch => postgres}/messages/getUserOutboxMessages.ts (100%) rename web-api/src/persistence/{dynamo => postgres}/messages/markMessageThreadRepliedTo.ts (100%) rename web-api/src/persistence/{dynamo => postgres}/messages/setMessageAsRead.ts (100%) rename web-api/src/persistence/{dynamo => postgres}/messages/updateMessage.ts (100%) diff --git a/1721165468631-JoinColumnMessages.ts b/1721165468631-JoinColumnMessages.ts new file mode 100644 index 00000000000..fc24d9c7a1c --- /dev/null +++ b/1721165468631-JoinColumnMessages.ts @@ -0,0 +1,29 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class JoinColumnMessages1721165468631 implements MigrationInterface { + name = 'JoinColumnMessages1721165468631'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "message" DROP CONSTRAINT "FK_2dad987847361722fd55a8c19fa"', + ); + await queryRunner.query( + 'ALTER TABLE "message" DROP COLUMN "caseDocketNumber"', + ); + await queryRunner.query( + 'ALTER TABLE "message" ADD CONSTRAINT "FK_5c6b9074994ba166011d5dd0b26" FOREIGN KEY ("docketNumber") REFERENCES "case"("docketNumber") ON DELETE NO ACTION ON UPDATE NO ACTION', + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "message" DROP CONSTRAINT "FK_5c6b9074994ba166011d5dd0b26"', + ); + await queryRunner.query( + 'ALTER TABLE "message" ADD "caseDocketNumber" character varying', + ); + await queryRunner.query( + 'ALTER TABLE "message" ADD CONSTRAINT "FK_2dad987847361722fd55a8c19fa" FOREIGN KEY ("caseDocketNumber") REFERENCES "case"("docketNumber") ON DELETE NO ACTION ON UPDATE NO ACTION', + ); + } +} diff --git a/package-lock.json b/package-lock.json index 7b6169e3e62..8d3b261e0e5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -97,8 +97,8 @@ "servor": "4.0.2", "supports-color": "9.4.0", "tmp": "0.2.3", - "typeorm": "^0.3.20", - "typeorm-extension": "^3.5.1", + "typeorm": "0.3.20", + "typeorm-extension": "3.5.1", "util": "0.12.5", "uuid": "10.0.0", "websocket": "1.0.35", diff --git a/package.json b/package.json index 4fb796f19c2..1aaa833e895 100644 --- a/package.json +++ b/package.json @@ -240,6 +240,7 @@ "verify-authorizers": "./scripts/circleci/verify-authorizers.sh", "verify-private-elasticsearch": "./scripts/circleci/verify-private-elasticsearch.sh", "visualize-bundle": "esbuild-visualizer --metadata ./metadata.json && open stats.html", + "postgres:run": "cd postgres && docker compose up &", "typeorm:migrations:migrate": "npx typeorm-ts-node-commonjs migration:run -d web-api/src/data-source.ts", "typeorm:migrations:revert": "npx typeorm-ts-node-commonjs migration:revert -d web-api/src/data-source.ts", "typeorm:migrations:generate": "npx typeorm-ts-node-commonjs migration:generate ${MIGRATION_NAME} -d web-api/src/data-source.ts", diff --git a/postgres/seed/seed.ts b/postgres/seed/seed.ts index 61a3011bfa3..13d7573dec2 100644 --- a/postgres/seed/seed.ts +++ b/postgres/seed/seed.ts @@ -4,6 +4,27 @@ import { getDataSource } from '../../web-api/src/data-source'; async function main() { const appDataSource = await getDataSource(); + + const caseRepository = appDataSource.getRepository(Case); + const cases = [ + { + docketNumber: '105-20', + trialDate: new Date('2021-03-18T18:07:36.333Z').toISOString(), + trialLocation: 'Detroit, Michigan', + }, + { + docketNumber: '103-20', + trialDate: new Date('2023-04-18T18:07:36.333Z').toISOString(), + trialLocation: 'Denver, Colorado', + }, + { + docketNumber: '104-19', + trialDate: new Date('2022-05-18T18:07:36.333Z').toISOString(), + trialLocation: 'Chicago, Illinois', + }, + ]; + + await caseRepository.save(cases); const messageRepository = appDataSource.getRepository(Message); const messages = [ { @@ -79,27 +100,6 @@ async function main() { }, ]; await messageRepository.save(messages); - - const caseRepository = appDataSource.getRepository(Case); - const cases = [ - { - docketNumber: '105-20', - trialDate: new Date('2021-03-18T18:07:36.333Z').toISOString(), - trialLocation: 'Detroit, Michigan', - }, - { - docketNumber: '103-20', - trialDate: new Date('2023-04-18T18:07:36.333Z').toISOString(), - trialLocation: 'Denver, Colorado', - }, - { - docketNumber: '104-19', - trialDate: new Date('2022-05-18T18:07:36.333Z').toISOString(), - trialLocation: 'Chicago, Illinois', - }, - ]; - - await caseRepository.save(cases); } main().catch(console.error); diff --git a/web-api/src/persistence/dynamo/messages/createMessage.ts b/web-api/src/persistence/postgres/messages/createMessage.ts similarity index 100% rename from web-api/src/persistence/dynamo/messages/createMessage.ts rename to web-api/src/persistence/postgres/messages/createMessage.ts diff --git a/web-api/src/persistence/elasticsearch/messages/getCompletedSectionInboxMessages.ts b/web-api/src/persistence/postgres/messages/getCompletedSectionInboxMessages.ts similarity index 100% rename from web-api/src/persistence/elasticsearch/messages/getCompletedSectionInboxMessages.ts rename to web-api/src/persistence/postgres/messages/getCompletedSectionInboxMessages.ts diff --git a/web-api/src/persistence/elasticsearch/messages/getCompletedUserInboxMessages.ts b/web-api/src/persistence/postgres/messages/getCompletedUserInboxMessages.ts similarity index 100% rename from web-api/src/persistence/elasticsearch/messages/getCompletedUserInboxMessages.ts rename to web-api/src/persistence/postgres/messages/getCompletedUserInboxMessages.ts diff --git a/web-api/src/persistence/dynamo/messages/getMessageById.ts b/web-api/src/persistence/postgres/messages/getMessageById.ts similarity index 100% rename from web-api/src/persistence/dynamo/messages/getMessageById.ts rename to web-api/src/persistence/postgres/messages/getMessageById.ts diff --git a/web-api/src/persistence/dynamo/messages/getMessageThreadByParentId.ts b/web-api/src/persistence/postgres/messages/getMessageThreadByParentId.ts similarity index 100% rename from web-api/src/persistence/dynamo/messages/getMessageThreadByParentId.ts rename to web-api/src/persistence/postgres/messages/getMessageThreadByParentId.ts diff --git a/web-api/src/persistence/dynamo/messages/getMessagesByDocketNumber.ts b/web-api/src/persistence/postgres/messages/getMessagesByDocketNumber.ts similarity index 100% rename from web-api/src/persistence/dynamo/messages/getMessagesByDocketNumber.ts rename to web-api/src/persistence/postgres/messages/getMessagesByDocketNumber.ts diff --git a/web-api/src/persistence/elasticsearch/messages/getSectionInboxMessages.ts b/web-api/src/persistence/postgres/messages/getSectionInboxMessages.ts similarity index 100% rename from web-api/src/persistence/elasticsearch/messages/getSectionInboxMessages.ts rename to web-api/src/persistence/postgres/messages/getSectionInboxMessages.ts diff --git a/web-api/src/persistence/elasticsearch/messages/getSectionOutboxMessages.ts b/web-api/src/persistence/postgres/messages/getSectionOutboxMessages.ts similarity index 100% rename from web-api/src/persistence/elasticsearch/messages/getSectionOutboxMessages.ts rename to web-api/src/persistence/postgres/messages/getSectionOutboxMessages.ts diff --git a/web-api/src/persistence/elasticsearch/messages/getUserInboxMessages.ts b/web-api/src/persistence/postgres/messages/getUserInboxMessages.ts similarity index 100% rename from web-api/src/persistence/elasticsearch/messages/getUserInboxMessages.ts rename to web-api/src/persistence/postgres/messages/getUserInboxMessages.ts diff --git a/web-api/src/persistence/elasticsearch/messages/getUserOutboxMessages.ts b/web-api/src/persistence/postgres/messages/getUserOutboxMessages.ts similarity index 100% rename from web-api/src/persistence/elasticsearch/messages/getUserOutboxMessages.ts rename to web-api/src/persistence/postgres/messages/getUserOutboxMessages.ts diff --git a/web-api/src/persistence/dynamo/messages/markMessageThreadRepliedTo.ts b/web-api/src/persistence/postgres/messages/markMessageThreadRepliedTo.ts similarity index 100% rename from web-api/src/persistence/dynamo/messages/markMessageThreadRepliedTo.ts rename to web-api/src/persistence/postgres/messages/markMessageThreadRepliedTo.ts diff --git a/web-api/src/persistence/dynamo/messages/setMessageAsRead.ts b/web-api/src/persistence/postgres/messages/setMessageAsRead.ts similarity index 100% rename from web-api/src/persistence/dynamo/messages/setMessageAsRead.ts rename to web-api/src/persistence/postgres/messages/setMessageAsRead.ts diff --git a/web-api/src/persistence/dynamo/messages/updateMessage.ts b/web-api/src/persistence/postgres/messages/updateMessage.ts similarity index 100% rename from web-api/src/persistence/dynamo/messages/updateMessage.ts rename to web-api/src/persistence/postgres/messages/updateMessage.ts diff --git a/web-api/src/persistence/repository/Message.ts b/web-api/src/persistence/repository/Message.ts index e81cc6fc05c..8cfa75ca202 100644 --- a/web-api/src/persistence/repository/Message.ts +++ b/web-api/src/persistence/repository/Message.ts @@ -1,5 +1,5 @@ import { Case } from '@web-api/persistence/repository/Case'; -import { Column, Entity, ManyToOne, PrimaryColumn } from 'typeorm'; +import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm'; @Entity() export class Message { @@ -81,5 +81,6 @@ export class Message { toUserId!: string; @ManyToOne(() => Case, item => item.docketNumber) + @JoinColumn({ name: 'docketNumber' }) case!: Case; } From 3eb0c93e919eb71a921a583482a5666535ebcafd Mon Sep 17 00:00:00 2001 From: Cody Seibert Date: Tue, 16 Jul 2024 17:50:22 -0400 Subject: [PATCH 13/30] turning on logging for now --- .../processCaseEntries.ts | 2 ++ web-api/src/data-source.ts | 2 +- web-api/src/getPersistenceGateway.ts | 26 +++++++++---------- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/web-api/src/business/useCases/processStreamRecords/processCaseEntries.ts b/web-api/src/business/useCases/processStreamRecords/processCaseEntries.ts index bb4d23ada5a..a0d535ce97d 100644 --- a/web-api/src/business/useCases/processStreamRecords/processCaseEntries.ts +++ b/web-api/src/business/useCases/processStreamRecords/processCaseEntries.ts @@ -26,6 +26,8 @@ export const processCaseEntries = async ({ docketNumber: caseNewImage.docketNumber.S, }); + // TODO: use the caseNewImage to update the case table if the trialLocation or trialDate changes? + const marshalledCase = marshall(caseMetadataWithCounsel); caseRecords.push({ diff --git a/web-api/src/data-source.ts b/web-api/src/data-source.ts index 62e7dd50905..d0ee78f32a4 100644 --- a/web-api/src/data-source.ts +++ b/web-api/src/data-source.ts @@ -7,7 +7,7 @@ export const AppDataSource = new DataSource({ database: 'postgres', entities: [Message, Case], host: 'localhost', - logging: false, + logging: true, migrations: ['postgres/migrations/*.ts'], password: 'example', port: 5432, diff --git a/web-api/src/getPersistenceGateway.ts b/web-api/src/getPersistenceGateway.ts index 27dabcf0898..759dac6c5d0 100644 --- a/web-api/src/getPersistenceGateway.ts +++ b/web-api/src/getPersistenceGateway.ts @@ -18,7 +18,7 @@ import { getLock, removeLock, } from './persistence/dynamo/locks/acquireLock'; -import { createMessage } from './persistence/dynamo/messages/createMessage'; +import { createMessage } from './persistence/postgres/messages/createMessage'; import { createNewPetitionerUser } from './persistence/dynamo/users/createNewPetitionerUser'; import { createNewPractitionerUser } from './persistence/dynamo/users/createNewPractitionerUser'; import { createOrUpdatePractitionerUser } from './persistence/dynamo/users/createOrUpdatePractitionerUser'; @@ -76,8 +76,8 @@ import { import { getCasesMetadataByLeadDocketNumber } from './persistence/dynamo/cases/getCasesMetadataByLeadDocketNumber'; import { getClientId } from './persistence/cognito/getClientId'; import { getColdCases } from './persistence/elasticsearch/reports/getColdCases'; -import { getCompletedSectionInboxMessages } from './persistence/elasticsearch/messages/getCompletedSectionInboxMessages'; -import { getCompletedUserInboxMessages } from './persistence/elasticsearch/messages/getCompletedUserInboxMessages'; +import { getCompletedSectionInboxMessages } from './persistence/postgres/messages/getCompletedSectionInboxMessages'; +import { getCompletedUserInboxMessages } from './persistence/postgres/messages/getCompletedUserInboxMessages'; import { getConfigurationItemValue } from './persistence/dynamo/deployTable/getConfigurationItemValue'; import { getConsolidatedCasesCount } from '@web-api/persistence/dynamo/cases/getConsolidatedCasesCount'; import { getCountOfConsolidatedCases } from '@web-api/persistence/elasticsearch/getCountOfConsolidatedCases'; @@ -100,9 +100,9 @@ import { getFeatureFlagValue } from './persistence/dynamo/deployTable/getFeature import { getFirstSingleCaseRecord } from './persistence/elasticsearch/getFirstSingleCaseRecord'; import { getInternalUsers } from './persistence/dynamo/users/getInternalUsers'; import { getMaintenanceMode } from './persistence/dynamo/deployTable/getMaintenanceMode'; -import { getMessageById } from './persistence/dynamo/messages/getMessageById'; -import { getMessageThreadByParentId } from './persistence/dynamo/messages/getMessageThreadByParentId'; -import { getMessagesByDocketNumber } from './persistence/dynamo/messages/getMessagesByDocketNumber'; +import { getMessageById } from './persistence/postgres/messages/getMessageById'; +import { getMessageThreadByParentId } from './persistence/postgres/messages/getMessageThreadByParentId'; +import { getMessagesByDocketNumber } from './persistence/postgres/messages/getMessagesByDocketNumber'; import { getPractitionerByBarNumber } from './persistence/dynamo/users/getPractitionerByBarNumber'; import { getPractitionerDocumentByFileId } from './persistence/dynamo/practitioners/getPractitionerDocumentByFileId'; import { getPractitionerDocuments } from './persistence/dynamo/practitioners/getPractitionerDocuments'; @@ -110,8 +110,8 @@ import { getPractitionersByName } from './persistence/elasticsearch/getPractitio import { getReadyForTrialCases } from './persistence/elasticsearch/getReadyForTrialCases'; import { getReconciliationReport } from './persistence/elasticsearch/getReconciliationReport'; import { getRequestResults } from '@web-api/persistence/dynamo/polling/getRequestResults'; -import { getSectionInboxMessages } from './persistence/elasticsearch/messages/getSectionInboxMessages'; -import { getSectionOutboxMessages } from './persistence/elasticsearch/messages/getSectionOutboxMessages'; +import { getSectionInboxMessages } from './persistence/postgres/messages/getSectionInboxMessages'; +import { getSectionOutboxMessages } from './persistence/postgres/messages/getSectionOutboxMessages'; import { getSesStatus } from './persistence/ses/getSesStatus'; import { getStoredApplicationHealth } from '@web-api/persistence/dynamo/deployTable/getStoredApplicationHealth'; import { getTableStatus } from './persistence/dynamo/getTableStatus'; @@ -125,8 +125,8 @@ import { getUserByEmail } from './persistence/dynamo/users/getUserByEmail'; import { getUserById } from './persistence/dynamo/users/getUserById'; import { getUserCaseNote } from './persistence/dynamo/userCaseNotes/getUserCaseNote'; import { getUserCaseNoteForCases } from './persistence/dynamo/userCaseNotes/getUserCaseNoteForCases'; -import { getUserInboxMessages } from './persistence/elasticsearch/messages/getUserInboxMessages'; -import { getUserOutboxMessages } from './persistence/elasticsearch/messages/getUserOutboxMessages'; +import { getUserInboxMessages } from './persistence/postgres/messages/getUserInboxMessages'; +import { getUserOutboxMessages } from './persistence/postgres/messages/getUserOutboxMessages'; import { getUsersById } from './persistence/dynamo/users/getUsersById'; import { getUsersBySearchKey } from './persistence/dynamo/users/getUsersBySearchKey'; import { getUsersInSection } from './persistence/dynamo/users/getUsersInSection'; @@ -137,7 +137,7 @@ import { getWorkItemsByWorkItemId } from './persistence/dynamo/workitems/getWork import { incrementCounter } from './persistence/dynamo/helpers/incrementCounter'; import { isEmailAvailable } from './persistence/cognito/isEmailAvailable'; import { isFileExists } from './persistence/s3/isFileExists'; -import { markMessageThreadRepliedTo } from './persistence/dynamo/messages/markMessageThreadRepliedTo'; +import { markMessageThreadRepliedTo } from './persistence/postgres/messages/markMessageThreadRepliedTo'; import { persistUser } from './persistence/dynamo/users/persistUser'; import { putWorkItemInOutbox } from './persistence/dynamo/workitems/putWorkItemInOutbox'; import { putWorkItemInUsersOutbox } from './persistence/dynamo/workitems/putWorkItemInUsersOutbox'; @@ -153,7 +153,7 @@ import { saveUserConnection } from './persistence/dynamo/notifications/saveUserC import { saveWorkItem } from './persistence/dynamo/workitems/saveWorkItem'; import { saveWorkItemForDocketClerkFilingExternalDocument } from './persistence/dynamo/workitems/saveWorkItemForDocketClerkFilingExternalDocument'; import { setChangeOfAddressCaseAsDone } from './persistence/dynamo/jobs/ChangeOfAddress/setChangeOfAddressCaseAsDone'; -import { setMessageAsRead } from './persistence/dynamo/messages/setMessageAsRead'; +import { setMessageAsRead } from './persistence/postgres/messages/setMessageAsRead'; import { setPriorityOnAllWorkItems } from './persistence/dynamo/workitems/setPriorityOnAllWorkItems'; import { setStoredApplicationHealth } from '@web-api/persistence/dynamo/deployTable/setStoredApplicationHealth'; import { setTrialSessionJobStatusForCase } from './persistence/dynamo/trialSessions/setTrialSessionJobStatusForCase'; @@ -171,7 +171,7 @@ import { updatePrivatePractitionerOnCase, } from './persistence/dynamo/cases/updatePractitionerOnCase'; import { updateMaintenanceMode } from './persistence/dynamo/deployTable/updateMaintenanceMode'; -import { updateMessage } from './persistence/dynamo/messages/updateMessage'; +import { updateMessage } from './persistence/postgres/messages/updateMessage'; import { updatePractitionerUser } from './persistence/dynamo/users/updatePractitionerUser'; import { updateTrialSession } from './persistence/dynamo/trialSessions/updateTrialSession'; import { updateTrialSessionWorkingCopy } from './persistence/dynamo/trialSessions/updateTrialSessionWorkingCopy'; From 9bda01bf935f908f2a96b4f2084c8239992add99 Mon Sep 17 00:00:00 2001 From: Cody Seibert Date: Thu, 18 Jul 2024 13:58:23 -0400 Subject: [PATCH 14/30] 10391 - working on removing the message index --- babel.config.js | 6 +- package-lock.json | 33 ++++ package.json | 5 +- postgres/seed/seed.ts | 21 --- run-local.sh | 2 + .../elasticsearch/efcms-message-mappings.ts | 84 ---------- .../elasticsearch/elasticsearch-mappings.ts | 5 - .../processCaseEntries.ts | 4 + web-api/src/getPersistenceGateway.ts | 2 + .../elasticsearch/bulkDeleteRecords.test.ts | 10 +- .../elasticsearch/bulkIndexRecords.test.ts | 105 +------------ .../elasticsearch/bulkIndexRecords.ts | 3 - .../getIndexNameForRecord.test.ts | 25 --- .../elasticsearch/getIndexNameForRecord.ts | 7 - .../helpers/getIndexName.test.ts | 8 - .../searchClient.test.constants.ts | 145 ------------------ .../elasticsearch/searchClient.test.ts | 17 -- .../persistence/postgres/cases/updateCase.ts | 7 + .../storage/fixtures/seed/efcms-local.json | 84 +--------- 19 files changed, 65 insertions(+), 508 deletions(-) delete mode 100644 web-api/elasticsearch/efcms-message-mappings.ts create mode 100644 web-api/src/persistence/postgres/cases/updateCase.ts diff --git a/babel.config.js b/babel.config.js index 601ea63fdc4..e38e5626094 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,5 +1,9 @@ module.exports = { - plugins: ['babel-plugin-cerebral', 'transform-html-import-require-to-string'], + plugins: [ + 'babel-plugin-cerebral', + 'transform-html-import-require-to-string', + ['@babel/plugin-proposal-decorators', { version: '2023-11' }], + ], presets: [ [ '@babel/preset-env', diff --git a/package-lock.json b/package-lock.json index 8d3b261e0e5..417cc0b5032 100644 --- a/package-lock.json +++ b/package-lock.json @@ -111,6 +111,7 @@ "@babel/cli": "7.24.8", "@babel/core": "7.24.8", "@babel/eslint-parser": "7.24.8", + "@babel/plugin-proposal-decorators": "^7.24.7", "@babel/preset-env": "7.24.8", "@babel/preset-react": "7.24.7", "@babel/preset-typescript": "7.24.7", @@ -7656,6 +7657,23 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.24.7.tgz", + "integrity": "sha512-RL9GR0pUG5Kc8BUWLNDm2T5OpYwSX15r98I0IkgmRQTXuELq/OynH8xtMTMvTJFjXbMWFVTKtYkTaYQsuAwQlQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-decorators": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-proposal-private-property-in-object": { "version": "7.21.0-placeholder-for-preset-env.2", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", @@ -7719,6 +7737,21 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.24.7.tgz", + "integrity": "sha512-Ui4uLJJrRV1lb38zg1yYTmRKmiZLiftDEvZN2iq3kd9kUFU+PttmzTbAFC2ucRk/XJmtek6G23gPsuZbhrT8fQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-dynamic-import": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", diff --git a/package.json b/package.json index 1aaa833e895..1f3b54e10ee 100644 --- a/package.json +++ b/package.json @@ -195,6 +195,7 @@ "secrets:rotate-environment": "npx ts-node --transpile-only scripts/user/rotate-environment-secrets.ts", "seed:db": "npx ts-node --transpile-only ./web-api/create-dynamo-tables.ts && npx ts-node --transpile-only ./web-api/seed-dynamo.ts", "seed:elasticsearch": "./web-api/seed-elasticsearch.sh", + "seed:postgres": "npx ts-node postgres/seed/seed.ts", "seed:s3": "cp -R ./web-api/storage/fixtures/s3/* ./web-api/storage/s3", "seed": "run-p seed:db seed:s3", "shell": "docker-compose run -it shell /bin/bash", @@ -243,8 +244,7 @@ "postgres:run": "cd postgres && docker compose up &", "typeorm:migrations:migrate": "npx typeorm-ts-node-commonjs migration:run -d web-api/src/data-source.ts", "typeorm:migrations:revert": "npx typeorm-ts-node-commonjs migration:revert -d web-api/src/data-source.ts", - "typeorm:migrations:generate": "npx typeorm-ts-node-commonjs migration:generate ${MIGRATION_NAME} -d web-api/src/data-source.ts", - "typeorm:seed": "npx ts-node postgres/seed/seed.ts" + "typeorm:migrations:generate": "npx typeorm-ts-node-commonjs migration:generate ${MIGRATION_NAME} -d web-api/src/data-source.ts" }, "overrides": { "axios": "$axios", @@ -258,6 +258,7 @@ "@babel/cli": "7.24.8", "@babel/core": "7.24.8", "@babel/eslint-parser": "7.24.8", + "@babel/plugin-proposal-decorators": "^7.24.7", "@babel/preset-env": "7.24.8", "@babel/preset-react": "7.24.7", "@babel/preset-typescript": "7.24.7", diff --git a/postgres/seed/seed.ts b/postgres/seed/seed.ts index 13d7573dec2..122ccd96432 100644 --- a/postgres/seed/seed.ts +++ b/postgres/seed/seed.ts @@ -1,30 +1,9 @@ -import { Case } from '@web-api/persistence/repository/Case'; import { Message } from '../../web-api/src/persistence/repository/Message'; import { getDataSource } from '../../web-api/src/data-source'; async function main() { const appDataSource = await getDataSource(); - const caseRepository = appDataSource.getRepository(Case); - const cases = [ - { - docketNumber: '105-20', - trialDate: new Date('2021-03-18T18:07:36.333Z').toISOString(), - trialLocation: 'Detroit, Michigan', - }, - { - docketNumber: '103-20', - trialDate: new Date('2023-04-18T18:07:36.333Z').toISOString(), - trialLocation: 'Denver, Colorado', - }, - { - docketNumber: '104-19', - trialDate: new Date('2022-05-18T18:07:36.333Z').toISOString(), - trialLocation: 'Chicago, Illinois', - }, - ]; - - await caseRepository.save(cases); const messageRepository = appDataSource.getRepository(Message); const messages = [ { diff --git a/run-local.sh b/run-local.sh index 5059b15d678..79b5e619207 100755 --- a/run-local.sh +++ b/run-local.sh @@ -49,6 +49,8 @@ else fi fi +npm run seed:postgres + echo "Seeding cognito-local users" npx ts-node .cognito/seedCognitoLocal.ts --transpile-only diff --git a/web-api/elasticsearch/efcms-message-mappings.ts b/web-api/elasticsearch/efcms-message-mappings.ts deleted file mode 100644 index fc6a52e79db..00000000000 --- a/web-api/elasticsearch/efcms-message-mappings.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { createHash } from 'crypto'; - -export const efcmsMessageMappings = { - properties: { - case_relations: { - relations: { - case: 'message', - }, - type: 'join', - }, - 'caseStatus.S': { - type: 'keyword', - }, - 'caseTitle.S': { - type: 'text', - }, - 'completedAt.S': { - type: 'date', - }, - 'completedBy.S': { - type: 'text', - }, - 'completedBySection.S': { - type: 'keyword', - }, - 'completedByUserId.S': { - type: 'keyword', - }, - 'completedMessage.S': { - type: 'text', - }, - 'createdAt.S': { - type: 'date', - }, - 'docketNumberWithSuffix.S': { - type: 'keyword', - }, - 'entityName.S': { - type: 'keyword', - }, - 'from.S': { - type: 'text', - }, - 'fromSection.S': { - type: 'keyword', - }, - 'fromUserId.S': { - type: 'keyword', - }, - 'indexedTimestamp.N': { - type: 'text', - }, - 'isCompleted.BOOL': { - type: 'boolean', - }, - 'isRepliedTo.BOOL': { - type: 'boolean', - }, - 'message.S': { - type: 'text', - }, - 'parentMessageId.S': { - type: 'keyword', - }, - 'subject.S': { - type: 'text', - }, - 'to.S': { - type: 'text', - }, - 'toSection.S': { - type: 'keyword', - }, - 'toUserId.S': { - type: 'keyword', - }, - }, -}; - -const efcmsMessageMappingsHash: string = createHash('md5') - .update(JSON.stringify(efcmsMessageMappings), 'utf8') - .digest('hex'); - -export const efcmsMessageIndex: string = `efcms-message-${efcmsMessageMappingsHash}`; diff --git a/web-api/elasticsearch/elasticsearch-mappings.ts b/web-api/elasticsearch/elasticsearch-mappings.ts index 8637b4a85d8..4f26e8d06e3 100644 --- a/web-api/elasticsearch/elasticsearch-mappings.ts +++ b/web-api/elasticsearch/elasticsearch-mappings.ts @@ -7,10 +7,6 @@ import { efcmsDocketEntryIndex, efcmsDocketEntryMappings, } from './efcms-docket-entry-mappings'; -import { - efcmsMessageIndex, - efcmsMessageMappings, -} from './efcms-message-mappings'; import { efcmsUserIndex, efcmsUserMappings } from './efcms-user-mappings'; import { efcmsWorkItemIndex, @@ -39,7 +35,6 @@ export const elasticsearchMappings = { [efcmsCaseDeadlineIndex]: efcmsCaseDeadlineMappings, [efcmsCaseIndex]: efcmsCaseMappings, [efcmsDocketEntryIndex]: efcmsDocketEntryMappings, - [efcmsMessageIndex]: efcmsMessageMappings, [efcmsUserIndex]: efcmsUserMappings, [efcmsWorkItemIndex]: efcmsWorkItemMappings, }; diff --git a/web-api/src/business/useCases/processStreamRecords/processCaseEntries.ts b/web-api/src/business/useCases/processStreamRecords/processCaseEntries.ts index a0d535ce97d..9a931930316 100644 --- a/web-api/src/business/useCases/processStreamRecords/processCaseEntries.ts +++ b/web-api/src/business/useCases/processStreamRecords/processCaseEntries.ts @@ -49,6 +49,10 @@ export const processCaseEntries = async ({ eventName: 'MODIFY', }); + await applicationContext + .getPersistenceGateway() + .updateCasePostgres(caseMetadataWithCounsel); + caseRecords.push({ dynamodb: { Keys: { diff --git a/web-api/src/getPersistenceGateway.ts b/web-api/src/getPersistenceGateway.ts index 759dac6c5d0..71fb3f36227 100644 --- a/web-api/src/getPersistenceGateway.ts +++ b/web-api/src/getPersistenceGateway.ts @@ -161,6 +161,7 @@ import { setTrialSessionProcessingStatus } from './persistence/dynamo/trialSessi import { updateCase } from './persistence/dynamo/cases/updateCase'; import { updateCaseCorrespondence } from './persistence/dynamo/correspondence/updateCaseCorrespondence'; import { updateCaseHearing } from './persistence/dynamo/trialSessions/updateCaseHearing'; +import { updateCase as updateCasePostgres } from './persistence/postgres/cases/updateCase'; import { updateCaseWorksheet } from '@web-api/persistence/dynamo/caseWorksheet/updateCaseWorksheet'; import { updateDocketEntry } from './persistence/dynamo/documents/updateDocketEntry'; import { updateDocketEntryPendingServiceStatus } from './persistence/dynamo/documents/updateDocketEntryPendingServiceStatus'; @@ -390,6 +391,7 @@ const gatewayMethods = { removePrivatePractitionerOnCase, setChangeOfAddressCaseAsDone, setStoredApplicationHealth, + updateCasePostgres, uploadDocument, verifyCaseForUser, verifyPendingCaseForUser, diff --git a/web-api/src/persistence/elasticsearch/bulkDeleteRecords.test.ts b/web-api/src/persistence/elasticsearch/bulkDeleteRecords.test.ts index 0d3be9ab0f9..1994a54227e 100644 --- a/web-api/src/persistence/elasticsearch/bulkDeleteRecords.test.ts +++ b/web-api/src/persistence/elasticsearch/bulkDeleteRecords.test.ts @@ -4,7 +4,7 @@ import { } from '../../../../shared/src/business/entities/EntityConstants'; import { applicationContext } from '../../../../shared/src/business/test/createTestApplicationContext'; import { bulkDeleteRecords } from './bulkDeleteRecords'; -import { efcmsMessageIndex } from '../../../elasticsearch/efcms-message-mappings'; +import { efcmsUserIndex } from '../../../elasticsearch/efcms-user-mappings'; describe('bulkDeleteRecords', () => { const oldImageRecord = { @@ -12,7 +12,7 @@ describe('bulkDeleteRecords', () => { createdAt: { S: '2020-06-10T15:10:23.553Z' }, docketNumber: { S: '105-19' }, docketNumberWithSuffix: { S: '105-19' }, - entityName: { S: 'Message' }, + entityName: { S: 'User' }, from: { S: 'Test Docketclerk' }, fromSection: { S: DOCKET_SECTION }, fromUserId: { S: '1805d1ab-18d0-43ec-bafb-654e83405416' }, @@ -74,9 +74,9 @@ describe('bulkDeleteRecords', () => { items: [ { delete: { - _index: efcmsMessageIndex, + _index: efcmsUserIndex, error: { - index: efcmsMessageIndex, + index: efcmsUserIndex, index_uuid: 'aAsFqTI0Tc2W0LCWgPNrOA', reason: 'document missing', shard: '0', @@ -97,7 +97,7 @@ describe('bulkDeleteRecords', () => { expect(result.failedRecords).toEqual([ { _id: `${oldImageRecord.pk.S}_${oldImageRecord.sk.S}`, - _index: efcmsMessageIndex, + _index: efcmsUserIndex, }, ]); }); diff --git a/web-api/src/persistence/elasticsearch/bulkIndexRecords.test.ts b/web-api/src/persistence/elasticsearch/bulkIndexRecords.test.ts index 6e6a0ceaebb..982af4b2f82 100644 --- a/web-api/src/persistence/elasticsearch/bulkIndexRecords.test.ts +++ b/web-api/src/persistence/elasticsearch/bulkIndexRecords.test.ts @@ -5,7 +5,6 @@ import { import { applicationContext } from '@shared/business/test/createTestApplicationContext'; import { bulkIndexRecords } from './bulkIndexRecords'; import { efcmsDocketEntryIndex } from '../../../elasticsearch/efcms-docket-entry-mappings'; -import { efcmsMessageIndex } from '../../../elasticsearch/efcms-message-mappings'; import { efcmsWorkItemIndex } from '../../../elasticsearch/efcms-work-item-mappings'; describe('bulkIndexRecords', () => { @@ -14,7 +13,7 @@ describe('bulkIndexRecords', () => { createdAt: { S: '2020-06-10T15:10:23.553Z' }, docketNumber: { S: '105-19' }, docketNumberWithSuffix: { S: '105-19' }, - entityName: { S: 'Message' }, + entityName: { S: 'DocketEntry' }, from: { S: 'Test Docketclerk' }, fromSection: { S: DOCKET_SECTION }, fromUserId: { S: '1805d1ab-18d0-43ec-bafb-654e83405416' }, @@ -57,9 +56,9 @@ describe('bulkIndexRecords', () => { items: [ { index: { - _index: efcmsMessageIndex, + _index: efcmsDocketEntryIndex, error: { - index: efcmsMessageIndex, + index: efcmsDocketEntryIndex, index_uuid: 'aAsFqTI0Tc2W0LCWgPNrOA', reason: 'document missing', shard: '0', @@ -129,55 +128,6 @@ describe('bulkIndexRecords', () => { }); }); - it('uses the routing parameter when the item is a Message', async () => { - applicationContext.getSearchClient.mockReturnValue({ - bulk: jest.fn().mockReturnValue({ - errors: false, - items: [{}], - took: 100, - }), - }); - - await bulkIndexRecords({ - applicationContext, - records: [ - { - dynamodb: { - NewImage: { - entityName: { S: 'Message' }, - pk: { S: 'case|123-45' }, - sk: { S: 'message|8675309' }, - }, - }, - }, - ], - }); - - expect(applicationContext.getSearchClient().bulk).toHaveBeenCalledWith({ - body: [ - { - index: { - _id: 'case|123-45_message|8675309', - _index: efcmsMessageIndex, - routing: 'case|123-45_case|123-45|mapping', - }, - }, - { - entityName: { - S: 'Message', - }, - pk: { - S: 'case|123-45', - }, - sk: { - S: 'message|8675309', - }, - }, - ], - refresh: false, - }); - }); - it('uses the routing parameter when the item is a WorkItem', async () => { applicationContext.getSearchClient.mockReturnValue({ bulk: jest.fn().mockReturnValue({ @@ -276,55 +226,6 @@ describe('bulkIndexRecords', () => { }); }); - it('sets an altered _id if the item is a CaseMessageMapping', async () => { - applicationContext.getSearchClient.mockReturnValue({ - bulk: jest.fn().mockReturnValue({ - errors: false, - items: [{}], - took: 100, - }), - }); - - await bulkIndexRecords({ - applicationContext, - records: [ - { - dynamodb: { - NewImage: { - entityName: { S: 'CaseMessageMapping' }, - pk: { S: 'case|123-45' }, - sk: { S: 'case|123-45' }, - }, - }, - }, - ], - }); - - expect(applicationContext.getSearchClient().bulk).toHaveBeenCalledWith({ - body: [ - { - index: { - _id: 'case|123-45_case|123-45|mapping', - _index: efcmsMessageIndex, - routing: '', - }, - }, - { - entityName: { - S: 'CaseMessageMapping', - }, - pk: { - S: 'case|123-45', - }, - sk: { - S: 'case|123-45', - }, - }, - ], - refresh: false, - }); - }); - it('sets an altered _id if the item is a CaseWorkItemMapping', async () => { applicationContext.getSearchClient.mockReturnValue({ bulk: jest.fn().mockReturnValue({ diff --git a/web-api/src/persistence/elasticsearch/bulkIndexRecords.ts b/web-api/src/persistence/elasticsearch/bulkIndexRecords.ts index 3ef1a896958..9310d9f2da5 100644 --- a/web-api/src/persistence/elasticsearch/bulkIndexRecords.ts +++ b/web-api/src/persistence/elasticsearch/bulkIndexRecords.ts @@ -35,9 +35,6 @@ export const bulkIndexRecords = async ({ if (doc.entityName.S === 'DocketEntry') { routing = `${doc.pk.S}_${doc.pk.S}|mapping`; } - if (doc.entityName.S === 'Message') { - routing = `${doc.pk.S}_${doc.pk.S}|mapping`; - } if (doc.entityName.S === 'WorkItem') { routing = `${doc.pk.S}_${doc.pk.S}|mapping`; } diff --git a/web-api/src/persistence/elasticsearch/getIndexNameForRecord.test.ts b/web-api/src/persistence/elasticsearch/getIndexNameForRecord.test.ts index 81eb0153082..67f2a446183 100644 --- a/web-api/src/persistence/elasticsearch/getIndexNameForRecord.test.ts +++ b/web-api/src/persistence/elasticsearch/getIndexNameForRecord.test.ts @@ -1,7 +1,6 @@ import { efcmsCaseDeadlineIndex } from '../../../elasticsearch/efcms-case-deadline-mappings'; import { efcmsCaseIndex } from '../../../elasticsearch/efcms-case-mappings'; import { efcmsDocketEntryIndex } from '../../../elasticsearch/efcms-docket-entry-mappings'; -import { efcmsMessageIndex } from '../../../elasticsearch/efcms-message-mappings'; import { efcmsUserIndex } from '../../../elasticsearch/efcms-user-mappings'; import { efcmsWorkItemIndex } from '../../../elasticsearch/efcms-work-item-mappings'; import { getIndexNameForRecord } from './getIndexNameForRecord'; @@ -55,18 +54,6 @@ describe('getIndexNameForRecord', () => { expect(result).toEqual(efcmsDocketEntryIndex); }); - it('returns efcms-message for CaseMessageMapping records', () => { - const record = { - entityName: { - S: 'CaseMessageMapping', - }, - }; - - const result = getIndexNameForRecord(record); - - expect(result).toEqual(efcmsMessageIndex); - }); - it('returns efcms-user for User records', () => { const record = { entityName: { @@ -157,18 +144,6 @@ describe('getIndexNameForRecord', () => { expect(result).toEqual(efcmsUserIndex); }); - it('returns efcms-message for Message records', () => { - const record = { - entityName: { - S: 'Message', - }, - }; - - const result = getIndexNameForRecord(record); - - expect(result).toEqual(efcmsMessageIndex); - }); - it('returns efcms-case-deadline for CaseDeadline records', () => { const record = { entityName: { diff --git a/web-api/src/persistence/elasticsearch/getIndexNameForRecord.ts b/web-api/src/persistence/elasticsearch/getIndexNameForRecord.ts index 4ef56dd07dc..6dc98ee2107 100644 --- a/web-api/src/persistence/elasticsearch/getIndexNameForRecord.ts +++ b/web-api/src/persistence/elasticsearch/getIndexNameForRecord.ts @@ -1,7 +1,6 @@ import { efcmsCaseDeadlineIndex } from '../../../elasticsearch/efcms-case-deadline-mappings'; import { efcmsCaseIndex } from '../../../elasticsearch/efcms-case-mappings'; import { efcmsDocketEntryIndex } from '../../../elasticsearch/efcms-docket-entry-mappings'; -import { efcmsMessageIndex } from '../../../elasticsearch/efcms-message-mappings'; import { efcmsUserIndex } from '../../../elasticsearch/efcms-user-mappings'; import { efcmsWorkItemIndex } from '../../../elasticsearch/efcms-work-item-mappings'; import { isObject, isString } from 'lodash'; @@ -36,10 +35,6 @@ const isRecordOfType = (record, type) => { return true; } - if (type == 'Message' && entityName === 'CaseMessageMapping') { - return true; - } - if (type == 'WorkItem' && entityName === 'CaseWorkItemMapping') { return true; } @@ -65,8 +60,6 @@ export const getIndexNameForRecord = record => { index = efcmsDocketEntryIndex; } else if (isRecordOfType(record, 'User')) { index = efcmsUserIndex; - } else if (isRecordOfType(record, 'Message')) { - index = efcmsMessageIndex; } else if (isRecordOfType(record, 'CaseDeadline')) { index = efcmsCaseDeadlineIndex; } else if (isRecordOfType(record, 'WorkItem')) { diff --git a/web-api/src/persistence/elasticsearch/helpers/getIndexName.test.ts b/web-api/src/persistence/elasticsearch/helpers/getIndexName.test.ts index 726e107e36d..7b37e5ffb4d 100644 --- a/web-api/src/persistence/elasticsearch/helpers/getIndexName.test.ts +++ b/web-api/src/persistence/elasticsearch/helpers/getIndexName.test.ts @@ -1,7 +1,6 @@ import { efcmsCaseDeadlineIndex } from '../../../../elasticsearch/efcms-case-deadline-mappings'; import { efcmsCaseIndex } from '../../../../elasticsearch/efcms-case-mappings'; import { efcmsDocketEntryIndex } from '../../../../elasticsearch/efcms-docket-entry-mappings'; -import { efcmsMessageIndex } from '../../../../elasticsearch/efcms-message-mappings'; import { efcmsUserIndex } from '../../../../elasticsearch/efcms-user-mappings'; import { efcmsWorkItemIndex } from '../../../../elasticsearch/efcms-work-item-mappings'; import { updateIndex } from './getIndexName'; @@ -38,13 +37,6 @@ describe('updateIndex', () => { expect(mockSearchParameters.index).not.toEqual('efcms-docket-entry'); expect(mockSearchParameters.index).toEqual(efcmsDocketEntryIndex); }); - it('transforms efcms-message into the correct index name', () => { - const mockSearchParameters = { index: 'efcms-message' }; - updateIndex({ searchParameters: mockSearchParameters }); - expect(mockSearchParameters.index.match(/-/g)!.length).toEqual(2); - expect(mockSearchParameters.index).not.toEqual('efcms-message'); - expect(mockSearchParameters.index).toEqual(efcmsMessageIndex); - }); it('transforms efcms-user into the correct index name', () => { const mockSearchParameters = { index: 'efcms-user' }; updateIndex({ searchParameters: mockSearchParameters }); diff --git a/web-api/src/persistence/elasticsearch/searchClient.test.constants.ts b/web-api/src/persistence/elasticsearch/searchClient.test.constants.ts index 8794994333c..6e997272cd3 100644 --- a/web-api/src/persistence/elasticsearch/searchClient.test.constants.ts +++ b/web-api/src/persistence/elasticsearch/searchClient.test.constants.ts @@ -1,7 +1,6 @@ /* eslint-disable max-lines */ import { efcmsCaseIndex } from '../../../elasticsearch/efcms-case-mappings'; import { efcmsDocketEntryIndex } from '../../../elasticsearch/efcms-docket-entry-mappings'; -import { efcmsMessageIndex } from '../../../elasticsearch/efcms-message-mappings'; import { efcmsWorkItemIndex } from '../../../elasticsearch/efcms-work-item-mappings'; export const emptyResults = { @@ -234,150 +233,6 @@ export const mockDocketEntrySearchResult = { }, }; -export const mockMessageSearchResult = { - body: { - _shards: { - failed: 0, - skipped: 0, - successful: 1, - total: 1, - }, - hits: { - hits: [ - { - _id: 'case|312-21_message|25100ec6-eeeb-4e88-872f-c99fad1fe6c7', - _index: efcmsMessageIndex, - _routing: 'case|312-21_case|312-21|mapping', - _score: null, - _source: { - attachments: { - L: [ - { - M: { - documentId: { - S: '4227bd1d-4bcf-46b0-942f-445cd8024bbe', - }, - }, - }, - { - M: { - documentId: { - S: '67ce8e4d-a64c-41a4-9857-b8ca7ae6b876', - }, - }, - }, - ], - }, - case_relations: { - name: 'message', - parent: 'case|312-21_case|312-21|mapping', - }, - caseStatus: { - S: 'Closed', - }, - caseTitle: { - S: 'Case 312-21', - }, - createdAt: { - S: '2021-09-02T03:00:45.330Z', - }, - docketNumber: { - S: '312-21', - }, - docketNumberWithSuffix: { - S: '312-21', - }, - entityName: { - S: 'Message', - }, - from: { - S: 'Buch', - }, - fromSection: { - S: 'buchsChambers', - }, - fromUserId: { - S: '06b6fb09-889f-427d-9d45-b99023f6539b', - }, - gsi1pk: { - S: 'message|25100ec6-eeeb-4e88-872f-c99fad1fe6c7', - }, - isCompleted: { - BOOL: false, - }, - isRead: { - BOOL: true, - }, - isRepliedTo: { - BOOL: true, - }, - message: { - S: 'Thanks!', - }, - messageId: { - S: '25100ec6-eeeb-4e88-872f-c99fad1fe6c7', - }, - parentMessageId: { - S: '25100ec6-eeeb-4e88-872f-c99fad1fe6c7', - }, - pk: { - S: 'case|312-21', - }, - sk: { - S: 'message|25100ec6-eeeb-4e88-872f-c99fad1fe6c7', - }, - subject: { - S: 'Order', - }, - to: { - S: 'Docket Clerk 1', - }, - toSection: { - S: 'buchsChambers', - }, - toUserId: { - S: 'b6570a72-f6df-4f41-8256-ea2edb51d665', - }, - }, - _type: '_doc', - inner_hits: { - 'case-mappings': { - hits: { - hits: [ - { - _id: 'case|312-21_case|312-21|mapping', - _index: efcmsMessageIndex, - _score: 1, - _source: { - leadDocketNumber: { - S: '312-21', - }, - }, - _type: '_doc', - }, - ], - max_score: 1, - total: { - relation: 'eq', - value: 1, - }, - }, - }, - }, - sort: [1629483399420], - }, - ], - max_score: null, - total: { - relation: 'eq', - value: 1, - }, - }, - timed_out: false, - took: 5, - }, -}; - export const mockWorkItemSearchResult = { body: { _shards: { diff --git a/web-api/src/persistence/elasticsearch/searchClient.test.ts b/web-api/src/persistence/elasticsearch/searchClient.test.ts index d192c59c8ed..1dd0eb760e7 100644 --- a/web-api/src/persistence/elasticsearch/searchClient.test.ts +++ b/web-api/src/persistence/elasticsearch/searchClient.test.ts @@ -6,7 +6,6 @@ import { mockCaseSearchResult, mockDocketEntrySearchResult, mockMalformedQueryResult, - mockMessageSearchResult, mockNonexistentDocumentCountResult, mockOpenCasesReceivedOnJulyFourthCountResult, mockOpenCasesReceivedOnJulyFourthFormattedResults, @@ -411,22 +410,6 @@ describe('searchClient', () => { expect(formatDocketEntryResult).toHaveBeenCalledTimes(1); }); - it('search should format and return the list of results when they are message search results', async () => { - applicationContext - .getSearchClient() - .search.mockReturnValue(mockMessageSearchResult); - - await search({ - applicationContext, - searchParameters: {}, - }); - - expect(applicationContext.getSearchClient().search).toHaveBeenCalledTimes( - 1, - ); - expect(formatMessageResult).toHaveBeenCalledTimes(1); - }); - it('should format and return the list of results when they are work item search results', async () => { applicationContext .getSearchClient() diff --git a/web-api/src/persistence/postgres/cases/updateCase.ts b/web-api/src/persistence/postgres/cases/updateCase.ts new file mode 100644 index 00000000000..d5759782719 --- /dev/null +++ b/web-api/src/persistence/postgres/cases/updateCase.ts @@ -0,0 +1,7 @@ +import { AppDataSource } from '@web-api/data-source'; +import { Case } from '@web-api/persistence/repository/Case'; + +export async function updateCase(caseToUpdate: Case) { + const caseRepository = AppDataSource.getRepository(Case); + await caseRepository.save(caseToUpdate); +} diff --git a/web-api/storage/fixtures/seed/efcms-local.json b/web-api/storage/fixtures/seed/efcms-local.json index 21a6d0a6939..5ff1310e44b 100644 --- a/web-api/storage/fixtures/seed/efcms-local.json +++ b/web-api/storage/fixtures/seed/efcms-local.json @@ -12386,35 +12386,7 @@ "pk": "case|103-20", "docketNumber": "103-20" }, - { - "attachments": [ - { - "documentId": "4796a931-14fb-43e6-948f-d2b67ce4c1cb" - } - ], - "isRepliedTo": false, - "caseStatus": "Calendared", - "fromUserId": "9d7d63b7-d7a5-4905-ba89-ef71bf30057f", - "subject": "Administrative Record", - "toSection": "petitions", - "gsi1pk": "message|1d4c1fd9-5265-4e46-894f-b8426d3a6836", - "caseTitle": "Reuben Blair", - "isRead": false, - "messageId": "1d4c1fd9-5265-4e46-894f-b8426d3a6836", - "message": "Could you please review this?", - "toUserId": "3805d1ab-18d0-43ec-bafb-654e83405416", - "createdAt": "2023-06-02T21:15:50.105Z", - "entityName": "Message", - "parentMessageId": "1d4c1fd9-5265-4e46-894f-b8426d3a6836", - "sk": "message|1d4c1fd9-5265-4e46-894f-b8426d3a6836", - "docketNumberWithSuffix": "103-20L", - "from": "Test Admissions Clerk", - "to": "Test Petitionsclerk", - "pk": "case|103-20", - "fromSection": "admissions", - "docketNumber": "103-20", - "isCompleted": false - }, + { "role": "privatePractitioner", "serviceIndicator": "Electronic", @@ -13680,35 +13652,6 @@ "documentTitle": "Petition", "docketNumber": "104-19" }, - { - "attachments": [ - { - "documentId": "8ed9bad9-db58-43c8-b03f-c2e3ad92995f" - } - ], - "isRepliedTo": false, - "caseStatus": "New", - "fromUserId": "1805d1ab-18d0-43ec-bafb-654e83405416", - "subject": "Order", - "toSection": "docket", - "gsi1pk": "message|2d1191d3-4597-454a-a2b2-84e267ccf01e", - "caseTitle": "Mufutau Wade", - "isRead": false, - "messageId": "2d1191d3-4597-454a-a2b2-84e267ccf01e", - "message": "Test message with deleted document.", - "toUserId": "1805d1ab-18d0-43ec-bafb-654e83405416", - "createdAt": "2020-08-18T18:07:36.333Z", - "entityName": "Message", - "sk": "message|2d1191d3-4597-454a-a2b2-84e267ccf01e", - "parentMessageId": "2d1191d3-4597-454a-a2b2-84e267ccf01e", - "docketNumberWithSuffix": "104-19", - "from": "Test Docketclerk", - "pk": "case|104-19", - "to": "Test Docketclerk", - "fromSection": "docket", - "docketNumber": "104-19", - "isCompleted": false - }, { "associatedJudge": "Chief Judge", "isSealed": false, @@ -15124,31 +15067,6 @@ "servedAt": "2020-09-25T19:27:16.469Z", "docketNumber": "105-20" }, - { - "isRepliedTo": false, - "attachments": [], - "caseStatus": "General Docket - Not at Issue", - "fromUserId": "3805d1ab-18d0-43ec-bafb-654e83405416", - "subject": "message to myself", - "toSection": "petitions", - "gsi1pk": "message|eb0a139a-8951-4de1-8b83-f02a27504105", - "caseTitle": "Bill Burr", - "isRead": false, - "messageId": "eb0a139a-8951-4de1-8b83-f02a27504105", - "message": "hello!", - "toUserId": "3805d1ab-18d0-43ec-bafb-654e83405416", - "createdAt": "2020-06-05T18:02:25.280Z", - "entityName": "Message", - "sk": "message|eb0a139a-8951-4de1-8b83-f02a27504105", - "parentMessageId": "eb0a139a-8951-4de1-8b83-f02a27504105", - "docketNumberWithSuffix": "105-20L", - "from": "Test Petitionsclerk", - "pk": "case|105-20", - "to": "Test Petitionsclerk", - "fromSection": "petitions", - "docketNumber": "105-20", - "isCompleted": false - }, { "role": "privatePractitioner", "representing": ["7805d1ab-18d0-43ec-bafb-654e83405416"], From 5036c6dde256824d9936e1e6f6f4f68068be69e3 Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Thu, 18 Jul 2024 12:08:44 -0600 Subject: [PATCH 15/30] 10391: update so e2e tests run --- .github/workflows/e2e-cypress.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/e2e-cypress.yml b/.github/workflows/e2e-cypress.yml index 4f6bffd2939..ff46a5ba15d 100644 --- a/.github/workflows/e2e-cypress.yml +++ b/.github/workflows/e2e-cypress.yml @@ -50,7 +50,7 @@ jobs: run: npm ci - name: Seed Postgres run: | - npm run typeorm:seed + npm run seed:postgres - name: Run E2E Cypress run: | mkdir -p /tmp/cypress/ From fdc3290fe6ccf73552076841d6f1fb2facf8108c Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Thu, 18 Jul 2024 12:34:08 -0600 Subject: [PATCH 16/30] 10391: fix additional cypress tests --- .github/workflows/e2e-cypress-accessibility.yml | 15 +++++++++++++++ .github/workflows/e2e-cypress-public.yml | 15 +++++++++++++++ .../workflows/e2e-cypress-smoketests-local.yml | 15 +++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/.github/workflows/e2e-cypress-accessibility.yml b/.github/workflows/e2e-cypress-accessibility.yml index fc5f69b71d8..f7b087e237c 100644 --- a/.github/workflows/e2e-cypress-accessibility.yml +++ b/.github/workflows/e2e-cypress-accessibility.yml @@ -16,6 +16,18 @@ jobs: CI: true CI_NODE_TOTAL: ${{ matrix.ci_node_total }} CI_NODE_INDEX: ${{ matrix.ci_node_index }} + services: + postgres: + image: postgres + env: + POSTGRES_PASSWORD: example + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -36,6 +48,9 @@ jobs: comment_on_pr: false - name: Install Node Dependencies run: npm ci + - name: Seed Postgres + run: | + npm run seed:postgres - name: Run E2E Cypress run: | mkdir -p /tmp/cypress/ diff --git a/.github/workflows/e2e-cypress-public.yml b/.github/workflows/e2e-cypress-public.yml index 9b1aff14822..088a8e077c4 100644 --- a/.github/workflows/e2e-cypress-public.yml +++ b/.github/workflows/e2e-cypress-public.yml @@ -10,6 +10,18 @@ jobs: env: CI: true CHECK_DEPLOY_DATE_INTERVAL: 5000 + services: + postgres: + image: postgres + env: + POSTGRES_PASSWORD: example + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -30,6 +42,9 @@ jobs: comment_on_pr: false - name: Install Node Dependencies run: npm ci + - name: Seed Postgres + run: | + npm run seed:postgres - name: Run E2E Cypress run: | mkdir -p /tmp/cypress/ diff --git a/.github/workflows/e2e-cypress-smoketests-local.yml b/.github/workflows/e2e-cypress-smoketests-local.yml index 9e4e8e7a321..442eeb292fb 100644 --- a/.github/workflows/e2e-cypress-smoketests-local.yml +++ b/.github/workflows/e2e-cypress-smoketests-local.yml @@ -9,6 +9,18 @@ jobs: env: CI: true + services: + postgres: + image: postgres + env: + POSTGRES_PASSWORD: example + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -35,6 +47,9 @@ jobs: comment_on_pr: false - name: Install Node Dependencies run: npm ci + - name: Seed Postgres + run: | + npm run seed:postgres - name: Run E2E Cypress Smoketests run: | mkdir -p /tmp/cypress/ From 139c3147e239f61bf88bd53874c7822cef429bd2 Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Thu, 18 Jul 2024 12:43:35 -0600 Subject: [PATCH 17/30] 10391: Add postgres seed step for integration tests --- .github/workflows/client-integration-public.yml | 15 +++++++++++++++ .github/workflows/client-integration.yml | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/.github/workflows/client-integration-public.yml b/.github/workflows/client-integration-public.yml index d831162f6c7..2d2527c3405 100644 --- a/.github/workflows/client-integration-public.yml +++ b/.github/workflows/client-integration-public.yml @@ -15,6 +15,18 @@ jobs: env: CI_NODE_TOTAL: ${{ matrix.ci_node_total }} CI_NODE_INDEX: ${{ matrix.ci_node_index }} + services: + postgres: + image: postgres + env: + POSTGRES_PASSWORD: example + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -41,6 +53,9 @@ jobs: comment_on_pr: false - name: Install Node Dependencies run: npm ci + - name: Seed Postgres + run: | + npm run seed:postgres - name: Web Client - Integration Tests Public run: | mkdir -p /tmp/web-client diff --git a/.github/workflows/client-integration.yml b/.github/workflows/client-integration.yml index f41e5bf1337..b488bf13aa6 100644 --- a/.github/workflows/client-integration.yml +++ b/.github/workflows/client-integration.yml @@ -15,6 +15,18 @@ jobs: env: CI_NODE_TOTAL: ${{ matrix.ci_node_total }} CI_NODE_INDEX: ${{ matrix.ci_node_index }} + services: + postgres: + image: postgres + env: + POSTGRES_PASSWORD: example + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -41,6 +53,9 @@ jobs: comment_on_pr: false - name: Install Node Dependencies run: npm ci + - name: Seed Postgres + run: | + npm run seed:postgres - name: Web Client - Integration Tests run: | mkdir -p /tmp/web-client From 1023c0d5531dc059f94abfac3a4da8fa29e1134c Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Thu, 18 Jul 2024 14:01:06 -0600 Subject: [PATCH 18/30] 10391: wip for rds tf setup --- web-api/terraform/applyables/allColors/allColors.tf | 5 +++++ web-api/terraform/modules/rds/rds.tf | 13 +++++++++++++ web-api/terraform/modules/rds/variables.tf | 13 +++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 web-api/terraform/modules/rds/rds.tf create mode 100644 web-api/terraform/modules/rds/variables.tf diff --git a/web-api/terraform/applyables/allColors/allColors.tf b/web-api/terraform/applyables/allColors/allColors.tf index 52c568e886f..3c2add2c87a 100644 --- a/web-api/terraform/applyables/allColors/allColors.tf +++ b/web-api/terraform/applyables/allColors/allColors.tf @@ -114,3 +114,8 @@ module "ui-healthcheck" { alarm_name = "app.${var.dns_domain} is accessible over HTTPS" dns_domain = "app.${var.dns_domain}" } + +module "rds" { + source = "../../modules/rds" + environment = var.environment +} diff --git a/web-api/terraform/modules/rds/rds.tf b/web-api/terraform/modules/rds/rds.tf new file mode 100644 index 00000000000..21401fd070f --- /dev/null +++ b/web-api/terraform/modules/rds/rds.tf @@ -0,0 +1,13 @@ + + +resource "aws_db_instance" "postgres" { + allocated_storage = 20 + engine = "postgres" + engine_version = "16.3" + instance_class = "db.t4g.small" + db_name = "${var.environment}_dawson" + username = var.db_username + password = var.db_password + parameter_group_name = "default.postgres12" + skip_final_snapshot = true +} diff --git a/web-api/terraform/modules/rds/variables.tf b/web-api/terraform/modules/rds/variables.tf new file mode 100644 index 00000000000..f1b9731a9bc --- /dev/null +++ b/web-api/terraform/modules/rds/variables.tf @@ -0,0 +1,13 @@ +variable "db_username" { + type = string + default = "mydbuser" +} + +variable "db_password" { + type = string + default = "mypassword" +} + +variable "environment" { + type = string +} From b0cff43c7ae45afe52d38771ad591d78013c0ae1 Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Thu, 18 Jul 2024 15:56:04 -0600 Subject: [PATCH 19/30] 10391: wip postgres tf --- web-api/terraform/modules/rds/rds.tf | 113 +++++++++++++++++++-- web-api/terraform/modules/rds/variables.tf | 6 +- 2 files changed, 105 insertions(+), 14 deletions(-) diff --git a/web-api/terraform/modules/rds/rds.tf b/web-api/terraform/modules/rds/rds.tf index 21401fd070f..9794ef72e7c 100644 --- a/web-api/terraform/modules/rds/rds.tf +++ b/web-api/terraform/modules/rds/rds.tf @@ -1,13 +1,106 @@ +resource "aws_db_instance" "postgres" { + allocated_storage = 20 + engine = "postgres" + engine_version = "16.3" + instance_class = "db.t4g.small" + db_name = "${var.environment}_dawson" + username = var.environment.POSTGRES_USERNAME + password = var.environment.POSTGRES_PASSWORD + parameter_group_name = aws_db_parameter_group.postgres.name + vpc_security_group_ids = [aws_security_group.db.id] + skip_final_snapshot = true +} +resource "aws_db_parameter_group" "postgres" { + name = "postgres" + family = "postgres16" -resource "aws_db_instance" "postgres" { - allocated_storage = 20 - engine = "postgres" - engine_version = "16.3" - instance_class = "db.t4g.small" - db_name = "${var.environment}_dawson" - username = var.db_username - password = var.db_password - parameter_group_name = "default.postgres12" - skip_final_snapshot = true + parameter { + name = "log_connections" + value = "1" + } } + +# TODO Additional resources + +# resource "aws_db_subnet_group" "postgres" { +# name = "main-subnet-group" +# subnet_ids = [aws_subnet.private.id] + +# tags = { +# Name = "main-subnet-group" +# } +# } + +# resource "aws_security_group" "postgres" { +# vpc_id = aws_vpc.main.id + +# ingress { +# from_port = 3306 +# to_port = 3306 +# protocol = "tcp" +# cidr_blocks = ["your-ip-address/32"] +# } + +# egress { +# from_port = 0 +# to_port = 0 +# protocol = "-1" +# cidr_blocks = ["0.0.0.0/0"] +# } + +# tags = { +# Name = "db-security-group" +# } +# } + +# resource "aws_route_table_association" "public" { +# subnet_id = aws_subnet.public.id +# route_table_id = aws_route_table.public.id +# } + +# # Create a VPC +# resource "aws_vpc" "main" { +# cidr_block = "10.0.0.0/16" +# enable_dns_support = true +# enable_dns_hostnames = true + +# tags = { +# Name = "main-vpc" +# } +# } + +# resource "aws_subnet" "postgres-public" { +# vpc_id = aws_vpc.main.id +# cidr_block = "10.0.1.0/24" +# map_public_ip_on_launch = true +# availability_zone = "your-region-a" + +# tags = { +# Name = "public-subnet" +# } +# } + + +# resource "aws_subnet" "postgres-private" { +# vpc_id = aws_vpc.main.id +# cidr_block = "10.0.2.0/24" +# availability_zone = "your-region-a" + +# tags = { +# Name = "private-subnet" +# } +# } + +# resource "aws_internet_gateway" "postgres" { +# vpc_id = aws_vpc.postgres.id +# } + +# resource "aws_route_table" "postgres" { +# vpc_id = aws_vpc.postgres.id + +# route { +# cidr_block = "0.0.0.0/0" +# gateway_id = aws_internet_gateway.postgres.id +# } +# } diff --git a/web-api/terraform/modules/rds/variables.tf b/web-api/terraform/modules/rds/variables.tf index f1b9731a9bc..8bc0eea0a7b 100644 --- a/web-api/terraform/modules/rds/variables.tf +++ b/web-api/terraform/modules/rds/variables.tf @@ -1,11 +1,9 @@ variable "db_username" { - type = string - default = "mydbuser" + type = string } variable "db_password" { - type = string - default = "mypassword" + type = string } variable "environment" { From e0a395a3d04e29e279d6617a255bd02efd824b58 Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Fri, 19 Jul 2024 12:40:44 -0600 Subject: [PATCH 20/30] 10391: Prepare for Hosted Env Deployment --- run-api.sh | 3 ++- run-local.sh | 1 + setup-local-env.sh | 3 +++ web-api/src/data-source.ts | 9 +++++---- .../applyables/allColors/allColors.tf | 6 ++++-- .../applyables/allColors/variables.tf | 8 ++++++++ .../terraform/bin/deploy-app-all-colors.sh | 2 ++ web-api/terraform/modules/rds/rds.tf | 20 +++++++++---------- web-api/terraform/modules/rds/variables.tf | 4 ++-- 9 files changed, 37 insertions(+), 19 deletions(-) diff --git a/run-api.sh b/run-api.sh index 80d17f0f6c5..c7022f358d0 100755 --- a/run-api.sh +++ b/run-api.sh @@ -26,7 +26,6 @@ S3RVER_PID=$! URL=http://0.0.0.0:9001/ ./wait-until.sh npm run seed:s3 - if [ -n "${RESUME}" ]; then echo "Resuming operation with previous s3 and dynamo data" else @@ -39,6 +38,8 @@ if [ "${exitCode}" != 0 ]; then echo "Failed to seed data!". 1>&2 && exit 1 fi +npm run typeorm:migrations:migrate +npm run seed:postgres if [[ -z "${RUN_DIR}" ]]; then RUN_DIR="src" diff --git a/run-local.sh b/run-local.sh index 79b5e619207..e32acddd8af 100755 --- a/run-local.sh +++ b/run-local.sh @@ -49,6 +49,7 @@ else fi fi +npm run typeorm:migrations:migrate npm run seed:postgres echo "Seeding cognito-local users" diff --git a/setup-local-env.sh b/setup-local-env.sh index 2a8c83e03ba..352fe789cc1 100755 --- a/setup-local-env.sh +++ b/setup-local-env.sh @@ -14,3 +14,6 @@ export USER_POOL_ID='local_2pHzece7' export COGNITO_CLIENT_ID='bvjrggnd3co403c0aahscinne' export DISABLE_EMAILS=true export ENV=local +export POSTGRES_USERNAME='postgres' +export POSTGRES_PASSWORD='example' +export POSTGRES_HOST='localhost' \ No newline at end of file diff --git a/web-api/src/data-source.ts b/web-api/src/data-source.ts index d0ee78f32a4..8d28983ec5d 100644 --- a/web-api/src/data-source.ts +++ b/web-api/src/data-source.ts @@ -3,18 +3,19 @@ import { Case } from '@web-api/persistence/repository/Case'; import { DataSource } from 'typeorm'; import { Message } from './persistence/repository/Message'; +console.log('*** pass', process.env.POSTGRES_PASSWORD); + export const AppDataSource = new DataSource({ database: 'postgres', entities: [Message, Case], - host: 'localhost', + host: process.env.POSTGRES_HOST, logging: true, migrations: ['postgres/migrations/*.ts'], - password: 'example', + password: process.env.POSTGRES_PASSWORD, port: 5432, subscribers: [], - synchronize: true, type: 'postgres', - username: 'postgres', + username: process.env.POSTGRES_USERNAME, }); const dataSource = AppDataSource.initialize().then(() => AppDataSource); diff --git a/web-api/terraform/applyables/allColors/allColors.tf b/web-api/terraform/applyables/allColors/allColors.tf index 3c2add2c87a..7137adccb85 100644 --- a/web-api/terraform/applyables/allColors/allColors.tf +++ b/web-api/terraform/applyables/allColors/allColors.tf @@ -116,6 +116,8 @@ module "ui-healthcheck" { } module "rds" { - source = "../../modules/rds" - environment = var.environment + source = "../../modules/rds" + environment = var.environment + postgres_username = var.postgres_username + postgres_password = var.postgres_password } diff --git a/web-api/terraform/applyables/allColors/variables.tf b/web-api/terraform/applyables/allColors/variables.tf index a47280609d1..d27e296ee4e 100644 --- a/web-api/terraform/applyables/allColors/variables.tf +++ b/web-api/terraform/applyables/allColors/variables.tf @@ -78,3 +78,11 @@ variable "viewer_protocol_policy" { default = "redirect-to-https" } +variable "postgres_username" { + type = string +} + +variable "postgres_password" { + type = string +} + diff --git a/web-api/terraform/bin/deploy-app-all-colors.sh b/web-api/terraform/bin/deploy-app-all-colors.sh index 094a7d0bf1f..737a8a51aae 100755 --- a/web-api/terraform/bin/deploy-app-all-colors.sh +++ b/web-api/terraform/bin/deploy-app-all-colors.sh @@ -98,6 +98,8 @@ export TF_VAR_is_dynamsoft_enabled=$IS_DYNAMSOFT_ENABLED export TF_VAR_dynamsoft_s3_zip_path=$DYNAMSOFT_S3_ZIP_PATH export TF_VAR_dynamsoft_url=$DYNAMSOFT_URL export TF_VAR_dynamsoft_product_keys=$DYNAMSOFT_PRODUCT_KEYS +export TF_VAR_postgres_username=$POSTGRES_USERNAME +export TF_VAR_postgres_password=$POSTGRES_PASSWORD if [[ -n "${CW_VIEWER_PROTOCOL_POLICY}" ]] then diff --git a/web-api/terraform/modules/rds/rds.tf b/web-api/terraform/modules/rds/rds.tf index 9794ef72e7c..7c825d00f67 100644 --- a/web-api/terraform/modules/rds/rds.tf +++ b/web-api/terraform/modules/rds/rds.tf @@ -1,14 +1,14 @@ resource "aws_db_instance" "postgres" { - allocated_storage = 20 - engine = "postgres" - engine_version = "16.3" - instance_class = "db.t4g.small" - db_name = "${var.environment}_dawson" - username = var.environment.POSTGRES_USERNAME - password = var.environment.POSTGRES_PASSWORD - parameter_group_name = aws_db_parameter_group.postgres.name - vpc_security_group_ids = [aws_security_group.db.id] - skip_final_snapshot = true + allocated_storage = 20 + engine = "postgres" + engine_version = "16.3" + instance_class = "db.t4g.small" + db_name = "${var.environment}_dawson" + username = var.postgres_username + password = var.postgres_password + parameter_group_name = aws_db_parameter_group.postgres.name + # vpc_security_group_ids = [aws_security_group.db.id] + skip_final_snapshot = true } resource "aws_db_parameter_group" "postgres" { diff --git a/web-api/terraform/modules/rds/variables.tf b/web-api/terraform/modules/rds/variables.tf index 8bc0eea0a7b..7fee973703a 100644 --- a/web-api/terraform/modules/rds/variables.tf +++ b/web-api/terraform/modules/rds/variables.tf @@ -1,8 +1,8 @@ -variable "db_username" { +variable "postgres_username" { type = string } -variable "db_password" { +variable "postgres_password" { type = string } From 3b99b347d8cacac15442f8050a4ffad59af7bbd4 Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Fri, 19 Jul 2024 12:41:37 -0600 Subject: [PATCH 21/30] 10391: remove console.log of password --- web-api/src/data-source.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/web-api/src/data-source.ts b/web-api/src/data-source.ts index 8d28983ec5d..eeac3ed1057 100644 --- a/web-api/src/data-source.ts +++ b/web-api/src/data-source.ts @@ -3,8 +3,6 @@ import { Case } from '@web-api/persistence/repository/Case'; import { DataSource } from 'typeorm'; import { Message } from './persistence/repository/Message'; -console.log('*** pass', process.env.POSTGRES_PASSWORD); - export const AppDataSource = new DataSource({ database: 'postgres', entities: [Message, Case], From fdef4470331f0eb2c3facc30dbe24a8754fef0c5 Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Fri, 19 Jul 2024 14:32:40 -0600 Subject: [PATCH 22/30] 10391: wip setup blue/green deployment --- web-api/terraform/applyables/allColors/outputs.tf | 4 ++++ web-api/terraform/applyables/blue/blue.tf | 3 +++ web-api/terraform/applyables/blue/variables.tf | 8 ++++++++ web-api/terraform/applyables/green/green.tf | 3 +++ web-api/terraform/applyables/green/variables.tf | 8 ++++++++ web-api/terraform/bin/deploy-app-color.sh | 2 ++ .../terraform/modules/ci-cd/ci-cd-permissions.tf | 15 +++++++++++++++ web-api/terraform/modules/rds/outputs.tf | 3 +++ web-api/terraform/modules/rds/rds.tf | 1 + 9 files changed, 47 insertions(+) create mode 100644 web-api/terraform/modules/rds/outputs.tf diff --git a/web-api/terraform/applyables/allColors/outputs.tf b/web-api/terraform/applyables/allColors/outputs.tf index 26d7b6c55c5..8383d3c70c8 100644 --- a/web-api/terraform/applyables/allColors/outputs.tf +++ b/web-api/terraform/applyables/allColors/outputs.tf @@ -45,4 +45,8 @@ output "aws_cognito_user_pool_id" { output "aws_cognito_user_pool_irs_id" { value = module.ef-cms_apis.aws_cognito_user_pool_irs_id +} + +output "rds_host_name" { + value = module.rds.endpoint } \ No newline at end of file diff --git a/web-api/terraform/applyables/blue/blue.tf b/web-api/terraform/applyables/blue/blue.tf index 811d741bbe4..ee4d0d700c0 100644 --- a/web-api/terraform/applyables/blue/blue.tf +++ b/web-api/terraform/applyables/blue/blue.tf @@ -78,6 +78,9 @@ resource "terraform_data" "locals" { STAGE = var.environment USER_POOL_ID = data.terraform_remote_state.remote.outputs.aws_cognito_user_pool_id USER_POOL_IRS_ID = data.terraform_remote_state.remote.outputs.aws_cognito_user_pool_irs_id + POSTGRES_HOST = data.terraform_remote_state.remote.outputs.rds_host_name + POSTGRES_USERNAME = var.postgres_username + POSTGRES_PASSWORD = var.postgres_password } } diff --git a/web-api/terraform/applyables/blue/variables.tf b/web-api/terraform/applyables/blue/variables.tf index 5a7ecaf8af2..cbf29075767 100644 --- a/web-api/terraform/applyables/blue/variables.tf +++ b/web-api/terraform/applyables/blue/variables.tf @@ -80,3 +80,11 @@ variable "viewer_protocol_policy" { default = "redirect-to-https" } +variable "postgres_username" { + type = string +} + +variable "postgres_password" { + type = string +} + diff --git a/web-api/terraform/applyables/green/green.tf b/web-api/terraform/applyables/green/green.tf index a1ca8308580..d1884a68b90 100644 --- a/web-api/terraform/applyables/green/green.tf +++ b/web-api/terraform/applyables/green/green.tf @@ -78,6 +78,9 @@ resource "terraform_data" "locals" { STAGE = var.environment USER_POOL_ID = data.terraform_remote_state.remote.outputs.aws_cognito_user_pool_id USER_POOL_IRS_ID = data.terraform_remote_state.remote.outputs.aws_cognito_user_pool_irs_id + POSTGRES_HOST = data.terraform_remote_state.remote.outputs.rds_host_name + POSTGRES_USERNAME = var.postgres_username + POSTGRES_PASSWORD = var.postgres_password } } diff --git a/web-api/terraform/applyables/green/variables.tf b/web-api/terraform/applyables/green/variables.tf index 27e13c7bd99..a17221b7966 100644 --- a/web-api/terraform/applyables/green/variables.tf +++ b/web-api/terraform/applyables/green/variables.tf @@ -79,3 +79,11 @@ variable "viewer_protocol_policy" { type = string default = "redirect-to-https" } + +variable "postgres_username" { + type = string +} + +variable "postgres_password" { + type = string +} diff --git a/web-api/terraform/bin/deploy-app-color.sh b/web-api/terraform/bin/deploy-app-color.sh index f8fdcdf5cfd..66d593151e6 100755 --- a/web-api/terraform/bin/deploy-app-color.sh +++ b/web-api/terraform/bin/deploy-app-color.sh @@ -129,6 +129,8 @@ export TF_VAR_scanner_resource_uri=$SCANNER_RESOURCE_URI export TF_VAR_slack_webhook_url=$SLACK_WEBHOOK_URL export TF_VAR_green_elasticsearch_domain=$GREEN_ELASTICSEARCH_DOMAIN export TF_VAR_green_table_name=$GREEN_TABLE_NAME +export TF_VAR_postgres_username=$POSTGRES_USERNAME +export TF_VAR_postgres_password=$POSTGRES_PASSWORD if [[ -n "${CW_VIEWER_PROTOCOL_POLICY}" ]] then diff --git a/web-api/terraform/modules/ci-cd/ci-cd-permissions.tf b/web-api/terraform/modules/ci-cd/ci-cd-permissions.tf index 7231fae22f8..943dfb9f31b 100644 --- a/web-api/terraform/modules/ci-cd/ci-cd-permissions.tf +++ b/web-api/terraform/modules/ci-cd/ci-cd-permissions.tf @@ -221,6 +221,21 @@ resource "aws_iam_policy" "ci_cd_policy" { "arn:aws:secretsmanager:*:*:secret:*_deploy*" ] }, + { + "Sid": "RDS", + "Effect": "Allow", + "Action": [ + "rds:DescribeDBParameterGroups", + "rds:DescribeDBParameters", + "rds:ListTagsForResource", + "rds:DescribeDBInstances", + "rds:ModifyDBInstance" + ], + "Resource": [ + "arn:aws:rds:us-east-1:${data.aws_caller_identity.current.account_id}:pg:postgres", + "arn:aws:rds:us-east-1:${data.aws_caller_identity.current.account_id}:db:*" + ] + }, { "Action": [ "ecs:CreateCluster", diff --git a/web-api/terraform/modules/rds/outputs.tf b/web-api/terraform/modules/rds/outputs.tf new file mode 100644 index 00000000000..55993021969 --- /dev/null +++ b/web-api/terraform/modules/rds/outputs.tf @@ -0,0 +1,3 @@ +output "endpoint" { + value = aws_db_instance.postgres.endpoint +} diff --git a/web-api/terraform/modules/rds/rds.tf b/web-api/terraform/modules/rds/rds.tf index 7c825d00f67..959e32e27a3 100644 --- a/web-api/terraform/modules/rds/rds.tf +++ b/web-api/terraform/modules/rds/rds.tf @@ -9,6 +9,7 @@ resource "aws_db_instance" "postgres" { parameter_group_name = aws_db_parameter_group.postgres.name # vpc_security_group_ids = [aws_security_group.db.id] skip_final_snapshot = true + publicly_accessible = true } resource "aws_db_parameter_group" "postgres" { From b1957daddba2dd97e83ac8f09c91dfd73f53222e Mon Sep 17 00:00:00 2001 From: Cody Seibert Date: Mon, 22 Jul 2024 12:22:58 -0400 Subject: [PATCH 23/30] 10391 - attempt to add public rds certs --- public-certs/us-east-1-bundle.pem | 124 ++++++++++++++++++ web-api/src/data-source.ts | 6 + .../modules/lambda/esbuildLambda.mjs | 4 + 3 files changed, 134 insertions(+) create mode 100644 public-certs/us-east-1-bundle.pem diff --git a/public-certs/us-east-1-bundle.pem b/public-certs/us-east-1-bundle.pem new file mode 100644 index 00000000000..881d0946e57 --- /dev/null +++ b/public-certs/us-east-1-bundle.pem @@ -0,0 +1,124 @@ +-----BEGIN CERTIFICATE----- +MIIEBjCCAu6gAwIBAgIJAMc0ZzaSUK51MA0GCSqGSIb3DQEBCwUAMIGPMQswCQYD +VQQGEwJVUzEQMA4GA1UEBwwHU2VhdHRsZTETMBEGA1UECAwKV2FzaGluZ3RvbjEi +MCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1h +em9uIFJEUzEgMB4GA1UEAwwXQW1hem9uIFJEUyBSb290IDIwMTkgQ0EwHhcNMTkw +ODIyMTcwODUwWhcNMjQwODIyMTcwODUwWjCBjzELMAkGA1UEBhMCVVMxEDAOBgNV +BAcMB1NlYXR0bGUxEzARBgNVBAgMCldhc2hpbmd0b24xIjAgBgNVBAoMGUFtYXpv +biBXZWIgU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxIDAeBgNV +BAMMF0FtYXpvbiBSRFMgUm9vdCAyMDE5IENBMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEArXnF/E6/Qh+ku3hQTSKPMhQQlCpoWvnIthzX6MK3p5a0eXKZ +oWIjYcNNG6UwJjp4fUXl6glp53Jobn+tWNX88dNH2n8DVbppSwScVE2LpuL+94vY +0EYE/XxN7svKea8YvlrqkUBKyxLxTjh+U/KrGOaHxz9v0l6ZNlDbuaZw3qIWdD/I +6aNbGeRUVtpM6P+bWIoxVl/caQylQS6CEYUk+CpVyJSkopwJlzXT07tMoDL5WgX9 +O08KVgDNz9qP/IGtAcRduRcNioH3E9v981QO1zt/Gpb2f8NqAjUUCUZzOnij6mx9 +McZ+9cWX88CRzR0vQODWuZscgI08NvM69Fn2SQIDAQABo2MwYTAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUc19g2LzLA5j0Kxc0LjZa +pmD/vB8wHwYDVR0jBBgwFoAUc19g2LzLA5j0Kxc0LjZapmD/vB8wDQYJKoZIhvcN +AQELBQADggEBAHAG7WTmyjzPRIM85rVj+fWHsLIvqpw6DObIjMWokpliCeMINZFV +ynfgBKsf1ExwbvJNzYFXW6dihnguDG9VMPpi2up/ctQTN8tm9nDKOy08uNZoofMc +NUZxKCEkVKZv+IL4oHoeayt8egtv3ujJM6V14AstMQ6SwvwvA93EP/Ug2e4WAXHu +cbI1NAbUgVDqp+DRdfvZkgYKryjTWd/0+1fS8X1bBZVWzl7eirNVnHbSH2ZDpNuY +0SBd8dj5F6ld3t58ydZbrTHze7JJOd8ijySAp4/kiu9UfZWuTPABzDa/DSdz9Dk/ +zPW4CXXvhLmE02TA9/HeCw3KEHIwicNuEfw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEBzCCAu+gAwIBAgICJVUwDQYJKoZIhvcNAQELBQAwgY8xCzAJBgNVBAYTAlVT +MRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK +DBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT +MSAwHgYDVQQDDBdBbWF6b24gUkRTIFJvb3QgMjAxOSBDQTAeFw0xOTA5MTkxODE2 +NTNaFw0yNDA4MjIxNzA4NTBaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2Fz +aGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBT +ZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzElMCMGA1UEAwwcQW1h +em9uIFJEUyB1cy1lYXN0LTEgMjAxOSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAM3i/k2u6cqbMdcISGRvh+m+L0yaSIoOXjtpNEoIftAipTUYoMhL +InXGlQBVA4shkekxp1N7HXe1Y/iMaPEyb3n+16pf3vdjKl7kaSkIhjdUz3oVUEYt +i8Z/XeJJ9H2aEGuiZh3kHixQcZczn8cg3dA9aeeyLSEnTkl/npzLf//669Ammyhs +XcAo58yvT0D4E0D/EEHf2N7HRX7j/TlyWvw/39SW0usiCrHPKDLxByLojxLdHzso +QIp/S04m+eWn6rmD+uUiRteN1hI5ncQiA3wo4G37mHnUEKo6TtTUh+sd/ku6a8HK +glMBcgqudDI90s1OpuIAWmuWpY//8xEG2YECAwEAAaNmMGQwDgYDVR0PAQH/BAQD +AgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFPqhoWZcrVY9mU7tuemR +RBnQIj1jMB8GA1UdIwQYMBaAFHNfYNi8ywOY9CsXNC42WqZg/7wfMA0GCSqGSIb3 +DQEBCwUAA4IBAQB6zOLZ+YINEs72heHIWlPZ8c6WY8MDU+Be5w1M+BK2kpcVhCUK +PJO4nMXpgamEX8DIiaO7emsunwJzMSvavSPRnxXXTKIc0i/g1EbiDjnYX9d85DkC +E1LaAUCmCZBVi9fIe0H2r9whIh4uLWZA41oMnJx/MOmo3XyMfQoWcqaSFlMqfZM4 +0rNoB/tdHLNuV4eIdaw2mlHxdWDtF4oH+HFm+2cVBUVC1jXKrFv/euRVtsTT+A6i +h2XBHKxQ1Y4HgAn0jACP2QSPEmuoQEIa57bEKEcZsBR8SDY6ZdTd2HLRIApcCOSF +MRM8CKLeF658I0XgF8D5EsYoKPsA+74Z+jDH +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID/zCCAuegAwIBAgIRAPVSMfFitmM5PhmbaOFoGfUwDQYJKoZIhvcNAQELBQAw +gZcxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ +bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEwMC4GA1UEAwwn +QW1hem9uIFJEUyB1cy1lYXN0LTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQH +DAdTZWF0dGxlMCAXDTIxMDUyNTIyMzQ1N1oYDzIwNjEwNTI1MjMzNDU3WjCBlzEL +MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x +EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdBbWF6 +b24gUkRTIHVzLWVhc3QtMSBSb290IENBIFJTQTIwNDggRzExEDAOBgNVBAcMB1Nl +YXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDu9H7TBeGoDzMr +dxN6H8COntJX4IR6dbyhnj5qMD4xl/IWvp50lt0VpmMd+z2PNZzx8RazeGC5IniV +5nrLg0AKWRQ2A/lGGXbUrGXCSe09brMQCxWBSIYe1WZZ1iU1IJ/6Bp4D2YEHpXrW +bPkOq5x3YPcsoitgm1Xh8ygz6vb7PsvJvPbvRMnkDg5IqEThapPjmKb8ZJWyEFEE +QRrkCIRueB1EqQtJw0fvP4PKDlCJAKBEs/y049FoOqYpT3pRy0WKqPhWve+hScMd +6obq8kxTFy1IHACjHc51nrGII5Bt76/MpTWhnJIJrCnq1/Uc3Qs8IVeb+sLaFC8K +DI69Sw6bAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE7PCopt +lyOgtXX0Y1lObBUxuKaCMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC +AQEAFj+bX8gLmMNefr5jRJfHjrL3iuZCjf7YEZgn89pS4z8408mjj9z6Q5D1H7yS +jNETVV8QaJip1qyhh5gRzRaArgGAYvi2/r0zPsy+Tgf7v1KGL5Lh8NT8iCEGGXwF +g3Ir+Nl3e+9XUp0eyyzBIjHtjLBm6yy8rGk9p6OtFDQnKF5OxwbAgip42CD75r/q +p421maEDDvvRFR4D+99JZxgAYDBGqRRceUoe16qDzbMvlz0A9paCZFclxeftAxv6 +QlR5rItMz/XdzpBJUpYhdzM0gCzAzdQuVO5tjJxmXhkSMcDP+8Q+Uv6FA9k2VpUV +E/O5jgpqUJJ2Hc/5rs9VkAPXeA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF/jCCA+agAwIBAgIQaRHaEqqacXN20e8zZJtmDDANBgkqhkiG9w0BAQwFADCB +lzELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu +Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdB +bWF6b24gUkRTIHVzLWVhc3QtMSBSb290IENBIFJTQTQwOTYgRzExEDAOBgNVBAcM +B1NlYXR0bGUwIBcNMjEwNTI1MjIzODM1WhgPMjEyMTA1MjUyMzM4MzVaMIGXMQsw +CQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjET +MBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMDAuBgNVBAMMJ0FtYXpv +biBSRFMgdXMtZWFzdC0xIFJvb3QgQ0EgUlNBNDA5NiBHMTEQMA4GA1UEBwwHU2Vh +dHRsZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAInfBCaHuvj6Rb5c +L5Wmn1jv2PHtEGMHm+7Z8dYosdwouG8VG2A+BCYCZfij9lIGszrTXkY4O7vnXgru +JUNdxh0Q3M83p4X+bg+gODUs3jf+Z3Oeq7nTOk/2UYvQLcxP4FEXILxDInbQFcIx +yen1ESHggGrjEodgn6nbKQNRfIhjhW+TKYaewfsVWH7EF2pfj+cjbJ6njjgZ0/M9 +VZifJFBgat6XUTOf3jwHwkCBh7T6rDpgy19A61laImJCQhdTnHKvzTpxcxiLRh69 +ZObypR7W04OAUmFS88V7IotlPmCL8xf7kwxG+gQfvx31+A9IDMsiTqJ1Cc4fYEKg +bL+Vo+2Ii4W2esCTGVYmHm73drznfeKwL+kmIC/Bq+DrZ+veTqKFYwSkpHRyJCEe +U4Zym6POqQ/4LBSKwDUhWLJIlq99bjKX+hNTJykB+Lbcx0ScOP4IAZQoxmDxGWxN +S+lQj+Cx2pwU3S/7+OxlRndZAX/FKgk7xSMkg88HykUZaZ/ozIiqJqSnGpgXCtED +oQ4OJw5ozAr+/wudOawaMwUWQl5asD8fuy/hl5S1nv9XxIc842QJOtJFxhyeMIXt +LVECVw/dPekhMjS3Zo3wwRgYbnKG7YXXT5WMxJEnHu8+cYpMiRClzq2BEP6/MtI2 +AZQQUFu2yFjRGL2OZA6IYjxnXYiRAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8w +HQYDVR0OBBYEFADCcQCPX2HmkqQcmuHfiQ2jjqnrMA4GA1UdDwEB/wQEAwIBhjAN +BgkqhkiG9w0BAQwFAAOCAgEASXkGQ2eUmudIKPeOIF7RBryCoPmMOsqP0+1qxF8l +pGkwmrgNDGpmd9s0ArfIVBTc1jmpgB3oiRW9c6n2OmwBKL4UPuQ8O3KwSP0iD2sZ +KMXoMEyphCEzW1I2GRvYDugL3Z9MWrnHkoaoH2l8YyTYvszTvdgxBPpM2x4pSkp+ +76d4/eRpJ5mVuQ93nC+YG0wXCxSq63hX4kyZgPxgCdAA+qgFfKIGyNqUIqWgeyTP +n5OgKaboYk2141Rf2hGMD3/hsGm0rrJh7g3C0ZirPws3eeJfulvAOIy2IZzqHUSY +jkFzraz6LEH3IlArT3jUPvWKqvh2lJWnnp56aqxBR7qHH5voD49UpJWY1K0BjGnS +OHcurpp0Yt/BIs4VZeWdCZwI7JaSeDcPMaMDBvND3Ia5Fga0thgYQTG6dE+N5fgF +z+hRaujXO2nb0LmddVyvE8prYlWRMuYFv+Co8hcMdJ0lEZlfVNu0jbm9/GmwAZ+l +9umeYO9yz/uC7edC8XJBglMAKUmVK9wNtOckUWAcCfnPWYLbYa/PqtXBYcxrso5j +iaS/A7iEW51uteHBGrViCy1afGG+hiUWwFlesli+Rq4dNstX3h6h2baWABaAxEVJ +y1RnTQSz6mROT1VmZSgSVO37rgIyY0Hf0872ogcTS+FfvXgBxCxsNWEbiQ/XXva4 +0Ws= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICrjCCAjSgAwIBAgIRAPAlEk8VJPmEzVRRaWvTh2AwCgYIKoZIzj0EAwMwgZYx +CzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu +MRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEvMC0GA1UEAwwmQW1h +em9uIFJEUyB1cy1lYXN0LTEgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1Nl +YXR0bGUwIBcNMjEwNTI1MjI0MTU1WhgPMjEyMTA1MjUyMzQxNTVaMIGWMQswCQYD +VQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEG +A1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExLzAtBgNVBAMMJkFtYXpvbiBS +RFMgdXMtZWFzdC0xIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQHDAdTZWF0dGxl +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEx5xjrup8II4HOJw15NTnS3H5yMrQGlbj +EDA5MMGnE9DmHp5dACIxmPXPMe/99nO7wNdl7G71OYPCgEvWm0FhdvVUeTb3LVnV +BnaXt32Ek7/oxGk1T+Df03C+W0vmuJ+wo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0G +A1UdDgQWBBTGXmqBWN/1tkSea4pNw0oHrjk2UDAOBgNVHQ8BAf8EBAMCAYYwCgYI +KoZIzj0EAwMDaAAwZQIxAIqqZWCSrIkZ7zsv/FygtAusW6yvlL935YAWYPVXU30m +jkMFLM+/RJ9GMvnO8jHfCgIwB+whlkcItzE9CRQ6CsMo/d5cEHDUu/QW6jSIh9BR +OGh9pTYPVkUbBiKPA7lVVhre +-----END CERTIFICATE----- diff --git a/web-api/src/data-source.ts b/web-api/src/data-source.ts index eeac3ed1057..c4ec275cf65 100644 --- a/web-api/src/data-source.ts +++ b/web-api/src/data-source.ts @@ -11,6 +11,12 @@ export const AppDataSource = new DataSource({ migrations: ['postgres/migrations/*.ts'], password: process.env.POSTGRES_PASSWORD, port: 5432, + ssl: + process.env.NODE_ENV === 'production' + ? { + cert: './us-east-1-bundle.pem', + } + : undefined, subscribers: [], type: 'postgres', username: process.env.POSTGRES_USERNAME, diff --git a/web-api/terraform/modules/lambda/esbuildLambda.mjs b/web-api/terraform/modules/lambda/esbuildLambda.mjs index 6384aae7710..93aa47c514d 100644 --- a/web-api/terraform/modules/lambda/esbuildLambda.mjs +++ b/web-api/terraform/modules/lambda/esbuildLambda.mjs @@ -40,6 +40,10 @@ await esbuild.build({ keepStructure: true, to: [getPathFromRoot(`dist-lambdas/${fileName}/out`)], }, + { + from: [getPathFromRoot('./public-certs/us-east-1-bundle.pem')], + to: [getPathFromRoot(`dist-lambdas/${fileName}/out`)], + }, ], }), clean({ From fa254623b540e6eb96a98354403c5b0343dcc455 Mon Sep 17 00:00:00 2001 From: Cody Seibert Date: Mon, 22 Jul 2024 12:35:26 -0400 Subject: [PATCH 24/30] 10391 - switching to use ca instead of cert --- web-api/src/data-source.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web-api/src/data-source.ts b/web-api/src/data-source.ts index c4ec275cf65..d8689ac42ec 100644 --- a/web-api/src/data-source.ts +++ b/web-api/src/data-source.ts @@ -14,7 +14,7 @@ export const AppDataSource = new DataSource({ ssl: process.env.NODE_ENV === 'production' ? { - cert: './us-east-1-bundle.pem', + ca: './us-east-1-bundle.pem', } : undefined, subscribers: [], From ea02501f496ff1526e271e88881bc50c19d8fa4a Mon Sep 17 00:00:00 2001 From: Cody Seibert Date: Mon, 22 Jul 2024 16:55:34 -0400 Subject: [PATCH 25/30] refactor terraform to use address --- package.json | 2 +- .../migrations/1721165468631-JoinColumnMessages.ts | 0 .../us-east-1-bundle.pem => us-east-1-bundle.pem | 0 web-api/src/data-source.ts | 10 ++++------ web-api/terraform/applyables/allColors/outputs.tf | 2 +- web-api/terraform/modules/lambda/esbuildLambda.mjs | 2 +- web-api/terraform/modules/rds/outputs.tf | 4 ++-- 7 files changed, 9 insertions(+), 11 deletions(-) rename 1721165468631-JoinColumnMessages.ts => postgres/migrations/1721165468631-JoinColumnMessages.ts (100%) rename public-certs/us-east-1-bundle.pem => us-east-1-bundle.pem (100%) diff --git a/package.json b/package.json index 1f3b54e10ee..f4d54f47c3d 100644 --- a/package.json +++ b/package.json @@ -244,7 +244,7 @@ "postgres:run": "cd postgres && docker compose up &", "typeorm:migrations:migrate": "npx typeorm-ts-node-commonjs migration:run -d web-api/src/data-source.ts", "typeorm:migrations:revert": "npx typeorm-ts-node-commonjs migration:revert -d web-api/src/data-source.ts", - "typeorm:migrations:generate": "npx typeorm-ts-node-commonjs migration:generate ${MIGRATION_NAME} -d web-api/src/data-source.ts" + "typeorm:migrations:generate": "npx typeorm-ts-node-commonjs migration:generate ${MIGRATION_NAME} -d web-api/src/data-source.ts ./postgres/migrations" }, "overrides": { "axios": "$axios", diff --git a/1721165468631-JoinColumnMessages.ts b/postgres/migrations/1721165468631-JoinColumnMessages.ts similarity index 100% rename from 1721165468631-JoinColumnMessages.ts rename to postgres/migrations/1721165468631-JoinColumnMessages.ts diff --git a/public-certs/us-east-1-bundle.pem b/us-east-1-bundle.pem similarity index 100% rename from public-certs/us-east-1-bundle.pem rename to us-east-1-bundle.pem diff --git a/web-api/src/data-source.ts b/web-api/src/data-source.ts index d8689ac42ec..48166511ac3 100644 --- a/web-api/src/data-source.ts +++ b/web-api/src/data-source.ts @@ -2,6 +2,7 @@ import 'reflect-metadata'; import { Case } from '@web-api/persistence/repository/Case'; import { DataSource } from 'typeorm'; import { Message } from './persistence/repository/Message'; +import fs from 'fs'; export const AppDataSource = new DataSource({ database: 'postgres', @@ -11,12 +12,9 @@ export const AppDataSource = new DataSource({ migrations: ['postgres/migrations/*.ts'], password: process.env.POSTGRES_PASSWORD, port: 5432, - ssl: - process.env.NODE_ENV === 'production' - ? { - ca: './us-east-1-bundle.pem', - } - : undefined, + ssl: { + ca: fs.readFileSync('us-east-1-bundle.pem').toString(), + }, subscribers: [], type: 'postgres', username: process.env.POSTGRES_USERNAME, diff --git a/web-api/terraform/applyables/allColors/outputs.tf b/web-api/terraform/applyables/allColors/outputs.tf index 8383d3c70c8..a1c240a1a13 100644 --- a/web-api/terraform/applyables/allColors/outputs.tf +++ b/web-api/terraform/applyables/allColors/outputs.tf @@ -48,5 +48,5 @@ output "aws_cognito_user_pool_irs_id" { } output "rds_host_name" { - value = module.rds.endpoint + value = module.rds.address } \ No newline at end of file diff --git a/web-api/terraform/modules/lambda/esbuildLambda.mjs b/web-api/terraform/modules/lambda/esbuildLambda.mjs index 93aa47c514d..c6deeb8cb92 100644 --- a/web-api/terraform/modules/lambda/esbuildLambda.mjs +++ b/web-api/terraform/modules/lambda/esbuildLambda.mjs @@ -41,7 +41,7 @@ await esbuild.build({ to: [getPathFromRoot(`dist-lambdas/${fileName}/out`)], }, { - from: [getPathFromRoot('./public-certs/us-east-1-bundle.pem')], + from: [getPathFromRoot('./us-east-1-bundle.pem')], to: [getPathFromRoot(`dist-lambdas/${fileName}/out`)], }, ], diff --git a/web-api/terraform/modules/rds/outputs.tf b/web-api/terraform/modules/rds/outputs.tf index 55993021969..76f89e93ea2 100644 --- a/web-api/terraform/modules/rds/outputs.tf +++ b/web-api/terraform/modules/rds/outputs.tf @@ -1,3 +1,3 @@ -output "endpoint" { - value = aws_db_instance.postgres.endpoint +output "address" { + value = aws_db_instance.postgres.address } From 53e4f1f68d1da15cecad2ffd6c3bf6a1a1d5f682 Mon Sep 17 00:00:00 2001 From: Cody Seibert Date: Tue, 23 Jul 2024 10:48:24 -0400 Subject: [PATCH 26/30] add back the column type annotations in type orm entities and fix location for migration scripts --- .circleci/config.yml | 6 +++ package.json | 2 +- scripts/env/env-for-circle.sh | 1 + .../migration/get-postgres-migrate-flag.sh | 21 ++++++++ web-api/src/data-source.ts | 9 ++-- web-api/src/persistence/repository/Case.ts | 6 +-- web-api/src/persistence/repository/Message.ts | 48 +++++++++---------- 7 files changed, 62 insertions(+), 31 deletions(-) create mode 100755 scripts/migration/get-postgres-migrate-flag.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index 2fcf8086f9f..8f8ff73f6b3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -230,6 +230,12 @@ jobs: if [ "$MIGRATE_FLAG" == "true" ]; then npm run start:migration -- $ENV fi + - run: + name: Run Postgres Migration + command: | + if [ "$POSTGRES_MIGRATE_FLAG" == "true" ]; then + npm run typeorm:migrations:migrate + fi - run: name: Enable Check Migration Status Cron command: | diff --git a/package.json b/package.json index f4d54f47c3d..f0a12f60a85 100644 --- a/package.json +++ b/package.json @@ -244,7 +244,7 @@ "postgres:run": "cd postgres && docker compose up &", "typeorm:migrations:migrate": "npx typeorm-ts-node-commonjs migration:run -d web-api/src/data-source.ts", "typeorm:migrations:revert": "npx typeorm-ts-node-commonjs migration:revert -d web-api/src/data-source.ts", - "typeorm:migrations:generate": "npx typeorm-ts-node-commonjs migration:generate ${MIGRATION_NAME} -d web-api/src/data-source.ts ./postgres/migrations" + "typeorm:migrations:generate": "npx typeorm-ts-node-commonjs migration:generate postgres/migrations/${MIGRATION_NAME} -d web-api/src/data-source.ts" }, "overrides": { "axios": "$axios", diff --git a/scripts/env/env-for-circle.sh b/scripts/env/env-for-circle.sh index d0df0c9ad67..301942c9cb7 100755 --- a/scripts/env/env-for-circle.sh +++ b/scripts/env/env-for-circle.sh @@ -64,6 +64,7 @@ cat .env.sh >> "${BASH_ENV}" echo "export DEPLOYING_COLOR=$(./scripts/dynamo/get-deploying-color.sh $ENV)" echo "export DESTINATION_TABLE=$(./scripts/dynamo/get-destination-table.sh $ENV)" echo "export MIGRATE_FLAG=$(./scripts/migration/get-migrate-flag.sh $ENV)" + echo "export POSTGRES_MIGRATE_FLAG=$(./scripts/migration/get-postgres-migrate-flag.sh $ENV)" echo "export SOURCE_TABLE=$(./scripts/dynamo/get-source-table.sh $ENV)" echo "export SOURCE_ELASTICSEARCH=$(./scripts/elasticsearch/get-source-elasticsearch.sh $ENV)" } >> "${BASH_ENV}" diff --git a/scripts/migration/get-postgres-migrate-flag.sh b/scripts/migration/get-postgres-migrate-flag.sh new file mode 100755 index 00000000000..4ad4508b7d0 --- /dev/null +++ b/scripts/migration/get-postgres-migrate-flag.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# Gets the migrate flag for the environment + +# Usage +# ./get-migrate-flag.sh dev + +# Arguments +# - $1 - the environment to check + +( ! command -v jq > /dev/null ) && echo "jq must be installed on your machine." && exit 1 +[ -z "$1" ] && echo "The environment to check must be provided as the \$1 argument." && exit 1 +[ -z "${AWS_ACCESS_KEY_ID}" ] && echo "You must have AWS_ACCESS_KEY_ID set in your environment" && exit 1 +[ -z "${AWS_SECRET_ACCESS_KEY}" ] && echo "You must have AWS_SECRET_ACCESS_KEY set in your environment" && exit 1 + +ENV=$1 + +MIGRATE_FLAG=$(aws dynamodb get-item --region us-east-1 --table-name "efcms-deploy-${ENV}" --key '{"pk":{"S":"postgres-migrate"},"sk":{"S":"postgres-migrate"}}' | jq -r ".Item.current.BOOL") +[ -z "$MIGRATE_FLAG" ] && MIGRATE_FLAG="false" + +echo "${MIGRATE_FLAG}" diff --git a/web-api/src/data-source.ts b/web-api/src/data-source.ts index 48166511ac3..8bb09d7fd5c 100644 --- a/web-api/src/data-source.ts +++ b/web-api/src/data-source.ts @@ -12,9 +12,12 @@ export const AppDataSource = new DataSource({ migrations: ['postgres/migrations/*.ts'], password: process.env.POSTGRES_PASSWORD, port: 5432, - ssl: { - ca: fs.readFileSync('us-east-1-bundle.pem').toString(), - }, + ssl: + process.env.NODE_ENV === 'production' || process.env.CIRCLE_BRANCH + ? { + ca: fs.readFileSync('us-east-1-bundle.pem').toString(), + } + : undefined, subscribers: [], type: 'postgres', username: process.env.POSTGRES_USERNAME, diff --git a/web-api/src/persistence/repository/Case.ts b/web-api/src/persistence/repository/Case.ts index d07dc9a0351..c9eee3809db 100644 --- a/web-api/src/persistence/repository/Case.ts +++ b/web-api/src/persistence/repository/Case.ts @@ -3,13 +3,13 @@ import { Message } from '@web-api/persistence/repository/Message'; @Entity() export class Case { - @PrimaryColumn() + @PrimaryColumn('varchar') docketNumber!: string; - @Column({ nullable: true }) + @Column('varchar', { nullable: true }) trialLocation?: string; - @Column({ nullable: true }) + @Column('varchar', { nullable: true }) trialDate?: string; @OneToMany(() => Message, message => message.docketNumber) diff --git a/web-api/src/persistence/repository/Message.ts b/web-api/src/persistence/repository/Message.ts index 8cfa75ca202..583d841089e 100644 --- a/web-api/src/persistence/repository/Message.ts +++ b/web-api/src/persistence/repository/Message.ts @@ -8,76 +8,76 @@ export class Message { documentId: string; }[]; - @Column() + @Column('varchar') caseStatus!: string; - @Column() + @Column('varchar') caseTitle!: string; - @Column({ nullable: true }) + @Column('varchar', { nullable: true }) completedAt?: string; - @Column({ nullable: true }) + @Column('varchar', { nullable: true }) completedBy?: string; - @Column({ nullable: true }) + @Column('varchar', { nullable: true }) completedBySection?: string; - @Column({ nullable: true }) + @Column('varchar', { nullable: true }) completedByUserId?: string; - @Column({ nullable: true }) + @Column('varchar', { nullable: true }) completedMessage?: string; - @Column() + @Column('varchar') createdAt!: string; - @Column() + @Column('varchar') docketNumber!: string; - @Column() + @Column('varchar') docketNumberWithSuffix!: string; - @Column() + @Column('varchar') from!: string; - @Column() + @Column('varchar') fromSection!: string; - @Column() + @Column('varchar') fromUserId!: string; - @Column() + @Column('bool') isCompleted!: boolean; - @Column() + @Column('bool') isRead!: boolean; - @Column() + @Column('bool') isRepliedTo!: boolean; - @Column({ nullable: true }) + @Column('varchar', { nullable: true }) leadDocketNumber?: string; - @Column() + @Column('varchar') message!: string; - @PrimaryColumn() + @PrimaryColumn('varchar') messageId!: string; - @Column() + @Column('varchar') parentMessageId!: string; - @Column() + @Column('varchar') subject!: string; - @Column() + @Column('varchar') to!: string; - @Column() + @Column('varchar') toSection!: string; - @Column() + @Column('varchar') toUserId!: string; @ManyToOne(() => Case, item => item.docketNumber) From 570f84f93338df1c60d4110ecaddead419ee4be4 Mon Sep 17 00:00:00 2001 From: Cody Seibert Date: Tue, 23 Jul 2024 12:36:33 -0400 Subject: [PATCH 27/30] 10391 - adding index to the column --- .../migrations/1721752460593-AddingIndex.ts | 59 +++++++++++++++++++ web-api/src/persistence/repository/Message.ts | 17 +++++- 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 postgres/migrations/1721752460593-AddingIndex.ts diff --git a/postgres/migrations/1721752460593-AddingIndex.ts b/postgres/migrations/1721752460593-AddingIndex.ts new file mode 100644 index 00000000000..273a6f4f2f4 --- /dev/null +++ b/postgres/migrations/1721752460593-AddingIndex.ts @@ -0,0 +1,59 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class AddingIndex1721752460593 implements MigrationInterface { + name = 'AddingIndex1721752460593'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'CREATE INDEX "IDX_cca9e3abeff4b0939aa8a25b3e" ON "message" ("completedBySection") ', + ); + await queryRunner.query( + 'CREATE INDEX "IDX_db0d579b205db9e5cea5e2e0df" ON "message" ("completedByUserId") ', + ); + await queryRunner.query( + 'CREATE INDEX "IDX_5c6b9074994ba166011d5dd0b2" ON "message" ("docketNumber") ', + ); + await queryRunner.query( + 'CREATE INDEX "IDX_c2d824eb9ff032e8caa384467d" ON "message" ("fromSection") ', + ); + await queryRunner.query( + 'CREATE INDEX "IDX_c59262513a3006fd8f58bb4b7c" ON "message" ("fromUserId") ', + ); + await queryRunner.query( + 'CREATE INDEX "IDX_575b24e003b8881e64fa53cd16" ON "message" ("parentMessageId") ', + ); + await queryRunner.query( + 'CREATE INDEX "IDX_09e34b5dac1edc3182e0b349ef" ON "message" ("toSection") ', + ); + await queryRunner.query( + 'CREATE INDEX "IDX_96789153e31e0bb7885ea13a27" ON "message" ("toUserId") ', + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'DROP INDEX "public"."IDX_96789153e31e0bb7885ea13a27"', + ); + await queryRunner.query( + 'DROP INDEX "public"."IDX_09e34b5dac1edc3182e0b349ef"', + ); + await queryRunner.query( + 'DROP INDEX "public"."IDX_575b24e003b8881e64fa53cd16"', + ); + await queryRunner.query( + 'DROP INDEX "public"."IDX_c59262513a3006fd8f58bb4b7c"', + ); + await queryRunner.query( + 'DROP INDEX "public"."IDX_c2d824eb9ff032e8caa384467d"', + ); + await queryRunner.query( + 'DROP INDEX "public"."IDX_5c6b9074994ba166011d5dd0b2"', + ); + await queryRunner.query( + 'DROP INDEX "public"."IDX_db0d579b205db9e5cea5e2e0df"', + ); + await queryRunner.query( + 'DROP INDEX "public"."IDX_cca9e3abeff4b0939aa8a25b3e"', + ); + } +} diff --git a/web-api/src/persistence/repository/Message.ts b/web-api/src/persistence/repository/Message.ts index 583d841089e..b1bde469dd8 100644 --- a/web-api/src/persistence/repository/Message.ts +++ b/web-api/src/persistence/repository/Message.ts @@ -1,5 +1,12 @@ import { Case } from '@web-api/persistence/repository/Case'; -import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm'; +import { + Column, + Entity, + Index, + JoinColumn, + ManyToOne, + PrimaryColumn, +} from 'typeorm'; @Entity() export class Message { @@ -21,9 +28,11 @@ export class Message { completedBy?: string; @Column('varchar', { nullable: true }) + @Index() completedBySection?: string; @Column('varchar', { nullable: true }) + @Index() completedByUserId?: string; @Column('varchar', { nullable: true }) @@ -33,6 +42,7 @@ export class Message { createdAt!: string; @Column('varchar') + @Index() docketNumber!: string; @Column('varchar') @@ -42,9 +52,11 @@ export class Message { from!: string; @Column('varchar') + @Index() fromSection!: string; @Column('varchar') + @Index() fromUserId!: string; @Column('bool') @@ -66,6 +78,7 @@ export class Message { messageId!: string; @Column('varchar') + @Index() parentMessageId!: string; @Column('varchar') @@ -75,9 +88,11 @@ export class Message { to!: string; @Column('varchar') + @Index() toSection!: string; @Column('varchar') + @Index() toUserId!: string; @ManyToOne(() => Case, item => item.docketNumber) From 0d004cc97c183a17639fc72d87e044120c824b72 Mon Sep 17 00:00:00 2001 From: Cody Seibert Date: Tue, 23 Jul 2024 16:53:09 -0400 Subject: [PATCH 28/30] import the data source promise instead --- web-api/src/persistence/postgres/cases/updateCase.ts | 5 +++-- web-api/src/persistence/postgres/messages/createMessage.ts | 5 +++-- .../postgres/messages/getCompletedSectionInboxMessages.ts | 5 +++-- .../postgres/messages/getCompletedUserInboxMessages.ts | 5 +++-- .../postgres/messages/getMessageThreadByParentId.ts | 5 +++-- .../postgres/messages/getMessagesByDocketNumber.ts | 5 +++-- .../persistence/postgres/messages/getSectionInboxMessages.ts | 5 +++-- .../postgres/messages/getSectionOutboxMessages.ts | 5 +++-- .../persistence/postgres/messages/getUserInboxMessages.ts | 5 +++-- .../persistence/postgres/messages/getUserOutboxMessages.ts | 5 +++-- .../postgres/messages/markMessageThreadRepliedTo.ts | 5 +++-- .../src/persistence/postgres/messages/setMessageAsRead.ts | 5 +++-- web-api/src/persistence/postgres/messages/updateMessage.ts | 5 +++-- 13 files changed, 39 insertions(+), 26 deletions(-) diff --git a/web-api/src/persistence/postgres/cases/updateCase.ts b/web-api/src/persistence/postgres/cases/updateCase.ts index d5759782719..a64a738e5c3 100644 --- a/web-api/src/persistence/postgres/cases/updateCase.ts +++ b/web-api/src/persistence/postgres/cases/updateCase.ts @@ -1,7 +1,8 @@ -import { AppDataSource } from '@web-api/data-source'; import { Case } from '@web-api/persistence/repository/Case'; +import { getDataSource } from '@web-api/data-source'; export async function updateCase(caseToUpdate: Case) { - const caseRepository = AppDataSource.getRepository(Case); + const dataSource = await getDataSource(); + const caseRepository = dataSource.getRepository(Case); await caseRepository.save(caseToUpdate); } diff --git a/web-api/src/persistence/postgres/messages/createMessage.ts b/web-api/src/persistence/postgres/messages/createMessage.ts index b59648a5ac4..23ffa94f575 100644 --- a/web-api/src/persistence/postgres/messages/createMessage.ts +++ b/web-api/src/persistence/postgres/messages/createMessage.ts @@ -1,6 +1,6 @@ -import { AppDataSource } from '@web-api/data-source'; import { Message } from '@web-api/persistence/repository/Message'; import { RawMessage } from '@shared/business/entities/Message'; +import { getDataSource } from '@web-api/data-source'; /** * createMessage @@ -17,7 +17,8 @@ export const createMessage = async ({ applicationContext: IApplicationContext; message: RawMessage; }) => { - const messageRepository = AppDataSource.getRepository(Message); + const dataSource = await getDataSource(); + const messageRepository = dataSource.getRepository(Message); return await messageRepository.save({ ...message, diff --git a/web-api/src/persistence/postgres/messages/getCompletedSectionInboxMessages.ts b/web-api/src/persistence/postgres/messages/getCompletedSectionInboxMessages.ts index 4f51e4e875e..3061f09152d 100644 --- a/web-api/src/persistence/postgres/messages/getCompletedSectionInboxMessages.ts +++ b/web-api/src/persistence/postgres/messages/getCompletedSectionInboxMessages.ts @@ -1,6 +1,6 @@ -import { AppDataSource } from '@web-api/data-source'; import { Message } from '@shared/business/entities/Message'; import { calculateISODate } from '@shared/business/utilities/DateHandler'; +import { getDataSource } from '@web-api/data-source'; import { Message as messageRepo } from '@web-api/persistence/repository/Message'; import { transformNullToUndefined } from 'postgres/helpers/transformNullToUndefined'; @@ -13,7 +13,8 @@ export const getCompletedSectionInboxMessages = async ({ }) => { const filterDate = calculateISODate({ howMuch: -7 }); - const messageRepository = AppDataSource.getRepository(messageRepo); + const dataSource = await getDataSource(); + const messageRepository = dataSource.getRepository(messageRepo); const messages = await messageRepository .createQueryBuilder('message') diff --git a/web-api/src/persistence/postgres/messages/getCompletedUserInboxMessages.ts b/web-api/src/persistence/postgres/messages/getCompletedUserInboxMessages.ts index 7ca50a13459..db368b4847e 100644 --- a/web-api/src/persistence/postgres/messages/getCompletedUserInboxMessages.ts +++ b/web-api/src/persistence/postgres/messages/getCompletedUserInboxMessages.ts @@ -1,6 +1,6 @@ -import { AppDataSource } from '@web-api/data-source'; import { Message } from '@shared/business/entities/Message'; import { calculateISODate } from '@shared/business/utilities/DateHandler'; +import { getDataSource } from '@web-api/data-source'; import { Message as messageRepo } from '@web-api/persistence/repository/Message'; import { transformNullToUndefined } from 'postgres/helpers/transformNullToUndefined'; @@ -13,7 +13,8 @@ export const getCompletedUserInboxMessages = async ({ }) => { const filterDate = calculateISODate({ howMuch: -7 }); - const messageRepository = AppDataSource.getRepository(messageRepo); + const dataSource = await getDataSource(); + const messageRepository = dataSource.getRepository(messageRepo); const messages = await messageRepository .createQueryBuilder('message') diff --git a/web-api/src/persistence/postgres/messages/getMessageThreadByParentId.ts b/web-api/src/persistence/postgres/messages/getMessageThreadByParentId.ts index f71766ffbe3..2231e2f540a 100644 --- a/web-api/src/persistence/postgres/messages/getMessageThreadByParentId.ts +++ b/web-api/src/persistence/postgres/messages/getMessageThreadByParentId.ts @@ -1,5 +1,5 @@ -import { AppDataSource } from '@web-api/data-source'; import { Message } from '@shared/business/entities/Message'; +import { getDataSource } from '@web-api/data-source'; import { Message as messageRepo } from '@web-api/persistence/repository/Message'; import { transformNullToUndefined } from 'postgres/helpers/transformNullToUndefined'; @@ -18,7 +18,8 @@ export const getMessageThreadByParentId = async ({ applicationContext: IApplicationContext; parentMessageId: string; }) => { - const messageRepository = AppDataSource.getRepository(messageRepo); + const dataSource = await getDataSource(); + const messageRepository = dataSource.getRepository(messageRepo); const messages = await messageRepository.find({ where: { diff --git a/web-api/src/persistence/postgres/messages/getMessagesByDocketNumber.ts b/web-api/src/persistence/postgres/messages/getMessagesByDocketNumber.ts index 59930430f3b..088179460dd 100644 --- a/web-api/src/persistence/postgres/messages/getMessagesByDocketNumber.ts +++ b/web-api/src/persistence/postgres/messages/getMessagesByDocketNumber.ts @@ -1,5 +1,5 @@ -import { AppDataSource } from '@web-api/data-source'; import { Message } from '@shared/business/entities/Message'; +import { getDataSource } from '@web-api/data-source'; import { Message as messageRepo } from '@web-api/persistence/repository/Message'; import { transformNullToUndefined } from 'postgres/helpers/transformNullToUndefined'; @@ -18,7 +18,8 @@ export const getMessagesByDocketNumber = async ({ applicationContext: IApplicationContext; docketNumber: string; }) => { - const messageRepository = AppDataSource.getRepository(messageRepo); + const dataSource = await getDataSource(); + const messageRepository = dataSource.getRepository(messageRepo); const messages = await messageRepository .createQueryBuilder('message') diff --git a/web-api/src/persistence/postgres/messages/getSectionInboxMessages.ts b/web-api/src/persistence/postgres/messages/getSectionInboxMessages.ts index 2f039b886a8..296aeaf1b53 100644 --- a/web-api/src/persistence/postgres/messages/getSectionInboxMessages.ts +++ b/web-api/src/persistence/postgres/messages/getSectionInboxMessages.ts @@ -1,5 +1,5 @@ -import { AppDataSource } from '@web-api/data-source'; import { Message } from '@shared/business/entities/Message'; +import { getDataSource } from '@web-api/data-source'; import { Message as messageRepo } from '@web-api/persistence/repository/Message'; import { transformNullToUndefined } from 'postgres/helpers/transformNullToUndefined'; @@ -12,7 +12,8 @@ export const getSectionInboxMessages = async ({ }) => { applicationContext.logger.info('getSectionInboxMessages start'); - const messageRepository = AppDataSource.getRepository(messageRepo); + const dataSource = await getDataSource(); + const messageRepository = dataSource.getRepository(messageRepo); const messages = await messageRepository .createQueryBuilder('message') diff --git a/web-api/src/persistence/postgres/messages/getSectionOutboxMessages.ts b/web-api/src/persistence/postgres/messages/getSectionOutboxMessages.ts index b491a11018c..9a2ce1ba1a6 100644 --- a/web-api/src/persistence/postgres/messages/getSectionOutboxMessages.ts +++ b/web-api/src/persistence/postgres/messages/getSectionOutboxMessages.ts @@ -1,6 +1,6 @@ -import { AppDataSource } from '@web-api/data-source'; import { Message } from '@shared/business/entities/Message'; import { calculateISODate } from '@shared/business/utilities/DateHandler'; +import { getDataSource } from '@web-api/data-source'; import { Message as messageRepo } from '@web-api/persistence/repository/Message'; import { transformNullToUndefined } from 'postgres/helpers/transformNullToUndefined'; @@ -13,7 +13,8 @@ export const getSectionOutboxMessages = async ({ }) => { const filterDate = calculateISODate({ howMuch: -7 }); - const messageRepository = AppDataSource.getRepository(messageRepo); + const dataSource = await getDataSource(); + const messageRepository = dataSource.getRepository(messageRepo); const messages = await messageRepository .createQueryBuilder('message') diff --git a/web-api/src/persistence/postgres/messages/getUserInboxMessages.ts b/web-api/src/persistence/postgres/messages/getUserInboxMessages.ts index 96da98a097c..65d7cd42493 100644 --- a/web-api/src/persistence/postgres/messages/getUserInboxMessages.ts +++ b/web-api/src/persistence/postgres/messages/getUserInboxMessages.ts @@ -1,5 +1,5 @@ -import { AppDataSource } from '@web-api/data-source'; import { MessageResult } from '@shared/business/entities/MessageResult'; +import { getDataSource } from '@web-api/data-source'; import { Message as messageRepo } from '@web-api/persistence/repository/Message'; import { transformNullToUndefined } from 'postgres/helpers/transformNullToUndefined'; @@ -12,7 +12,8 @@ export const getUserInboxMessages = async ({ }) => { applicationContext.logger.info('getUserInboxMessages start'); - const messageRepository = AppDataSource.getRepository(messageRepo); + const dataSource = await getDataSource(); + const messageRepository = dataSource.getRepository(messageRepo); const messages = await messageRepository.find({ relations: { case: true }, diff --git a/web-api/src/persistence/postgres/messages/getUserOutboxMessages.ts b/web-api/src/persistence/postgres/messages/getUserOutboxMessages.ts index 133af419605..dac9371c36a 100644 --- a/web-api/src/persistence/postgres/messages/getUserOutboxMessages.ts +++ b/web-api/src/persistence/postgres/messages/getUserOutboxMessages.ts @@ -1,6 +1,6 @@ -import { AppDataSource } from '@web-api/data-source'; import { Message } from '@shared/business/entities/Message'; import { calculateISODate } from '@shared/business/utilities/DateHandler'; +import { getDataSource } from '@web-api/data-source'; import { Message as messageRepo } from '@web-api/persistence/repository/Message'; import { transformNullToUndefined } from 'postgres/helpers/transformNullToUndefined'; @@ -13,7 +13,8 @@ export const getUserOutboxMessages = async ({ }) => { const filterDate = calculateISODate({ howMuch: -7 }); - const messageRepository = AppDataSource.getRepository(messageRepo); + const dataSource = await getDataSource(); + const messageRepository = dataSource.getRepository(messageRepo); const messages = await messageRepository .createQueryBuilder('message') diff --git a/web-api/src/persistence/postgres/messages/markMessageThreadRepliedTo.ts b/web-api/src/persistence/postgres/messages/markMessageThreadRepliedTo.ts index 1697163475b..46bfe94923c 100644 --- a/web-api/src/persistence/postgres/messages/markMessageThreadRepliedTo.ts +++ b/web-api/src/persistence/postgres/messages/markMessageThreadRepliedTo.ts @@ -1,5 +1,5 @@ -import { AppDataSource } from '@web-api/data-source'; import { Message } from '@web-api/persistence/repository/Message'; +import { getDataSource } from '@web-api/data-source'; import { getMessageThreadByParentId } from './getMessageThreadByParentId'; /** @@ -23,7 +23,8 @@ export const markMessageThreadRepliedTo = async ({ }); if (messages.length) { - const messageRepository = AppDataSource.getRepository(Message); + const dataSource = await getDataSource(); + const messageRepository = dataSource.getRepository(Message); await Promise.all( messages.map(async message => { diff --git a/web-api/src/persistence/postgres/messages/setMessageAsRead.ts b/web-api/src/persistence/postgres/messages/setMessageAsRead.ts index 9d181e623a5..b7fd0741eb9 100644 --- a/web-api/src/persistence/postgres/messages/setMessageAsRead.ts +++ b/web-api/src/persistence/postgres/messages/setMessageAsRead.ts @@ -1,5 +1,5 @@ -import { AppDataSource } from '@web-api/data-source'; import { Message } from '@web-api/persistence/repository/Message'; +import { getDataSource } from '@web-api/data-source'; export const setMessageAsRead = async ({ applicationContext, @@ -10,7 +10,8 @@ export const setMessageAsRead = async ({ messageId: string; docketNumber: string; }) => { - const messageRepository = AppDataSource.getRepository(Message); + const dataSource = await getDataSource(); + const messageRepository = dataSource.getRepository(Message); await messageRepository.update({ docketNumber, messageId }, { isRead: true }); }; diff --git a/web-api/src/persistence/postgres/messages/updateMessage.ts b/web-api/src/persistence/postgres/messages/updateMessage.ts index b4de56193ca..1657cf91105 100644 --- a/web-api/src/persistence/postgres/messages/updateMessage.ts +++ b/web-api/src/persistence/postgres/messages/updateMessage.ts @@ -1,6 +1,6 @@ -import { AppDataSource } from '@web-api/data-source'; import { Message } from '@web-api/persistence/repository/Message'; import { RawMessage } from '@shared/business/entities/Message'; +import { getDataSource } from '@web-api/data-source'; /** * updateMessage @@ -17,7 +17,8 @@ export const updateMessage = async ({ applicationContext: IApplicationContext; message: RawMessage; }) => { - const messageRepository = AppDataSource.getRepository(Message); + const dataSource = await getDataSource(); + const messageRepository = dataSource.getRepository(Message); const existingMessage = await messageRepository.findOne({ where: { messageId: message.messageId }, From 7062a43693494236753d2535daf8e6df88211331 Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Wed, 24 Jul 2024 08:56:27 -0600 Subject: [PATCH 29/30] 10391: add table name to repo entities --- web-api/src/persistence/repository/Case.ts | 2 +- web-api/src/persistence/repository/Message.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/web-api/src/persistence/repository/Case.ts b/web-api/src/persistence/repository/Case.ts index c9eee3809db..55b750bd08a 100644 --- a/web-api/src/persistence/repository/Case.ts +++ b/web-api/src/persistence/repository/Case.ts @@ -1,7 +1,7 @@ import { Column, Entity, OneToMany, PrimaryColumn } from 'typeorm'; import { Message } from '@web-api/persistence/repository/Message'; -@Entity() +@Entity({ name: 'case' }) export class Case { @PrimaryColumn('varchar') docketNumber!: string; diff --git a/web-api/src/persistence/repository/Message.ts b/web-api/src/persistence/repository/Message.ts index b1bde469dd8..a972a87cb0d 100644 --- a/web-api/src/persistence/repository/Message.ts +++ b/web-api/src/persistence/repository/Message.ts @@ -8,7 +8,7 @@ import { PrimaryColumn, } from 'typeorm'; -@Entity() +@Entity({ name: 'message' }) export class Message { @Column('jsonb', { nullable: true }) attachments?: { From 46150885da38dd659b81e410e14894c852df974c Mon Sep 17 00:00:00 2001 From: Kaitlyn Swann Date: Wed, 24 Jul 2024 11:06:15 -0600 Subject: [PATCH 30/30] 10391: rework relationship with message and case --- package.json | 2 +- .../1721834206951-MessageCaseOptional.ts | 17 ++++++ .../postgres/messages/getUserInboxMessages.ts | 57 +++++++++++++++---- web-api/src/persistence/repository/Case.ts | 4 +- web-api/src/persistence/repository/Message.ts | 6 +- 5 files changed, 69 insertions(+), 17 deletions(-) create mode 100644 postgres/migrations/1721834206951-MessageCaseOptional.ts diff --git a/package.json b/package.json index f0a12f60a85..355cb445852 100644 --- a/package.json +++ b/package.json @@ -130,7 +130,7 @@ "cypress:smoketests:local:file": "./scripts/run-cypress.sh -sl -t", "cypress:smoketests:local": "./scripts/run-cypress.sh -sl", "cypress:smoketests:open:local": "./scripts/run-cypress.sh -sol", - "cypress:smoketests:open": "./scripts/run-cypress.sh -sco", + "cypress:smoketests:open": "./scripts/run-cypress.sh -so", "cypress:smoketests": "./scripts/run-cypress.sh -s", "delete:api-gateway-mappings": "./scripts/delete-api-gateway-mappings.sh", "delete:dynamo-table": "./scripts/dynamo/delete-dynamo-table.sh", diff --git a/postgres/migrations/1721834206951-MessageCaseOptional.ts b/postgres/migrations/1721834206951-MessageCaseOptional.ts new file mode 100644 index 00000000000..8dc62d2a33a --- /dev/null +++ b/postgres/migrations/1721834206951-MessageCaseOptional.ts @@ -0,0 +1,17 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class MessageCaseOptional1721834206951 implements MigrationInterface { + name = 'MessageCaseOptional1721834206951'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "message" DROP CONSTRAINT "FK_5c6b9074994ba166011d5dd0b26"', + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "message" ADD CONSTRAINT "FK_5c6b9074994ba166011d5dd0b26" FOREIGN KEY ("docketNumber") REFERENCES "case"("docketNumber") ON DELETE NO ACTION ON UPDATE NO ACTION', + ); + } +} diff --git a/web-api/src/persistence/postgres/messages/getUserInboxMessages.ts b/web-api/src/persistence/postgres/messages/getUserInboxMessages.ts index 65d7cd42493..6b9ae2c6540 100644 --- a/web-api/src/persistence/postgres/messages/getUserInboxMessages.ts +++ b/web-api/src/persistence/postgres/messages/getUserInboxMessages.ts @@ -1,4 +1,6 @@ import { MessageResult } from '@shared/business/entities/MessageResult'; + +import { Case } from '@web-api/persistence/repository/Case'; import { getDataSource } from '@web-api/data-source'; import { Message as messageRepo } from '@web-api/persistence/repository/Message'; import { transformNullToUndefined } from 'postgres/helpers/transformNullToUndefined'; @@ -15,24 +17,57 @@ export const getUserInboxMessages = async ({ const dataSource = await getDataSource(); const messageRepository = dataSource.getRepository(messageRepo); - const messages = await messageRepository.find({ - relations: { case: true }, - take: 5000, - where: { - isCompleted: false, - isRepliedTo: false, - toUserId: userId, - }, - }); + // const messages = await messageRepository.find({ + // take: 5000, + // where: { + // isCompleted: false, + // isRepliedTo: false, + // toUserId: userId, + // }, + // }); + + // const messages: any = await messageRepository + // .createQueryBuilder('message') + // .leftJoin('case', 'case', 'case.docketNumber = message.docketNumber') + // .addSelect(['case.trialLocation', 'case.trialDate']) + // .where('message.toUserId = :userId', { userId }) + // .andWhere('message.isCompleted = :isCompleted', { isCompleted: false }) + // .andWhere('message.isRepliedTo = :isRepliedTo', { isRepliedTo: false }) + // .take(5000) + // .getMany(); + + const messages = await messageRepository + .createQueryBuilder('message') + .leftJoinAndSelect(Case, 'c', 'c.docketNumber = message.docketNumber') + .addSelect(['c.trialLocation', 'c.trialDate']) + // .where('message.toUserId = :toUserId', { + // toUserId: '1805d1ab-18d0-43ec-bafb-654e83405416', + // }) + // .andWhere('message.isCompleted IS FALSE') + // .andWhere('message.isRepliedTo IS FALSE') + .getMany(); + + // const messages = await dataSource.query(`SELECT + // * + // FROM + // "message" + // LEFT JOIN "case" ON "case"."docketNumber" = "message"."docketNumber" + // WHERE + // "message"."toUserId" = '1805d1ab-18d0-43ec-bafb-654e83405416' + // AND "message"."isCompleted" IS FALSE + // AND "message"."isRepliedTo" IS FALSE`); applicationContext.logger.info('getUserInboxMessages end'); + console.log('*** messages', messages); + return messages.map(message => new MessageResult( transformNullToUndefined({ ...message, - trialDate: message.case?.trialDate, - trialLocation: message.case?.trialLocation, + + // trialDate: message.case?.trialDate, + // trialLocation: message.case?.trialLocation, }), { applicationContext, diff --git a/web-api/src/persistence/repository/Case.ts b/web-api/src/persistence/repository/Case.ts index 55b750bd08a..876e73fc15a 100644 --- a/web-api/src/persistence/repository/Case.ts +++ b/web-api/src/persistence/repository/Case.ts @@ -12,6 +12,6 @@ export class Case { @Column('varchar', { nullable: true }) trialDate?: string; - @OneToMany(() => Message, message => message.docketNumber) - messages?: Message[]; + // @OneToMany(() => Message, message => message.docketNumber, { nullable: true }) + // messages?: Message[]; } diff --git a/web-api/src/persistence/repository/Message.ts b/web-api/src/persistence/repository/Message.ts index a972a87cb0d..ebf4d052cb2 100644 --- a/web-api/src/persistence/repository/Message.ts +++ b/web-api/src/persistence/repository/Message.ts @@ -95,7 +95,7 @@ export class Message { @Index() toUserId!: string; - @ManyToOne(() => Case, item => item.docketNumber) - @JoinColumn({ name: 'docketNumber' }) - case!: Case; + // @ManyToOne(() => Case, item => item.docketNumber, { nullable: true }) + // @JoinColumn({ name: 'docketNumber' }) + // case?: Case; }