From 45d1ccf35680ebc14efba887223cc54cc5c31a27 Mon Sep 17 00:00:00 2001 From: estney Date: Mon, 5 Feb 2024 17:33:48 +0800 Subject: [PATCH 01/29] created base. import cors, dotenv, postgres, seq. uppdated index --- .gitignore | 4 +- index.js | 30 +- package-lock.json | 2211 ++++++++++++++++++++++++++++++++++++++++++++- package.json | 9 +- 4 files changed, 2216 insertions(+), 38 deletions(-) diff --git a/.gitignore b/.gitignore index 40b878db..a0d218e3 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -node_modules/ \ No newline at end of file +node_modules +dist +.env \ No newline at end of file diff --git a/index.js b/index.js index 3fd92432..9164191a 100644 --- a/index.js +++ b/index.js @@ -1,8 +1,34 @@ -import express from "express"; +//Enable CORS access to this server +const cors = require("cors"); -const PORT = 3000; +//import express to read json +const express = require("express"); + +// import env file +require("dotenv").config(); + +//-----------import auth0 middleware + +//-----------initializing Controllers, lowercase for the key + +//-----------initializing controllers + +//-----------importing DB +// const db = require("./db/models/index"); +// const {} = db; + +//port and express +const PORT = process.env.PORT; const app = express(); +// Enable CORS access to this server +app.use(cors()); + +// Enable reading JSON request bodies +app.use(express.json()); + +// <----- ROUTERS -----> + app.get("/", (req, res) => { res.send("Hello, World!"); }); diff --git a/package-lock.json b/package-lock.json index bc0ea392..61f92246 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,10 +8,15 @@ "name": "project3-backend-bootcamp", "version": "1.0.0", "dependencies": { - "express": "^4.18.1" + "cors": "^2.8.5", + "dotenv": "^16.4.1", + "express": "^4.18.1", + "pg": "^8.11.3", + "sequelize": "^6.36.0" }, "devDependencies": { - "eslint": "^8.16.0" + "eslint": "^8.16.0", + "sequelize-cli": "^6.6.2" } }, "node_modules/@eslint/eslintrc": { @@ -100,6 +105,153 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "node_modules/@isaacs/cliui": { + "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", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "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" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "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" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/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 + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "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", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "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" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "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", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@one-ini/wasm": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", + "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", + "dev": true + }, + "node_modules/@pkgjs/parseargs": { + "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" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" + }, + "node_modules/@types/node": { + "version": "20.11.16", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.16.tgz", + "integrity": "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/validator": { + "version": "13.11.8", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.8.tgz", + "integrity": "sha512-c/hzNDBh7eRF+KbCf+OoZxKbnkpaK/cKp9iLQWqB7muXtM+MtL9SUUH8vCFcLn6dH1Qm05jiexK0ofWY7TfOhQ==" + }, + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -184,12 +336,27 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, "node_modules/body-parser": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", @@ -223,6 +390,14 @@ "concat-map": "0.0.1" } }, + "node_modules/buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", + "engines": { + "node": ">=4" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -268,6 +443,33 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/cli-color": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.3.tgz", + "integrity": "sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.61", + "es6-iterator": "^2.0.3", + "memoizee": "^0.4.15", + "timers-ext": "^0.1.7" + }, + "engines": { + "node": ">=0.10" + } + }, + "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==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -286,12 +488,31 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -324,6 +545,18 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -338,6 +571,16 @@ "node": ">= 8" } }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -381,11 +624,81 @@ "node": ">=6.0.0" } }, + "node_modules/dotenv": { + "version": "16.4.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.1.tgz", + "integrity": "sha512-CjA3y+Dr3FyFDOAMnxZEGtnW9KBR2M0JvvUtXNW+dYJL5ROWxP9DUHCwgFqpMk0OXCc0ljhaNTr2w/kutYIcHQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, + "node_modules/dottie": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.6.tgz", + "integrity": "sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA==" + }, + "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 + }, + "node_modules/editorconfig": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", + "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", + "dev": true, + "dependencies": { + "@one-ini/wasm": "0.1.1", + "commander": "^10.0.0", + "minimatch": "9.0.1", + "semver": "^7.5.3" + }, + "bin": { + "editorconfig": "bin/editorconfig" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/brace-expansion": { + "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" + } + }, + "node_modules/editorconfig/node_modules/minimatch": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", + "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "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 + }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -394,6 +707,63 @@ "node": ">= 0.8" } }, + "node_modules/es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -599,6 +969,16 @@ "node": ">= 0.6" } }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, "node_modules/express": { "version": "4.18.1", "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", @@ -640,6 +1020,21 @@ "node": ">= 0.10.0" } }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -706,6 +1101,22 @@ "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", "dev": true }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -722,6 +1133,21 @@ "node": ">= 0.6" } }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -729,9 +1155,12 @@ "dev": true }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/functional-red-black-tree": { "version": "1.0.1", @@ -739,6 +1168,15 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "node_modules/get-caller-file": { + "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.*" + } + }, "node_modules/get-intrinsic": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", @@ -799,6 +1237,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -830,6 +1274,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -890,6 +1346,14 @@ "node": ">=0.8.19" } }, + "node_modules/inflection": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.13.4.tgz", + "integrity": "sha512-6I/HUDeYFfuNCVS3td055BaXBwKYuzw7K3ExVMStBowKo9oOAMJIXIHvdyR3iboTCp1b+1i5DSkIZTcwIktuDw==", + "engines": [ + "node >= 0.4.0" + ] + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -905,6 +1369,12 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -913,6 +1383,18 @@ "node": ">= 0.10" } }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -922,6 +1404,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -934,22 +1425,112 @@ "node": ">=0.10.0" } }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", "dev": true, "dependencies": { - "argparse": "^2.0.1" + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-beautify": { + "version": "1.14.11", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.11.tgz", + "integrity": "sha512-rPogWqAfoYh1Ryqqh2agUpVfbxAhbjuN1SmU86dskQUKouRiggUTCO4+2ym9UPXllc2WAp0J+T5qxn7Um3lCdw==", + "dev": true, + "dependencies": { + "config-chain": "^1.1.13", + "editorconfig": "^1.0.3", + "glob": "^10.3.3", + "nopt": "^7.2.0" }, "bin": { - "js-yaml": "bin/js-yaml.js" + "css-beautify": "js/bin/css-beautify.js", + "html-beautify": "js/bin/html-beautify.js", + "js-beautify": "js/bin/js-beautify.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/js-beautify/node_modules/brace-expansion": { + "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" + } + }, + "node_modules/js-beautify/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/js-beautify/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, "node_modules/json-schema-traverse": { @@ -964,6 +1545,18 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -977,12 +1570,37 @@ "node": ">= 0.8.0" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "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/lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", + "dev": true, + "dependencies": { + "es5-ext": "~0.10.2" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -991,6 +1609,22 @@ "node": ">= 0.6" } }, + "node_modules/memoizee": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", + "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.53", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + } + }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -1046,6 +1680,34 @@ "node": "*" } }, + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "engines": { + "node": "*" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.45", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.45.tgz", + "integrity": "sha512-HIWmqA86KcmCAhnMAN0wuDOARV/525R2+lOLotuGFzn4HO+FH+/645z2wx0Dt3iDv6/p61SIvKnDstISainhLQ==", + "dependencies": { + "moment": "^2.29.4" + }, + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -1065,6 +1727,35 @@ "node": ">= 0.6" } }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + }, + "node_modules/nopt": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", + "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==", + "dev": true, + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-inspect": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.1.tgz", @@ -1110,6 +1801,11 @@ "node": ">= 0.8.0" } }, + "node_modules/packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -1148,11 +1844,160 @@ "node": ">=8" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "node_modules/pg": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz", + "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==", + "dependencies": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.6.2", + "pg-pool": "^3.6.1", + "pg-protocol": "^1.6.0", + "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.2", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", + "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz", + "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", + "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" + }, + "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/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/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/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/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/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/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -1162,6 +2007,12 @@ "node": ">= 0.8.0" } }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -1231,6 +2082,32 @@ "url": "https://github.com/sponsors/mysticatea" } }, + "node_modules/require-directory": { + "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" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -1240,6 +2117,11 @@ "node": ">=4" } }, + "node_modules/retry-as-promised": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-7.0.4.tgz", + "integrity": "sha512-XgmCoxKWkDofwH8WddD0w85ZfqYz+ZHlr5yo+3YUCfycWawU56T5ckWXsScsj5B8tqUcIG67DxXByo3VUgiAdA==" + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -1279,6 +2161,20 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -1307,6 +2203,118 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, + "node_modules/sequelize": { + "version": "6.36.0", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.36.0.tgz", + "integrity": "sha512-PqOa11EHwA/zLmGDU4aynbsavbHJUlgRvFuC/2cA4LhOuV6NHKcQ0IXB+hNdFrGT3rULmvc4kdIwnfCNsrECMQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/sequelize" + } + ], + "dependencies": { + "@types/debug": "^4.1.8", + "@types/validator": "^13.7.17", + "debug": "^4.3.4", + "dottie": "^2.0.6", + "inflection": "^1.13.4", + "lodash": "^4.17.21", + "moment": "^2.29.4", + "moment-timezone": "^0.5.43", + "pg-connection-string": "^2.6.1", + "retry-as-promised": "^7.0.4", + "semver": "^7.5.4", + "sequelize-pool": "^7.1.0", + "toposort-class": "^1.0.1", + "uuid": "^8.3.2", + "validator": "^13.9.0", + "wkx": "^0.5.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependenciesMeta": { + "ibm_db": { + "optional": true + }, + "mariadb": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "oracledb": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-hstore": { + "optional": true + }, + "snowflake-sdk": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "tedious": { + "optional": true + } + } + }, + "node_modules/sequelize-cli": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/sequelize-cli/-/sequelize-cli-6.6.2.tgz", + "integrity": "sha512-V8Oh+XMz2+uquLZltZES6MVAD+yEnmMfwfn+gpXcDiwE3jyQygLt4xoI0zG8gKt6cRcs84hsKnXAKDQjG/JAgg==", + "dev": true, + "dependencies": { + "cli-color": "^2.0.3", + "fs-extra": "^9.1.0", + "js-beautify": "^1.14.5", + "lodash": "^4.17.21", + "resolve": "^1.22.1", + "umzug": "^2.3.0", + "yargs": "^16.2.0" + }, + "bin": { + "sequelize": "lib/sequelize", + "sequelize-cli": "lib/sequelize" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/sequelize-pool": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-7.1.0.tgz", + "integrity": "sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/sequelize/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/sequelize/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", @@ -1360,6 +2368,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/signal-exit": { + "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" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -1368,6 +2396,35 @@ "node": ">= 0.8" } }, + "node_modules/string-width": { + "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", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "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", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -1380,6 +2437,19 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "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" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -1404,12 +2474,34 @@ "node": ">=8" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "node_modules/timers-ext": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", + "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", + "dev": true, + "dependencies": { + "es5-ext": "~0.10.46", + "next-tick": "1" + } + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -1418,6 +2510,17 @@ "node": ">=0.6" } }, + "node_modules/toposort-class": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", + "integrity": "sha512-OsLcGGbYF3rMjPUf8oKktyvCiUxSbqMMS39m33MAjLTC1DVIH6x3WSt63/M77ihI09+Sdfk1AXvfhCEeUmC7mg==" + }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -1454,6 +2557,32 @@ "node": ">= 0.6" } }, + "node_modules/umzug": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz", + "integrity": "sha512-Z274K+e8goZK8QJxmbRPhl89HPO1K+ORFtm6rySPhFKfKc5GHhqdzD0SGhSWHkzoXasqJuItdhorSvY7/Cgflw==", + "dev": true, + "dependencies": { + "bluebird": "^3.7.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -1479,12 +2608,28 @@ "node": ">= 0.4.0" } }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, + "node_modules/validator": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", + "integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -1508,20 +2653,112 @@ "node": ">= 8" } }, + "node_modules/wkx": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz", + "integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/wrap-ansi": { + "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", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "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", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true + }, + "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" + } + }, + "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", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "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/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==", + "dev": true, + "engines": { + "node": ">=10" + } } }, "dependencies": { @@ -1593,6 +2830,116 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "requires": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true + }, + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true + }, + "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 + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + } + } + } + }, + "@one-ini/wasm": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", + "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", + "dev": true + }, + "@pkgjs/parseargs": { + "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 + }, + "@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "requires": { + "@types/ms": "*" + } + }, + "@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" + }, + "@types/node": { + "version": "20.11.16", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.16.tgz", + "integrity": "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ==", + "requires": { + "undici-types": "~5.26.4" + } + }, + "@types/validator": { + "version": "13.11.8", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.8.tgz", + "integrity": "sha512-c/hzNDBh7eRF+KbCf+OoZxKbnkpaK/cKp9iLQWqB7muXtM+MtL9SUUH8vCFcLn6dH1Qm05jiexK0ofWY7TfOhQ==" + }, + "abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true + }, "accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -1653,12 +3000,24 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, "body-parser": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", @@ -1688,6 +3047,11 @@ "concat-map": "0.0.1" } }, + "buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" + }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -1718,6 +3082,30 @@ "supports-color": "^7.1.0" } }, + "cli-color": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.3.tgz", + "integrity": "sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==", + "dev": true, + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.61", + "es6-iterator": "^2.0.3", + "memoizee": "^0.4.15", + "timers-ext": "^0.1.7" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1733,12 +3121,28 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, "content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -1762,6 +3166,15 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1773,6 +3186,16 @@ "which": "^2.0.1" } }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -1797,24 +3220,128 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dotenv": { + "version": "16.4.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.1.tgz", + "integrity": "sha512-CjA3y+Dr3FyFDOAMnxZEGtnW9KBR2M0JvvUtXNW+dYJL5ROWxP9DUHCwgFqpMk0OXCc0ljhaNTr2w/kutYIcHQ==" + }, + "dottie": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.6.tgz", + "integrity": "sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA==" + }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "editorconfig": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", + "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", + "dev": true, + "requires": { + "@one-ini/wasm": "0.1.1", + "commander": "^10.0.0", + "minimatch": "9.0.1", + "semver": "^7.5.3" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", + "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "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 + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "dev": true, + "requires": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", "dev": true, "requires": { - "esutils": "^2.0.2" + "d": "^1.0.1", + "ext": "^1.1.2" } }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + "es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true }, "escape-html": { "version": "1.0.3", @@ -1966,6 +3493,16 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, "express": { "version": "4.18.1", "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", @@ -2004,6 +3541,23 @@ "vary": "~1.1.2" } }, + "ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "requires": { + "type": "^2.7.2" + }, + "dependencies": { + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + } + } + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2061,6 +3615,16 @@ "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", "dev": true }, + "foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + } + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -2071,6 +3635,18 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2078,9 +3654,9 @@ "dev": true }, "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" }, "functional-red-black-tree": { "version": "1.0.1", @@ -2088,6 +3664,12 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "get-caller-file": { + "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 + }, "get-intrinsic": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", @@ -2130,6 +3712,12 @@ "type-fest": "^0.20.2" } }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -2149,6 +3737,15 @@ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" }, + "hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "requires": { + "function-bind": "^1.1.2" + } + }, "http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -2191,6 +3788,11 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "inflection": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.13.4.tgz", + "integrity": "sha512-6I/HUDeYFfuNCVS3td055BaXBwKYuzw7K3ExVMStBowKo9oOAMJIXIHvdyR3iboTCp1b+1i5DSkIZTcwIktuDw==" + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -2206,17 +3808,38 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, + "is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "requires": { + "hasown": "^2.0.0" + } + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -2226,12 +3849,73 @@ "is-extglob": "^2.1.1" } }, + "is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "requires": { + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" + } + }, + "js-beautify": { + "version": "1.14.11", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.11.tgz", + "integrity": "sha512-rPogWqAfoYh1Ryqqh2agUpVfbxAhbjuN1SmU86dskQUKouRiggUTCO4+2ym9UPXllc2WAp0J+T5qxn7Um3lCdw==", + "dev": true, + "requires": { + "config-chain": "^1.1.13", + "editorconfig": "^1.0.3", + "glob": "^10.3.3", + "nopt": "^7.2.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "requires": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + } + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -2253,6 +3937,16 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2263,17 +3957,55 @@ "type-check": "~0.4.0" } }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "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" + } + }, + "lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", + "dev": true, + "requires": { + "es5-ext": "~0.10.2" + } + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, + "memoizee": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", + "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", + "dev": true, + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.53", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + } + }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -2311,6 +4043,25 @@ "brace-expansion": "^1.1.7" } }, + "minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true + }, + "moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==" + }, + "moment-timezone": { + "version": "0.5.45", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.45.tgz", + "integrity": "sha512-HIWmqA86KcmCAhnMAN0wuDOARV/525R2+lOLotuGFzn4HO+FH+/645z2wx0Dt3iDv6/p61SIvKnDstISainhLQ==", + "requires": { + "moment": "^2.29.4" + } + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -2327,6 +4078,26 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" }, + "next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + }, + "nopt": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", + "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==", + "dev": true, + "requires": { + "abbrev": "^2.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + }, "object-inspect": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.1.tgz", @@ -2363,6 +4134,11 @@ "word-wrap": "^1.2.3" } }, + "packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -2389,17 +4165,132 @@ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "requires": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true + } + } + }, "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "pg": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz", + "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==", + "requires": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-cloudflare": "^1.1.1", + "pg-connection-string": "^2.6.2", + "pg-pool": "^3.6.1", + "pg-protocol": "^1.6.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + } + }, + "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 + }, + "pg-connection-string": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", + "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" + }, + "pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" + }, + "pg-pool": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz", + "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==", + "requires": {} + }, + "pg-protocol": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", + "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" + }, + "pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "requires": { + "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" + } + }, + "pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "requires": { + "split2": "^4.1.0" + } + }, + "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==" + }, + "postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==" + }, + "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==" + }, + "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==", + "requires": { + "xtend": "^4.0.0" + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -2445,12 +4336,34 @@ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, + "require-directory": { + "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 + }, + "resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "requires": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, + "retry-as-promised": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-7.0.4.tgz", + "integrity": "sha512-XgmCoxKWkDofwH8WddD0w85ZfqYz+ZHlr5yo+3YUCfycWawU56T5ckWXsScsj5B8tqUcIG67DxXByo3VUgiAdA==" + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -2470,6 +4383,14 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "requires": { + "lru-cache": "^6.0.0" + } + }, "send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -2497,6 +4418,64 @@ } } }, + "sequelize": { + "version": "6.36.0", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.36.0.tgz", + "integrity": "sha512-PqOa11EHwA/zLmGDU4aynbsavbHJUlgRvFuC/2cA4LhOuV6NHKcQ0IXB+hNdFrGT3rULmvc4kdIwnfCNsrECMQ==", + "requires": { + "@types/debug": "^4.1.8", + "@types/validator": "^13.7.17", + "debug": "^4.3.4", + "dottie": "^2.0.6", + "inflection": "^1.13.4", + "lodash": "^4.17.21", + "moment": "^2.29.4", + "moment-timezone": "^0.5.43", + "pg-connection-string": "^2.6.1", + "retry-as-promised": "^7.0.4", + "semver": "^7.5.4", + "sequelize-pool": "^7.1.0", + "toposort-class": "^1.0.1", + "uuid": "^8.3.2", + "validator": "^13.9.0", + "wkx": "^0.5.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "sequelize-cli": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/sequelize-cli/-/sequelize-cli-6.6.2.tgz", + "integrity": "sha512-V8Oh+XMz2+uquLZltZES6MVAD+yEnmMfwfn+gpXcDiwE3jyQygLt4xoI0zG8gKt6cRcs84hsKnXAKDQjG/JAgg==", + "dev": true, + "requires": { + "cli-color": "^2.0.3", + "fs-extra": "^9.1.0", + "js-beautify": "^1.14.5", + "lodash": "^4.17.21", + "resolve": "^1.22.1", + "umzug": "^2.3.0", + "yargs": "^16.2.0" + } + }, + "sequelize-pool": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-7.1.0.tgz", + "integrity": "sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg==" + }, "serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", @@ -2538,11 +4517,44 @@ "object-inspect": "^1.9.0" } }, + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true + }, + "split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==" + }, "statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" }, + "string-width": { + "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, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "string-width-cjs": { + "version": "npm:string-width@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, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -2552,6 +4564,15 @@ "ansi-regex": "^5.0.1" } }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -2567,17 +4588,44 @@ "has-flag": "^4.0.0" } }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "timers-ext": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", + "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", + "dev": true, + "requires": { + "es5-ext": "~0.10.46", + "next-tick": "1" + } + }, "toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, + "toposort-class": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", + "integrity": "sha512-OsLcGGbYF3rMjPUf8oKktyvCiUxSbqMMS39m33MAjLTC1DVIH6x3WSt63/M77ihI09+Sdfk1AXvfhCEeUmC7mg==" + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -2602,6 +4650,26 @@ "mime-types": "~2.1.24" } }, + "umzug": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz", + "integrity": "sha512-Z274K+e8goZK8QJxmbRPhl89HPO1K+ORFtm6rySPhFKfKc5GHhqdzD0SGhSWHkzoXasqJuItdhorSvY7/Cgflw==", + "dev": true, + "requires": { + "bluebird": "^3.7.2" + } + }, + "undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -2621,12 +4689,22 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, "v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, + "validator": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", + "integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -2641,17 +4719,84 @@ "isexe": "^2.0.0" } }, + "wkx": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz", + "integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==", + "requires": { + "@types/node": "*" + } + }, "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true }, + "wrap-ansi": { + "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, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "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", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "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" + } + }, + "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==", + "dev": true } } } diff --git a/package.json b/package.json index 09b3bc32..37a0790c 100644 --- a/package.json +++ b/package.json @@ -5,9 +5,14 @@ "start": "nodemon index.js" }, "dependencies": { - "express": "^4.18.1" + "cors": "^2.8.5", + "dotenv": "^16.4.1", + "express": "^4.18.1", + "pg": "^8.11.3", + "sequelize": "^6.36.0" }, "devDependencies": { - "eslint": "^8.16.0" + "eslint": "^8.16.0", + "sequelize-cli": "^6.6.2" } } From f755783c19fc78e408edd2a07a5288e52f00271e Mon Sep 17 00:00:00 2001 From: estney Date: Mon, 5 Feb 2024 18:23:36 +0800 Subject: [PATCH 02/29] Create Sequelize Folders --- .sequelizerc | 8 ++++++++ config/database.js | 11 +++++++++++ db/models/index.js | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 .sequelizerc create mode 100644 config/database.js create mode 100644 db/models/index.js diff --git a/.sequelizerc b/.sequelizerc new file mode 100644 index 00000000..409a4bed --- /dev/null +++ b/.sequelizerc @@ -0,0 +1,8 @@ +const path = require("path"); + +module.exports = { + config: path.resolve("config", "database.js"), + "models-path": path.resolve("db", "models"), + "seeders-path": path.resolve("db", "seeders"), + "migrations-path": path.resolve("db", "migrations"), +}; diff --git a/config/database.js b/config/database.js new file mode 100644 index 00000000..bed84df2 --- /dev/null +++ b/config/database.js @@ -0,0 +1,11 @@ +require("dotenv").config(); + +module.exports = { + development: { + username: process.env.DB_USERNAME, + password: process.env.DB_PASSWORD, + database: process.env.DB_NAME, + host: process.env.DB_HOST, + dialect: process.env.DB_DIALECT, + }, +}; diff --git a/db/models/index.js b/db/models/index.js new file mode 100644 index 00000000..5edbd256 --- /dev/null +++ b/db/models/index.js @@ -0,0 +1,43 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const Sequelize = require('sequelize'); +const process = require('process'); +const basename = path.basename(__filename); +const env = process.env.NODE_ENV || 'development'; +const config = require(__dirname + '/../../config/database.js')[env]; +const db = {}; + +let sequelize; +if (config.use_env_variable) { + sequelize = new Sequelize(process.env[config.use_env_variable], config); +} else { + sequelize = new Sequelize(config.database, config.username, config.password, config); +} + +fs + .readdirSync(__dirname) + .filter(file => { + return ( + file.indexOf('.') !== 0 && + file !== basename && + file.slice(-3) === '.js' && + file.indexOf('.test.js') === -1 + ); + }) + .forEach(file => { + const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes); + db[model.name] = model; + }); + +Object.keys(db).forEach(modelName => { + if (db[modelName].associate) { + db[modelName].associate(db); + } +}); + +db.sequelize = sequelize; +db.Sequelize = Sequelize; + +module.exports = db; From aefc724fdb4caad2a0251a6c2822b52d96c2c383 Mon Sep 17 00:00:00 2001 From: estney Date: Tue, 6 Feb 2024 16:54:33 +0800 Subject: [PATCH 03/29] added primary tables models --- .../20240206071629-primary_tables.js | 109 ++++++++++++++++++ db/models/benefits.js | 20 ++++ db/models/employers.js | 23 ++++ db/models/talents.js | 21 ++++ db/seeders/20240206073417-primary_tables.js | 107 +++++++++++++++++ index.js | 1 + middlewares/auth.js | 11 ++ package-lock.json | 33 ++++++ package.json | 1 + 9 files changed, 326 insertions(+) create mode 100644 db/migrations/20240206071629-primary_tables.js create mode 100644 db/models/benefits.js create mode 100644 db/models/employers.js create mode 100644 db/models/talents.js create mode 100644 db/seeders/20240206073417-primary_tables.js create mode 100644 middlewares/auth.js diff --git a/db/migrations/20240206071629-primary_tables.js b/db/migrations/20240206071629-primary_tables.js new file mode 100644 index 00000000..a69ed877 --- /dev/null +++ b/db/migrations/20240206071629-primary_tables.js @@ -0,0 +1,109 @@ +"use strict"; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.createTable("talents", { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER, + }, + first_name: { + type: Sequelize.STRING, + allowNull: false, + }, + last_name: { + type: Sequelize.STRING, + allowNull: false, + }, + photo: { + type: Sequelize.STRING, + }, + email: { + type: Sequelize.STRING, + allowNull: false, + }, + created_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + allowNull: false, + }, + updated_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + allowNull: false, + }, + }); + + await queryInterface.createTable("employers", { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER, + }, + first_name: { + type: Sequelize.STRING, + allowNull: false, + }, + last_name: { + type: Sequelize.STRING, + allowNull: false, + }, + company_name: { + type: Sequelize.STRING, + }, + description: { + type: Sequelize.STRING, + }, + photo: { + type: Sequelize.STRING, + }, + email: { + type: Sequelize.STRING, + allowNull: false, + }, + created_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + }, + updated_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + }, + }); + + await queryInterface.createTable("benefits", { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER, + }, + category: { + type: Sequelize.STRING, + allowNull: false, + }, + description: { + type: Sequelize.STRING, + allowNull: false, + }, + created_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + }, + updated_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + }, + }); + }, + + async down(queryInterface, Sequelize) { + await queryInterface.dropTable("talents"); + await queryInterface.dropTable("employers"); + await queryInterface.dropTable("benefits"); + }, +}; diff --git a/db/models/benefits.js b/db/models/benefits.js new file mode 100644 index 00000000..e7c4edf1 --- /dev/null +++ b/db/models/benefits.js @@ -0,0 +1,20 @@ +"use strict"; + +//write in JS format. + +const { Model } = require("sequelize"); +module.exports = (sequelize, DataTypes) => { + class Benefit extends Model {} + Benefit.init( + { + category: DataTypes.STRING, + description: DataTypes.STRING, + }, + { + sequelize, + modelName: "benefit", //non-plurul + underscored: true, + } + ); + return Benefit; +}; diff --git a/db/models/employers.js b/db/models/employers.js new file mode 100644 index 00000000..494983ac --- /dev/null +++ b/db/models/employers.js @@ -0,0 +1,23 @@ +"use strict"; + +//write in JS format. + +const { Model } = require("sequelize"); +module.exports = (sequelize, DataTypes) => { + class Employer extends Model {} + Employer.init( + { + firstName: DataTypes.STRING, + lastName: DataTypes.STRING, + companyName: DataTypes.STRING, + description: DataTypes.STRING, + email: DataTypes.STRING, + }, + { + sequelize, + modelName: "employer", //non-plurul + underscored: true, + } + ); + return Employer; +}; diff --git a/db/models/talents.js b/db/models/talents.js new file mode 100644 index 00000000..336c1bcb --- /dev/null +++ b/db/models/talents.js @@ -0,0 +1,21 @@ +"use strict"; + +//write in JS format. + +const { Model } = require("sequelize"); +module.exports = (sequelize, DataTypes) => { + class Talent extends Model {} + Talent.init( + { + firstName: DataTypes.STRING, + lastName: DataTypes.STRING, + email: DataTypes.STRING, + }, + { + sequelize, + modelName: "talent", //non-plurul + underscored: true, + } + ); + return Talent; +}; diff --git a/db/seeders/20240206073417-primary_tables.js b/db/seeders/20240206073417-primary_tables.js new file mode 100644 index 00000000..d3ecdca0 --- /dev/null +++ b/db/seeders/20240206073417-primary_tables.js @@ -0,0 +1,107 @@ +"use strict"; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.bulkInsert("talents", [ + { + first_name: "Spidey", + last_name: "boy", + email: "kid2010@text.com", + }, + { + first_name: "Genz", + last_name: "Goose", + email: "goosegoose@text.com", + }, + { + first_name: "Cat", + last_name: "Dog", + email: "bestpetever@text.com", + }, + ]); + + await queryInterface.bulkInsert("employers", [ + { + first_name: "Tony", + last_name: "Stark", + company_name: "Avengers", + description: "somewhere in NYC", + email: "tonystark@test.com", + }, + { + first_name: "Widow", + last_name: "Black", + company_name: "Red Room", + description: "everywhere", + email: "blackwidow@text.com", + }, + { + first_name: "Hulk", + last_name: "Green", + company_name: "underground lab", + description: "everywhere", + email: "blackwidow@text.com", + }, + ]); + + await queryInterface.bulkInsert("benefits", [ + { + category: "Meaningful Impact", + description: + "Cultivate personal fulfilment by contributing to a purpose-driven organisation, creating a positive impact that extends beyond the confines of the workplace.", + }, + { + category: "Harmony in Life and Work", + description: + "Achieving a harmonious balance between personal and professional life promotes well-being and contentment for all involved.", + }, + { + category: "Professional Advancement", + description: + "Unlock continuous pathways for career growth, providing opportunities for individuals to progress and excel in their chosen fields.", + }, + { + category: "Competitive Compensation", + description: + "Receive equitable and competitive compensation packages, ensuring financial security and acknowledgement for valuable contributions in the dynamic job market.", + }, + { + category: "Stability and Assurance", + description: + "Establish a foundation of job security, creating a stable environment for organisational growth and individual flourishing in a secure professional space.", + }, + { + category: "Inclusive Workplace Culture", + description: + "Embrace diversity and nurture a company culture that values inclusivity, fostering a collaborative environment that attracts and retains a rich tapestry of talents.", + }, + { + category: "Flexible Work Arrangements", + description: + "Tailor work setups to accommodate diverse needs, promoting flexibility in the workplace to enhance productivity and job satisfaction.", + }, + { + category: "Guidance and Continuous Learning:", + description: + "Access mentorship and a spectrum of learning opportunities for continuous personal and professional development, empowering growth for individuals at all career stages.", + }, + { + category: "Holistic Well-being Support", + description: + "Prioritise health and overall well-being through comprehensive support systems, including insurance, ensuring the holistic welfare of everyone involved.", + }, + { + category: "Community Impact and Social Responsibility", + description: + "Contribute to a broader social impact by aligning with organisations that make a positive difference.", + }, + ]); + }, + + async down(queryInterface, Sequelize) { + await queryInterface.dropTable("talents"); + await queryInterface.dropTable("employers"); + await queryInterface.dropTable("benefits"); + }, +}; diff --git a/index.js b/index.js index 9164191a..0dd3f829 100644 --- a/index.js +++ b/index.js @@ -8,6 +8,7 @@ const express = require("express"); require("dotenv").config(); //-----------import auth0 middleware +const auth = require("./middlewares/auth"); //-----------initializing Controllers, lowercase for the key diff --git a/middlewares/auth.js b/middlewares/auth.js new file mode 100644 index 00000000..e825fc57 --- /dev/null +++ b/middlewares/auth.js @@ -0,0 +1,11 @@ +// server.js + +const { auth } = require("express-oauth2-jwt-bearer"); +require("dotenv").config(); + +// Authorization middleware. When used, the Access Token must +// exist and be verified against the Auth0 JSON Web Key Set. +const checkJwt = auth({ + audience: process.env.AUTH_AUDIENCE, + issuerBaseURL: process.env.AUTH_ISSUER_BASE_URL, +}); diff --git a/package-lock.json b/package-lock.json index 61f92246..0ebb345a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "cors": "^2.8.5", "dotenv": "^16.4.1", "express": "^4.18.1", + "express-oauth2-jwt-bearer": "^1.6.0", "pg": "^8.11.3", "sequelize": "^6.36.0" }, @@ -1020,6 +1021,17 @@ "node": ">= 0.10.0" } }, + "node_modules/express-oauth2-jwt-bearer": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/express-oauth2-jwt-bearer/-/express-oauth2-jwt-bearer-1.6.0.tgz", + "integrity": "sha512-HXnez7vocYlOqlfF3ozPcf/WE3zxT7zfUNfeg5FHJnvNwhBYlNXiPOvuCtBalis8xcigvwtInzEKhBuH87+9ug==", + "dependencies": { + "jose": "^4.13.1" + }, + "engines": { + "node": "^12.19.0 || ^14.15.0 || ^16.13.0 || ^18.12.0 || ^20.2.0" + } + }, "node_modules/ext": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", @@ -1455,6 +1467,14 @@ "@pkgjs/parseargs": "^0.11.0" } }, + "node_modules/jose": { + "version": "4.15.4", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.4.tgz", + "integrity": "sha512-W+oqK4H+r5sITxfxpSU+MMdr/YSWGvgZMQDIsNoBDGGy4i7GBPTtvFKibQzW06n3U3TqHjhvBJsirShsEJ6eeQ==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/js-beautify": { "version": "1.14.11", "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.11.tgz", @@ -3541,6 +3561,14 @@ "vary": "~1.1.2" } }, + "express-oauth2-jwt-bearer": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/express-oauth2-jwt-bearer/-/express-oauth2-jwt-bearer-1.6.0.tgz", + "integrity": "sha512-HXnez7vocYlOqlfF3ozPcf/WE3zxT7zfUNfeg5FHJnvNwhBYlNXiPOvuCtBalis8xcigvwtInzEKhBuH87+9ug==", + "requires": { + "jose": "^4.13.1" + } + }, "ext": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", @@ -3871,6 +3899,11 @@ "@pkgjs/parseargs": "^0.11.0" } }, + "jose": { + "version": "4.15.4", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.4.tgz", + "integrity": "sha512-W+oqK4H+r5sITxfxpSU+MMdr/YSWGvgZMQDIsNoBDGGy4i7GBPTtvFKibQzW06n3U3TqHjhvBJsirShsEJ6eeQ==" + }, "js-beautify": { "version": "1.14.11", "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.11.tgz", diff --git a/package.json b/package.json index 37a0790c..74e46575 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "cors": "^2.8.5", "dotenv": "^16.4.1", "express": "^4.18.1", + "express-oauth2-jwt-bearer": "^1.6.0", "pg": "^8.11.3", "sequelize": "^6.36.0" }, From c7bb5919bf5c8d427704eb14cc84f61c47ef071c Mon Sep 17 00:00:00 2001 From: estney Date: Tue, 6 Feb 2024 18:32:09 +0800 Subject: [PATCH 04/29] created contollers and routers. Talent controller and router for getting all users worked. Yet to test out create Talent --- controllers/BaseController.js | 18 ++++++++++++++ controllers/TalentController.js | 26 ++++++++++++++++++++ db/models/{benefits.js => benefit.js} | 0 db/models/{employers.js => employer.js} | 0 db/models/{talents.js => talent.js} | 0 index.js | 32 +++++++++++++------------ routers/TalentRouter.js | 16 +++++++++++++ 7 files changed, 77 insertions(+), 15 deletions(-) create mode 100644 controllers/BaseController.js create mode 100644 controllers/TalentController.js rename db/models/{benefits.js => benefit.js} (100%) rename db/models/{employers.js => employer.js} (100%) rename db/models/{talents.js => talent.js} (100%) create mode 100644 routers/TalentRouter.js diff --git a/controllers/BaseController.js b/controllers/BaseController.js new file mode 100644 index 00000000..e2a7e9f4 --- /dev/null +++ b/controllers/BaseController.js @@ -0,0 +1,18 @@ +class BaseController { + constructor(model) { + this.model = model; + } + + /* All controllers that extend this BASE controller will have access to the below function **/ + async getAll(req, res) { + try { + console.log("hello!"); + const output = await this.model.findAll(); + return res.json(output); + } catch (err) { + return res.status(400).json({ error: true, msg: err }); + } + } +} + +module.exports = BaseController; diff --git a/controllers/TalentController.js b/controllers/TalentController.js new file mode 100644 index 00000000..5cdd26ef --- /dev/null +++ b/controllers/TalentController.js @@ -0,0 +1,26 @@ +const BaseController = require("./BaseController"); + +class TalentController extends BaseController { + constructor(model) { + super(model); + } + + // Create talent + async insertOne(req, res) { + const { firstName, lastName, email } = req.body; + try { + // Create new talent + const newTalent = await this.model.create({ + firstName: firstName, + lastName: lastName, + email: email, + }); + // Respond with new sighting + return res.json(newTalent); + } catch (err) { + return res.status(400).json({ error: true, msg: err }); + } + } +} + +module.exports = TalentController; diff --git a/db/models/benefits.js b/db/models/benefit.js similarity index 100% rename from db/models/benefits.js rename to db/models/benefit.js diff --git a/db/models/employers.js b/db/models/employer.js similarity index 100% rename from db/models/employers.js rename to db/models/employer.js diff --git a/db/models/talents.js b/db/models/talent.js similarity index 100% rename from db/models/talents.js rename to db/models/talent.js diff --git a/index.js b/index.js index 0dd3f829..b8212027 100644 --- a/index.js +++ b/index.js @@ -1,22 +1,22 @@ +// import env file +require("dotenv").config(); //Enable CORS access to this server const cors = require("cors"); - //import express to read json const express = require("express"); -// import env file -require("dotenv").config(); - -//-----------import auth0 middleware +//import auth0 middleware const auth = require("./middlewares/auth"); -//-----------initializing Controllers, lowercase for the key +//import DB +const db = require("./db/models/index"); +const { talent } = db; -//-----------initializing controllers +//import controllers +const TalentController = require("./controllers/TalentController"); -//-----------importing DB -// const db = require("./db/models/index"); -// const {} = db; +//import router +const TalentRouter = require("./routers/TalentRouter"); //port and express const PORT = process.env.PORT; @@ -24,15 +24,17 @@ const app = express(); // Enable CORS access to this server app.use(cors()); - // Enable reading JSON request bodies app.use(express.json()); -// <----- ROUTERS -----> +//initialise contollers +const talentController = new TalentController(talent); -app.get("/", (req, res) => { - res.send("Hello, World!"); -}); +//initialise router +const talentRouter = new TalentRouter(talentController).routes(); + +// <----- USAGE-----> +app.use("/talents", talentRouter); app.listen(PORT, () => { console.log(`Express app listening on port ${PORT}!`); diff --git a/routers/TalentRouter.js b/routers/TalentRouter.js new file mode 100644 index 00000000..a8723f22 --- /dev/null +++ b/routers/TalentRouter.js @@ -0,0 +1,16 @@ +const express = require("express"); +const router = express.Router(); + +class TalentRouter { + constructor(talentController) { + this.controller = talentController; + } + + routes() { + router.get("/", this.controller.getAll.bind(this.controller)); + router.post("/", this.controller.insertOne.bind(this.controller)); + return router; // Return the router instance + } +} + +module.exports = TalentRouter; From 8b9e6950ddc05d54e5037a4771f7470955d3c2a5 Mon Sep 17 00:00:00 2001 From: estney Date: Wed, 7 Feb 2024 08:51:52 +0800 Subject: [PATCH 05/29] created controllers and routers for Benefit and Talent --- controllers/BenefitController.js | 11 +++++++++++ controllers/EmployerController.js | 26 ++++++++++++++++++++++++++ controllers/TalentController.js | 2 +- index.js | 12 +++++++++++- routers/BenefitRouter.js | 15 +++++++++++++++ routers/EmployerRouter.js | 15 +++++++++++++++ 6 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 controllers/BenefitController.js create mode 100644 controllers/EmployerController.js create mode 100644 routers/BenefitRouter.js create mode 100644 routers/EmployerRouter.js diff --git a/controllers/BenefitController.js b/controllers/BenefitController.js new file mode 100644 index 00000000..392da519 --- /dev/null +++ b/controllers/BenefitController.js @@ -0,0 +1,11 @@ +const BaseController = require("./BaseController"); + +class BenefitController extends BaseController { + constructor(model) { + super(model); + } +} + +//just get all only. + +module.exports = BenefitController; diff --git a/controllers/EmployerController.js b/controllers/EmployerController.js new file mode 100644 index 00000000..ab56878c --- /dev/null +++ b/controllers/EmployerController.js @@ -0,0 +1,26 @@ +const BaseController = require("./BaseController"); + +class EmployerController extends BaseController { + constructor(model) { + super(model); + } + + // Create talent + async insertOne(req, res) { + const { firstName, lastName, email } = req.body; + try { + // Create new talent + const newEmployer = await this.model.create({ + firstName: firstName, + lastName: lastName, + email: email, + }); + // Respond with new talent + return res.json(newEmployert); + } catch (err) { + return res.status(400).json({ error: true, msg: err }); + } + } +} + +module.exports = EmployerController; diff --git a/controllers/TalentController.js b/controllers/TalentController.js index 5cdd26ef..20a2fe9b 100644 --- a/controllers/TalentController.js +++ b/controllers/TalentController.js @@ -15,7 +15,7 @@ class TalentController extends BaseController { lastName: lastName, email: email, }); - // Respond with new sighting + // Respond with new talent return res.json(newTalent); } catch (err) { return res.status(400).json({ error: true, msg: err }); diff --git a/index.js b/index.js index b8212027..08e16f9f 100644 --- a/index.js +++ b/index.js @@ -10,13 +10,17 @@ const auth = require("./middlewares/auth"); //import DB const db = require("./db/models/index"); -const { talent } = db; +const { talent, benefit, employer } = db; //import controllers const TalentController = require("./controllers/TalentController"); +const BenefitController = require("./controllers/BenefitController"); +const EmployerController = require("./controllers/EmployerController"); //import router const TalentRouter = require("./routers/TalentRouter"); +const BenefitRouter = require("./routers/BenefitRouter"); +const EmployerRouter = require("./routers/EmployerRouter"); //port and express const PORT = process.env.PORT; @@ -29,12 +33,18 @@ app.use(express.json()); //initialise contollers const talentController = new TalentController(talent); +const benefitController = new BenefitController(benefit); +const employerController = new EmployerController(employer); //initialise router const talentRouter = new TalentRouter(talentController).routes(); +const benefitRouter = new BenefitRouter(benefitController).routes(); +const employerRouter = new EmployerRouter(employerController).routes(); // <----- USAGE-----> app.use("/talents", talentRouter); +app.use("/benefits", benefitRouter); +app.use("/employers", employerRouter); app.listen(PORT, () => { console.log(`Express app listening on port ${PORT}!`); diff --git a/routers/BenefitRouter.js b/routers/BenefitRouter.js new file mode 100644 index 00000000..469a0b1f --- /dev/null +++ b/routers/BenefitRouter.js @@ -0,0 +1,15 @@ +const express = require("express"); +const router = express.Router(); + +class BenefitRouter { + constructor(benefitController) { + this.controller = benefitController; + } + + routes() { + router.get("/", this.controller.getAll.bind(this.controller)); + return router; // Return the router instance + } +} + +module.exports = BenefitRouter; diff --git a/routers/EmployerRouter.js b/routers/EmployerRouter.js new file mode 100644 index 00000000..6f55b733 --- /dev/null +++ b/routers/EmployerRouter.js @@ -0,0 +1,15 @@ +const express = require("express"); +const router = express.Router(); + +class EmployerRouter { + constructor(employerController) { + this.controller = employerController; + } + + routes() { + router.get("/", this.controller.getAll.bind(this.controller)); + return router; // Return the router instance + } +} + +module.exports = EmployerRouter; From 9716e8f3af776f2c3a577c33fc55a885e35e930b Mon Sep 17 00:00:00 2001 From: estney Date: Wed, 7 Feb 2024 11:15:53 +0800 Subject: [PATCH 06/29] completed benefit, employer, talent contoller and routers. corrected employer and talent models --- controllers/BenefitController.js | 3 ++- controllers/EmployerController.js | 42 ++++++++++++++++++++++++++++--- controllers/TalentController.js | 33 ++++++++++++++++++++++-- db/models/employer.js | 1 + db/models/talent.js | 1 + routers/EmployerRouter.js | 5 ++++ routers/TalentRouter.js | 6 ++++- 7 files changed, 84 insertions(+), 7 deletions(-) diff --git a/controllers/BenefitController.js b/controllers/BenefitController.js index 392da519..0479532a 100644 --- a/controllers/BenefitController.js +++ b/controllers/BenefitController.js @@ -6,6 +6,7 @@ class BenefitController extends BaseController { } } -//just get all only. +// allow users to read info, and select data only. +// user cannot add, edit or delete benefits. module.exports = BenefitController; diff --git a/controllers/EmployerController.js b/controllers/EmployerController.js index ab56878c..3577aeee 100644 --- a/controllers/EmployerController.js +++ b/controllers/EmployerController.js @@ -6,21 +6,57 @@ class EmployerController extends BaseController { } // Create talent - async insertOne(req, res) { - const { firstName, lastName, email } = req.body; + async addEmployer(req, res) { + const { firstName, lastName, companyName, email, photo, description } = + req.body; try { // Create new talent const newEmployer = await this.model.create({ firstName: firstName, lastName: lastName, + companyName: companyName, email: email, + photo: photo, + description: description, }); // Respond with new talent - return res.json(newEmployert); + return res.json(newEmployer); + } catch (err) { + return res.status(400).json({ error: true, msg: err }); + } + } + + // Edit and Update Employer + async updateEmployer(req, res) { + const { firstName, lastName, companyName, email, photo, description } = + req.body; + const { employerId } = req.params; + try { + await this.model.update( + { + firstName: firstName, + lastName: lastName, + companyName: companyName, + email: email, + photo: photo, + description: description, + }, + { + where: { + id: employerId, + }, + } + ); + const output = await this.model.findAll(); + return res.json(output); } catch (err) { return res.status(400).json({ error: true, msg: err }); } } } +// Update employer content +// get all user info under base controller +// delete is not required - user can't delete profile + module.exports = EmployerController; diff --git a/controllers/TalentController.js b/controllers/TalentController.js index 20a2fe9b..760fe1aa 100644 --- a/controllers/TalentController.js +++ b/controllers/TalentController.js @@ -6,14 +6,15 @@ class TalentController extends BaseController { } // Create talent - async insertOne(req, res) { - const { firstName, lastName, email } = req.body; + async addTalent(req, res) { + const { firstName, lastName, email, photo } = req.body; try { // Create new talent const newTalent = await this.model.create({ firstName: firstName, lastName: lastName, email: email, + photo: photo, }); // Respond with new talent return res.json(newTalent); @@ -21,6 +22,34 @@ class TalentController extends BaseController { return res.status(400).json({ error: true, msg: err }); } } + + // Edit and Update Talent + async updateTalent(req, res) { + const { firstName, lastName, email, photo } = req.body; + const { talentId } = req.params; + try { + await this.model.update( + { + firstName: firstName, + lastName: lastName, + email: email, + photo: photo, + }, + { + where: { + id: talentId, + }, + } + ); + const output = await this.model.findAll(); + return res.json(output); + } catch (err) { + return res.status(400).json({ error: true, msg: err }); + } + } } +// get all user info under base controller +// delete is not required - user can't delete profile + module.exports = TalentController; diff --git a/db/models/employer.js b/db/models/employer.js index 494983ac..1b9d2955 100644 --- a/db/models/employer.js +++ b/db/models/employer.js @@ -11,6 +11,7 @@ module.exports = (sequelize, DataTypes) => { lastName: DataTypes.STRING, companyName: DataTypes.STRING, description: DataTypes.STRING, + photo: DataTypes.STRING, email: DataTypes.STRING, }, { diff --git a/db/models/talent.js b/db/models/talent.js index 336c1bcb..d07fb3b4 100644 --- a/db/models/talent.js +++ b/db/models/talent.js @@ -10,6 +10,7 @@ module.exports = (sequelize, DataTypes) => { firstName: DataTypes.STRING, lastName: DataTypes.STRING, email: DataTypes.STRING, + photo: DataTypes.STRING, }, { sequelize, diff --git a/routers/EmployerRouter.js b/routers/EmployerRouter.js index 6f55b733..3c3424f9 100644 --- a/routers/EmployerRouter.js +++ b/routers/EmployerRouter.js @@ -8,6 +8,11 @@ class EmployerRouter { routes() { router.get("/", this.controller.getAll.bind(this.controller)); + router.post("/", this.controller.addEmployer.bind(this.controller)); + router.post( + "/:employerId", + this.controller.updateEmployer.bind(this.controller) + ); return router; // Return the router instance } } diff --git a/routers/TalentRouter.js b/routers/TalentRouter.js index a8723f22..ffacd087 100644 --- a/routers/TalentRouter.js +++ b/routers/TalentRouter.js @@ -8,7 +8,11 @@ class TalentRouter { routes() { router.get("/", this.controller.getAll.bind(this.controller)); - router.post("/", this.controller.insertOne.bind(this.controller)); + router.post("/", this.controller.addTalent.bind(this.controller)); + router.post( + "/:talentId", + this.controller.updateTalent.bind(this.controller) + ); return router; // Return the router instance } } From a31a303c6d905a7367dd35073b42f4a38f844693 Mon Sep 17 00:00:00 2001 From: estney Date: Wed, 7 Feb 2024 11:16:52 +0800 Subject: [PATCH 07/29] to include employer controller --- controllers/EmployerController.js | 1 - 1 file changed, 1 deletion(-) diff --git a/controllers/EmployerController.js b/controllers/EmployerController.js index 3577aeee..fe778088 100644 --- a/controllers/EmployerController.js +++ b/controllers/EmployerController.js @@ -55,7 +55,6 @@ class EmployerController extends BaseController { } } -// Update employer content // get all user info under base controller // delete is not required - user can't delete profile From 172c5152093d455a5b7c8fb762ad75f1c4b32366 Mon Sep 17 00:00:00 2001 From: estney Date: Wed, 7 Feb 2024 22:13:20 +0800 Subject: [PATCH 08/29] auth0 completed for adding new talent. --- controllers/BaseController.js | 2 +- index.js | 17 +++++++++++++---- middlewares/auth.js | 11 ----------- routers/TalentRouter.js | 9 +++++++-- 4 files changed, 21 insertions(+), 18 deletions(-) delete mode 100644 middlewares/auth.js diff --git a/controllers/BaseController.js b/controllers/BaseController.js index e2a7e9f4..5c61f7b7 100644 --- a/controllers/BaseController.js +++ b/controllers/BaseController.js @@ -6,7 +6,7 @@ class BaseController { /* All controllers that extend this BASE controller will have access to the below function **/ async getAll(req, res) { try { - console.log("hello!"); + console.log("hello world!"); const output = await this.model.findAll(); return res.json(output); } catch (err) { diff --git a/index.js b/index.js index 08e16f9f..916b2292 100644 --- a/index.js +++ b/index.js @@ -6,7 +6,14 @@ const cors = require("cors"); const express = require("express"); //import auth0 middleware -const auth = require("./middlewares/auth"); +const { auth } = require("express-oauth2-jwt-bearer"); + +// Authorization middleware. When used, the Access Token must +// exist and be verified against the Auth0 JSON Web Key Set. +const checkJwt = auth({ + audience: process.env.AUTH_AUDIENCE, + issuerBaseURL: process.env.AUTH_ISSUER_BASE_URL, +}); //import DB const db = require("./db/models/index"); @@ -37,14 +44,16 @@ const benefitController = new BenefitController(benefit); const employerController = new EmployerController(employer); //initialise router -const talentRouter = new TalentRouter(talentController).routes(); +const talentRouter = new TalentRouter(talentController, checkJwt).routes(); const benefitRouter = new BenefitRouter(benefitController).routes(); const employerRouter = new EmployerRouter(employerController).routes(); // <----- USAGE-----> -app.use("/talents", talentRouter); +// talent and employer is singular to standardise with frontend's nav bar. + +app.use("/talent", talentRouter); app.use("/benefits", benefitRouter); -app.use("/employers", employerRouter); +app.use("/employer", employerRouter); app.listen(PORT, () => { console.log(`Express app listening on port ${PORT}!`); diff --git a/middlewares/auth.js b/middlewares/auth.js deleted file mode 100644 index e825fc57..00000000 --- a/middlewares/auth.js +++ /dev/null @@ -1,11 +0,0 @@ -// server.js - -const { auth } = require("express-oauth2-jwt-bearer"); -require("dotenv").config(); - -// Authorization middleware. When used, the Access Token must -// exist and be verified against the Auth0 JSON Web Key Set. -const checkJwt = auth({ - audience: process.env.AUTH_AUDIENCE, - issuerBaseURL: process.env.AUTH_ISSUER_BASE_URL, -}); diff --git a/routers/TalentRouter.js b/routers/TalentRouter.js index ffacd087..191fa295 100644 --- a/routers/TalentRouter.js +++ b/routers/TalentRouter.js @@ -2,13 +2,18 @@ const express = require("express"); const router = express.Router(); class TalentRouter { - constructor(talentController) { + constructor(talentController, checkJwt) { this.controller = talentController; + this.checkJwt = checkJwt; } routes() { router.get("/", this.controller.getAll.bind(this.controller)); - router.post("/", this.controller.addTalent.bind(this.controller)); + router.post( + "/", + this.checkJwt, + this.controller.addTalent.bind(this.controller) + ); router.post( "/:talentId", this.controller.updateTalent.bind(this.controller) From 122ee974c73fed6afaa7b525749fe589e2d8d9e6 Mon Sep 17 00:00:00 2001 From: estney Date: Thu, 8 Feb 2024 14:52:14 +0800 Subject: [PATCH 09/29] edit comment --- controllers/EmployerController.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/controllers/EmployerController.js b/controllers/EmployerController.js index fe778088..c834ae90 100644 --- a/controllers/EmployerController.js +++ b/controllers/EmployerController.js @@ -5,12 +5,12 @@ class EmployerController extends BaseController { super(model); } - // Create talent + // Create employer async addEmployer(req, res) { const { firstName, lastName, companyName, email, photo, description } = req.body; try { - // Create new talent + // Create new employer const newEmployer = await this.model.create({ firstName: firstName, lastName: lastName, @@ -19,7 +19,7 @@ class EmployerController extends BaseController { photo: photo, description: description, }); - // Respond with new talent + // Respond with new employer return res.json(newEmployer); } catch (err) { return res.status(400).json({ error: true, msg: err }); From 3a91abf2302c6a09e92ee146e503762e8f77a3df Mon Sep 17 00:00:00 2001 From: estney Date: Mon, 12 Feb 2024 09:23:12 +0800 Subject: [PATCH 10/29] sec and tert tables migration and seeders completed --- .../20240211024810-secondary_tables.js | 300 ++++++++++++++++++ .../20240211025151-tertiary_tables.js | 122 +++++++ db/seeders/20240211125828-secondary_tables.js | 181 +++++++++++ db/seeders/20240211125839-tertiary_tables.js | 51 +++ 4 files changed, 654 insertions(+) create mode 100644 db/migrations/20240211024810-secondary_tables.js create mode 100644 db/migrations/20240211025151-tertiary_tables.js create mode 100644 db/seeders/20240211125828-secondary_tables.js create mode 100644 db/seeders/20240211125839-tertiary_tables.js diff --git a/db/migrations/20240211024810-secondary_tables.js b/db/migrations/20240211024810-secondary_tables.js new file mode 100644 index 00000000..51038d82 --- /dev/null +++ b/db/migrations/20240211024810-secondary_tables.js @@ -0,0 +1,300 @@ +"use strict"; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.createTable("talents_resume", { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER, + }, + talent_id: { + type: Sequelize.INTEGER, + references: { + model: "talents", + key: "id", + }, + }, + location: { + type: Sequelize.STRING, + }, + industry: { + type: Sequelize.STRING, + }, + title: { + type: Sequelize.STRING, + }, + objective: { + type: Sequelize.STRING, + }, + created_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + allowNull: false, + }, + updated_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + allowNull: false, + }, + }); + + await queryInterface.createTable("talents_work_experiences", { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER, + }, + talent_id: { + type: Sequelize.INTEGER, + references: { + model: "talents", + key: "id", + }, + }, + company_name: { + type: Sequelize.STRING, + allowNull: false, + }, + position: { + type: Sequelize.STRING, + allowNull: false, + }, + responsibility: { + type: Sequelize.STRING, + allowNull: false, + }, + start_month: { + type: Sequelize.STRING, + allowNull: false, + }, + start_year: { + type: Sequelize.STRING, + allowNull: false, + }, + end_month: { + type: Sequelize.STRING, + }, + end_year: { + type: Sequelize.STRING, + }, + created_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + allowNull: false, + }, + updated_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + allowNull: false, + }, + }); + + await queryInterface.createTable("talents_skill_set", { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER, + }, + talent_id: { + type: Sequelize.INTEGER, + references: { + model: "talents", + key: "id", + }, + }, + skill: { + type: Sequelize.STRING, + }, + proficiency_level: { + type: Sequelize.STRING, + }, + created_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + allowNull: false, + }, + updated_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + allowNull: false, + }, + }); + + await queryInterface.createTable("talents_education", { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER, + }, + talent_id: { + type: Sequelize.INTEGER, + references: { + model: "talents", + key: "id", + }, + }, + institution: { + type: Sequelize.STRING, + allowNull: false, + }, + degree: { + type: Sequelize.STRING, + allowNull: false, + }, + field_of_study: { + type: Sequelize.STRING, + allowNull: false, + }, + graduation_month: { + type: Sequelize.STRING, + }, + graduation_year: { + type: Sequelize.STRING, + }, + created_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + allowNull: false, + }, + updated_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + allowNull: false, + }, + }); + + await queryInterface.createTable("job_listings", { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER, + }, + employer_id: { + type: Sequelize.INTEGER, + references: { + model: "employers", + key: "id", + }, + }, + job_title: { + type: Sequelize.STRING, + allowNull: false, + }, + description: { + type: Sequelize.STRING, + allowNull: false, + }, + job_responsibility: { + type: Sequelize.STRING, + allowNull: false, + }, + skill_set: { + type: Sequelize.STRING, + allowNull: false, + }, + application_start_date: { + type: Sequelize.STRING, + allowNull: false, + }, + application_end_date: { + type: Sequelize.STRING, + allowNull: false, + }, + created_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + allowNull: false, + }, + updated_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + allowNull: false, + }, + }); + + await queryInterface.createTable("applications", { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER, + }, + job_listing_id: { + type: Sequelize.INTEGER, + references: { + model: "job_listings", + key: "id", + }, + }, + talent_id: { + type: Sequelize.INTEGER, + references: { + model: "talents", + key: "id", + }, + }, + application_date: { + type: Sequelize.DATE, + defaultValue: new Date(), + allowNull: false, + }, + application_status: { + type: Sequelize.STRING, + allowNull: false, + }, + created_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + allowNull: false, + }, + updated_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + allowNull: false, + }, + }); + + await queryInterface.createTable("chatrooms", { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER, + }, + application_id: { + type: Sequelize.INTEGER, + references: { + model: "applications", + key: "id", + }, + }, + created_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + allowNull: false, + }, + updated_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + allowNull: false, + }, + }); + }, + + async down(queryInterface, Sequelize) { + await queryInterface.dropTable("talents_resume"); + await queryInterface.dropTable("talents_work_experiences"); + await queryInterface.dropTable("talents_skill_set"); + await queryInterface.dropTable("talents_education"); + await queryInterface.dropTable("job_listings"); + await queryInterface.dropTable("applications"); + await queryInterface.dropTable("chatrooms"); + }, +}; diff --git a/db/migrations/20240211025151-tertiary_tables.js b/db/migrations/20240211025151-tertiary_tables.js new file mode 100644 index 00000000..98b38ba0 --- /dev/null +++ b/db/migrations/20240211025151-tertiary_tables.js @@ -0,0 +1,122 @@ +"use strict"; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.createTable("job_listing_benefits", { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER, + }, + job_listing_id: { + type: Sequelize.INTEGER, + references: { + model: "job_listings", + key: "id", + }, + }, + benefit_id: { + type: Sequelize.INTEGER, + references: { + model: "benefits", + key: "id", + }, + }, + created_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + allowNull: false, + }, + updated_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + allowNull: false, + }, + }); + + await queryInterface.createTable("talent_benefits", { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER, + }, + talent_id: { + type: Sequelize.INTEGER, + references: { + model: "talents", + key: "id", + }, + }, + benefit_id: { + type: Sequelize.INTEGER, + references: { + model: "benefits", + key: "id", + }, + }, + created_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + allowNull: false, + }, + updated_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + allowNull: false, + }, + }); + + await queryInterface.createTable("messages", { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER, + }, + talent_id: { + type: Sequelize.INTEGER, + references: { + model: "talents", + key: "id", + }, + }, + employer_id: { + type: Sequelize.INTEGER, + references: { + model: "employers", + key: "id", + }, + }, + chatroom_id: { + type: Sequelize.INTEGER, + references: { + model: "chatrooms", + key: "id", + }, + }, + message: { + type: Sequelize.STRING, + allowNull: false, + }, + created_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + allowNull: false, + }, + updated_at: { + type: Sequelize.DATE, + defaultValue: new Date(), + allowNull: false, + }, + }); + }, + + async down(queryInterface, Sequelize) { + await queryInterface.dropTable("job_listing_benefits"); + await queryInterface.dropTable("talent_benefits"); + await queryInterface.dropTable("messages"); + }, +}; diff --git a/db/seeders/20240211125828-secondary_tables.js b/db/seeders/20240211125828-secondary_tables.js new file mode 100644 index 00000000..6c6df228 --- /dev/null +++ b/db/seeders/20240211125828-secondary_tables.js @@ -0,0 +1,181 @@ +"use strict"; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.bulkInsert("talents_resume", [ + { + talent_id: 1, + location: "Singapore", + industry: "Technology", + title: "Software Engineer", + objective: "Seeking a challenging role in software development.", + }, + { + talent_id: 2, + location: "Malaysia", + industry: "Finance", + title: "Financial Analyst", + objective: + "Experienced financial analyst looking for new opportunities.", + }, + { + talent_id: 3, + location: "Hong Kong", + industry: "Marketing", + title: "Marketing Specialist", + objective: + "Marketing professional with expertise in digital marketing strategies.", + }, + ]); + + await queryInterface.bulkInsert("talents_work_experiences", [ + // talent_id: 1 + { + talent_id: 1, + company_name: "ABC Inc.", + position: "Software Developer", + responsibility: "Developing web applications.", + start_month: "January", + start_year: "2020", + end_month: "December", + end_year: "2022", + }, + { + talent_id: 1, + company_name: "Shopping Co.", + position: "Senior Software Engineer", + responsibility: "Leading development projects.", + start_month: "January", + start_year: "2023", + }, + // talent_id: 2 + { + talent_id: 2, + company_name: "123 Investments", + position: "Financial Analyst Intern", + responsibility: "Analyzed financial data and prepared reports.", + start_month: "June", + start_year: "2021", + end_month: "August", + end_year: "2021", + }, + // talent_id: 3 + { + talent_id: 3, + company_name: "Market Solutions Inc.", + position: "Marketing Assistant", + responsibility: "Assisted in developing marketing strategies.", + start_month: "March", + start_year: "2022", + end_month: "June", + end_year: "2022", + }, + ]); + + await queryInterface.bulkInsert("talents_skill_set", [ + // talent_id: 1 + { + talent_id: 1, + skill: "JavaScript", + proficiency_level: "Intermediate", + }, + { + talent_id: 1, + skill: "React", + proficiency_level: "Advanced", + }, + // talent_id: 2 + { + talent_id: 2, + skill: "Financial Modeling", + proficiency_level: "Great", + }, + // talent_id: 3 + { + talent_id: 3, + skill: "Digital Marketing", + proficiency_level: "Expert", + }, + ]); + + await queryInterface.bulkInsert("talents_education", [ + // Education for talent_id: 1 + { + talent_id: 1, + institution: "XYZ University", + degree: "Bachelor of Science in Computer Science", + field_of_study: "Computer Science", + graduation_month: "May", + graduation_year: "2020", + }, + { + talent_id: 1, + institution: "ABC University", + degree: "Master of Science in Software Engineering", + field_of_study: "Software Engineering", + graduation_month: "June", + graduation_year: "2022", + }, + // Education for talent_id: 2 + { + talent_id: 2, + institution: "University of ABC", + degree: "Bachelor of Business Administration", + field_of_study: "Finance", + graduation_month: "May", + graduation_year: "2021", + }, + // Education for talent_id: 3 + { + talent_id: 3, + institution: "XYZ University of ABC", + degree: "Bachelor of Marketing", + field_of_study: "Marketing", + graduation_month: "April", + graduation_year: "2022", + }, + ]); + + await queryInterface.bulkInsert("job_listings", [ + { + employer_id: 1, + job_title: "Senior Software Engineer", + description: "Developing and maintaining web applications.", + job_responsibility: "Lead development projects.", + skill_set: "JavaScript, React, Node.js", + application_start_date: "2024-02-01", + application_end_date: "2024-02-15", + }, + ]); + + await queryInterface.bulkInsert("applications", [ + { + job_listing_id: 1, + talent_id: 1, + application_date: new Date(), + application_status: "Pending", + created_at: new Date(), + updated_at: new Date(), + }, + ]); + + await queryInterface.bulkInsert("chatrooms", [ + { + application_id: 1, + created_at: new Date(), + updated_at: new Date(), + }, + ]); + }, + + async down(queryInterface, Sequelize) { + await queryInterface.dropTable("talents_resume"); + await queryInterface.dropTable("talents_work_experiences"); + await queryInterface.dropTable("talents_skill_set"); + await queryInterface.dropTable("talents_education"); + await queryInterface.dropTable("job_listings"); + await queryInterface.dropTable("applications"); + await queryInterface.dropTable("chatrooms"); + }, +}; diff --git a/db/seeders/20240211125839-tertiary_tables.js b/db/seeders/20240211125839-tertiary_tables.js new file mode 100644 index 00000000..7f7fb8db --- /dev/null +++ b/db/seeders/20240211125839-tertiary_tables.js @@ -0,0 +1,51 @@ +"use strict"; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.bulkInsert("job_listing_benefits", [ + { + job_listing_id: 1, + benefit_id: 1, + }, + { + job_listing_id: 1, + benefit_id: 3, + }, + { + job_listing_id: 1, + benefit_id: 7, + }, + ]); + + await queryInterface.bulkInsert("talent_benefits", [ + { + talent_id: 1, + benefit_id: 2, + }, + { + talent_id: 1, + benefit_id: 4, + }, + { + talent_id: 1, + benefit_id: 6, + }, + ]); + + await queryInterface.bulkInsert("messages", [ + { + talent_id: 1, + chatroom_id: 1, + message: "Hello, I am interested in the job listing.", + }, + ]); + }, + + async down(queryInterface, Sequelize) { + await queryInterface.dropTable("job_listing_benefits"); + await queryInterface.dropTable("talent_benefits"); + + await queryInterface.dropTable("messages"); + }, +}; From fae196c38ee47de08f2b343560d4fb3d7eccc125 Mon Sep 17 00:00:00 2001 From: estney Date: Mon, 12 Feb 2024 15:31:45 +0800 Subject: [PATCH 11/29] talent resume, education, skillset, work experience router and controller completed --- controllers/TalentController.js | 176 +++++++++++++++++- .../20240211024810-secondary_tables.js | 16 +- db/models/benefit.js | 6 +- db/models/talent.js | 10 +- db/models/talentEducation.js | 29 +++ db/models/talentResume.js | 28 +++ db/models/talentSkillSet.js | 26 +++ db/models/talentWorkExperience.js | 31 +++ db/seeders/20240211125828-secondary_tables.js | 16 +- db/seeders/20240211125839-tertiary_tables.js | 1 - index.js | 18 +- routers/TalentRouter.js | 53 +++++- 12 files changed, 384 insertions(+), 26 deletions(-) create mode 100644 db/models/talentEducation.js create mode 100644 db/models/talentResume.js create mode 100644 db/models/talentSkillSet.js create mode 100644 db/models/talentWorkExperience.js diff --git a/controllers/TalentController.js b/controllers/TalentController.js index 760fe1aa..47d75245 100644 --- a/controllers/TalentController.js +++ b/controllers/TalentController.js @@ -1,8 +1,18 @@ const BaseController = require("./BaseController"); class TalentController extends BaseController { - constructor(model) { + constructor( + model, + talentResumeModel, + talentWorkExperienceModel, + talentSkillSetModel, + talentEducationModel + ) { super(model); + this.talentResumeModel = talentResumeModel; + this.talentWorkExperienceModel = talentWorkExperienceModel; + this.talentSkillSetModel = talentSkillSetModel; + this.talentEducationModel = talentEducationModel; } // Create talent @@ -47,6 +57,170 @@ class TalentController extends BaseController { return res.status(400).json({ error: true, msg: err }); } } + + // <------------------------ RESUME ------------------------ > + + async addResume(req, res) { + const { talentId } = req.params; + const { location, industry, title, objective } = req.body; + try { + //tag to talent ID + const newResume = await this.talentResumeModel.create({ + location: location, + title: title, + industry: industry, + objective: objective, + talentId: talentId, + }); + // Respond with the new work experience + return res.json(newResume); + } catch (err) { + return res.status(400).json({ error: true, msg: err }); + } + } + + async getResume(req, res) { + const { talentId } = req.params; + try { + //tag to talent ID + const resume = await this.talentResumeModel.findAll({ + where: { + talentId: talentId, + }, + }); + // Respond with the new work experience + return res.json(resume); + } catch (err) { + return res.status(400).json({ error: true, msg: err }); + } + } + + // <------------------------ WORK EXPERIENCE ------------------------ > + + async addWorkExperience(req, res) { + const { talentId } = req.params; + const { + companyName, + position, + responsibility, + startMonth, + startYear, + endMonth, + endYear, + } = req.body; + try { + //tag to talent ID + const newWorkExperience = await this.talentWorkExperienceModel.create({ + companyName: companyName, + position: position, + responsibility: responsibility, + startMonth: startMonth, + startYear: startYear, + endMonth: endMonth, + endYear: endYear, + talentId: talentId, + }); + // Respond with the new work experience + return res.json(newWorkExperience); + } catch (err) { + return res.status(400).json({ error: true, msg: err }); + } + } + + async getWorkExperiences(req, res) { + const { talentId } = req.params; + try { + //tag to talent ID + const workExperiences = await this.talentWorkExperienceModel.findAll({ + where: { + talentId: talentId, + }, + }); + // Respond with the new work experience + return res.json(workExperiences); + } catch (err) { + return res.status(400).json({ error: true, msg: err }); + } + } + + // <------------------------ SKILL SET ------------------------ > + + async addSkillSet(req, res) { + const { talentId } = req.params; + const { skill, proficiencyLevel } = req.body; + try { + //tag to talent ID + const newSkill = await this.talentSkillSetModel.create({ + skill: skill, + proficiencyLevel: proficiencyLevel, + talentId: talentId, + }); + // Respond with the new work experience + return res.json(newSkill); + } catch (err) { + return res.status(400).json({ error: true, msg: err }); + } + } + + async getSkillSet(req, res) { + const { talentId } = req.params; + try { + //tag to talent ID + const skill = await this.talentSkillSetModel.findAll({ + where: { + talentId: talentId, + }, + }); + // Respond with the new work experience + return res.json(skill); + } catch (err) { + return res.status(400).json({ error: true, msg: err }); + } + } + + // <------------------------ EDUCATION ------------------------ > + + async addEducation(req, res) { + const { talentId } = req.params; + const { + institution, + degree, + fieldOfStudy, + graduationMonth, + graduationYear, + } = req.body; + try { + //tag to talent ID + const newEducation = await this.talentEducationModel.create({ + institution: institution, + degree: degree, + fieldOfStudy: fieldOfStudy, + graduationMonth: graduationMonth, + graduationYear: graduationYear, + talentId: talentId, + }); + // Respond with the new work experience + return res.json(newEducation); + } catch (err) { + return res.status(400).json({ error: true, msg: err }); + } + } + + async getEducation(req, res) { + const { talentId } = req.params; + try { + //tag to talent ID + const education = await this.talentEducationModel.findAll({ + where: { + talentId: talentId, + }, + }); + // Respond with the new work experience + return res.json(education); + } catch (err) { + return res.status(400).json({ error: true, msg: err }); + } + } } // get all user info under base controller diff --git a/db/migrations/20240211024810-secondary_tables.js b/db/migrations/20240211024810-secondary_tables.js index 51038d82..d9c15bac 100644 --- a/db/migrations/20240211024810-secondary_tables.js +++ b/db/migrations/20240211024810-secondary_tables.js @@ -3,7 +3,7 @@ /** @type {import('sequelize-cli').Migration} */ module.exports = { async up(queryInterface, Sequelize) { - await queryInterface.createTable("talents_resume", { + await queryInterface.createTable("talent_resumes", { id: { allowNull: false, autoIncrement: true, @@ -41,7 +41,7 @@ module.exports = { }, }); - await queryInterface.createTable("talents_work_experiences", { + await queryInterface.createTable("talent_work_experiences", { id: { allowNull: false, autoIncrement: true, @@ -93,7 +93,7 @@ module.exports = { }, }); - await queryInterface.createTable("talents_skill_set", { + await queryInterface.createTable("talent_skill_sets", { id: { allowNull: false, autoIncrement: true, @@ -125,7 +125,7 @@ module.exports = { }, }); - await queryInterface.createTable("talents_education", { + await queryInterface.createTable("talent_educations", { id: { allowNull: false, autoIncrement: true, @@ -289,10 +289,10 @@ module.exports = { }, async down(queryInterface, Sequelize) { - await queryInterface.dropTable("talents_resume"); - await queryInterface.dropTable("talents_work_experiences"); - await queryInterface.dropTable("talents_skill_set"); - await queryInterface.dropTable("talents_education"); + await queryInterface.dropTable("talent_resumes"); + await queryInterface.dropTable("talent_work_experiences"); + await queryInterface.dropTable("talent_skill_sets"); + await queryInterface.dropTable("talent_educations"); await queryInterface.dropTable("job_listings"); await queryInterface.dropTable("applications"); await queryInterface.dropTable("chatrooms"); diff --git a/db/models/benefit.js b/db/models/benefit.js index e7c4edf1..9ed698e2 100644 --- a/db/models/benefit.js +++ b/db/models/benefit.js @@ -4,7 +4,11 @@ const { Model } = require("sequelize"); module.exports = (sequelize, DataTypes) => { - class Benefit extends Model {} + class Benefit extends Model { + static associate(models) { + this.belongsToMany(models.talent, { through: "talent_benefits" }); + } + } Benefit.init( { category: DataTypes.STRING, diff --git a/db/models/talent.js b/db/models/talent.js index d07fb3b4..7a8adda0 100644 --- a/db/models/talent.js +++ b/db/models/talent.js @@ -4,7 +4,15 @@ const { Model } = require("sequelize"); module.exports = (sequelize, DataTypes) => { - class Talent extends Model {} + class Talent extends Model { + static associate(models) { + this.hasOne(models.talentResume, { foreignKey: "talentId" }); + this.hasMany(models.talentWorkExperience, { foreignKey: "talentId" }); + this.hasMany(models.talentSkillSet, { foreignKey: "talentId" }); + this.hasMany(models.talentEducation, { foreignKey: "talentId" }); + this.belongsToMany(models.benefit, { through: "talent_benefits" }); + } + } Talent.init( { firstName: DataTypes.STRING, diff --git a/db/models/talentEducation.js b/db/models/talentEducation.js new file mode 100644 index 00000000..6ad62f47 --- /dev/null +++ b/db/models/talentEducation.js @@ -0,0 +1,29 @@ +"use strict"; + +const { Model } = require("sequelize"); +module.exports = (sequelize, DataTypes) => { + class TalentEducation extends Model { + static associate(models) { + this.belongsTo(models.talent, { foreignKey: "talentId" }); + } + } + TalentEducation.init( + { + institution: DataTypes.STRING, + degree: DataTypes.STRING, + fieldOfStudy: DataTypes.STRING, + graduationMonth: DataTypes.STRING, + graduationYear: DataTypes.STRING, + talentId: { + type: DataTypes.INTEGER, + allowNull: false, + }, + }, + { + sequelize, + modelName: "talentEducation", + underscored: true, + } + ); + return TalentEducation; +}; diff --git a/db/models/talentResume.js b/db/models/talentResume.js new file mode 100644 index 00000000..cb028470 --- /dev/null +++ b/db/models/talentResume.js @@ -0,0 +1,28 @@ +"use strict"; + +const { Model } = require("sequelize"); +module.exports = (sequelize, DataTypes) => { + class TalentResume extends Model { + static associate(models) { + this.belongsTo(models.talent, { foreignKey: "talentId" }); + } + } + TalentResume.init( + { + location: DataTypes.STRING, + industry: DataTypes.STRING, + title: DataTypes.STRING, + objective: DataTypes.STRING, + talentId: { + type: DataTypes.INTEGER, + allowNull: false, + }, + }, + { + sequelize, + modelName: "talentResume", //non-plurul + underscored: true, + } + ); + return TalentResume; +}; diff --git a/db/models/talentSkillSet.js b/db/models/talentSkillSet.js new file mode 100644 index 00000000..33d20e00 --- /dev/null +++ b/db/models/talentSkillSet.js @@ -0,0 +1,26 @@ +"use strict"; + +const { Model } = require("sequelize"); +module.exports = (sequelize, DataTypes) => { + class TalentSkillSet extends Model { + static associate(models) { + this.belongsTo(models.talent, { foreignKey: "talentId" }); + } + } + TalentSkillSet.init( + { + skill: DataTypes.STRING, + proficiencyLevel: DataTypes.STRING, + talentId: { + type: DataTypes.INTEGER, + allowNull: false, + }, + }, + { + sequelize, + modelName: "talentSkillSet", + underscored: true, + } + ); + return TalentSkillSet; +}; diff --git a/db/models/talentWorkExperience.js b/db/models/talentWorkExperience.js new file mode 100644 index 00000000..f1fa5d92 --- /dev/null +++ b/db/models/talentWorkExperience.js @@ -0,0 +1,31 @@ +"use strict"; + +const { Model } = require("sequelize"); +module.exports = (sequelize, DataTypes) => { + class TalentWorkExperience extends Model { + static associate(models) { + this.belongsTo(models.talent, { foreignKey: "talentId" }); + } + } + TalentWorkExperience.init( + { + companyName: DataTypes.STRING, + position: DataTypes.STRING, + responsibility: DataTypes.STRING, + startMonth: DataTypes.STRING, + startYear: DataTypes.STRING, + endMonth: DataTypes.STRING, + endYear: DataTypes.STRING, + talentId: { + type: DataTypes.INTEGER, + allowNull: false, + }, + }, + { + sequelize, + modelName: "talentWorkExperience", + underscored: true, + } + ); + return TalentWorkExperience; +}; diff --git a/db/seeders/20240211125828-secondary_tables.js b/db/seeders/20240211125828-secondary_tables.js index 6c6df228..6a3f7635 100644 --- a/db/seeders/20240211125828-secondary_tables.js +++ b/db/seeders/20240211125828-secondary_tables.js @@ -3,7 +3,7 @@ /** @type {import('sequelize-cli').Migration} */ module.exports = { async up(queryInterface, Sequelize) { - await queryInterface.bulkInsert("talents_resume", [ + await queryInterface.bulkInsert("talent_resumes", [ { talent_id: 1, location: "Singapore", @@ -29,7 +29,7 @@ module.exports = { }, ]); - await queryInterface.bulkInsert("talents_work_experiences", [ + await queryInterface.bulkInsert("talent_work_experiences", [ // talent_id: 1 { talent_id: 1, @@ -73,7 +73,7 @@ module.exports = { }, ]); - await queryInterface.bulkInsert("talents_skill_set", [ + await queryInterface.bulkInsert("talent_skill_sets", [ // talent_id: 1 { talent_id: 1, @@ -99,7 +99,7 @@ module.exports = { }, ]); - await queryInterface.bulkInsert("talents_education", [ + await queryInterface.bulkInsert("talent_educations", [ // Education for talent_id: 1 { talent_id: 1, @@ -170,10 +170,10 @@ module.exports = { }, async down(queryInterface, Sequelize) { - await queryInterface.dropTable("talents_resume"); - await queryInterface.dropTable("talents_work_experiences"); - await queryInterface.dropTable("talents_skill_set"); - await queryInterface.dropTable("talents_education"); + await queryInterface.dropTable("talent_resumes"); + await queryInterface.dropTable("talent_work_experiences"); + await queryInterface.dropTable("talent_skill_sets"); + await queryInterface.dropTable("talent_educations"); await queryInterface.dropTable("job_listings"); await queryInterface.dropTable("applications"); await queryInterface.dropTable("chatrooms"); diff --git a/db/seeders/20240211125839-tertiary_tables.js b/db/seeders/20240211125839-tertiary_tables.js index 7f7fb8db..65eda62a 100644 --- a/db/seeders/20240211125839-tertiary_tables.js +++ b/db/seeders/20240211125839-tertiary_tables.js @@ -45,7 +45,6 @@ module.exports = { async down(queryInterface, Sequelize) { await queryInterface.dropTable("job_listing_benefits"); await queryInterface.dropTable("talent_benefits"); - await queryInterface.dropTable("messages"); }, }; diff --git a/index.js b/index.js index 916b2292..ad33ffee 100644 --- a/index.js +++ b/index.js @@ -17,7 +17,15 @@ const checkJwt = auth({ //import DB const db = require("./db/models/index"); -const { talent, benefit, employer } = db; +const { + talent, + benefit, + employer, + talentResume, + talentWorkExperience, + talentSkillSet, + talentEducation, +} = db; //import controllers const TalentController = require("./controllers/TalentController"); @@ -39,7 +47,13 @@ app.use(cors()); app.use(express.json()); //initialise contollers -const talentController = new TalentController(talent); +const talentController = new TalentController( + talent, + talentResume, + talentWorkExperience, + talentSkillSet, + talentEducation +); const benefitController = new BenefitController(benefit); const employerController = new EmployerController(employer); diff --git a/routers/TalentRouter.js b/routers/TalentRouter.js index 191fa295..d371d8ec 100644 --- a/routers/TalentRouter.js +++ b/routers/TalentRouter.js @@ -3,21 +3,66 @@ const router = express.Router(); class TalentRouter { constructor(talentController, checkJwt) { - this.controller = talentController; + this.talentController = talentController; this.checkJwt = checkJwt; } routes() { - router.get("/", this.controller.getAll.bind(this.controller)); + router.get("/", this.talentController.getAll.bind(this.talentController)); router.post( "/", this.checkJwt, - this.controller.addTalent.bind(this.controller) + this.talentController.addTalent.bind(this.talentController) ); router.post( "/:talentId", - this.controller.updateTalent.bind(this.controller) + this.talentController.updateTalent.bind(this.talentController) ); + + // <------------------------ RESUME ------------------------ > + + router.post( + "/:talentId/resume", + this.talentController.addResume.bind(this.talentController) + ); + router.get( + "/:talentId/resume", + this.talentController.getResume.bind(this.talentController) + ); + + // <------------------------ WORK EXPERIENCE ------------------------ > + + router.post( + "/:talentId/workexperience", + this.talentController.addWorkExperience.bind(this.talentController) + ); + router.get( + "/:talentId/workexperience", + this.talentController.getWorkExperiences.bind(this.talentController) + ); + + // <------------------------ SKILL SET ------------------------ > + + router.post( + "/:talentId/skill", + this.talentController.addSkillSet.bind(this.talentController) + ); + router.get( + "/:talentId/skill", + this.talentController.getSkillSet.bind(this.talentController) + ); + + // <------------------------ EDUCATION ------------------------ > + + router.post( + "/:talentId/education", + this.talentController.addEducation.bind(this.talentController) + ); + router.get( + "/:talentId/education", + this.talentController.getEducation.bind(this.talentController) + ); + return router; // Return the router instance } } From ad9a29917e897cb557aeaa258e5231923189131f Mon Sep 17 00:00:00 2001 From: estney Date: Mon, 12 Feb 2024 17:26:07 +0800 Subject: [PATCH 12/29] added routers and controllers for talent --- controllers/EmployerController.js | 49 ++++++++++++++++++++++++++++++- controllers/TalentController.js | 45 +++++++++++++++++++++++++++- db/models/employer.js | 6 +++- db/models/jobListing.js | 32 ++++++++++++++++++++ index.js | 6 ++-- routers/EmployerRouter.js | 11 +++++++ routers/TalentRouter.js | 12 ++++++++ 7 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 db/models/jobListing.js diff --git a/controllers/EmployerController.js b/controllers/EmployerController.js index c834ae90..1dda7b1d 100644 --- a/controllers/EmployerController.js +++ b/controllers/EmployerController.js @@ -1,8 +1,9 @@ const BaseController = require("./BaseController"); class EmployerController extends BaseController { - constructor(model) { + constructor(model, jobListingModel) { super(model); + this.jobListingModel = jobListingModel; } // Create employer @@ -53,6 +54,52 @@ class EmployerController extends BaseController { return res.status(400).json({ error: true, msg: err }); } } + + // <------------------------ JOB LISTING ------------------------ > + + async addJobListing(req, res) { + const { employerId } = req.params; + const { + jobTitle, + description, + jobResponsibility, + skillSet, + applicationStartDate, + applicationEndDate, + } = req.body; + try { + //tag to employerID + const newJobListing = await this.jobListingModel.create({ + jobTitle: jobTitle, + description: description, + jobResponsibility: jobResponsibility, + skillSet: skillSet, + applicationStartDate: applicationStartDate, + applicationEndDate: applicationEndDate, + employerId: employerId, + }); + // Respond with the new work experience + return res.json(newJobListing); + } catch (err) { + return res.status(400).json({ error: true, msg: err }); + } + } + + async getJobListing(req, res) { + const { employerId } = req.params; + try { + //tag to talent ID + const jobListing = await this.jobListingModel.findAll({ + where: { + employerId: employerId, + }, + }); + // Respond with the new work experience + return res.json(jobListing); + } catch (err) { + return res.status(400).json({ error: true, msg: err }); + } + } } // get all user info under base controller diff --git a/controllers/TalentController.js b/controllers/TalentController.js index 47d75245..442cf749 100644 --- a/controllers/TalentController.js +++ b/controllers/TalentController.js @@ -6,13 +6,15 @@ class TalentController extends BaseController { talentResumeModel, talentWorkExperienceModel, talentSkillSetModel, - talentEducationModel + talentEducationModel, + benefitModel ) { super(model); this.talentResumeModel = talentResumeModel; this.talentWorkExperienceModel = talentWorkExperienceModel; this.talentSkillSetModel = talentSkillSetModel; this.talentEducationModel = talentEducationModel; + this.benefitModel = benefitModel; } // Create talent @@ -221,6 +223,47 @@ class TalentController extends BaseController { return res.status(400).json({ error: true, msg: err }); } } + + // <------------------------ BENEFIT ------------------------ > + + async getBenefit(req, res) { + const { talentId } = req.params; + try { + const talent = await this.model.findByPk(talentId, { + include: this.benefitModel, + }); + + //show benefits only + const benefit = talent.benefits; + return res.json(talent); + } catch (err) { + return res.status(400).json({ error: true, msg: err }); + } + } + + async addBenefit(req, res) { + const { talentId } = req.params; + const { selectedBenefitId } = req.body; + try { + // Check if the talent exists + const talent = await this.model.findByPk(talentId); + if (!talent) { + return res.status(404).json({ error: true, msg: "Talent not found" }); + } + + // Create a new benefit and associate it with the talent + const addNewBenefit = await this.benefitModel.findAll({ + where: { + benefitId: selectedBenefitId, + }, + }); + await talent.setBenefits(addNewBenefit); + // Respond with the newly created benefit + return res.json(addNewBenefit); + } catch (err) { + return res.status(400).json({ error: true, msg: err }); + } + } } // get all user info under base controller diff --git a/db/models/employer.js b/db/models/employer.js index 1b9d2955..272be480 100644 --- a/db/models/employer.js +++ b/db/models/employer.js @@ -4,7 +4,11 @@ const { Model } = require("sequelize"); module.exports = (sequelize, DataTypes) => { - class Employer extends Model {} + class Employer extends Model { + static associate(models) { + this.hasMany(models.jobListing, { foreignKey: "employerId" }); + } + } Employer.init( { firstName: DataTypes.STRING, diff --git a/db/models/jobListing.js b/db/models/jobListing.js new file mode 100644 index 00000000..8220f49b --- /dev/null +++ b/db/models/jobListing.js @@ -0,0 +1,32 @@ +"use strict"; + +const { Model } = require("sequelize"); +module.exports = (sequelize, DataTypes) => { + class JobListing extends Model { + static associate(models) { + this.belongsTo(models.employer, { foreignKey: "employerId" }); + this.belongsToMany(models.benefit, { through: "job_listing_benefits" }); + } + } + JobListing.init( + { + jobTitle: DataTypes.STRING, + description: DataTypes.STRING, + jobResponsibility: DataTypes.STRING, + skillSet: DataTypes.STRING, + applicationStartDate: DataTypes.STRING, + applicationEndDate: DataTypes.STRING, + employerId: { + type: DataTypes.INTEGER, + allowNull: false, + }, + }, + { + sequelize, + modelName: "jobListing", + underscored: true, + } + ); + + return JobListing; +}; diff --git a/index.js b/index.js index ad33ffee..bc95dd9c 100644 --- a/index.js +++ b/index.js @@ -25,6 +25,7 @@ const { talentWorkExperience, talentSkillSet, talentEducation, + jobListing, } = db; //import controllers @@ -52,10 +53,11 @@ const talentController = new TalentController( talentResume, talentWorkExperience, talentSkillSet, - talentEducation + talentEducation, + benefit ); const benefitController = new BenefitController(benefit); -const employerController = new EmployerController(employer); +const employerController = new EmployerController(employer, jobListing); //initialise router const talentRouter = new TalentRouter(talentController, checkJwt).routes(); diff --git a/routers/EmployerRouter.js b/routers/EmployerRouter.js index 3c3424f9..7785d730 100644 --- a/routers/EmployerRouter.js +++ b/routers/EmployerRouter.js @@ -13,6 +13,17 @@ class EmployerRouter { "/:employerId", this.controller.updateEmployer.bind(this.controller) ); + + // <------------------------ JOB LISTING ------------------------ > + router.post( + "/:employerId/job", + this.controller.addJobListing.bind(this.controller) + ); + router.get( + "/:employerId/job", + this.controller.getJobListing.bind(this.controller) + ); + return router; // Return the router instance } } diff --git a/routers/TalentRouter.js b/routers/TalentRouter.js index d371d8ec..23815a58 100644 --- a/routers/TalentRouter.js +++ b/routers/TalentRouter.js @@ -63,6 +63,18 @@ class TalentRouter { this.talentController.getEducation.bind(this.talentController) ); + // <------------------------ BENEFIT ------------------------ > + + router.get( + "/:talentId", + this.talentController.getBenefit.bind(this.talentController) + ); + + router.get( + "/:talentId", + this.talentController.addBenefit.bind(this.talentController) + ); + return router; // Return the router instance } } From 8ff1616eaf757e0d27fda249d3349c406b34b4f4 Mon Sep 17 00:00:00 2001 From: estney Date: Tue, 13 Feb 2024 21:06:02 +0800 Subject: [PATCH 13/29] create updateResume controller and router --- controllers/TalentController.js | 85 +++++++++++++++++++++++++++++++++ db/models/benefit.js | 1 + routers/TalentRouter.js | 9 ++++ 3 files changed, 95 insertions(+) diff --git a/controllers/TalentController.js b/controllers/TalentController.js index 442cf749..43458add 100644 --- a/controllers/TalentController.js +++ b/controllers/TalentController.js @@ -96,6 +96,42 @@ class TalentController extends BaseController { return res.status(400).json({ error: true, msg: err }); } } + // Edit and Update Resume + async updateResume(req, res) { + const { talentId } = req.params; + const { location, title, industry, objective } = req.body; + try { + // Check if talent resume exists + const existingResume = await this.talentResumeModel.findOne({ + where: { + talentId: talentId, + }, + }); + + if (!existingResume) { + return res.status(404).json({ error: true, msg: "Resume not found" }); + } + + // Update the resume + await existingResume.update({ + location: location || existingResume.location, + title: title || existingResume.title, + industry: industry || existingResume.industry, + objective: objective || existingResume.objective, + }); + + // Fetch the updated resume + const updatedResume = await this.talentResumeModel.findOne({ + where: { + talentId: talentId, + }, + }); + + return res.json(updatedResume); + } catch (err) { + return res.status(400).json({ error: true, msg: err }); + } + } // <------------------------ WORK EXPERIENCE ------------------------ > @@ -145,6 +181,55 @@ class TalentController extends BaseController { } } + //update work experience + + async updateWorkExp(req, res) { + const { talentId } = req.params; + const { + companyName, + position, + responsibility, + startMonth, + startYear, + endMonth, + endYear, + } = req.body; + try { + // Check if talent resume exists + const existingWorkExp = await this.talentWorkExperienceModel.findOne({ + where: { + talentId: talentId, + }, + }); + + if (!existingWorkExp) { + return res.status(404).json({ error: true, msg: "Resume not found" }); + } + + // Update the resume + await existingWorkExp.update({ + companyName: companyName || existingWorkExp.companyName, + position: position || existingWorkExp.position, + responsibility: responsibility || existingWorkExp.responsibility, + startMonth: startMonth || existingWorkExp.startMonth, + startYear: startYear || existingWorkExp.startYear, + endMonth: endMonth || existingWorkExp.endMonth, + endYear: endYear || existingWorkExp.endYear, + }); + + // Fetch the updated work exp + const updatedWorkExp = await this.talentWorkExperienceModel.findOne({ + where: { + talentId: talentId, + }, + }); + + return res.json(updatedWorkExp); + } catch (err) { + return res.status(400).json({ error: true, msg: err }); + } + } + // <------------------------ SKILL SET ------------------------ > async addSkillSet(req, res) { diff --git a/db/models/benefit.js b/db/models/benefit.js index 9ed698e2..f773df5b 100644 --- a/db/models/benefit.js +++ b/db/models/benefit.js @@ -7,6 +7,7 @@ module.exports = (sequelize, DataTypes) => { class Benefit extends Model { static associate(models) { this.belongsToMany(models.talent, { through: "talent_benefits" }); + this.belongsToMany(models.talent, { through: "job_listing_benefits" }); } } Benefit.init( diff --git a/routers/TalentRouter.js b/routers/TalentRouter.js index 23815a58..35b91e42 100644 --- a/routers/TalentRouter.js +++ b/routers/TalentRouter.js @@ -14,6 +14,7 @@ class TalentRouter { this.checkJwt, this.talentController.addTalent.bind(this.talentController) ); + router.post( "/:talentId", this.talentController.updateTalent.bind(this.talentController) @@ -29,6 +30,10 @@ class TalentRouter { "/:talentId/resume", this.talentController.getResume.bind(this.talentController) ); + router.put( + "/:talentId/resume", + this.talentController.updateResume.bind(this.talentController) + ); // <------------------------ WORK EXPERIENCE ------------------------ > @@ -40,6 +45,10 @@ class TalentRouter { "/:talentId/workexperience", this.talentController.getWorkExperiences.bind(this.talentController) ); + router.put( + "/:talentId/workexperience", + this.talentController.updateWorkExp.bind(this.talentController) + ); // <------------------------ SKILL SET ------------------------ > From 74905b215b7d369a809d872023f40be4365e9dc3 Mon Sep 17 00:00:00 2001 From: estney Date: Wed, 14 Feb 2024 15:15:54 +0800 Subject: [PATCH 14/29] updated edit for skill, education and work experience --- controllers/TalentController.js | 194 ++++++++++++++++++++++++++------ routers/TalentRouter.js | 9 ++ 2 files changed, 167 insertions(+), 36 deletions(-) diff --git a/controllers/TalentController.js b/controllers/TalentController.js index 43458add..e8f9f31a 100644 --- a/controllers/TalentController.js +++ b/controllers/TalentController.js @@ -182,54 +182,102 @@ class TalentController extends BaseController { } //update work experience - async updateWorkExp(req, res) { - const { talentId } = req.params; - const { - companyName, - position, - responsibility, - startMonth, - startYear, - endMonth, - endYear, - } = req.body; + //check if it's an array, same name as Frontend + const { workExpData } = req.body; try { - // Check if talent resume exists - const existingWorkExp = await this.talentWorkExperienceModel.findOne({ - where: { - talentId: talentId, - }, - }); + console.log("Request to update work experience"); + console.log(req.body); + + // Iterate over each provided work experience and update it + for (const workExp of workExpData) { + await this.talentWorkExperienceModel.update( + { + companyName: workExp.companyName, + position: workExp.position, + responsibility: workExp.responsibility, + startMonth: workExp.startMonth, + startYear: workExp.startYear, + endMonth: workExp.endMonth, + endYear: workExp.endYear, + }, + //pull workexp ID instead of talentId + { + where: { id: workExp.id }, + } + ); - if (!existingWorkExp) { - return res.status(404).json({ error: true, msg: "Resume not found" }); + console.log(`Work experience updated`); } - // Update the resume - await existingWorkExp.update({ - companyName: companyName || existingWorkExp.companyName, - position: position || existingWorkExp.position, - responsibility: responsibility || existingWorkExp.responsibility, - startMonth: startMonth || existingWorkExp.startMonth, - startYear: startYear || existingWorkExp.startYear, - endMonth: endMonth || existingWorkExp.endMonth, - endYear: endYear || existingWorkExp.endYear, - }); + console.log("All work exp updated"); - // Fetch the updated work exp - const updatedWorkExp = await this.talentWorkExperienceModel.findOne({ - where: { - talentId: talentId, - }, + return res.status(200).json({ + success: true, + message: "Work experiences updated successfully", }); - - return res.json(updatedWorkExp); } catch (err) { + console.error("Error updating work experiences:", err); return res.status(400).json({ error: true, msg: err }); } } + // async updateWorkExp(req, res) { + // const { talentId } = req.params; + // const { + // companyName, + // position, + // responsibility, + // startMonth, + // startYear, + // endMonth, + // endYear, + // } = req.body; + // try { + // console.log("request to update work experience"); + // console.log(req.body); + // // Check if talent resume exists + // const existingWorkExp = await this.talentWorkExperienceModel.findOne({ + // where: { + // talentId: talentId, + // //try passing workexpID instead + // }, + // }); + + // if (!existingWorkExp) { + // return res.status(404).json({ error: true, msg: "data not found" }); + // } + + // console.log("work exp found"); + + // // Update the resume + // await existingWorkExp.update({ + // companyName: companyName || existingWorkExp.companyName, + // position: position || existingWorkExp.position, + // responsibility: responsibility || existingWorkExp.responsibility, + // startMonth: startMonth || existingWorkExp.startMonth, + // startYear: startYear || existingWorkExp.startYear, + // endMonth: endMonth || existingWorkExp.endMonth, + // endYear: endYear || existingWorkExp.endYear, + // }); + + // console.log("new work exp updated"); + + // // Fetch the updated work exp + // const updatedWorkExp = await this.talentWorkExperienceModel.findOne({ + // where: { + // talentId: talentId, + // }, + // }); + + // console.log("all work exp updated"); + + // return res.json(updatedWorkExp); + // } catch (err) { + // return res.status(400).json({ error: true, msg: err }); + // } + // } + // <------------------------ SKILL SET ------------------------ > async addSkillSet(req, res) { @@ -265,6 +313,42 @@ class TalentController extends BaseController { } } + //update work experience + async updateSkill(req, res) { + //check if it's an array, same name as Frontend + const { skillData } = req.body; + try { + console.log("Request to update skill"); + console.log(req.body); + + // Iterate over each provided work experience and update it + for (const skill of skillData) { + await this.talentSkillSetModel.update( + { + skill: skill.skill, + proficiencyLevel: skill.proficiencyLevel, + }, + //pull workexp ID instead of talentId + { + where: { id: skill.id }, + } + ); + + console.log("skills updated"); + } + + console.log("All skills updated"); + + return res.status(200).json({ + success: true, + message: "skills updated successfully", + }); + } catch (err) { + console.error("Error updating skills:", err); + return res.status(400).json({ error: true, msg: err }); + } + } + // <------------------------ EDUCATION ------------------------ > async addEducation(req, res) { @@ -309,6 +393,44 @@ class TalentController extends BaseController { } } + async updateEdu(req, res) { + //check if it's an array, same name as Frontend + const { eduData } = req.body; + try { + console.log("Request to update work experience"); + console.log(req.body); + + // Iterate over each provided work experience and update it + for (const edu of eduData) { + await this.talentEducationModel.update( + { + institution: edu.institution, + degree: edu.degree, + fieldOfStudy: edu.fieldOfStudy, + graduationMonth: edu.graduationMonth, + graduationYear: edu.graduationYear, + }, + //pull workexp ID instead of talentId + { + where: { id: edu.id }, + } + ); + + console.log(`Education updated`); + } + + console.log("All edu updated"); + + return res.status(200).json({ + success: true, + message: "Edu updated successfully", + }); + } catch (err) { + console.error("Error updating edu:", err); + return res.status(400).json({ error: true, msg: err }); + } + } + // <------------------------ BENEFIT ------------------------ > async getBenefit(req, res) { diff --git a/routers/TalentRouter.js b/routers/TalentRouter.js index 35b91e42..086807c8 100644 --- a/routers/TalentRouter.js +++ b/routers/TalentRouter.js @@ -61,6 +61,11 @@ class TalentRouter { this.talentController.getSkillSet.bind(this.talentController) ); + router.put( + "/:talentId/skill", + this.talentController.updateSkill.bind(this.talentController) + ); + // <------------------------ EDUCATION ------------------------ > router.post( @@ -71,6 +76,10 @@ class TalentRouter { "/:talentId/education", this.talentController.getEducation.bind(this.talentController) ); + router.put( + "/:talentId/education", + this.talentController.updateEdu.bind(this.talentController) + ); // <------------------------ BENEFIT ------------------------ > From 99206175202f6ab47da3d67b4833a0372ce63ac5 Mon Sep 17 00:00:00 2001 From: estney Date: Wed, 14 Feb 2024 18:38:33 +0800 Subject: [PATCH 15/29] add benefits for talent works --- controllers/TalentController.js | 5 +++-- routers/TalentRouter.js | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/controllers/TalentController.js b/controllers/TalentController.js index e8f9f31a..67e6f62e 100644 --- a/controllers/TalentController.js +++ b/controllers/TalentController.js @@ -450,9 +450,10 @@ class TalentController extends BaseController { async addBenefit(req, res) { const { talentId } = req.params; - const { selectedBenefitId } = req.body; + const { selectedBenefitIds } = req.body; try { // Check if the talent exists + console.log("did data went through?", req.body); const talent = await this.model.findByPk(talentId); if (!talent) { return res.status(404).json({ error: true, msg: "Talent not found" }); @@ -461,7 +462,7 @@ class TalentController extends BaseController { // Create a new benefit and associate it with the talent const addNewBenefit = await this.benefitModel.findAll({ where: { - benefitId: selectedBenefitId, + id: selectedBenefitIds, }, }); await talent.setBenefits(addNewBenefit); diff --git a/routers/TalentRouter.js b/routers/TalentRouter.js index 086807c8..db8b6fb1 100644 --- a/routers/TalentRouter.js +++ b/routers/TalentRouter.js @@ -84,12 +84,12 @@ class TalentRouter { // <------------------------ BENEFIT ------------------------ > router.get( - "/:talentId", + "/:talentId/benefits", this.talentController.getBenefit.bind(this.talentController) ); - router.get( - "/:talentId", + router.post( + "/:talentId/benefits", this.talentController.addBenefit.bind(this.talentController) ); From c14dc81176967510bf945c95b782e6b88e51ffc2 Mon Sep 17 00:00:00 2001 From: estney Date: Wed, 14 Feb 2024 18:39:19 +0800 Subject: [PATCH 16/29] save file --- controllers/TalentController.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/controllers/TalentController.js b/controllers/TalentController.js index 67e6f62e..d5c39763 100644 --- a/controllers/TalentController.js +++ b/controllers/TalentController.js @@ -441,7 +441,7 @@ class TalentController extends BaseController { }); //show benefits only - const benefit = talent.benefits; + const benefits = talent.benefits; return res.json(talent); } catch (err) { return res.status(400).json({ error: true, msg: err }); @@ -458,7 +458,6 @@ class TalentController extends BaseController { if (!talent) { return res.status(404).json({ error: true, msg: "Talent not found" }); } - // Create a new benefit and associate it with the talent const addNewBenefit = await this.benefitModel.findAll({ where: { From d12b178473290a0c9229f738cb7f7e180103f44b Mon Sep 17 00:00:00 2001 From: estney Date: Thu, 15 Feb 2024 09:23:10 +0800 Subject: [PATCH 17/29] added delete function for work exp, edu and skill --- controllers/TalentController.js | 80 +++++++++++++++++++++++++++++++++ routers/TalentRouter.js | 16 +++++++ 2 files changed, 96 insertions(+) diff --git a/controllers/TalentController.js b/controllers/TalentController.js index d5c39763..d040b0b4 100644 --- a/controllers/TalentController.js +++ b/controllers/TalentController.js @@ -278,6 +278,32 @@ class TalentController extends BaseController { // } // } + async deleteWorkExp(req, res) { + const { workExpID } = req.params; + try { + // Check if the skill set exists + const workExp = await this.talentWorkExperienceModel.findOne({ + where: { + id: workExpID, + }, + }); + + if (!workExp) { + return res.status(404).json({ error: true, msg: "Work not found" }); + } + + // Delete the skill set + await workExp.destroy(); + + return res.json({ + success: true, + msg: "Work exp set deleted successfully", + }); + } catch (err) { + return res.status(400).json({ error: true, msg: err.message }); + } + } + // <------------------------ SKILL SET ------------------------ > async addSkillSet(req, res) { @@ -349,6 +375,31 @@ class TalentController extends BaseController { } } + async deleteSkill(req, res) { + const { skillId } = req.params; + try { + // Check if the skill set exists + const skillSet = await this.talentSkillSetModel.findOne({ + where: { + id: skillId, + }, + }); + + if (!skillSet) { + return res + .status(404) + .json({ error: true, msg: "Skill set not found" }); + } + + // Delete the skill set + await skillSet.destroy(); + + return res.json({ success: true, msg: "Skill set deleted successfully" }); + } catch (err) { + return res.status(400).json({ error: true, msg: err.message }); + } + } + // <------------------------ EDUCATION ------------------------ > async addEducation(req, res) { @@ -431,6 +482,35 @@ class TalentController extends BaseController { } } + async deleteEdu(req, res) { + const { educationID } = req.params; + console.log("EDUCATION ID", educationID); + try { + // Check if the education entry exists + const eduSet = await this.talentEducationModel.findOne({ + where: { + id: educationID, + }, + }); + + if (!eduSet) { + return res + .status(404) + .json({ error: true, msg: "Education set not found" }); + } + + // Delete the education entry + await eduSet.destroy(); + + return res.json({ + success: true, + msg: "Education set deleted successfully", + }); + } catch (err) { + return res.status(400).json({ error: true, msg: err.message }); + } + } + // <------------------------ BENEFIT ------------------------ > async getBenefit(req, res) { diff --git a/routers/TalentRouter.js b/routers/TalentRouter.js index db8b6fb1..8e6a518d 100644 --- a/routers/TalentRouter.js +++ b/routers/TalentRouter.js @@ -45,11 +45,17 @@ class TalentRouter { "/:talentId/workexperience", this.talentController.getWorkExperiences.bind(this.talentController) ); + router.put( "/:talentId/workexperience", this.talentController.updateWorkExp.bind(this.talentController) ); + router.delete( + "/:talentId/workexperience/:workExpID", + this.talentController.deleteWorkExp.bind(this.talentController) + ); + // <------------------------ SKILL SET ------------------------ > router.post( @@ -66,6 +72,11 @@ class TalentRouter { this.talentController.updateSkill.bind(this.talentController) ); + router.delete( + "/:talentId/skill/:skillId", + this.talentController.deleteSkill.bind(this.talentController) + ); + // <------------------------ EDUCATION ------------------------ > router.post( @@ -81,6 +92,11 @@ class TalentRouter { this.talentController.updateEdu.bind(this.talentController) ); + router.delete( + "/:talentId/education/:educationID", + this.talentController.deleteEdu.bind(this.talentController) + ); + // <------------------------ BENEFIT ------------------------ > router.get( From ed2027468912c5285c2487aa32d137f52e94b721 Mon Sep 17 00:00:00 2001 From: estney Date: Thu, 15 Feb 2024 15:04:43 +0800 Subject: [PATCH 18/29] a new router to show job listing to talents --- controllers/EmployerController.js | 3 +- controllers/TalentController.js | 38 +++++- db/seeders/20240215025813-job_listings.js | 148 ++++++++++++++++++++++ index.js | 12 +- routers/TalentRouter.js | 7 + 5 files changed, 204 insertions(+), 4 deletions(-) create mode 100644 db/seeders/20240215025813-job_listings.js diff --git a/controllers/EmployerController.js b/controllers/EmployerController.js index 1dda7b1d..a21bdbc8 100644 --- a/controllers/EmployerController.js +++ b/controllers/EmployerController.js @@ -1,9 +1,10 @@ const BaseController = require("./BaseController"); class EmployerController extends BaseController { - constructor(model, jobListingModel) { + constructor(model, jobListingModel, benefitModel) { super(model); this.jobListingModel = jobListingModel; + this.benefitModel = benefitModel; } // Create employer diff --git a/controllers/TalentController.js b/controllers/TalentController.js index d040b0b4..8e5eca2f 100644 --- a/controllers/TalentController.js +++ b/controllers/TalentController.js @@ -7,7 +7,9 @@ class TalentController extends BaseController { talentWorkExperienceModel, talentSkillSetModel, talentEducationModel, - benefitModel + benefitModel, + employerModel, + jobListing ) { super(model); this.talentResumeModel = talentResumeModel; @@ -15,6 +17,8 @@ class TalentController extends BaseController { this.talentSkillSetModel = talentSkillSetModel; this.talentEducationModel = talentEducationModel; this.benefitModel = benefitModel; + this.employerModel = employerModel; + this.jobListingModel = jobListing; } // Create talent @@ -551,6 +555,38 @@ class TalentController extends BaseController { return res.status(400).json({ error: true, msg: err }); } } + + // <------------------------ JOB LISTINGS ------------------------ > + + async getEmAndJobListing(req, res) { + try { + // Include associated employer data when querying for job listings + console.log("hello, get employer and job listing."); + console.log(this.jobListingModel); + const jobListing = await this.jobListingModel.findAll({ + include: [ + { + model: this.employerModel, + attributes: ["companyName", "description"], + }, + { + model: this.benefitModel, + attributes: ["id", "category"], //benefits modal + through: { + attributes: ["jobListingId"], //joint modal + }, + }, + ], + }); + + console.log(jobListing); + // Respond with the job listings including associated employer data + return res.json(jobListing); + } catch (err) { + console.log(err); + return res.status(400).json({ error: true, msg: err }); + } + } } // get all user info under base controller diff --git a/db/seeders/20240215025813-job_listings.js b/db/seeders/20240215025813-job_listings.js new file mode 100644 index 00000000..d0b5ec74 --- /dev/null +++ b/db/seeders/20240215025813-job_listings.js @@ -0,0 +1,148 @@ +"use strict"; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.bulkInsert("job_listings", [ + { + employer_id: 1, + job_title: "Frontend Developer", + description: "Building user interfaces for web applications.", + job_responsibility: "Design and implement user-facing features.", + skill_set: "HTML, CSS, JavaScript, React", + application_start_date: "2024-02-10", + application_end_date: "2024-03-20", + }, + { + employer_id: 1, + job_title: "Backend Developer", + description: "Creating and maintaining server-side logic.", + job_responsibility: "Develop backend components and APIs.", + skill_set: "Node.js, Express, MongoDB", + application_start_date: "2024-02-03", + application_end_date: "2024-02-28", + }, + { + employer_id: 2, + job_title: "Accountant", + description: "Managing financial records and transactions.", + job_responsibility: "Prepare financial statements and reports.", + skill_set: "Accounting software, Financial analysis, Taxation", + application_start_date: "2024-02-04", + application_end_date: "2024-03-04", + }, + { + employer_id: 3, + job_title: "Graphic Designer", + description: + "Creating visual concepts and designs for various projects.", + job_responsibility: + "Develop visual elements for print and digital media.", + skill_set: "Adobe Creative Suite, Graphic design principles", + application_start_date: "2024-02-03", + application_end_date: "2024-03-28", + }, + { + employer_id: 3, + job_title: "UI/UX Designer", + description: + "Designing user interfaces and experiences for digital products.", + job_responsibility: "Create wireframes, mockups, and prototypes.", + skill_set: "UI/UX design tools, User research, Prototyping", + application_start_date: "2024-02-03", + application_end_date: "2024-03-28", + }, + { + employer_id: 3, + job_title: "Web Designer", + description: + "Designing and creating websites with a focus on aesthetics and usability.", + job_responsibility: + "Develop visually appealing and functional web layouts.", + skill_set: "HTML, CSS, JavaScript, Responsive design", + application_start_date: "2024-02-03", + application_end_date: "2024-03-28", + }, + ]); + + await queryInterface.bulkInsert("job_listing_benefits", [ + { + job_listing_id: 2, + benefit_id: 4, + }, + { + job_listing_id: 2, + benefit_id: 7, + }, + { + job_listing_id: 2, + benefit_id: 9, + }, + { + job_listing_id: 3, + benefit_id: 1, + }, + { + job_listing_id: 3, + benefit_id: 3, + }, + { + job_listing_id: 3, + benefit_id: 8, + }, + { + job_listing_id: 4, + benefit_id: 2, + }, + { + job_listing_id: 4, + benefit_id: 5, + }, + { + job_listing_id: 4, + benefit_id: 10, + }, + { + job_listing_id: 5, + benefit_id: 1, + }, + { + job_listing_id: 5, + benefit_id: 6, + }, + { + job_listing_id: 5, + benefit_id: 8, + }, + { + job_listing_id: 6, + benefit_id: 3, + }, + { + job_listing_id: 6, + benefit_id: 4, + }, + { + job_listing_id: 6, + benefit_id: 9, + }, + { + job_listing_id: 7, + benefit_id: 2, + }, + { + job_listing_id: 7, + benefit_id: 5, + }, + { + job_listing_id: 7, + benefit_id: 10, + }, + ]); + }, + + async down(queryInterface, Sequelize) { + await queryInterface.dropTable("job_listings"); + await queryInterface.dropTable("job_listing_benefits"); + }, +}; diff --git a/index.js b/index.js index bc95dd9c..c02b958f 100644 --- a/index.js +++ b/index.js @@ -27,6 +27,8 @@ const { talentEducation, jobListing, } = db; +console.log("index tal", talent); +console.log("index", jobListing); //import controllers const TalentController = require("./controllers/TalentController"); @@ -54,10 +56,16 @@ const talentController = new TalentController( talentWorkExperience, talentSkillSet, talentEducation, + benefit, + employer, + jobListing +); +const benefitController = new BenefitController(benefit, employer); +const employerController = new EmployerController( + employer, + jobListing, benefit ); -const benefitController = new BenefitController(benefit); -const employerController = new EmployerController(employer, jobListing); //initialise router const talentRouter = new TalentRouter(talentController, checkJwt).routes(); diff --git a/routers/TalentRouter.js b/routers/TalentRouter.js index 8e6a518d..8a5210a8 100644 --- a/routers/TalentRouter.js +++ b/routers/TalentRouter.js @@ -109,6 +109,13 @@ class TalentRouter { this.talentController.addBenefit.bind(this.talentController) ); + // <------------------- JOB LISTINGS ------------------- > + + router.get( + "/joblistings", + this.talentController.getEmAndJobListing.bind(this.talentController) + ); + return router; // Return the router instance } } From 376842d68308a5acc851a8ca53997a288b6ca279 Mon Sep 17 00:00:00 2001 From: estney Date: Thu, 15 Feb 2024 18:50:17 +0800 Subject: [PATCH 19/29] added application works --- controllers/TalentController.js | 33 +++++++++++++++++++++++++++++---- db/models/application.js | 28 ++++++++++++++++++++++++++++ db/models/jobListing.js | 1 + db/models/talent.js | 1 + index.js | 6 +++--- routers/TalentRouter.js | 11 ++++++++++- 6 files changed, 72 insertions(+), 8 deletions(-) create mode 100644 db/models/application.js diff --git a/controllers/TalentController.js b/controllers/TalentController.js index 8e5eca2f..0fd1007a 100644 --- a/controllers/TalentController.js +++ b/controllers/TalentController.js @@ -9,7 +9,8 @@ class TalentController extends BaseController { talentEducationModel, benefitModel, employerModel, - jobListing + jobListing, + application ) { super(model); this.talentResumeModel = talentResumeModel; @@ -19,6 +20,7 @@ class TalentController extends BaseController { this.benefitModel = benefitModel; this.employerModel = employerModel; this.jobListingModel = jobListing; + this.applicationModel = application; } // Create talent @@ -562,7 +564,6 @@ class TalentController extends BaseController { try { // Include associated employer data when querying for job listings console.log("hello, get employer and job listing."); - console.log(this.jobListingModel); const jobListing = await this.jobListingModel.findAll({ include: [ { @@ -578,10 +579,34 @@ class TalentController extends BaseController { }, ], }); - - console.log(jobListing); // Respond with the job listings including associated employer data return res.json(jobListing); + } catch (err) { + return res.status(400).json({ error: true, msg: err }); + } + } + + // <-------------------- APPLICATION ---------------------- > + + async addApplication(req, res) { + const { talentId } = req.params; + const { applicationStatus, jobListingId } = req.body; + console.log("ADD APPLICATION"); + console.log(applicationStatus); + console.log(talentId); + console.log(jobListingId); + try { + console.log("passing through"); + + //tag to talent ID + const newApplication = await this.applicationModel.create({ + jobListingId: jobListingId, + talentId: talentId, + applicationStatus: applicationStatus, + }); + console.log("job get posted."); + // Respond with the new work experience + return res.json(newApplication); } catch (err) { console.log(err); return res.status(400).json({ error: true, msg: err }); diff --git a/db/models/application.js b/db/models/application.js new file mode 100644 index 00000000..7a03b422 --- /dev/null +++ b/db/models/application.js @@ -0,0 +1,28 @@ +const { Model } = require("sequelize"); +module.exports = (sequelize, DataTypes) => { + class Application extends Model { + static associate(models) { + this.belongsTo(models.talent, { foreignKey: "talentId" }); + this.belongsTo(models.jobListing, { foreignKey: "jobListingId" }); + } + } + Application.init( + { + applicationStatus: DataTypes.STRING, + talentId: { + type: DataTypes.INTEGER, + allowNull: false, + }, + jobListingId: { + type: DataTypes.INTEGER, + allowNull: false, + }, + }, + { + sequelize, + modelName: "application", //non-plurul + underscored: true, + } + ); + return Application; +}; diff --git a/db/models/jobListing.js b/db/models/jobListing.js index 8220f49b..0a8803f3 100644 --- a/db/models/jobListing.js +++ b/db/models/jobListing.js @@ -5,6 +5,7 @@ module.exports = (sequelize, DataTypes) => { class JobListing extends Model { static associate(models) { this.belongsTo(models.employer, { foreignKey: "employerId" }); + this.hasMany(models.application, { foreignKey: "jobListingId" }); this.belongsToMany(models.benefit, { through: "job_listing_benefits" }); } } diff --git a/db/models/talent.js b/db/models/talent.js index 7a8adda0..71c21450 100644 --- a/db/models/talent.js +++ b/db/models/talent.js @@ -10,6 +10,7 @@ module.exports = (sequelize, DataTypes) => { this.hasMany(models.talentWorkExperience, { foreignKey: "talentId" }); this.hasMany(models.talentSkillSet, { foreignKey: "talentId" }); this.hasMany(models.talentEducation, { foreignKey: "talentId" }); + this.hasMany(models.application, { foreignKey: "talentId" }); this.belongsToMany(models.benefit, { through: "talent_benefits" }); } } diff --git a/index.js b/index.js index c02b958f..309df4fe 100644 --- a/index.js +++ b/index.js @@ -26,9 +26,8 @@ const { talentSkillSet, talentEducation, jobListing, + application, } = db; -console.log("index tal", talent); -console.log("index", jobListing); //import controllers const TalentController = require("./controllers/TalentController"); @@ -58,7 +57,8 @@ const talentController = new TalentController( talentEducation, benefit, employer, - jobListing + jobListing, + application ); const benefitController = new BenefitController(benefit, employer); const employerController = new EmployerController( diff --git a/routers/TalentRouter.js b/routers/TalentRouter.js index 8a5210a8..5e769e1e 100644 --- a/routers/TalentRouter.js +++ b/routers/TalentRouter.js @@ -112,10 +112,19 @@ class TalentRouter { // <------------------- JOB LISTINGS ------------------- > router.get( - "/joblistings", + "/:talentId/joblistings", + this.checkJwt, this.talentController.getEmAndJobListing.bind(this.talentController) ); + // <------------------- APPLICATION ------------------- > + + router.post( + "/:talentId/applications", + this.checkJwt, + this.talentController.addApplication.bind(this.talentController) + ); + return router; // Return the router instance } } From a3b78fddb40e7078f975d69b73619044305ff536 Mon Sep 17 00:00:00 2001 From: estney Date: Thu, 15 Feb 2024 19:41:46 +0800 Subject: [PATCH 20/29] added checkJWT to edu routers --- routers/TalentRouter.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/routers/TalentRouter.js b/routers/TalentRouter.js index 5e769e1e..1a2b5564 100644 --- a/routers/TalentRouter.js +++ b/routers/TalentRouter.js @@ -81,6 +81,7 @@ class TalentRouter { router.post( "/:talentId/education", + this.checkJwt, this.talentController.addEducation.bind(this.talentController) ); router.get( @@ -89,11 +90,13 @@ class TalentRouter { ); router.put( "/:talentId/education", + this.checkJwt, this.talentController.updateEdu.bind(this.talentController) ); router.delete( "/:talentId/education/:educationID", + this.checkJwt, this.talentController.deleteEdu.bind(this.talentController) ); From b5c44f74d1998bde088531fa598746fe16104ec5 Mon Sep 17 00:00:00 2001 From: estney Date: Thu, 15 Feb 2024 19:48:10 +0800 Subject: [PATCH 21/29] added checkjwt to benefits --- routers/TalentRouter.js | 1 + 1 file changed, 1 insertion(+) diff --git a/routers/TalentRouter.js b/routers/TalentRouter.js index 1a2b5564..d132a20e 100644 --- a/routers/TalentRouter.js +++ b/routers/TalentRouter.js @@ -109,6 +109,7 @@ class TalentRouter { router.post( "/:talentId/benefits", + this.checkJwt, this.talentController.addBenefit.bind(this.talentController) ); From 32ffed85870cac13f02ac9593964d9ce6e77cea2 Mon Sep 17 00:00:00 2001 From: estney Date: Thu, 15 Feb 2024 19:57:16 +0800 Subject: [PATCH 22/29] added jwt to skill --- routers/TalentRouter.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/routers/TalentRouter.js b/routers/TalentRouter.js index d132a20e..4d46aac8 100644 --- a/routers/TalentRouter.js +++ b/routers/TalentRouter.js @@ -60,6 +60,7 @@ class TalentRouter { router.post( "/:talentId/skill", + this.checkJwt, this.talentController.addSkillSet.bind(this.talentController) ); router.get( @@ -69,11 +70,13 @@ class TalentRouter { router.put( "/:talentId/skill", + this.checkJwt, this.talentController.updateSkill.bind(this.talentController) ); router.delete( "/:talentId/skill/:skillId", + this.checkJwt, this.talentController.deleteSkill.bind(this.talentController) ); From 01209024ebcbe34b2b4cb214f38b3f7b4d6dba90 Mon Sep 17 00:00:00 2001 From: estney Date: Thu, 15 Feb 2024 20:02:10 +0800 Subject: [PATCH 23/29] added jwt to work exp --- routers/TalentRouter.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/routers/TalentRouter.js b/routers/TalentRouter.js index 4d46aac8..e8e8b1c2 100644 --- a/routers/TalentRouter.js +++ b/routers/TalentRouter.js @@ -39,6 +39,7 @@ class TalentRouter { router.post( "/:talentId/workexperience", + this.checkJwt, this.talentController.addWorkExperience.bind(this.talentController) ); router.get( @@ -48,11 +49,13 @@ class TalentRouter { router.put( "/:talentId/workexperience", + this.checkJwt, this.talentController.updateWorkExp.bind(this.talentController) ); router.delete( "/:talentId/workexperience/:workExpID", + this.checkJwt, this.talentController.deleteWorkExp.bind(this.talentController) ); From b9103524adb8bb46e06955916967d3a5a2b32491 Mon Sep 17 00:00:00 2001 From: estney Date: Thu, 15 Feb 2024 22:45:20 +0800 Subject: [PATCH 24/29] created get function for talent's applied job --- controllers/TalentController.js | 29 +++++++++++++++++++++++++++++ routers/TalentRouter.js | 5 +++++ 2 files changed, 34 insertions(+) diff --git a/controllers/TalentController.js b/controllers/TalentController.js index 0fd1007a..58549ff5 100644 --- a/controllers/TalentController.js +++ b/controllers/TalentController.js @@ -1,3 +1,4 @@ +const talent = require("../db/models/talent"); const BaseController = require("./BaseController"); class TalentController extends BaseController { @@ -612,6 +613,34 @@ class TalentController extends BaseController { return res.status(400).json({ error: true, msg: err }); } } + + async getApplications(req, res) { + const { talentId } = req.params; + try { + console.log("talent id:", talentId); + const applications = await this.applicationModel.findAll({ + where: { + talentId: talentId, + }, + include: [ + { + model: this.jobListingModel, + include: [ + { + model: this.employerModel, + attributes: ["companyName"], + }, + ], + }, + ], + }); + console.log(applications); + // Respond with the applications data + return res.json(applications); + } catch (err) { + return res.status(400).json({ error: true, msg: err.message }); + } + } } // get all user info under base controller diff --git a/routers/TalentRouter.js b/routers/TalentRouter.js index e8e8b1c2..ecc398cf 100644 --- a/routers/TalentRouter.js +++ b/routers/TalentRouter.js @@ -135,6 +135,11 @@ class TalentRouter { this.talentController.addApplication.bind(this.talentController) ); + router.get( + "/:talentId/applications", + this.talentController.getApplications.bind(this.talentController) + ); + return router; // Return the router instance } } From a43a0fed71bc6aacd464f9b5cb54f975d144f292 Mon Sep 17 00:00:00 2001 From: estney Date: Fri, 16 Feb 2024 14:27:47 +0800 Subject: [PATCH 25/29] created controller to only display jobs that are not applied --- controllers/TalentController.js | 72 +++++++++++++++++++++++++++++++++ routers/TalentRouter.js | 5 +++ 2 files changed, 77 insertions(+) diff --git a/controllers/TalentController.js b/controllers/TalentController.js index 58549ff5..1f08e7d9 100644 --- a/controllers/TalentController.js +++ b/controllers/TalentController.js @@ -641,6 +641,78 @@ class TalentController extends BaseController { return res.status(400).json({ error: true, msg: err.message }); } } + + async getAllApplications(req, res) { + const { talentId } = req.params; + try { + // find all job listings - ok + // console.log("HHHHHEEEELLLLLOOOOOO WOOORRLLLDDD!!!!!"); + // console.log("non applications"); + // console.log("talent id:", talentId); + + const allJobListings = await this.jobListingModel.findAll({ + include: [ + { + model: this.employerModel, + attributes: ["companyName", "description"], + }, + { + model: this.benefitModel, + attributes: ["id", "category"], //benefits modal + through: { + attributes: ["jobListingId"], //joint modal + }, + }, + ], + }); + + // console.log("all job listingss", allJobListings); + + // find the applications that the user applied - ok + + const applications = await this.applicationModel.findAll({ + where: { + talentId: talentId, + }, + include: [ + { + model: this.jobListingModel, + include: [ + { + model: this.employerModel, + attributes: ["companyName"], + }, + ], + }, + ], + }); + + console.log(applications); + + // console.log("APPLIED JOBSSSSS", applications); + + // filter by job listing that they applied to by the joblisting ID in application model + // extract applied job listing ids - ok + + const appliedJobListingIds = applications.map( + (application) => application.jobListing.id + ); + + // console.log("appliedJobListingIds", appliedJobListingIds); + + // filter applications with the job listing ids + // dont want ids that matches with applied job listing ids + const unappliedJobs = allJobListings.filter( + (jobListing) => !appliedJobListingIds.includes(jobListing.id) + ); + + // console.log(unappliedJobs); + // Respond with the non - applications data + return res.json(unappliedJobs); + } catch (err) { + return res.status(400).json({ error: true, msg: err.message }); + } + } } // get all user info under base controller diff --git a/routers/TalentRouter.js b/routers/TalentRouter.js index ecc398cf..35db6ff3 100644 --- a/routers/TalentRouter.js +++ b/routers/TalentRouter.js @@ -127,6 +127,11 @@ class TalentRouter { this.talentController.getEmAndJobListing.bind(this.talentController) ); + router.get( + "/:talentId/alljoblistings", + this.talentController.getAllApplications.bind(this.talentController) + ); + // <------------------- APPLICATION ------------------- > router.post( From 211ea40cfeca8d822de2e21a509067fffa166ac0 Mon Sep 17 00:00:00 2001 From: estney Date: Fri, 16 Feb 2024 16:23:37 +0800 Subject: [PATCH 26/29] added edit names function --- controllers/TalentController.js | 26 ++++++++++++++++++++++++++ routers/TalentRouter.js | 6 ++++++ 2 files changed, 32 insertions(+) diff --git a/controllers/TalentController.js b/controllers/TalentController.js index 1f08e7d9..9d064897 100644 --- a/controllers/TalentController.js +++ b/controllers/TalentController.js @@ -67,6 +67,32 @@ class TalentController extends BaseController { } } + async editTalentName(req, res) { + const { talentId } = req.params; + const { userFirstName, userLastName } = req.body; + try { + console.log("EDITTT NAME"); + console.log("NAME", userFirstName); + const updatedTalent = await this.model.update( + { + firstName: userFirstName, + lastName: userLastName, + }, + { + where: { + id: talentId, + }, + } + ); + return res.json(updatedTalent); + } catch (err) { + console.error("Error updating talent:", err); + return res + .status(400) + .json({ error: true, msg: "Failed to update talent" }); + } + } + // <------------------------ RESUME ------------------------ > async addResume(req, res) { diff --git a/routers/TalentRouter.js b/routers/TalentRouter.js index 35db6ff3..bed83f47 100644 --- a/routers/TalentRouter.js +++ b/routers/TalentRouter.js @@ -20,6 +20,12 @@ class TalentRouter { this.talentController.updateTalent.bind(this.talentController) ); + router.put( + "/:talentId", + this.checkJwt, + this.talentController.editTalentName.bind(this.talentController) + ); + // <------------------------ RESUME ------------------------ > router.post( From 5e2f1c5916e887b8ee8c577ccd36f11838dcc3ab Mon Sep 17 00:00:00 2001 From: Mystjerne Date: Sat, 17 Feb 2024 02:56:30 +0800 Subject: [PATCH 27/29] Update Employer Controller Add joblistings to employer controller with benefits. --- controllers/EmployerController.js | 41 +++++++++++++++++++++++++++++-- package-lock.json | 14 +++++++++++ package.json | 1 + 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/controllers/EmployerController.js b/controllers/EmployerController.js index a21bdbc8..516571ae 100644 --- a/controllers/EmployerController.js +++ b/controllers/EmployerController.js @@ -33,7 +33,17 @@ class EmployerController extends BaseController { const { firstName, lastName, companyName, email, photo, description } = req.body; const { employerId } = req.params; + //if employerID /= in the list of employers, should throw error and not be able to update + try { + let employer_data = await this.model.findOne({ + where: { id: employerId }, + }); + if (employer_data == null) { + throw new Error( + "Employer you are trying to edit does not exist in the database." + ); + } await this.model.update( { firstName: firstName, @@ -52,7 +62,7 @@ class EmployerController extends BaseController { const output = await this.model.findAll(); return res.json(output); } catch (err) { - return res.status(400).json({ error: true, msg: err }); + return res.status(400).json({ error: true, msg: err.message }); } } @@ -68,6 +78,8 @@ class EmployerController extends BaseController { applicationStartDate, applicationEndDate, } = req.body; + + console.log(req.body); try { //tag to employerID const newJobListing = await this.jobListingModel.create({ @@ -80,7 +92,32 @@ class EmployerController extends BaseController { employerId: employerId, }); // Respond with the new work experience - return res.json(newJobListing); + { + const { employerId } = req.params; + const { benefit1, benefit2, benefit3 } = req.body; + + try { + // Check if the talent exists + console.log("req.body", req.body); + const employer = await this.model.findByPk(employerId); + if (!employer) { + return res + .status(404) + .json({ error: true, msg: "Employer not found" }); + } + // Create a new benefit and associate it with the talent + const addJobListingBenefit = await this.benefitModel.findAll({ + where: { + id: [benefit1, benefit2, benefit3], + }, + }); + await newJobListing.setBenefits(addJobListingBenefit); + // Respond with the newly created benefit + return res.json(addJobListingBenefit); + } catch (err) { + return res.status(400).json({ error: true, msg: err }); + } + } } catch (err) { return res.status(400).json({ error: true, msg: err }); } diff --git a/package-lock.json b/package-lock.json index 0ebb345a..e514324f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "dotenv": "^16.4.1", "express": "^4.18.1", "express-oauth2-jwt-bearer": "^1.6.0", + "i": "^0.3.7", "pg": "^8.11.3", "sequelize": "^6.36.0" }, @@ -1313,6 +1314,14 @@ "node": ">= 0.8" } }, + "node_modules/i": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/i/-/i-0.3.7.tgz", + "integrity": "sha512-FYz4wlXgkQwIPqhzC5TdNMLSE5+GS1IIDJZY/1ZiEPCT2S3COUVZeT5OW4BmW4r5LHLQuOosSwsvnroG9GR59Q==", + "engines": { + "node": ">=0.4" + } + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -3786,6 +3795,11 @@ "toidentifier": "1.0.1" } }, + "i": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/i/-/i-0.3.7.tgz", + "integrity": "sha512-FYz4wlXgkQwIPqhzC5TdNMLSE5+GS1IIDJZY/1ZiEPCT2S3COUVZeT5OW4BmW4r5LHLQuOosSwsvnroG9GR59Q==" + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", diff --git a/package.json b/package.json index 74e46575..2988e923 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "dotenv": "^16.4.1", "express": "^4.18.1", "express-oauth2-jwt-bearer": "^1.6.0", + "i": "^0.3.7", "pg": "^8.11.3", "sequelize": "^6.36.0" }, From 92dbf2b76d908c75a940298b5f9c36149a5e7f90 Mon Sep 17 00:00:00 2001 From: Mystjerne Date: Sun, 18 Feb 2024 03:54:07 +0800 Subject: [PATCH 28/29] can now accept and deny applications via a put request in the Applications section (i used the talentController for this) can now get a list of applications for each job listing --- controllers/EmployerController.js | 36 ++++++++++++++++++++++++++++++- controllers/TalentController.js | 30 ++++++++++++++++++++++++++ index.js | 3 ++- routers/EmployerRouter.js | 7 ++++++ routers/TalentRouter.js | 5 +++++ 5 files changed, 79 insertions(+), 2 deletions(-) diff --git a/controllers/EmployerController.js b/controllers/EmployerController.js index 516571ae..f45e8419 100644 --- a/controllers/EmployerController.js +++ b/controllers/EmployerController.js @@ -1,10 +1,11 @@ const BaseController = require("./BaseController"); class EmployerController extends BaseController { - constructor(model, jobListingModel, benefitModel) { + constructor(model, jobListingModel, benefitModel, applicationModel) { super(model); this.jobListingModel = jobListingModel; this.benefitModel = benefitModel; + this.applicationModel = applicationModel; } // Create employer @@ -124,6 +125,7 @@ class EmployerController extends BaseController { } async getJobListing(req, res) { + console.log("getJobListing is being called"); const { employerId } = req.params; try { //tag to talent ID @@ -138,8 +140,40 @@ class EmployerController extends BaseController { return res.status(400).json({ error: true, msg: err }); } } + + async getOneJobListingApps(req, res) { + console.log("req.params in getOneJobListing:", req.params); + const { employerId, jobListingId } = req.params; + + try { + //tag to talent ID + const jobListing = await this.jobListingModel.findByPk(jobListingId); + + const appsForJobListing = await jobListing.getApplications(); + console.log("i am apps for job listing", appsForJobListing); + + console.log("jobListing", jobListing); + console.log("applications for job listing", appsForJobListing); + const response = { + applications: appsForJobListing, + jobListing: jobListing, + }; + + return res.json(response); + } catch (err) { + console.log("err", err); + return res.status(400).json({ error: true, msg: err }); + } + } + //return res.json(jobListing); + //get all applications relating to the job listing. + //-> get the id of all applications that have a specific job listing id + //use stuff from the documentation } +//Employer Dashboard should get all job listings posted by the employer. +//Clicking on a job listing should bring the employer to a page where they can reject or accept applications associated with the job listing. + // get all user info under base controller // delete is not required - user can't delete profile diff --git a/controllers/TalentController.js b/controllers/TalentController.js index 9d064897..a123ca5e 100644 --- a/controllers/TalentController.js +++ b/controllers/TalentController.js @@ -1,3 +1,4 @@ +const { application } = require("express"); const talent = require("../db/models/talent"); const BaseController = require("./BaseController"); @@ -739,6 +740,35 @@ class TalentController extends BaseController { return res.status(400).json({ error: true, msg: err.message }); } } + + async putApplicationStatus(req, res) { + console.log("putApplicationStatus is being called"); + const { talentId } = req.params; + const { applicationStatus, jobListingId, applicationId } = req.body; + console.log(applicationStatus); + // console.log(talentId); + // console.log(jobListingId); + try { + console.log("passing through"); + + //tag to talent ID + const newApplicationStatus = await this.applicationModel.update( + { applicationStatus: applicationStatus }, + { + where: { + id: applicationId, + }, + } + ); + + console.log("Application status changed."); + // Respond with the new work experience + return res.json(newApplicationStatus); + } catch (err) { + console.log(err); + return res.status(400).json({ error: true, msg: err }); + } + } } // get all user info under base controller diff --git a/index.js b/index.js index 309df4fe..ccf37173 100644 --- a/index.js +++ b/index.js @@ -64,7 +64,8 @@ const benefitController = new BenefitController(benefit, employer); const employerController = new EmployerController( employer, jobListing, - benefit + benefit, + application ); //initialise router diff --git a/routers/EmployerRouter.js b/routers/EmployerRouter.js index 7785d730..94172b33 100644 --- a/routers/EmployerRouter.js +++ b/routers/EmployerRouter.js @@ -15,14 +15,21 @@ class EmployerRouter { ); // <------------------------ JOB LISTING ------------------------ > + router.post( "/:employerId/job", this.controller.addJobListing.bind(this.controller) ); + //for getting all job listings related to the employer router.get( "/:employerId/job", this.controller.getJobListing.bind(this.controller) ); + //for getting the specific one joblisting with the id and the employer + router.get( + "/:employerId/job/:jobListingId", + this.controller.getOneJobListingApps.bind(this.controller) + ); return router; // Return the router instance } diff --git a/routers/TalentRouter.js b/routers/TalentRouter.js index bed83f47..7fbdf67d 100644 --- a/routers/TalentRouter.js +++ b/routers/TalentRouter.js @@ -151,6 +151,11 @@ class TalentRouter { this.talentController.getApplications.bind(this.talentController) ); + router.put( + "/:talentId/applications", + this.talentController.putApplicationStatus.bind(this.talentController) + ); + return router; // Return the router instance } } From 508138c6b0d74cdc5cfedc5340a2cc5d171f9e37 Mon Sep 17 00:00:00 2001 From: Mystjerne Date: Mon, 8 Jul 2024 14:54:21 +0800 Subject: [PATCH 29/29] add more employers data, job_listings data 1. added more employers 2. added more employer information (mission statement, contact info) 3. added more job_listings (and their associated benefits) --- controllers/EmployerController.js | 32 ++++- .../20240206071629-primary_tables.js | 10 ++ db/models/employer.js | 4 + db/seeders/20240206073417-primary_tables.js | 95 +++++++++++++- db/seeders/20240215025813-job_listings.js | 118 ++++++++++++++++++ index.js | 7 +- 6 files changed, 254 insertions(+), 12 deletions(-) diff --git a/controllers/EmployerController.js b/controllers/EmployerController.js index f45e8419..3032e8aa 100644 --- a/controllers/EmployerController.js +++ b/controllers/EmployerController.js @@ -10,8 +10,17 @@ class EmployerController extends BaseController { // Create employer async addEmployer(req, res) { - const { firstName, lastName, companyName, email, photo, description } = - req.body; + const { + firstName, + lastName, + companyName, + email, + photo, + description, + mission_statement, + headquarters, + phone, + } = req.body; try { // Create new employer const newEmployer = await this.model.create({ @@ -21,6 +30,9 @@ class EmployerController extends BaseController { email: email, photo: photo, description: description, + mission_statement: mission_statement, + headquarters: headquarters, + phone: phone, }); // Respond with new employer return res.json(newEmployer); @@ -31,8 +43,17 @@ class EmployerController extends BaseController { // Edit and Update Employer async updateEmployer(req, res) { - const { firstName, lastName, companyName, email, photo, description } = - req.body; + const { + firstName, + lastName, + companyName, + email, + photo, + description, + mission_statement, + headquarters, + phone, + } = req.body; const { employerId } = req.params; //if employerID /= in the list of employers, should throw error and not be able to update @@ -53,6 +74,9 @@ class EmployerController extends BaseController { email: email, photo: photo, description: description, + mission_statement: mission_statement, + headquarters: headquarters, + phone: phone, }, { where: { diff --git a/db/migrations/20240206071629-primary_tables.js b/db/migrations/20240206071629-primary_tables.js index a69ed877..29553492 100644 --- a/db/migrations/20240206071629-primary_tables.js +++ b/db/migrations/20240206071629-primary_tables.js @@ -56,8 +56,18 @@ module.exports = { type: Sequelize.STRING, }, description: { + type: Sequelize.TEXT, + }, + mission_statement: { + type: Sequelize.TEXT, + }, + //Contact information + headquarters: { type: Sequelize.STRING, }, + phone: { + type: Sequelize.BIGINT, + }, photo: { type: Sequelize.STRING, }, diff --git a/db/models/employer.js b/db/models/employer.js index 272be480..e2acdfdf 100644 --- a/db/models/employer.js +++ b/db/models/employer.js @@ -15,6 +15,10 @@ module.exports = (sequelize, DataTypes) => { lastName: DataTypes.STRING, companyName: DataTypes.STRING, description: DataTypes.STRING, + missionStatement: DataTypes.STRING, + headquarters: DataTypes.STRING, + //not sure if should put number or int + phone: DataTypes.INTEGER, photo: DataTypes.STRING, email: DataTypes.STRING, }, diff --git a/db/seeders/20240206073417-primary_tables.js b/db/seeders/20240206073417-primary_tables.js index d3ecdca0..f244f204 100644 --- a/db/seeders/20240206073417-primary_tables.js +++ b/db/seeders/20240206073417-primary_tables.js @@ -26,23 +26,110 @@ module.exports = { first_name: "Tony", last_name: "Stark", company_name: "Avengers", - description: "somewhere in NYC", + description: + "The Avengers is a team of extraordinary individuals assembled to protect the world from threats beyond the capabilities of conventional military and law enforcement agencies. Comprised of some of the most powerful heroes on Earth, The Avengers stand as the first line of defense against global and interstellar dangers.", + mission_statement: + "To safeguard humanity and maintain peace by uniting the world’s greatest heroes against any threat, no matter how formidable.", + headquarters: "Avengers Tower, New York City, NY", + phone: 2484345508, email: "tonystark@test.com", }, { first_name: "Widow", last_name: "Black", company_name: "Red Room", - description: "everywhere", + description: + "The Red Room is a covert espionage and assassination program that operates in the shadows, training elite spies and assassins for high-stakes missions. Known for its rigorous training regimen and psychological manipulation, The Red Room has produced some of the world’s most dangerous operatives.", + mission_statement: + "To achieve strategic superiority through the deployment of expertly trained and highly skilled operatives capable of executing the most critical and covert missions.", + headquarters: "Everywhere", + phone: 2484345508, email: "blackwidow@text.com", }, { first_name: "Hulk", last_name: "Green", - company_name: "underground lab", - description: "everywhere", + company_name: "Avengers", + description: + "The Avengers is a team of extraordinary individuals assembled to protect the world from threats beyond the capabilities of conventional military and law enforcement agencies. Comprised of some of the most powerful heroes on Earth, The Avengers stand as the first line of defense against global and interstellar dangers.", + mission_statement: + "To safeguard humanity and maintain peace by uniting the world’s greatest heroes against any threat, no matter how formidable.", + headquarters: "Avengers Tower, New York City, NY", + phone: 2484345508, email: "blackwidow@text.com", }, + { + first_name: "Elon", + last_name: "Musk", + company_name: "Tesla", + description: + "Tesla is a company that specializes in electric vehicles, energy storage solutions, and renewable energy products. Tesla aims to accelerate the world's transition to sustainable energy with innovative products and technologies.", + mission_statement: + "To accelerate the world's transition to sustainable energy.", + headquarters: "Palo Alto, CA", + phone: 6506815000, + email: "elonmusk@tesla.com", + }, + { + first_name: "Jeff", + last_name: "Bezos", + company_name: "Amazon", + description: + "Amazon is a multinational technology company focusing on e-commerce, cloud computing, digital streaming, and artificial intelligence. Known for its disruption of well-established industries, Amazon is one of the world's most valuable brands.", + mission_statement: + "To be Earth's most customer-centric company, where customers can find and discover anything they might want to buy online.", + headquarters: "Seattle, WA", + phone: 2062661000, + email: "jeffbezos@amazon.com", + }, + { + first_name: "Satya", + last_name: "Nadella", + company_name: "Microsoft", + description: + "Microsoft is a leading global technology company that develops, manufactures, licenses, supports, and sells a range of software products, services, and devices. It is known for its software products like Windows, Office, and Azure.", + mission_statement: + "To empower every person and every organization on the planet to achieve more.", + headquarters: "Redmond, WA", + phone: 4258828080, + email: "satyanadella@microsoft.com", + }, + { + first_name: "Sundar", + last_name: "Pichai", + company_name: "Google", + description: + "Google is a global leader in technology, specializing in internet-related services and products, including online advertising technologies, a search engine, cloud computing, software, and hardware.", + mission_statement: + "To organize the world's information and make it universally accessible and useful.", + headquarters: "Mountain View, CA", + phone: 6502530000, + email: "sundarpichai@google.com", + }, + { + first_name: "Tim", + last_name: "Cook", + company_name: "Apple", + description: + "Apple Inc. is a multinational technology company that designs, manufactures, and markets consumer electronics, computer software, and online services. Known for its innovative products like the iPhone, iPad, and Mac computers.", + mission_statement: + "To bring the best user experience to its customers through its innovative hardware, software, and services.", + headquarters: "Cupertino, CA", + phone: 4089961010, + email: "timcook@apple.com", + }, + { + first_name: "Mark", + last_name: "Zuckerberg", + company_name: "Facebook", + description: + "Facebook is a leading social media and technology company that offers online social networking services. It aims to give people the power to build community and bring the world closer together.", + mission_statement: + "To give people the power to build community and bring the world closer together.", + headquarters: "Menlo Park, CA", + phone: 6505434800, + email: "markzuckerberg@facebook.com", + }, ]); await queryInterface.bulkInsert("benefits", [ diff --git a/db/seeders/20240215025813-job_listings.js b/db/seeders/20240215025813-job_listings.js index d0b5ec74..5f05724d 100644 --- a/db/seeders/20240215025813-job_listings.js +++ b/db/seeders/20240215025813-job_listings.js @@ -63,6 +63,64 @@ module.exports = { application_start_date: "2024-02-03", application_end_date: "2024-03-28", }, + { + employer_id: 4, + job_title: "Project Manager", + description: + "Overseeing project development and ensuring timely delivery.", + job_responsibility: + "Coordinate project activities and manage resources.", + skill_set: "Project management, Agile, Scrum", + application_start_date: "2024-02-01", + application_end_date: "2024-03-15", + }, + { + employer_id: 4, + job_title: "Data Scientist", + description: + "Analyzing and interpreting complex data to provide insights.", + job_responsibility: "Develop data models and algorithms.", + skill_set: "Python, R, Machine Learning, Data Analysis", + application_start_date: "2024-02-05", + application_end_date: "2024-03-10", + }, + { + employer_id: 5, + job_title: "Marketing Specialist", + description: "Planning and executing marketing campaigns.", + job_responsibility: "Develop marketing strategies and analyze results.", + skill_set: "SEO, Content Marketing, Social Media", + application_start_date: "2024-02-07", + application_end_date: "2024-03-25", + }, + { + employer_id: 6, + job_title: "Human Resources Manager", + description: "Managing HR operations and employee relations.", + job_responsibility: "Oversee recruitment and employee performance.", + skill_set: "HR management, Recruitment, Employee Relations", + application_start_date: "2024-02-10", + application_end_date: "2024-03-20", + }, + { + employer_id: 7, + job_title: "Software Tester", + description: "Ensuring the quality of software through testing.", + job_responsibility: "Develop and execute test plans and scripts.", + skill_set: "Manual Testing, Automated Testing, QA Tools", + application_start_date: "2024-02-12", + application_end_date: "2024-03-22", + }, + { + employer_id: 8, + job_title: "DevOps Engineer", + description: "Managing and automating software development processes.", + job_responsibility: "Implement CI/CD pipelines and monitor systems.", + skill_set: "AWS, Docker, Jenkins, Kubernetes", + application_start_date: "2024-02-14", + application_end_date: "2024-03-24", + }, + //12 job listings ]); await queryInterface.bulkInsert("job_listing_benefits", [ @@ -138,6 +196,66 @@ module.exports = { job_listing_id: 7, benefit_id: 10, }, + { + job_listing_id: 8, + benefit_id: 4, + }, + { + job_listing_id: 8, + benefit_id: 6, + }, + { + job_listing_id: 8, + benefit_id: 9, + }, + { + job_listing_id: 9, + benefit_id: 1, + }, + { + job_listing_id: 9, + benefit_id: 3, + }, + { + job_listing_id: 9, + benefit_id: 7, + }, + { + job_listing_id: 10, + benefit_id: 2, + }, + { + job_listing_id: 10, + benefit_id: 5, + }, + { + job_listing_id: 10, + benefit_id: 8, + }, + { + job_listing_id: 11, + benefit_id: 1, + }, + { + job_listing_id: 11, + benefit_id: 4, + }, + { + job_listing_id: 11, + benefit_id: 10, + }, + { + job_listing_id: 12, + benefit_id: 3, + }, + { + job_listing_id: 12, + benefit_id: 6, + }, + { + job_listing_id: 12, + benefit_id: 9, + }, ]); }, diff --git a/index.js b/index.js index ccf37173..6c992373 100644 --- a/index.js +++ b/index.js @@ -39,8 +39,7 @@ const TalentRouter = require("./routers/TalentRouter"); const BenefitRouter = require("./routers/BenefitRouter"); const EmployerRouter = require("./routers/EmployerRouter"); -//port and express -const PORT = process.env.PORT; +//express const app = express(); // Enable CORS access to this server @@ -80,6 +79,6 @@ app.use("/talent", talentRouter); app.use("/benefits", benefitRouter); app.use("/employer", employerRouter); -app.listen(PORT, () => { - console.log(`Express app listening on port ${PORT}!`); +app.listen(process.env.PORT, () => { + console.log(`Express app listening on port ${process.env.PORT}!`); });