From 51a4afdfc71b7d8fca789cb6aa228f3728a30b70 Mon Sep 17 00:00:00 2001 From: Shaun Lum Date: Thu, 11 Jul 2024 10:33:36 -0700 Subject: [PATCH 1/4] updated vulnerabilities --- backend/package-lock.json | 179 +++++-------- frontend/package-lock.json | 528 +++++++++++++++++++++++++++++++------ frontend/package.json | 3 +- frontend/src/stores/app.ts | 1 - 4 files changed, 520 insertions(+), 191 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index 65497be4..cf051ae4 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -126,11 +126,11 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/axios": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", - "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", "dependencies": { - "follow-redirects": "^1.15.0", + "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } @@ -149,12 +149,12 @@ } }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -162,7 +162,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -181,11 +181,11 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -352,9 +352,9 @@ } }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "engines": { "node": ">= 0.6" } @@ -473,16 +473,16 @@ } }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -532,9 +532,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -565,9 +565,9 @@ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "funding": [ { "type": "individual", @@ -877,12 +877,9 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/jsonwebtoken/node_modules/semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "bin": { "semver": "bin/semver.js" }, @@ -937,17 +934,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -1247,9 +1233,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -1330,9 +1316,9 @@ "integrity": "sha512-nZi59hW3Sl5P3+wOO89eHBAAGwmCPd2aE1+dLZV5MO+ItQctIvAqihzaAXIQhvtH4KJPxM080HsnqltR2y8cWg==" }, "node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "bin": { "semver": "bin/semver" } @@ -1662,11 +1648,6 @@ "node": ">=10" } }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -1771,11 +1752,11 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "axios": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", - "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", "requires": { - "follow-redirects": "^1.15.0", + "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } @@ -1791,12 +1772,12 @@ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" }, "body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "requires": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -1804,7 +1785,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" } @@ -1819,11 +1800,11 @@ } }, "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "requires": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" } }, "buffer-equal-constant-time": { @@ -1957,9 +1938,9 @@ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" }, "cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" }, "cookie-signature": { "version": "1.0.6", @@ -2047,16 +2028,16 @@ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, "express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -2103,9 +2084,9 @@ } }, "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "requires": { "to-regex-range": "^5.0.1" } @@ -2130,9 +2111,9 @@ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, "follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" }, "form-data": { "version": "4.0.0", @@ -2335,12 +2316,9 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", - "requires": { - "lru-cache": "^6.0.0" - } + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==" } } }, @@ -2393,14 +2371,6 @@ } } }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -2614,9 +2584,9 @@ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "requires": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -2668,9 +2638,9 @@ "integrity": "sha512-nZi59hW3Sl5P3+wOO89eHBAAGwmCPd2aE1+dLZV5MO+ItQctIvAqihzaAXIQhvtH4KJPxM080HsnqltR2y8cWg==" }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" }, "send": { "version": "0.18.0", @@ -2931,11 +2901,6 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 1c3e0be8..88dfa7d1 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -14,7 +14,8 @@ "pinia": "^2.1.4", "vue": "^3.3.4", "vue-router": "^4.2.2", - "vuetify": "^3.3.11" + "vuetify": "^3.3.11", + "ws": "^8.17.0" }, "devDependencies": { "@mdi/font": "^7.2.96", @@ -115,10 +116,346 @@ "ms": "^2.1.1" } }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", "cpu": [ "x64" ], @@ -288,9 +625,9 @@ "dev": true }, "node_modules/@sideway/address": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", - "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", "dev": true, "dependencies": { "@hapi/hoek": "^9.0.0" @@ -1240,13 +1577,14 @@ "dev": true }, "node_modules/axios": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", - "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", "dev": true, "dependencies": { - "follow-redirects": "^1.14.9", - "form-data": "^4.0.0" + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, "node_modules/axios/node_modules/form-data": { @@ -1263,6 +1601,12 @@ "node": ">= 6" } }, + "node_modules/axios/node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1333,12 +1677,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "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.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -1813,9 +2157,9 @@ "dev": true }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -2097,9 +2441,9 @@ } }, "node_modules/esbuild": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", - "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", "dev": true, "hasInstallScript": true, "bin": { @@ -2109,28 +2453,28 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.17.19", - "@esbuild/android-arm64": "0.17.19", - "@esbuild/android-x64": "0.17.19", - "@esbuild/darwin-arm64": "0.17.19", - "@esbuild/darwin-x64": "0.17.19", - "@esbuild/freebsd-arm64": "0.17.19", - "@esbuild/freebsd-x64": "0.17.19", - "@esbuild/linux-arm": "0.17.19", - "@esbuild/linux-arm64": "0.17.19", - "@esbuild/linux-ia32": "0.17.19", - "@esbuild/linux-loong64": "0.17.19", - "@esbuild/linux-mips64el": "0.17.19", - "@esbuild/linux-ppc64": "0.17.19", - "@esbuild/linux-riscv64": "0.17.19", - "@esbuild/linux-s390x": "0.17.19", - "@esbuild/linux-x64": "0.17.19", - "@esbuild/netbsd-x64": "0.17.19", - "@esbuild/openbsd-x64": "0.17.19", - "@esbuild/sunos-x64": "0.17.19", - "@esbuild/win32-arm64": "0.17.19", - "@esbuild/win32-ia32": "0.17.19", - "@esbuild/win32-x64": "0.17.19" + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" } }, "node_modules/escape-string-regexp": { @@ -2606,9 +2950,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "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" @@ -2653,9 +2997,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "dev": true, "funding": [ { @@ -2731,6 +3075,20 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -3584,14 +3942,14 @@ "dev": true }, "node_modules/joi": { - "version": "17.9.2", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.9.2.tgz", - "integrity": "sha512-Itk/r+V4Dx0V3c7RLFdRh12IOjySm2/WGPMubBT92cQvRfYZhPM2W0hZlctjj72iES8jsRCwp7S/cRmWBnJ4nw==", + "version": "17.13.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", + "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==", "dev": true, "dependencies": { - "@hapi/hoek": "^9.0.0", - "@hapi/topo": "^5.0.0", - "@sideway/address": "^4.1.3", + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", "@sideway/formula": "^3.0.1", "@sideway/pinpoint": "^2.0.0" } @@ -5105,9 +5463,9 @@ } }, "node_modules/rollup": { - "version": "3.25.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.25.3.tgz", - "integrity": "sha512-ZT279hx8gszBj9uy5FfhoG4bZx8c+0A1sbqtr7Q3KNWIizpTdDEPZbV2xcbvHsnFp4MavCQYZyzApJ+virB8Yw==", + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -5412,19 +5770,19 @@ "dev": true }, "node_modules/start-server-and-test": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-2.0.0.tgz", - "integrity": "sha512-UqKLw0mJbfrsG1jcRLTUlvuRi9sjNuUiDOLI42r7R5fA9dsFoywAy9DoLXNYys9B886E4RCKb+qM1Gzu96h7DQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-2.0.4.tgz", + "integrity": "sha512-CKNeBTcP0hVqIlNismHMudb9q3lLdAjcVPO13/7gfI66fcJpeIb/o4NzQd1JK/CD+lfWVqr10ZH9Y14+OwlJuw==", "dev": true, "dependencies": { "arg": "^5.0.2", "bluebird": "3.7.2", "check-more-types": "2.24.0", - "debug": "4.3.4", + "debug": "4.3.5", "execa": "5.1.1", "lazy-ass": "1.6.0", "ps-tree": "1.2.0", - "wait-on": "7.0.1" + "wait-on": "7.2.0" }, "bin": { "server-test": "src/bin/start.js", @@ -5432,7 +5790,7 @@ "start-test": "src/bin/start.js" }, "engines": { - "node": ">=6" + "node": ">=16" } }, "node_modules/start-server-and-test/node_modules/execa": { @@ -5971,14 +6329,14 @@ } }, "node_modules/vite": { - "version": "4.3.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", - "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz", + "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==", "dev": true, "dependencies": { - "esbuild": "^0.17.5", - "postcss": "^8.4.23", - "rollup": "^3.21.0" + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" }, "bin": { "vite": "bin/vite.js" @@ -5986,12 +6344,16 @@ "engines": { "node": "^14.18.0 || >=16.0.0" }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@types/node": ">= 14", "less": "*", + "lightningcss": "^1.21.0", "sass": "*", "stylus": "*", "sugarss": "*", @@ -6004,6 +6366,9 @@ "less": { "optional": true }, + "lightningcss": { + "optional": true + }, "sass": { "optional": true }, @@ -6273,16 +6638,16 @@ } }, "node_modules/wait-on": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.0.1.tgz", - "integrity": "sha512-9AnJE9qTjRQOlTZIldAaf/da2eW0eSRSgcqq85mXQja/DW3MriHxkpODDSUEg+Gri/rKEcXUZHe+cevvYItaog==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.2.0.tgz", + "integrity": "sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ==", "dev": true, "dependencies": { - "axios": "^0.27.2", - "joi": "^17.7.0", + "axios": "^1.6.1", + "joi": "^17.11.0", "lodash": "^4.17.21", - "minimist": "^1.2.7", - "rxjs": "^7.8.0" + "minimist": "^1.2.8", + "rxjs": "^7.8.1" }, "bin": { "wait-on": "bin/wait-on" @@ -6443,10 +6808,9 @@ "dev": true }, "node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", - "dev": true, + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "engines": { "node": ">=10.0.0" }, diff --git a/frontend/package.json b/frontend/package.json index 785314c0..855ce2af 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -21,7 +21,8 @@ "pinia": "^2.1.4", "vue": "^3.3.4", "vue-router": "^4.2.2", - "vuetify": "^3.3.11" + "vuetify": "^3.3.11", + "ws": "^8.17.0" }, "devDependencies": { "@mdi/font": "^7.2.96", diff --git a/frontend/src/stores/app.ts b/frontend/src/stores/app.ts index b0a6c1f6..8421c253 100644 --- a/frontend/src/stores/app.ts +++ b/frontend/src/stores/app.ts @@ -1,4 +1,3 @@ -import { configDefaults } from 'vitest/config'; import { storeToRefs, defineStore } from 'pinia'; import * as jsonexport from "jsonexport/dist" // import type definitions From a8ff0ab4afd6469d58605035b4c03decb89ed93e Mon Sep 17 00:00:00 2001 From: suzalflueck Date: Wed, 31 Jul 2024 13:32:41 -0700 Subject: [PATCH 2/4] Updated filtering on school, authority, and district routers --- backend/src/components/utils.js | 764 ++++++++++++++----------- backend/src/routes/authority-router.js | 69 ++- backend/src/routes/district-router.js | 126 ++-- backend/src/routes/school-router.js | 49 +- backend/src/util/constants.js | 0 5 files changed, 589 insertions(+), 419 deletions(-) delete mode 100644 backend/src/util/constants.js diff --git a/backend/src/components/utils.js b/backend/src/components/utils.js index ea0f424f..87e09f86 100644 --- a/backend/src/components/utils.js +++ b/backend/src/components/utils.js @@ -1,21 +1,20 @@ const ALLOWED_FILENAMES = new Set([ - - 'districtcontacts', - 'districtmailing', - 'publicschoolcontacts', - 'independentschoolcontacts', - 'allschoolcontacts', - 'allschoolmailing', - 'authoritycontacts', - 'authoritymailing', - 'offshoreschoolrepresentatives' + "districtcontacts", + "districtmailing", + "publicschoolcontacts", + "independentschoolcontacts", + "allschoolcontacts", + "allschoolmailing", + "authoritycontacts", + "authoritymailing", + "offshoreschoolrepresentatives", // Add more allowed filepaths as needed ]); const ALLOWED_SCHOOLCATEGORYCODES = new Set([ - 'PUBLIC', - 'INDEPEND', - 'OFFSHORE' + "PUBLIC", + "INDEPEND", + "OFFSHORE", // Add more allowed filepaths as needed ]); function isAllowedSchoolCategory(category) { @@ -31,17 +30,17 @@ function createList(list, options = {}) { fieldToInclude = null, // Updated option name valueToInclude = null, // Updated option name sortFunction = null, - sortField = null + sortField = null, } = options; const filteredList = list .filter(function (item) { // Change the condition from removal to inclusion - return (!fieldToInclude || item[fieldToInclude] === valueToInclude); + return !fieldToInclude || item[fieldToInclude] === valueToInclude; }) .map(function (item) { const itemData = {}; - fields.forEach(field => { + fields.forEach((field) => { itemData[field] = item[field]; }); return itemData; @@ -58,7 +57,6 @@ function createList(list, options = {}) { }); } - return filteredList; } function removeFieldsByCriteria(inputData, criteria) { @@ -79,355 +77,441 @@ function removeFieldsByCriteria(inputData, criteria) { } function appendMailingAddressDetailsAndRemoveAddresses(data) { if (data && data.addresses && data.addresses.length > 0) { - const physicalAddress = data.addresses.find(address => address.addressTypeCode === 'PHYSICAL'); - if (physicalAddress) { - // Extract specific name-value pairs from the mailing address - const { addressLine1, addressLine2, city, postal, provinceCode, countryCode } = physicalAddress; - - // Add these name-value pairs to the original district object - data.physicalAddressLine1 = addressLine1; - data.physicalAddressLine2 = addressLine2; - data.physicalCity = city; - data.physicalPostal = postal; - data.physicalProvinceCode = provinceCode; - data.physicalCountryCode = countryCode; - - // Remove the "addresses" property - - } - const courierAddress = data.addresses.find(address => address.addressTypeCode === 'MAILING'); - if (courierAddress) { - // Extract specific name-value pairs from the mailing address - const { addressLine1, addressLine2, city, postal, provinceCode, countryCode } = courierAddress; - - // Add these name-value pairs to the original district object - data.mailingAddressLine1 = addressLine1; - data.mailingAddressLine2 = addressLine2; - data.mailingCity = city; - data.mailingPostal = postal; - data.mailingProvinceCode = provinceCode; - data.mailingCountryCode = countryCode; - - // Remove the "addresses" property - } - delete data.addresses; - delete data.contacts; - } -} -function addDistrictLabels(jsonData, districtList) { - if (jsonData.content && Array.isArray(jsonData.content)) { - jsonData.content.forEach(dataItem => { - const district = districtList.find(item => item.districtId === dataItem.districtId); - if (district) { - dataItem.districtNumber = district.districtNumber; - dataItem.districtName = district.displayName; - } - }); + const physicalAddress = data.addresses.find( + (address) => address.addressTypeCode === "PHYSICAL" + ); + if (physicalAddress) { + // Extract specific name-value pairs from the mailing address + const { + addressLine1, + addressLine2, + city, + postal, + provinceCode, + countryCode, + } = physicalAddress; + + // Add these name-value pairs to the original district object + data.physicalAddressLine1 = addressLine1; + data.physicalAddressLine2 = addressLine2; + data.physicalCity = city; + data.physicalPostal = postal; + data.physicalProvinceCode = provinceCode; + data.physicalCountryCode = countryCode; + + // Remove the "addresses" property } - return jsonData - } - - function districtNumberSort(a, b) { - // Convert the strings to numbers for comparison - const numA = parseInt(a, 10); - const numB = parseInt(b, 10); - - if (numA < numB) { - return -1; + const courierAddress = data.addresses.find( + (address) => address.addressTypeCode === "MAILING" + ); + if (courierAddress) { + // Extract specific name-value pairs from the mailing address + const { + addressLine1, + addressLine2, + city, + postal, + provinceCode, + countryCode, + } = courierAddress; + + // Add these name-value pairs to the original district object + data.mailingAddressLine1 = addressLine1; + data.mailingAddressLine2 = addressLine2; + data.mailingCity = city; + data.mailingPostal = postal; + data.mailingProvinceCode = provinceCode; + data.mailingCountryCode = countryCode; + + // Remove the "addresses" property } - if (numA > numB) { - return 1; - } - return 0; + delete data.addresses; + delete data.contacts; } - function formatGrades(grades, schoolGrades) { - const result = {}; - - // Create a set of all school grade codes from the provided grades - const gradeCodesSet = new Set(grades.map(grade => grade.schoolGradeCode)); - - // Include all school grade codes in the result object - for (const grade of grades) { - result[grade.schoolGradeCode] = "Y"; - } - - // Set the value to "N" for school grade codes not in the provided grades - for (const grade of schoolGrades) { - if (!gradeCodesSet.has(grade.schoolGradeCode)) { - result[grade.schoolGradeCode] = "N"; +} +function addDistrictLabels(jsonData, districtList) { + if (jsonData.content && Array.isArray(jsonData.content)) { + jsonData.content.forEach((dataItem) => { + const district = districtList.find( + (item) => item.districtId === dataItem.districtId + ); + if (district) { + dataItem.districtNumber = district.districtNumber; + dataItem.districtName = district.displayName; } - } - - return result; - } - - function sortJSONByDistrictNumber(districts) { - return districts.slice().sort((a, b) => { - const districtNumberA = a['District Number'] || ''; - const districtNumberB = b['District Number'] || ''; - return districtNumberA.localeCompare(districtNumberB, undefined, { numeric: true, sensitivity: 'base' }); }); } - function sortJSONBySchoolCode(schools) { - return schools.slice().sort((a, b) => { - const schoolCodeA = a.mincode || ''; - const schoolCodeB = b.mincode || ''; - return schoolCodeA.localeCompare(schoolCodeB, undefined, { numeric: true, sensitivity: 'base' }); - }); - } + return jsonData; +} - function sortByProperty(arr, propertyName, options = { numeric: true, sensitivity: 'base' }) { - return arr.slice().sort((a, b) => { - const valueA = a[propertyName] || ''; - const valueB = b[propertyName] || ''; - return valueA.localeCompare(valueB, undefined, options); - }); - } - - function rearrangeAndRelabelObjectProperties(object, propertyList) { - const reorderedObject = {}; - propertyList.forEach((propertyInfo) => { - const prop = propertyInfo.property; - const label = propertyInfo.label; - reorderedObject[label] = object.hasOwnProperty(prop) ? object[prop] : ""; - }); - return reorderedObject; - } +function districtNumberSort(a, b) { + // Convert the strings to numbers for comparison + const numA = parseInt(a, 10); + const numB = parseInt(b, 10); - function normalizeJsonObject(sourceArray, referenceArray, matchKey, condition, includeFields) { - return sourceArray.map((item) => { - const matchingItem = referenceArray.find( - (info) => info[matchKey] === item[matchKey] && (!condition || condition(info)) - ); - if (matchingItem) { - return { - ...item, - ...includeFields.reduce((result, field) => { - result[matchKey + "_" + field] = matchingItem[field]; - return result; - }, {}), - }; - } - return item; - }); + if (numA < numB) { + return -1; } - function filterRemoveByField(data, field, valuesToExclude) { - return data.filter(item => !valuesToExclude.includes(item[field])); + if (numA > numB) { + return 1; } - function filterIncludeByField(data, field, valuesToInclude) { - return data.filter(item => valuesToInclude.includes(item[field])); - } - - function filterByPubliclyAvailableCodes(jsonArray, fieldName, publicCodes) { - // Filter the array based on the condition - const filteredArray = jsonArray.filter(item => { - // Extract the field value (or use an empty string if the field is not present) - const fieldValue = item[fieldName] || ''; - - // Check if the fieldValue exactly matches any string from the stringsToRemove array - return publicCodes.includes(fieldValue); - }); - - return filteredArray; + return 0; +} +function formatGrades(grades, schoolGrades) { + const result = {}; + + // Create a set of all school grade codes from the provided grades + const gradeCodesSet = new Set(grades.map((grade) => grade.schoolGradeCode)); + + // Include all school grade codes in the result object + for (const grade of grades) { + result[grade.schoolGradeCode] = "Y"; } - function filterByField(jsonArray, fieldName, stringsToRemove) { - // Filter the array based on the condition - const filteredArray = jsonArray.filter(item => { - // Extract the field value (or use an empty string if the field is not present) - const fieldValue = item[fieldName] || ''; - - // Check if the fieldValue exactly matches any string from the stringsToRemove array - return !stringsToRemove.includes(fieldValue); - }); - - return filteredArray; + + // Set the value to "N" for school grade codes not in the provided grades + for (const grade of schoolGrades) { + if (!gradeCodesSet.has(grade.schoolGradeCode)) { + result[grade.schoolGradeCode] = "N"; + } } - function filterByOpenedAndClosedDate(data){ - const currentDate = new Date(); - - return data.filter(item => { - const closedDate = item.closedDate ? new Date(item.closedDate) : null; - const openedDate = item.openedDate ? new Date(item.openedDate) : null; - - return (closedDate === null && currentDate > openedDate) || (currentDate < closedDate && currentDate > openedDate) ; + + return result; +} + +function sortJSONByDistrictNumber(districts) { + return districts.slice().sort((a, b) => { + const districtNumberA = a["District Number"] || ""; + const districtNumberB = b["District Number"] || ""; + return districtNumberA.localeCompare(districtNumberB, undefined, { + numeric: true, + sensitivity: "base", }); - } - function filterByExpiryDate(data) { - const currentDate = new Date(); - - return data.filter(item => { - const expiryDate = item.expiryDate ? new Date(item.expiryDate) : null; - const effectiveDate = item.effectiveDate ? new Date(item.effectiveDate) : null; - - return (expiryDate === null && currentDate > effectiveDate) || (currentDate < expiryDate && currentDate > effectiveDate) ; + }); +} +function sortJSONBySchoolCode(schools) { + return schools.slice().sort((a, b) => { + const schoolCodeA = a.mincode || ""; + const schoolCodeB = b.mincode || ""; + return schoolCodeA.localeCompare(schoolCodeB, undefined, { + numeric: true, + sensitivity: "base", }); - } - function getArrayofNonPubliclyAvailableCodes(codes, field) { - if (!Array.isArray(codes)) { - throw new Error('Invalid input. Expecting an array of objects.'); - } - - // Filter out objects where "publiclyAvailable" is false - const nonPubliclyAvailableCodes = codes - .filter(item => item && item.publiclyAvailable !== true) - .map(item => item[field]); - - return nonPubliclyAvailableCodes; - } - function addFundingGroups(schools, fundingGroups) { - try { - // Process each school in the array - const schoolsWithFunding = schools.map(school => { - // Find all matching funding groups by mincode - const matchingFundingGroups = fundingGroups.filter(fundingGroup => - fundingGroup.mincode === school.mincode - ); - - const schoolWithFunding = { - ...school, - primaryK3: "", // Replace with an appropriate default value - elementary47: "", // Replace with an appropriate default value - juniorSecondary810: "", // Replace with an appropriate default value - seniorSecondary1112: "" // Replace with an appropriate default value - }; - - // Iterate through the matching funding groups - matchingFundingGroups.forEach(matchingFundingGroup => { - // Access the fundingGroupCode and fundingSubCode properties - const fundingGroupCode = matchingFundingGroup.fundingGroupCode; - const fundingSubCode = matchingFundingGroup.fundingGroupSubCode; - - // Check the fundingSubCode and update the school information - switch (fundingSubCode) { - case "01": - schoolWithFunding.primaryK3 = fundingGroupCode; - break; - case "04": - schoolWithFunding.elementary47 = fundingGroupCode; - break; - case "08": - schoolWithFunding.juniorSecondary810 = fundingGroupCode; - break; - case "11": - schoolWithFunding.seniorSecondary1112 = fundingGroupCode; - break; - default: - break; - } - }); - - return schoolWithFunding; - }); + }); +} - return schoolsWithFunding; - } catch (error) { - // Handle the error here, you can log it or perform other actions - console.error("An error occurred in addFundingGroups:", error); - // Optionally, you can rethrow the error if needed - throw error; - } +function sortByProperty( + arr, + propertyName, + options = { numeric: true, sensitivity: "base" } +) { + return arr.slice().sort((a, b) => { + const valueA = a[propertyName] || ""; + const valueB = b[propertyName] || ""; + return valueA.localeCompare(valueB, undefined, options); + }); +} + +function rearrangeAndRelabelObjectProperties(object, propertyList) { + const reorderedObject = {}; + propertyList.forEach((propertyInfo) => { + const prop = propertyInfo.property; + const label = propertyInfo.label; + reorderedObject[label] = object.hasOwnProperty(prop) ? object[prop] : ""; + }); + return reorderedObject; } - function getArrayofPubliclyAvailableCodes(codes, field) { - if (!Array.isArray(codes)) { - throw new Error('Invalid input. Expecting an array of objects.'); + +function normalizeJsonObject( + sourceArray, + referenceArray, + matchKey, + condition, + includeFields +) { + return sourceArray.map((item) => { + const matchingItem = referenceArray.find( + (info) => + info[matchKey] === item[matchKey] && (!condition || condition(info)) + ); + if (matchingItem) { + return { + ...item, + ...includeFields.reduce((result, field) => { + result[matchKey + "_" + field] = matchingItem[field]; + return result; + }, {}), + }; } - - // Filter out objects where "publiclyAvailable" is true - const publiclyAvailableCodes = codes - .filter(item => item && item.publiclyAvailable === true) - .map(item => item[field]); - - return publiclyAvailableCodes; + return item; + }); +} +function filterRemoveByField(data, field, valuesToExclude) { + return data.filter((item) => !valuesToExclude.includes(item[field])); +} +function filterIncludeByField(data, field, valuesToInclude) { + return data.filter((item) => valuesToInclude.includes(item[field])); +} + +function filterByPubliclyAvailableCodes(jsonArray, fieldName, publicCodes) { + // Filter the array based on the condition + const filteredArray = jsonArray.filter((item) => { + // Extract the field value (or use an empty string if the field is not present) + const fieldValue = item[fieldName] || ""; + + // Check if the fieldValue exactly matches any string from the stringsToRemove array + return publicCodes.includes(fieldValue); + }); + + return filteredArray; +} +function filterByField(jsonArray, fieldName, stringsToRemove) { + // Filter the array based on the condition + const filteredArray = jsonArray.filter((item) => { + // Extract the field value (or use an empty string if the field is not present) + const fieldValue = item[fieldName] || ""; + + // Check if the fieldValue exactly matches any string from the stringsToRemove array + return !stringsToRemove.includes(fieldValue); + }); + + return filteredArray; +} +function filterByOpenedAndClosedDate(data) { + const currentDate = new Date(); + + return data.filter((item) => { + const closedDate = item.closedDate ? new Date(item.closedDate) : null; + const openedDate = item.openedDate ? new Date(item.openedDate) : null; + + return ( + (closedDate === null && currentDate > openedDate) || + (currentDate < closedDate && currentDate > openedDate) + ); + }); +} +function filterByExpiryDate(data) { + const currentDate = new Date(); + + return data.filter((item) => { + const expiryDate = item.expiryDate ? new Date(item.expiryDate) : null; + const effectiveDate = item.effectiveDate + ? new Date(item.effectiveDate) + : null; + + return ( + (expiryDate === null && currentDate > effectiveDate) || + (currentDate < expiryDate && currentDate > effectiveDate) + ); + }); +} +function getArrayofNonPubliclyAvailableCodes(codes, field) { + if (!Array.isArray(codes)) { + throw new Error("Invalid input. Expecting an array of objects."); } - function createSchoolCache(schoolData, schoolGrades) { - // Preload convertedGrades with schoolGrades.schoolGradeCode and set the value to "N" + // Filter out objects where "publiclyAvailable" is false + const nonPubliclyAvailableCodes = codes + .filter((item) => item && item.publiclyAvailable !== true) + .map((item) => item[field]); - // Map over each school object - return schoolData.map((school) => { - const convertedGrades = {}; - schoolGrades.forEach((grade) => { - convertedGrades[grade.schoolGradeCode] = "N"; - }); + return nonPubliclyAvailableCodes; +} +function addFundingGroups(schools, fundingGroups) { + try { + // Process each school in the array + const schoolsWithFunding = schools.map((school) => { + // Find all matching funding groups by mincode + const matchingFundingGroups = fundingGroups.filter( + (fundingGroup) => fundingGroup.mincode === school.mincode + ); - const addressFields = { - mailing: {}, - physical: {}, + const schoolWithFunding = { + ...school, + primaryK3: "", // Replace with an appropriate default value + elementary47: "", // Replace with an appropriate default value + juniorSecondary810: "", // Replace with an appropriate default value + seniorSecondary1112: "", // Replace with an appropriate default value }; - // Loop through the grades and set the value to "Y" for each grade - school.grades.forEach((grade) => { - convertedGrades[grade.schoolGradeCode] = "Y"; + // Iterate through the matching funding groups + matchingFundingGroups.forEach((matchingFundingGroup) => { + // Access the fundingGroupCode and fundingSubCode properties + const fundingGroupCode = matchingFundingGroup.fundingGroupCode; + const fundingSubCode = matchingFundingGroup.fundingGroupSubCode; + + // Check the fundingSubCode and update the school information + switch (fundingSubCode) { + case "01": + schoolWithFunding.primaryK3 = fundingGroupCode; + break; + case "04": + schoolWithFunding.elementary47 = fundingGroupCode; + break; + case "08": + schoolWithFunding.juniorSecondary810 = fundingGroupCode; + break; + case "11": + schoolWithFunding.seniorSecondary1112 = fundingGroupCode; + break; + default: + break; + } }); - // Extract and format principal contact information if it exists - const principalContact = school.contacts.find((contact) => contact.schoolContactTypeCode === "PRINCIPAL"); - if (principalContact) { - school.firstName = principalContact.firstName; - school.lastName = principalContact.lastName; - - - } + return schoolWithFunding; + }); - // Loop through addresses and update the fields based on addressTypeCode - school.addresses.forEach((address) => { - if (address.addressTypeCode === "MAILING") { - Object.keys(address).forEach((field) => { - // Exclude the specified fields - if (![ - "createUser", - "updateUser", - "createDate", - "updateDate", - "schoolAddressId", - "schoolId", - "addressTypeCode" - ].includes(field)) { - addressFields.mailing[`mailing_${field}`] = address[field]; - } - }); - } else if (address.addressTypeCode === "PHYSICAL") { - Object.keys(address).forEach((field) => { - if (![ - "createUser", - "updateUser", - "createDate", - "updateDate", - "schoolAddressId", - "schoolId", - "addressTypeCode" - ].includes(field)) { - addressFields.mailing[`physical_${field}`] = address[field]; - } - }); - } - }); + return schoolsWithFunding; + } catch (error) { + // Handle the error here, you can log it or perform other actions + console.error("An error occurred in addFundingGroups:", error); + // Optionally, you can rethrow the error if needed + throw error; + } +} +function getArrayofPubliclyAvailableCodes(codes, field) { + if (!Array.isArray(codes)) { + throw new Error("Invalid input. Expecting an array of objects."); + } + + // Filter out objects where "publiclyAvailable" is true + const publiclyAvailableCodes = codes + .filter((item) => item && item.publiclyAvailable === true) + .map((item) => item[field]); - // Concatenate neighborhoodLearningTypeCode into a single string - const nlc = school.neighborhoodLearning.map(learning => learning.neighborhoodLearningTypeCode).join(' | '); - - // Merge the address fields and nlc into the school object - Object.assign(school, convertedGrades, addressFields.mailing, addressFields.physical, { nlc }); - - // Remove the original grades property and the updated address object - delete school.grades; - delete school.addresses; - delete school.neighborhoodLearning; - delete school.createUser; - delete school.updateUser; - delete school.updateDate; - delete school.createDate; - delete school.schoolId; - delete school.openedDate; - delete school.closedDate; - delete school.notes; - delete school.schoolMove.createUser; - delete school.schoolMove; - - // Remove the contacts property - delete school.contacts; - - return school; + return publiclyAvailableCodes; +} +function createSchoolCache(schoolData, schoolGrades) { + // Preload convertedGrades with schoolGrades.schoolGradeCode and set the value to "N" + + // Map over each school object + return schoolData.map((school) => { + const convertedGrades = {}; + schoolGrades.forEach((grade) => { + convertedGrades[grade.schoolGradeCode] = "N"; }); + + const addressFields = { + mailing: {}, + physical: {}, + }; + + // Loop through the grades and set the value to "Y" for each grade + school.grades.forEach((grade) => { + convertedGrades[grade.schoolGradeCode] = "Y"; + }); + + // Extract and format principal contact information if it exists + const principalContact = school.contacts.find( + (contact) => contact.schoolContactTypeCode === "PRINCIPAL" + ); + if (principalContact) { + school.firstName = principalContact.firstName; + school.lastName = principalContact.lastName; + } + + // Loop through addresses and update the fields based on addressTypeCode + school.addresses.forEach((address) => { + if (address.addressTypeCode === "MAILING") { + Object.keys(address).forEach((field) => { + // Exclude the specified fields + if ( + ![ + "createUser", + "updateUser", + "createDate", + "updateDate", + "schoolAddressId", + "schoolId", + "addressTypeCode", + ].includes(field) + ) { + addressFields.mailing[`mailing_${field}`] = address[field]; + } + }); + } else if (address.addressTypeCode === "PHYSICAL") { + Object.keys(address).forEach((field) => { + if ( + ![ + "createUser", + "updateUser", + "createDate", + "updateDate", + "schoolAddressId", + "schoolId", + "addressTypeCode", + ].includes(field) + ) { + addressFields.mailing[`physical_${field}`] = address[field]; + } + }); + } + }); + + // Concatenate neighborhoodLearningTypeCode into a single string + const nlc = school.neighborhoodLearning + .map((learning) => learning.neighborhoodLearningTypeCode) + .join(" | "); + + // Merge the address fields and nlc into the school object + Object.assign( + school, + convertedGrades, + addressFields.mailing, + addressFields.physical, + { nlc } + ); + + // Remove the original grades property and the updated address object + delete school.grades; + delete school.addresses; + delete school.neighborhoodLearning; + delete school.createUser; + delete school.updateUser; + delete school.updateDate; + delete school.createDate; + delete school.schoolId; + delete school.openedDate; + delete school.closedDate; + delete school.notes; + delete school.schoolMove.createUser; + delete school.schoolMove; + + // Remove the contacts property + delete school.contacts; + + return school; + }); } - module.exports = {addFundingGroups, filterByOpenedAndClosedDate, filterByPubliclyAvailableCodes, getArrayofPubliclyAvailableCodes, filterByExpiryDate, filterRemoveByField,filterIncludeByField, sortByProperty,getArrayofNonPubliclyAvailableCodes,filterByField,appendMailingAddressDetailsAndRemoveAddresses,sortJSONBySchoolCode,sortJSONByDistrictNumber,normalizeJsonObject, removeFieldsByCriteria, createList, isSafeFilePath,isAllowedSchoolCategory, addDistrictLabels, districtNumberSort, createSchoolCache, formatGrades, rearrangeAndRelabelObjectProperties}; \ No newline at end of file + +function isActiveEntity(effective, expiry) { + let today = new Date(); + return today > new Date(effective) && (!expiry || today < new Date(expiry)); +} + +module.exports = { + addFundingGroups, + filterByOpenedAndClosedDate, + filterByPubliclyAvailableCodes, + getArrayofPubliclyAvailableCodes, + filterByExpiryDate, + filterRemoveByField, + filterIncludeByField, + sortByProperty, + getArrayofNonPubliclyAvailableCodes, + filterByField, + appendMailingAddressDetailsAndRemoveAddresses, + sortJSONBySchoolCode, + sortJSONByDistrictNumber, + normalizeJsonObject, + removeFieldsByCriteria, + createList, + isSafeFilePath, + isAllowedSchoolCategory, + addDistrictLabels, + districtNumberSort, + createSchoolCache, + formatGrades, + rearrangeAndRelabelObjectProperties, + isActiveEntity, +}; diff --git a/backend/src/routes/authority-router.js b/backend/src/routes/authority-router.js index 58fc2a03..41593888 100644 --- a/backend/src/routes/authority-router.js +++ b/backend/src/routes/authority-router.js @@ -12,6 +12,7 @@ const { appendMailingAddressDetailsAndRemoveAddresses, rearrangeAndRelabelObjectProperties, sortByProperty, + isActiveEntity, } = require("../components/utils.js"); //Batch Routes router.get("/all-mailing/:type", checkToken, getAllAuthorityMailing); @@ -87,34 +88,13 @@ async function getAllAuthorityMailing(req, res) { log.error("getData Error", e.response ? e.response.status : e.message); } } -async function getDistrictCodes(req) { - if (!listCache.has("districtCodesList")) { - const url = `${config.get( - "server:instituteAPIURL" - )}/institute/authority-contact-type-codes`; // Update the URL according to your API endpoint - try { - const response = await axios.get(url, { - headers: { Authorization: `Bearer ${req.accessToken}` }, - }); - const districtCodeList = response.data; - listCache.set("districtCodesList", districtCodeList); - return districtCodeList; - } catch (e) { - log.error( - "getDistrictList Error", - e.response ? e.response.status : e.message - ); - } - } else { - const districtCodeList = await listCache.get("districtCodesList"); - return districtCodeList; - } -} + async function getAuthority(req, res) { const { id } = req.params; + let currentDate = new Date().toISOString().substring(0, 19); const params = [ { - condition: null, + condition: "AND", searchCriteriaList: [ { key: "independentAuthorityId", @@ -125,6 +105,37 @@ async function getAuthority(req, res) { }, ], }, + { + condition: "AND", + searchCriteriaList: [ + { + key: "closedDate", + operation: "eq", + value: null, + valueType: "STRING", + condition: "OR", + }, + { + key: "closedDate", + operation: "gte", + value: currentDate, + valueType: "DATE_TIME", + condition: "OR", + }, + ], + }, + { + condition: "AND", + searchCriteriaList: [ + { + key: "openedDate", + operation: "lte", + value: currentDate, + valueType: "DATE_TIME", + condition: "AND", + }, + ], + }, ]; const jsonString = JSON.stringify(params); @@ -142,6 +153,14 @@ async function getAuthority(req, res) { headers: { Authorization: `Bearer ${req.accessToken}` }, }); + // Filter Authority Contacts + const filteredAuthorityContacts = + authorityDataResponse?.data?.contacts?.filter((contact) => + isActiveEntity(contact.effectiveDate, contact.expiryDate) + ); + // Overwrite Authority Contacts + authorityDataResponse.data.contacts = filteredAuthorityContacts; + const authoritySchoolsResponse = await axios.get(authoritySchoolsUrl, { headers: { Authorization: `Bearer ${req.accessToken}` }, }); @@ -162,6 +181,8 @@ async function getAuthority(req, res) { openedDate < today ); }); + + console.log(authorityDataResponse.data); const authorityJSON = { authorityData: authorityDataResponse.data, authoritySchools: filteredSchoolsResponse, diff --git a/backend/src/routes/district-router.js b/backend/src/routes/district-router.js index 8df54a90..5a26a2e7 100644 --- a/backend/src/routes/district-router.js +++ b/backend/src/routes/district-router.js @@ -7,8 +7,22 @@ const axios = require("axios"); const fs = require("fs"); const path = require("path"); const { checkToken } = require("../components/auth"); -const { listCache} = require("../components/cache"); -const {addFundingGroups, getArrayofPubliclyAvailableCodes,filterRemoveByField, filterByExpiryDate, getArrayofNonPubliclyAvailableCodes, filterByField,appendMailingAddressDetailsAndRemoveAddresses, rearrangeAndRelabelObjectProperties, addDistrictLabels, normalizeJsonObject, sortJSONByDistrictNumber, removeFieldsByCriteria, filterByPubliclyAvailableCodes} = require("../components/utils.js") +const { listCache } = require("../components/cache"); +const { + addFundingGroups, + getArrayofPubliclyAvailableCodes, + filterRemoveByField, + filterByExpiryDate, + getArrayofNonPubliclyAvailableCodes, + filterByField, + appendMailingAddressDetailsAndRemoveAddresses, + rearrangeAndRelabelObjectProperties, + addDistrictLabels, + normalizeJsonObject, + sortJSONByDistrictNumber, + removeFieldsByCriteria, + filterByPubliclyAvailableCodes, +} = require("../components/utils.js"); //Batch Routes router.get("/all-contacts", checkToken, getAllDistrictContacts); @@ -319,9 +333,10 @@ async function getAllDistrictMailing(req, res) { async function getDistrict(req, res) { const { id } = req.params; + let currentDate = new Date().toISOString().substring(0, 19); const params = [ { - condition: null, + condition: "AND", searchCriteriaList: [ { key: "districtID", @@ -330,13 +345,6 @@ async function getDistrict(req, res) { valueType: "UUID", condition: "AND", }, - { - key: "closedDate", - operation: "eq", - value: null, - valueType: "STRING", - condition: "AND", - }, { key: "schoolCategoryCode", operation: "neq", @@ -360,6 +368,37 @@ async function getDistrict(req, res) { }, ], }, + { + condition: "AND", + searchCriteriaList: [ + { + key: "closedDate", + operation: "eq", + value: null, + valueType: "STRING", + condition: "OR", + }, + { + key: "closedDate", + operation: "gte", + value: currentDate, + valueType: "DATE_TIME", + condition: "OR", + }, + ], + }, + { + condition: "AND", + searchCriteriaList: [ + { + key: "openedDate", + operation: "lte", + value: currentDate, + valueType: "DATE_TIME", + condition: "AND", + }, + ], + }, ]; const jsonString = JSON.stringify(params); @@ -381,13 +420,13 @@ async function getDistrict(req, res) { }); const contactTypeCodes = await getDistrictCodes(req); - const schoolCategoryCodes = await listCache.get("categoryCodes") - const facilityCodes = await listCache.get("facilityCodes") - const fundingGroups = await listCache.get("fundingGroups") - const districtContactCodeTypes = await listCache.get("codesList") - const nonPublicContactTypeCodes = getNonPublicContactTypeCodes(contactTypeCodes); - - + const schoolCategoryCodes = await listCache.get("categoryCodes"); + const facilityCodes = await listCache.get("facilityCodes"); + const fundingGroups = await listCache.get("fundingGroups"); + const districtContactCodeTypes = await listCache.get("codesList"); + const nonPublicContactTypeCodes = + getNonPublicContactTypeCodes(contactTypeCodes); + const districtDataPublic = removeContacts( districtDataResponse.data, nonPublicContactTypeCodes @@ -408,28 +447,43 @@ async function getDistrict(req, res) { districtDataPublicWithLabels.contacts ); - districtSchoolsResponse.data.content = normalizeJsonObject(districtSchoolsResponse.data.content, schoolCategoryCodes, "schoolCategoryCode", null, ["label", "description"]); - districtSchoolsResponse.data.content = normalizeJsonObject(districtSchoolsResponse.data.content, facilityCodes, "faciltyTypeCode", null, ["label", "description"]); - districtSchoolsResponse.data.content = addFundingGroups(districtSchoolsResponse.data.content, fundingGroups) + districtSchoolsResponse.data.content = normalizeJsonObject( + districtSchoolsResponse.data.content, + schoolCategoryCodes, + "schoolCategoryCode", + null, + ["label", "description"] + ); + districtSchoolsResponse.data.content = normalizeJsonObject( + districtSchoolsResponse.data.content, + facilityCodes, + "faciltyTypeCode", + null, + ["label", "description"] + ); + districtSchoolsResponse.data.content = addFundingGroups( + districtSchoolsResponse.data.content, + fundingGroups + ); - const today = new Date(); - const filteredSchoolsResponse = districtSchoolsResponse.data.content.filter( - (obj) => { - // if openedDate is a valid date is less than today, keep the object - const openedDate = new Date(obj.openedDate); + const today = new Date(); + const filteredSchoolsResponse = districtSchoolsResponse.data.content.filter( + (obj) => { + // if openedDate is a valid date is less than today, keep the object + const openedDate = new Date(obj.openedDate); - // If closedDate is a valid date greater than today, keep the object - const closedDate = new Date(obj.closedDate); + // If closedDate is a valid date greater than today, keep the object + const closedDate = new Date(obj.closedDate); - // return obj IF closedDate does not exist OR is after than current date - // AND openedDate exists AND is before current date - return ( - (!obj.closedDate || closedDate > today) && - obj.openedDate && - openedDate < today - ); - } - ); + // return obj IF closedDate does not exist OR is after than current date + // AND openedDate exists AND is before current date + return ( + (!obj.closedDate || closedDate > today) && + obj.openedDate && + openedDate < today + ); + } + ); const districtJSON = { districtData: districtDataPublicWithLabels, districtSchools: filteredSchoolsResponse, diff --git a/backend/src/routes/school-router.js b/backend/src/routes/school-router.js index 649f17b1..ee8f1acf 100644 --- a/backend/src/routes/school-router.js +++ b/backend/src/routes/school-router.js @@ -17,7 +17,8 @@ const { sortJSONBySchoolCode, rearrangeAndRelabelObjectProperties, filterByPubliclyAvailableCodes, - addFundingGroups + addFundingGroups, + isActiveEntity, } = require("../components/utils"); const { checkToken } = require("../components/auth"); const { schoolCache, listCache, codeCache } = require("../components/cache"); @@ -167,6 +168,7 @@ async function getSchool(req, res) { expiryDate: "2099-12-31T00:00:00", }, ]; + const schoolData = response.data; const includedFields = ["label", "description"]; @@ -177,7 +179,6 @@ async function getSchool(req, res) { (info) => info.publiclyAvailable === true, includedFields ); - schoolData.contacts = filterByPubliclyAvailableCodes( schoolData.contacts, @@ -186,26 +187,27 @@ async function getSchool(req, res) { contactTypeCodes.codesList.schoolContactTypeCodes, "schoolContactTypeCode" ) - ); + ).filter((contact) => + isActiveEntity(contact.effectiveDate, contact.expiryDate) + ); // Filter out inactive contacts schoolData.contacts = filterByExpiryDate(schoolData.contacts); const formattedGrades = formatGrades(schoolData.grades, schoolGrades); const schoolWithFormattedGrades = [{ ...schoolData, ...formattedGrades }]; - - const schoolsWithFundingGroups = addFundingGroups(schoolWithFormattedGrades, fundingGroups) + + const schoolsWithFundingGroups = addFundingGroups( + schoolWithFormattedGrades, + fundingGroups + ); res.json(schoolsWithFundingGroups[0]); - }) .catch((e) => { log.error("getSchools Error", e.response ? e.response.status : e.message); }); } -async function getAllSchoolMailing(req, res) { - const allSchools = await getAllSchools(req, res); - res.json(allSchools); -} + async function getAllSchools(req, res) { const { schoolCategory } = req.params; - const contactTypeCodes = await listCache.get("codesList"); + //const contactTypeCodes = await listCache.get("codesList"); let params = []; if (await !schoolCache.has("openschoollist" + schoolCategory)) { @@ -286,7 +288,7 @@ async function getAllSchools(req, res) { { property: "physical_addressLine1", label: "Physical Address" }, { property: "physical_city", label: "Physical City" }, { property: "physical_provinceCode", label: "Physical Province" }, - { property: "physical_postal", label: "Physical Postal Code" }, + { property: "physical_postal", label: "Physical Postal Code" }, { property: "firstName", label: "Principal First Name" }, { property: "lastName", label: "Principal Last Name" }, { property: "facilityTypeCode", label: "Type" }, @@ -315,9 +317,18 @@ async function getAllSchools(req, res) { { property: "GRADE11", label: "Grade 11 Enrollment" }, { property: "GRADE12", label: "Grade 12 Enrollment" }, { property: "primaryK3", label: "Group Classification Primary K-3" }, - { property: "elementary47", label: "Group Classification Elementary 4-7 EU" }, - { property: "juniorSecondary810", label: "Group Classification Junior Secondary 8-10 SU" }, - { property: "seniorSecondary1112", label: "Group Classification Senior Secondary 11-12" }, + { + property: "elementary47", + label: "Group Classification Elementary 4-7 EU", + }, + { + property: "juniorSecondary810", + label: "Group Classification Junior Secondary 8-10 SU", + }, + { + property: "seniorSecondary1112", + label: "Group Classification Senior Secondary 11-12", + }, ]; const mailingListpropertyOrder = [ { property: "districtNumber", label: "District Number" }, @@ -343,8 +354,8 @@ async function getAllSchools(req, res) { schoolGrades ) ); - - openSchoolList = addFundingGroups(openSchoolListSorted, fundingGroups) + + openSchoolList = addFundingGroups(openSchoolListSorted, fundingGroups); let openSchoolMailingList = [...openSchoolList]; openSchoolList = normalizeJsonObject( @@ -354,7 +365,7 @@ async function getAllSchools(req, res) { null, ["label", "description"] ); - + openSchoolList = normalizeJsonObject( openSchoolList, facilityCodes, @@ -430,4 +441,4 @@ async function getAllSchools(req, res) { } } -module.exports = router; \ No newline at end of file +module.exports = router; diff --git a/backend/src/util/constants.js b/backend/src/util/constants.js deleted file mode 100644 index e69de29b..00000000 From 49a10f26560f4a4c9421cbf71358fc96ac424c2a Mon Sep 17 00:00:00 2001 From: suzalflueck Date: Thu, 1 Aug 2024 14:05:18 -0700 Subject: [PATCH 3/4] remove console log --- backend/src/routes/authority-router.js | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/src/routes/authority-router.js b/backend/src/routes/authority-router.js index 41593888..a1a73f46 100644 --- a/backend/src/routes/authority-router.js +++ b/backend/src/routes/authority-router.js @@ -182,7 +182,6 @@ async function getAuthority(req, res) { ); }); - console.log(authorityDataResponse.data); const authorityJSON = { authorityData: authorityDataResponse.data, authoritySchools: filteredSchoolsResponse, From fea87702d5bd9a76c37d65b776d5460848a8a047 Mon Sep 17 00:00:00 2001 From: suzalflueck Date: Thu, 22 Aug 2024 10:27:45 -0700 Subject: [PATCH 4/4] fix build error --- frontend/src/common/apiService.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/common/apiService.ts b/frontend/src/common/apiService.ts index f5b6e4fd..72d91bef 100644 --- a/frontend/src/common/apiService.ts +++ b/frontend/src/common/apiService.ts @@ -1,4 +1,4 @@ -import axios, { type AxiosInstance, type AxiosRequestConfig, type AxiosResponse } from 'axios'; +import axios, { type AxiosInstance, type AxiosResponse } from 'axios'; // Buffer concurrent requests while refresh token is being acquired let failedQueue: { @@ -21,9 +21,9 @@ function processQueue(error: any, token: string | null = null): void { // Create new non-global axios instance and intercept strategy const apiAxios: AxiosInstance = axios.create(); const intercept = apiAxios.interceptors.response.use( - (config: AxiosRequestConfig) => config, + (config: AxiosResponse) => config, (error: any) => { - const originalRequest: AxiosRequestConfig = error.config; + const originalRequest: AxiosResponse = error.config; if (error.response.status !== 401) { return Promise.reject(error); }