From 93cdf2b090ca1bd6b2cd77e7e15b41f3d0f8f5aa Mon Sep 17 00:00:00 2001 From: Muhammad Saffi Ullah <42832684+saffiullah200@users.noreply.github.com> Date: Mon, 5 Aug 2024 20:55:44 +0200 Subject: [PATCH 01/67] library upgrade --- eslint.config.mjs | 15 + package-lock.json | 17900 +++++++++++--------- package.json | 78 +- src/helpers/constants.js | 258 +- src/helpers/db-connector.js | 203 +- src/helpers/index.js | 215 +- src/helpers/venue-review-summary.js | 55 +- src/index.js | 162 +- src/models/activation-ticket.js | 96 +- src/models/event.js | 282 +- src/models/password-ticket.js | 52 +- src/models/petition.js | 118 +- src/models/photo.js | 132 +- src/models/refresh-token.js | 54 +- src/models/review.js | 244 +- src/models/team.js | 124 +- src/models/user.js | 386 +- src/models/venue.js | 630 +- src/routes/auth/activate-account.js | 278 +- src/routes/auth/facebook-sign-in.js | 401 +- src/routes/auth/forgotten-password.js | 176 +- src/routes/auth/generate-token.js | 110 +- src/routes/auth/google-sign-in.js | 377 +- src/routes/auth/index.js | 54 +- src/routes/auth/reset-password.js | 266 +- src/routes/auth/sign-in.js | 139 +- src/routes/auth/sign-out.js | 68 +- src/routes/auth/sign-up.js | 316 +- src/routes/auth/validations.js | 310 +- src/routes/events/create-event.js | 374 +- src/routes/events/delete-event.js | 260 +- src/routes/events/edit-event.js | 764 +- src/routes/events/get-event.js | 414 +- src/routes/events/index.js | 62 +- src/routes/events/join-event.js | 268 +- src/routes/events/leave-event.js | 138 +- src/routes/events/list-events.js | 183 +- src/routes/events/validations.js | 956 +- src/routes/index.js | 50 +- src/routes/others/contact.js | 74 +- src/routes/others/index.js | 22 +- src/routes/others/migrate-scores.js | 61 +- src/routes/others/validations.js | 74 +- src/routes/petitions/create-petition.js | 948 +- src/routes/petitions/edit-petition.js | 1112 +- src/routes/petitions/index.js | 38 +- src/routes/petitions/list-petitions.js | 554 +- src/routes/petitions/validations.js | 158 +- src/routes/photos/create-photo.js | 230 +- src/routes/photos/delete-photo.js | 94 +- src/routes/photos/index.js | 34 +- src/routes/reviews/ban-review.js | 78 +- src/routes/reviews/create-review.js | 1112 +- src/routes/reviews/edit-review.js | 434 +- src/routes/reviews/flag-review.js | 100 +- src/routes/reviews/index.js | 58 +- src/routes/reviews/list-reviews.js | 368 +- src/routes/reviews/validations.js | 752 +- src/routes/reviews/vote-review.js | 98 +- src/routes/teams/create-team.js | 186 +- src/routes/teams/delete-team.js | 230 +- src/routes/teams/edit-team.js | 410 +- src/routes/teams/get-team.js | 288 +- src/routes/teams/index.js | 46 +- src/routes/teams/join-team.js | 196 +- src/routes/teams/leave-team.js | 118 +- src/routes/teams/list-teams.js | 208 +- src/routes/teams/validations.js | 268 +- src/routes/users/archive-user.js | 202 +- src/routes/users/block-user.js | 78 +- src/routes/users/change-password.js | 128 +- src/routes/users/create-user.js | 303 +- src/routes/users/delete-user.js | 72 +- src/routes/users/edit-user.js | 320 +- src/routes/users/get-profile.js | 186 +- src/routes/users/get-user.js | 254 +- src/routes/users/index.js | 86 +- src/routes/users/list-users.js | 150 +- src/routes/users/unblock-user.js | 82 +- src/routes/users/validations.js | 598 +- src/routes/venues/archive-venue.js | 78 +- src/routes/venues/get-venue.js | 695 +- src/routes/venues/index.js | 38 +- src/routes/venues/list-venues.js | 1272 +- src/routes/venues/validations.js | 308 +- src/scripts/db/import-events.js | 308 +- src/scripts/db/import-reviews.js | 298 +- src/scripts/db/import-teams.js | 540 +- src/scripts/db/import-users.js | 550 +- src/scripts/db/import-venues.js | 364 +- src/scripts/db/old-schemas/event.js | 166 +- src/scripts/db/old-schemas/photo.js | 74 +- src/scripts/db/old-schemas/review.js | 162 +- src/scripts/db/old-schemas/team.js | 98 +- src/scripts/db/old-schemas/user.js | 250 +- src/scripts/db/old-schemas/venue.js | 238 +- src/scripts/db/update-events-locations.js | 300 +- src/scripts/db/update-events-posters.js | 320 +- src/scripts/db/update-events-reviews.js | 208 +- src/scripts/db/update-users-avatars.js | 412 +- 100 files changed, 22983 insertions(+), 21472 deletions(-) create mode 100644 eslint.config.mjs diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..902e474 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,15 @@ +import globals from "globals"; +import pluginJs from "@eslint/js"; + +export default [ + { files: ["**/*.js"], languageOptions: { sourceType: "commonjs" } }, + { + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + }, + }, + }, + pluginJs.configs.recommended, +]; diff --git a/package-lock.json b/package-lock.json index 93eead2..860e757 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6530 +1,7825 @@ { "name": "api", - "version": "1.0.0", - "lockfileVersion": 1, + "version": "2.0.0", + "lockfileVersion": 3, "requires": true, - "dependencies": { - "@samverschueren/stream-to-observable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz", - "integrity": "sha512-MI4Xx6LHs4Webyvi6EbspgyAb4D2Q2VtnCQ1blOJcoLS6mVa8lNN2rkIy1CVxfTUpoyIbCTkXES1rLXztFD1lg==", + "packages": { + "": { + "name": "api", + "version": "2.0.0", + "dependencies": { + "aws-sdk": "2.1660.0", + "axios": "1.7.2", + "bcrypt-nodejs": "0.0.3", + "body-parser": "1.20.2", + "cors": "2.8.5", + "dotenv": "16.4.5", + "express": "4.19.2", + "form-data": "4.0.0", + "freemail": "1.7.0", + "google-auth-library": "9.11.0", + "helmet": "7.1.0", + "ip": "2.0.1", + "jimp": "0.22.12", + "jsonwebtoken": "9.0.2", + "lodash": "4.17.21", + "moment": "2.30.1", + "moment-timezone": "0.5.45", + "mongodb-uri": "0.9.7", + "mongoose": "8.5.1", + "morgan": "1.10.0", + "multer": "1.3.0", + "nodemailer": "6.9.14", + "now": "11.4.6", + "randomstring": "1.3.0", + "raven": "2.6.0", + "speakingurl": "14.0.1", + "validator": "13.12.0" + }, + "devDependencies": { + "@eslint/js": "^9.7.0", + "commitizen": "4.3.0", + "cross-env": "7.0.3", + "cz-conventional-changelog": "3.3.0", + "eslint": "^9.7.0", + "globals": "^15.8.0", + "gulp": "5.0.0", + "gulp-eslint-new": "^2.2.0", + "gulp-nodemon": "^2.2.1", + "husky": "9.1.1", + "lint-staged": "15.2.7", + "prettier": "3.3.3" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "dev": true, - "requires": { - "any-observable": "^0.3.0" + "optional": true, + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "dev": true, + "optional": true, + "engines": { + "node": ">=6.9.0" } }, - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", - "dev": true - }, - "acorn-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", - "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dev": true, - "requires": { - "acorn": "^3.0.4" + "optional": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@commitlint/config-validator": { + "version": "19.0.3", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-19.0.3.tgz", + "integrity": "sha512-2D3r4PKjoo59zBc2auodrSCaUnCSALCx54yveOFwwP/i2kfEAQrygwOleFWswLqK0UL/F9r07MFi5ev2ohyM4Q==", + "dev": true, + "optional": true, "dependencies": { - "acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", - "dev": true - } + "@commitlint/types": "^19.0.3", + "ajv": "^8.11.0" + }, + "engines": { + "node": ">=v18" } }, - "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "node_modules/@commitlint/execute-rule": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-19.0.0.tgz", + "integrity": "sha512-mtsdpY1qyWgAO/iOK0L6gSGeR7GFcdW7tIjcNFxcWkfLDF5qVbPHKuGATFqRMsxcO8OUKNj0+3WOHB7EHm4Jdw==", + "dev": true, + "optional": true, + "engines": { + "node": ">=v18" } }, - "ajv-keywords": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", - "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", - "dev": true + "node_modules/@commitlint/load": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-19.2.0.tgz", + "integrity": "sha512-XvxxLJTKqZojCxaBQ7u92qQLFMMZc4+p9qrIq/9kJDy8DOrEa7P1yx7Tjdc2u2JxIalqT4KOGraVgCE7eCYJyQ==", + "dev": true, + "optional": true, + "dependencies": { + "@commitlint/config-validator": "^19.0.3", + "@commitlint/execute-rule": "^19.0.0", + "@commitlint/resolve-extends": "^19.1.0", + "@commitlint/types": "^19.0.3", + "chalk": "^5.3.0", + "cosmiconfig": "^9.0.0", + "cosmiconfig-typescript-loader": "^5.0.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "lodash.uniq": "^4.5.0" + }, + "engines": { + "node": ">=v18" + } }, - "ansi-align": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", - "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", + "node_modules/@commitlint/load/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, - "requires": { - "string-width": "^2.0.0" + "optional": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@commitlint/resolve-extends": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-19.1.0.tgz", + "integrity": "sha512-z2riI+8G3CET5CPgXJPlzftH+RiWYLMYv4C9tSLdLXdr6pBNimSKukYP9MS27ejmscqCTVA4almdLh0ODD2KYg==", + "dev": true, + "optional": true, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } + "@commitlint/config-validator": "^19.0.3", + "@commitlint/types": "^19.0.3", + "global-directory": "^4.0.1", + "import-meta-resolve": "^4.0.0", + "lodash.mergewith": "^4.6.2", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=v18" } }, - "ansi-escapes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", - "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", - "dev": true + "node_modules/@commitlint/types": { + "version": "19.0.3", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-19.0.3.tgz", + "integrity": "sha512-tpyc+7i6bPG9mvaBbtKUeghfyZSDgWquIDfMgqYtTbmZ9Y9VzEm2je9EYcQ0aoz5o7NvGS+rcDec93yO08MHYA==", + "dev": true, + "optional": true, + "dependencies": { + "@types/conventional-commits-parser": "^5.0.0", + "chalk": "^5.3.0" + }, + "engines": { + "node": ">=v18" + } }, - "ansi-gray": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", - "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "node_modules/@commitlint/types/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, - "requires": { - "ansi-wrap": "0.1.0" + "optional": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } }, - "ansi-wrap": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", - "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", - "dev": true + "node_modules/@eslint-community/regexpp": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } }, - "any-observable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", - "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==", - "dev": true + "node_modules/@eslint/config-array": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", + "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "node_modules/@eslint/config-array/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true } } }, - "append-field": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/append-field/-/append-field-0.1.0.tgz", - "integrity": "sha1-bdxY+gg8e8VF08WZWygwzCNm1Eo=" + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/@eslint/js": { + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.7.0.tgz", + "integrity": "sha512-ChuWDQenef8OSFnvuxv0TCVxEwmu3+hPNKvM9B34qpM0rDRbjL8t5QkQeHHeAfsKQjuH9wS82WeCi1J/owatng==", "dev": true, - "requires": { - "sprintf-js": "~1.0.2" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", "dev": true, - "requires": { - "arr-flatten": "^1.0.1" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "arr-flatten": { + "node_modules/@gulpjs/messages": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true + "resolved": "https://registry.npmjs.org/@gulpjs/messages/-/messages-1.1.0.tgz", + "integrity": "sha512-Ys9sazDatyTgZVb4xPlDufLweJ/Os2uHWOv+Caxvy2O85JcnT4M3vc73bi8pdLWlv3fdWQz3pdI9tVwo8rQQSg==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } }, - "array-differ": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", - "dev": true + "node_modules/@gulpjs/to-absolute-glob": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@gulpjs/to-absolute-glob/-/to-absolute-glob-4.0.0.tgz", + "integrity": "sha512-kjotm7XJrJ6v+7knhPaRgaT6q8F8K2jiafwYdNHLzmV0uGLuZY43FK6smNSHUPrhq5kX2slCUy+RGG/xGqmIKA==", + "dev": true, + "dependencies": { + "is-negated-glob": "^1.0.0" + }, + "engines": { + "node": ">=10.13.0" + } }, - "array-each": { + "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", - "dev": true + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, - "array-slice": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", - "dev": true + "node_modules/@jimp/bmp": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.22.12.tgz", + "integrity": "sha512-aeI64HD0npropd+AR76MCcvvRaa+Qck6loCOS03CkkxGHN5/r336qTM5HPUdHKMDOGzqknuVPA8+kK1t03z12g==", + "dependencies": { + "@jimp/utils": "^0.22.12", + "bmp-js": "^0.1.0" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "array-uniq": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.2.tgz", - "integrity": "sha1-X8w3OSB3VyPP1k1lxkvvU7+eum0=" + "node_modules/@jimp/core": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/core/-/core-0.22.12.tgz", + "integrity": "sha512-l0RR0dOPyzMKfjUW1uebzueFEDtCOj9fN6pyTYWWOM/VS4BciXQ1VVrJs8pO3kycGYZxncRKhCoygbNr8eEZQA==", + "dependencies": { + "@jimp/utils": "^0.22.12", + "any-base": "^1.1.0", + "buffer": "^5.2.0", + "exif-parser": "^0.1.12", + "file-type": "^16.5.4", + "isomorphic-fetch": "^3.0.0", + "pixelmatch": "^4.0.2", + "tinycolor2": "^1.6.0" + } }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true + "node_modules/@jimp/core/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "requires": { - "safer-buffer": "~2.1.0" + "node_modules/@jimp/custom": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.22.12.tgz", + "integrity": "sha512-xcmww1O/JFP2MrlGUMd3Q78S3Qu6W3mYTXYuIqFq33EorgYHV/HqymHfXy9GjiCJ7OI+7lWx6nYFOzU7M4rd1Q==", + "dependencies": { + "@jimp/core": "^0.22.12" } }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + "node_modules/@jimp/gif": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/gif/-/gif-0.22.12.tgz", + "integrity": "sha512-y6BFTJgch9mbor2H234VSjd9iwAhaNf/t3US5qpYIs0TSbAvM02Fbc28IaDETj9+4YB4676sz4RcN/zwhfu1pg==", + "dependencies": { + "@jimp/utils": "^0.22.12", + "gifwrap": "^0.10.1", + "omggif": "^1.0.9" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true + "node_modules/@jimp/jpeg": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/jpeg/-/jpeg-0.22.12.tgz", + "integrity": "sha512-Rq26XC/uQWaQKyb/5lksCTCxXhtY01NJeBN+dQv5yNYedN0i7iYu+fXEoRsfaJ8xZzjoANH8sns7rVP4GE7d/Q==", + "dependencies": { + "@jimp/utils": "^0.22.12", + "jpeg-js": "^0.4.4" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", - "requires": { - "lodash": "^4.17.10" + "node_modules/@jimp/plugin-blit": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.22.12.tgz", + "integrity": "sha512-xslz2ZoFZOPLY8EZ4dC29m168BtDx95D6K80TzgUi8gqT7LY6CsajWO0FAxDwHz6h0eomHMfyGX0stspBrTKnQ==", + "dependencies": { + "@jimp/utils": "^0.22.12" }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-blur": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.22.12.tgz", + "integrity": "sha512-S0vJADTuh1Q9F+cXAwFPlrKWzDj2F9t/9JAbUvaaDuivpyWuImEKXVz5PUZw2NbpuSHjwssbTpOZ8F13iJX4uw==", "dependencies": { - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" - } + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" } }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true + "node_modules/@jimp/plugin-circle": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-circle/-/plugin-circle-0.22.12.tgz", + "integrity": "sha512-SWVXx1yiuj5jZtMijqUfvVOJBwOifFn0918ou4ftoHgegc5aHWW5dZbYPjvC9fLpvz7oSlptNl2Sxr1zwofjTg==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "node_modules/@jimp/plugin-color": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.22.12.tgz", + "integrity": "sha512-xImhTE5BpS8xa+mAN6j4sMRWaUgUDLoaGHhJhpC+r7SKKErYDR0WQV4yCE4gP+N0gozD0F3Ka1LUSaMXrn7ZIA==", + "dependencies": { + "@jimp/utils": "^0.22.12", + "tinycolor2": "^1.6.0" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true + "node_modules/@jimp/plugin-contain": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-0.22.12.tgz", + "integrity": "sha512-Eo3DmfixJw3N79lWk8q/0SDYbqmKt1xSTJ69yy8XLYQj9svoBbyRpSnHR+n9hOw5pKXytHwUW6nU4u1wegHNoQ==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5", + "@jimp/plugin-scale": ">=0.3.5" + } }, - "aws-sdk": { - "version": "2.94.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.94.0.tgz", - "integrity": "sha1-cEPePvjCTLarS/I18I2H2EFz4XQ=", - "requires": { - "buffer": "4.9.1", - "crypto-browserify": "1.0.9", - "events": "^1.1.1", - "jmespath": "0.15.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.0.1", - "xml2js": "0.4.17", - "xmlbuilder": "4.2.1" + "node_modules/@jimp/plugin-cover": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-0.22.12.tgz", + "integrity": "sha512-z0w/1xH/v/knZkpTNx+E8a7fnasQ2wHG5ze6y5oL2dhH1UufNua8gLQXlv8/W56+4nJ1brhSd233HBJCo01BXA==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-crop": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5", + "@jimp/plugin-scale": ">=0.3.5" } }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + "node_modules/@jimp/plugin-crop": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.22.12.tgz", + "integrity": "sha512-FNuUN0OVzRCozx8XSgP9MyLGMxNHHJMFt+LJuFjn1mu3k0VQxrzqbN06yIl46TVejhyAhcq5gLzqmSCHvlcBVw==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "aws4": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz", - "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==" + "node_modules/@jimp/plugin-displace": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-0.22.12.tgz", + "integrity": "sha512-qpRM8JRicxfK6aPPqKZA6+GzBwUIitiHaZw0QrJ64Ygd3+AsTc7BXr+37k2x7QcyCvmKXY4haUrSIsBug4S3CA==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "axios": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", - "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", - "requires": { - "follow-redirects": "^1.3.0", - "is-buffer": "^1.1.5" + "node_modules/@jimp/plugin-dither": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-0.22.12.tgz", + "integrity": "sha512-jYgGdSdSKl1UUEanX8A85v4+QUm+PE8vHFwlamaKk89s+PXQe7eVE3eNeSZX4inCq63EHL7cX580dMqkoC3ZLw==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" } }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" + "node_modules/@jimp/plugin-fisheye": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-fisheye/-/plugin-fisheye-0.22.12.tgz", + "integrity": "sha512-LGuUTsFg+fOp6KBKrmLkX4LfyCy8IIsROwoUvsUPKzutSqMJnsm3JGDW2eOmWIS/jJpPaeaishjlxvczjgII+Q==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" } }, - "babel-polyfill": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz", - "integrity": "sha1-g2TKYt+Or7gwSZ9pkXdGbDsDSZ0=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "core-js": "^2.4.0", - "regenerator-runtime": "^0.10.0" + "node_modules/@jimp/plugin-flip": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-0.22.12.tgz", + "integrity": "sha512-m251Rop7GN8W0Yo/rF9LWk6kNclngyjIJs/VXHToGQ6EGveOSTSQaX2Isi9f9lCDLxt+inBIb7nlaLLxnvHX8Q==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-rotate": ">=0.3.5" } }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "node_modules/@jimp/plugin-gaussian": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-gaussian/-/plugin-gaussian-0.22.12.tgz", + "integrity": "sha512-sBfbzoOmJ6FczfG2PquiK84NtVGeScw97JsCC3rpQv1PHVWyW+uqWFF53+n3c8Y0P2HWlUjflEla2h/vWShvhg==", + "dependencies": { + "@jimp/utils": "^0.22.12" }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-invert": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-invert/-/plugin-invert-0.22.12.tgz", + "integrity": "sha512-N+6rwxdB+7OCR6PYijaA/iizXXodpxOGvT/smd/lxeXsZ/empHmFFFJ/FaXcYh19Tm04dGDaXcNF/dN5nm6+xQ==", "dependencies": { - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true - } + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" } }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "node_modules/@jimp/plugin-mask": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-0.22.12.tgz", + "integrity": "sha512-4AWZg+DomtpUA099jRV8IEZUfn1wLv6+nem4NRJC7L/82vxzLCgXKTxvNvBcNmJjT9yS1LAAmiJGdWKXG63/NA==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" + "node_modules/@jimp/plugin-normalize": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-normalize/-/plugin-normalize-0.22.12.tgz", + "integrity": "sha512-0So0rexQivnWgnhacX4cfkM2223YdExnJTTy6d06WbkfZk5alHUx8MM3yEzwoCN0ErO7oyqEWRnEkGC+As1FtA==", + "dependencies": { + "@jimp/utils": "^0.22.12" }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-print": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-0.22.12.tgz", + "integrity": "sha512-c7TnhHlxm87DJeSnwr/XOLjJU/whoiKYY7r21SbuJ5nuH+7a78EW1teOaj5gEr2wYEd7QtkFqGlmyGXY/YclyQ==", "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } + "@jimp/utils": "^0.22.12", + "load-bmfont": "^1.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5" } }, - "base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + "node_modules/@jimp/plugin-resize": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.22.12.tgz", + "integrity": "sha512-3NyTPlPbTnGKDIbaBgQ3HbE6wXbAlFfxHVERmrbqAi8R3r6fQPxpCauA8UVDnieg5eo04D0T8nnnNIX//i/sXg==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "basic-auth": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", - "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=" + "node_modules/@jimp/plugin-rotate": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.22.12.tgz", + "integrity": "sha512-9YNEt7BPAFfTls2FGfKBVgwwLUuKqy+E8bDGGEsOqHtbuhbshVGxN2WMZaD4gh5IDWvR+emmmPPWGgaYNYt1gA==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5", + "@jimp/plugin-crop": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" + } }, - "bcrypt-nodejs": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/bcrypt-nodejs/-/bcrypt-nodejs-0.0.3.tgz", - "integrity": "sha1-xgkX8m3CNWYVZsaBBhwwPCsohCs=" + "node_modules/@jimp/plugin-scale": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.22.12.tgz", + "integrity": "sha512-dghs92qM6MhHj0HrV2qAwKPMklQtjNpoYgAB94ysYpsXslhRTiPisueSIELRwZGEr0J0VUxpUY7HgJwlSIgGZw==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" + } }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "requires": { - "tweetnacl": "^0.14.3" + "node_modules/@jimp/plugin-shadow": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-shadow/-/plugin-shadow-0.22.12.tgz", + "integrity": "sha512-FX8mTJuCt7/3zXVoeD/qHlm4YH2bVqBuWQHXSuBK054e7wFRnRnbSLPUqAwSeYP3lWqpuQzJtgiiBxV3+WWwTg==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blur": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" } }, - "beeper": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", - "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=", - "dev": true + "node_modules/@jimp/plugin-threshold": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-0.22.12.tgz", + "integrity": "sha512-4x5GrQr1a/9L0paBC/MZZJjjgjxLYrqSmWd+e+QfAEPvmRxdRoQ5uKEuNgXnm9/weHQBTnQBQsOY2iFja+XGAw==", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-color": ">=0.8.0", + "@jimp/plugin-resize": ">=0.8.0" + } }, - "bignumber.js": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.4.0.tgz", - "integrity": "sha1-g4qZLan51zfg9LLbC+YrsJ3Qxeg=" + "node_modules/@jimp/plugins": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugins/-/plugins-0.22.12.tgz", + "integrity": "sha512-yBJ8vQrDkBbTgQZLty9k4+KtUQdRjsIDJSPjuI21YdVeqZxYywifHl4/XWILoTZsjTUASQcGoH0TuC0N7xm3ww==", + "dependencies": { + "@jimp/plugin-blit": "^0.22.12", + "@jimp/plugin-blur": "^0.22.12", + "@jimp/plugin-circle": "^0.22.12", + "@jimp/plugin-color": "^0.22.12", + "@jimp/plugin-contain": "^0.22.12", + "@jimp/plugin-cover": "^0.22.12", + "@jimp/plugin-crop": "^0.22.12", + "@jimp/plugin-displace": "^0.22.12", + "@jimp/plugin-dither": "^0.22.12", + "@jimp/plugin-fisheye": "^0.22.12", + "@jimp/plugin-flip": "^0.22.12", + "@jimp/plugin-gaussian": "^0.22.12", + "@jimp/plugin-invert": "^0.22.12", + "@jimp/plugin-mask": "^0.22.12", + "@jimp/plugin-normalize": "^0.22.12", + "@jimp/plugin-print": "^0.22.12", + "@jimp/plugin-resize": "^0.22.12", + "@jimp/plugin-rotate": "^0.22.12", + "@jimp/plugin-scale": "^0.22.12", + "@jimp/plugin-shadow": "^0.22.12", + "@jimp/plugin-threshold": "^0.22.12", + "timm": "^1.6.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true + "node_modules/@jimp/png": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/png/-/png-0.22.12.tgz", + "integrity": "sha512-Mrp6dr3UTn+aLK8ty/dSKELz+Otdz1v4aAXzV5q53UDD2rbB5joKVJ/ChY310B+eRzNxIovbUF1KVrUsYdE8Hg==", + "dependencies": { + "@jimp/utils": "^0.22.12", + "pngjs": "^6.0.0" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "bluebird": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + "node_modules/@jimp/tiff": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/tiff/-/tiff-0.22.12.tgz", + "integrity": "sha512-E1LtMh4RyJsoCAfAkBRVSYyZDTtLq9p9LUiiYP0vPtXyxX4BiYBUYihTLSBlCQg5nF2e4OpQg7SPrLdJ66u7jg==", + "dependencies": { + "utif2": "^4.0.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "bmp-js": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.0.3.tgz", - "integrity": "sha1-ZBE+nHzxICs3btYHvzBibr5XsYo=" - }, - "body-parser": { - "version": "1.17.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.17.2.tgz", - "integrity": "sha1-+IkqvI+eYn1Crtr7yma/WrmRBO4=", - "requires": { - "bytes": "2.4.0", - "content-type": "~1.0.2", - "debug": "2.6.7", - "depd": "~1.1.0", - "http-errors": "~1.6.1", - "iconv-lite": "0.4.15", - "on-finished": "~2.3.0", - "qs": "6.4.0", - "raw-body": "~2.2.0", - "type-is": "~1.6.15" + "node_modules/@jimp/types": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/types/-/types-0.22.12.tgz", + "integrity": "sha512-wwKYzRdElE1MBXFREvCto5s699izFHNVvALUv79GXNbsOVqlwlOxlWJ8DuyOGIXoLP4JW/m30YyuTtfUJgMRMA==", + "dependencies": { + "@jimp/bmp": "^0.22.12", + "@jimp/gif": "^0.22.12", + "@jimp/jpeg": "^0.22.12", + "@jimp/png": "^0.22.12", + "@jimp/tiff": "^0.22.12", + "timm": "^1.6.1" }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/utils": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.22.12.tgz", + "integrity": "sha512-yJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHW/nMKXk8TrSwAE71zt716Q==", "dependencies": { - "debug": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz", - "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } + "regenerator-runtime": "^0.13.3" } }, - "boxen": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", - "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", - "dev": true, - "requires": { - "ansi-align": "^2.0.0", - "camelcase": "^4.0.0", - "chalk": "^2.0.1", - "cli-boxes": "^1.0.0", - "string-width": "^2.0.0", - "term-size": "^1.2.0", - "widest-line": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.8.tgz", + "integrity": "sha512-qKwC/M/nNNaKUBMQ0nuzm47b7ZYWQHN3pcXq4IIcoSBc2hOIrflAxJduIvvqmhoz3gR2TacTAs8vlsCVPkiEdQ==", + "dependencies": { + "sparse-bitfield": "^3.0.3" } }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" } }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, - "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" + "engines": { + "node": ">= 8" } }, - "bson": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/bson/-/bson-1.0.9.tgz", - "integrity": "sha512-IQX9/h7WdMBIW/q/++tGd+emQr0XMdeZ6icnT/74Xk9fnabWn+gZgpE+9V+gujL3hhJOoNrnDVY7tWdzc7NUTg==" - }, - "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" } }, - "buffer-equal": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", - "integrity": "sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs=" + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + "node_modules/@types/conventional-commits-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", + "integrity": "sha512-loB369iXNmAZglwWATL+WRe+CRMmmBPtpolYzIebFaX4YA3x+BEfLqhUAV9WanycKI3TG1IMr5bMJDajDKLlUQ==", + "dev": true, + "optional": true, + "dependencies": { + "@types/node": "*" + } }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + "node_modules/@types/eslint": { + "version": "8.56.11", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.11.tgz", + "integrity": "sha512-sVBpJMf7UPo/wGecYOpk2aQya2VUGeHhe38WG7/mN5FufNSubf5VT9Uh9Uyp8/eLJpu1/tuhJ/qTo4mhSB4V4Q==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, - "busboy": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", - "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", - "requires": { - "dicer": "0.2.5", - "readable-stream": "1.1.x" + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.14.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz", + "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" } }, - "bytes": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", - "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=" + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - }, + "node_modules/@types/whatwg-url": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } + "@types/webidl-conversions": "*" } }, - "cachedir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-1.3.0.tgz", - "integrity": "sha512-O1ji32oyON9laVPJL1IZ5bmwd2cB46VfpxkDequezH+15FDzzVddEyrGEeX4WusDSqKxdyFdDQDEG1yo1GoWkg==", - "dev": true, - "requires": { - "os-homedir": "^1.0.1" + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" } }, - "caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, - "requires": { - "callsites": "^2.0.0" + "bin": { + "acorn": "bin/acorn" }, - "dependencies": { - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "dev": true - } + "engines": { + "node": ">=0.4.0" } }, - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, - "requires": { - "callsites": "^0.2.0" + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", - "dev": true - }, - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } }, - "camelize": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", - "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" + "node_modules/agent-base/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } }, - "capture-stack-trace": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", - "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", - "dev": true + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "optional": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + "node_modules/ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, + "dependencies": { + "ansi-wrap": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", - "dev": true + "node_modules/ansi-gray": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - }, "dependencies": { - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.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-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - } + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" } }, - "ci-info": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", - "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", - "dev": true + "node_modules/ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", - "dev": true + "node_modules/any-base": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/any-base/-/any-base-1.1.0.tgz", + "integrity": "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg==" }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" } }, - "cli-boxes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", - "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", - "dev": true - }, - "cli-cursor": { + "node_modules/append-buffer": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", + "integrity": "sha512-WLbYiXzD3y/ATLZFufV/rZvWdZOs+Z/+5v1rBZ463Jn398pa6kcde27cvozYnBoxXblGZTFfoPpsaEw0orU5BA==", "dev": true, - "requires": { - "restore-cursor": "^1.0.1" + "dependencies": { + "buffer-equal": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "cli-truncate": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", - "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", + "node_modules/append-buffer/node_modules/buffer-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.1.tgz", + "integrity": "sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==", "dev": true, - "requires": { - "slice-ansi": "0.0.4", - "string-width": "^1.0.1" + "engines": { + "node": ">=0.4" }, - "dependencies": { - "slice-ansi": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", - "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", - "dev": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true + "node_modules/append-field": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-0.1.0.tgz", + "integrity": "sha1-bdxY+gg8e8VF08WZWygwzCNm1Eo=" }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", "dev": true }, - "clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", - "dev": true - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "engines": { + "node": ">=0.10.0" } }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/arr-filter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", + "integrity": "sha512-A2BETWCqhsecSvCkWAeVBFLH6sXEUGASuzkpjL3GR1SlL/PWL6M3J8EAAld2Uubmh39tvkJTqC9LeLHCUKmFXA==", "dev": true, - "requires": { - "color-name": "1.1.3" + "dependencies": { + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true - }, - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true - }, - "combined-stream": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", - "requires": { - "delayed-stream": "~1.0.0" + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "node_modules/arr-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", + "integrity": "sha512-tVqVTHt+Q5Xb09qRkbu+DidW1yYzz5izWS2Xm2yFm7qJnmUfz4HPzNxbHkdRJbz2lrqI7S+z17xNYdFcBBO8Hw==", + "dev": true, + "dependencies": { + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "commitizen": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-2.10.1.tgz", - "integrity": "sha1-jDld7zSolfTpSVLC78PJ60w2g70=", - "dev": true, - "requires": { - "cachedir": "^1.1.0", - "chalk": "1.1.3", - "cz-conventional-changelog": "2.0.0", - "dedent": "0.6.0", - "detect-indent": "4.0.0", - "find-node-modules": "1.0.4", - "find-root": "1.0.0", - "fs-extra": "^1.0.0", - "glob": "7.1.1", - "inquirer": "1.2.3", - "lodash": "4.17.5", - "minimist": "1.2.0", - "opencollective": "1.0.3", - "path-exists": "2.1.0", - "shelljs": "0.7.6", - "strip-json-comments": "2.0.1" - }, - "dependencies": { - "cz-conventional-changelog": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-2.0.0.tgz", - "integrity": "sha1-Val5r9/pXnAkh50qD1kkYwFwtTM=", - "dev": true, - "requires": { - "conventional-commit-types": "^2.0.0", - "lodash.map": "^4.5.1", - "longest": "^1.0.1", - "pad-right": "^0.2.2", - "right-pad": "^1.0.1", - "word-wrap": "^1.0.3" - } - }, - "lodash": { - "version": "4.17.5", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", - "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==", - "dev": true - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true + "node_modules/array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "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/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - }, + "node_modules/array-initial": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", + "integrity": "sha512-BC4Yl89vneCYfpLrs5JU2aAu9/a+xWbeKhvISg9PT7eWFB9UlRvI+rKEtk6mgxWr3dSkk9gQ8hCrdqt06NXPdw==", + "dev": true, "dependencies": { - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } + "array-slice": "^1.0.0", + "is-number": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "configstore": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", - "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", + "node_modules/array-initial/node_modules/is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", "dev": true, - "requires": { - "dot-prop": "^4.1.0", - "graceful-fs": "^4.1.2", - "make-dir": "^1.0.0", - "unique-string": "^1.0.0", - "write-file-atomic": "^2.0.0", - "xdg-basedir": "^3.0.0" + "engines": { + "node": ">=0.10.0" } }, - "connect": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.2.tgz", - "integrity": "sha1-aU6NIGgb/kkCgsiriGvpjwn0L+c=", - "requires": { - "debug": "2.6.7", - "finalhandler": "1.0.3", - "parseurl": "~1.3.1", - "utils-merge": "1.0.0" - }, + "node_modules/array-last": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", + "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", + "dev": true, "dependencies": { - "debug": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz", - "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=", - "requires": { - "ms": "2.0.0" - } - }, - "finalhandler": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.3.tgz", - "integrity": "sha1-70fneVDpmXgOhgIqVg4yF+DQzIk=", - "requires": { - "debug": "2.6.7", - "encodeurl": "~1.0.1", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.1", - "statuses": "~1.3.1", - "unpipe": "~1.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" - } + "is-number": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true - }, - "content-disposition": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + "node_modules/array-last/node_modules/is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "content-security-policy-builder": { + "node_modules/array-slice": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/content-security-policy-builder/-/content-security-policy-builder-1.1.0.tgz", - "integrity": "sha1-2R8bB2I2wRmFDH3umSS/VeBXcrM=", - "requires": { - "dashify": "^0.2.0" + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "conventional-commit-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-2.3.0.tgz", - "integrity": "sha512-6iB39PrcGYdz0n3z31kj6/Km6mK9hm9oMRhwcLnKxE7WNoeRKZbTAobliKrbYZ5jqyCvtcVEfjCiaEzhL3AVmQ==", - "dev": true - }, - "cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "core-js": { - "version": "2.6.10", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.10.tgz", - "integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "node_modules/array-sort": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", + "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", + "dev": true, + "dependencies": { + "default-compare": "^1.0.0", + "get-value": "^2.0.6", + "kind-of": "^5.0.2" + }, + "engines": { + "node": ">=0.10.0" + } }, - "cors": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.4.tgz", - "integrity": "sha1-K9OB8usgECAQXNUOpZ2mMJBpRoY=", - "requires": { - "object-assign": "^4", - "vary": "^1" + "node_modules/array-sort/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", - "dev": true, - "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" - }, - "dependencies": { - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - } + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "create-error-class": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", - "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", "dev": true, - "requires": { - "capture-stack-trace": "^1.0.0" + "engines": { + "node": ">=0.10.0" } }, - "cross-env": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.0.5.tgz", - "integrity": "sha1-Q4PTZNlmCHPdGFs5ivO/717//vM=", + "node_modules/async-done": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-2.0.0.tgz", + "integrity": "sha512-j0s3bzYq9yKIVLKGE/tWlCpa3PfFLcrDZLTSVdnnCTGagXuXBJO4SsY9Xdk/fQBirCkH4evW5xOeJXqlAQFdsw==", "dev": true, - "requires": { - "cross-spawn": "^5.1.0", - "is-windows": "^1.0.0" - }, "dependencies": { - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - } + "end-of-stream": "^1.4.4", + "once": "^1.4.0", + "stream-exhaust": "^1.0.2" + }, + "engines": { + "node": ">= 10.13.0" } }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "node_modules/async-each": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.6.tgz", + "integrity": "sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==", "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] }, - "crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" + "node_modules/async-settle": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-2.0.0.tgz", + "integrity": "sha512-Obu/KE8FurfQRN6ODdHN9LuXqwC+JFIM9NRyZqJJ4ZfLJmIYN9Rg0/kb+wF70VV5+fJusTMQlJ1t5rF7J/ETdg==", + "dev": true, + "dependencies": { + "async-done": "^2.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } }, - "crypto-browserify": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-1.0.9.tgz", - "integrity": "sha1-zFRJaF37hesRyYKKzHy4erW7/MA=" + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, - "crypto-random-string": { + "node_modules/at-least-node": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", - "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", - "dev": true - }, - "cz-conventional-changelog": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-2.1.0.tgz", - "integrity": "sha1-L0vHOQ4yROTfKT5ro1Hkx0Cnx2Q=", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true, - "requires": { - "conventional-commit-types": "^2.0.0", - "lodash.map": "^4.5.1", - "longest": "^1.0.1", - "right-pad": "^1.0.1", - "word-wrap": "^1.0.3" + "engines": { + "node": ">= 4.0.0" } }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "^1.0.0" + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true, + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" } }, - "dasherize": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dasherize/-/dasherize-2.0.0.tgz", - "integrity": "sha1-bYCcnNDPe7iVLYD8hPoT1H3bEwg=" - }, - "dashify": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dashify/-/dashify-0.2.2.tgz", - "integrity": "sha1-agdBWgHJH69KMuONnfunH2HLIP4=" - }, - "date-fns": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", - "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", - "dev": true + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "dateformat": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", - "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=", - "dev": true + "node_modules/aws-sdk": { + "version": "2.1660.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1660.0.tgz", + "integrity": "sha512-nyCEm6J4exq4gxeK5/LB5Q9unQTzFy6fbFHnrrmJZvp1KnRbJ10W2UtwQmeibPAz9b4w+RTKJMe6QEZ38eXeqA==", + "hasInstallScript": true, + "dependencies": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.16.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "util": "^0.12.4", + "uuid": "8.0.0", + "xml2js": "0.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "requires": { - "ms": "^2.1.1" + "node_modules/axios": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "node_modules/b4a": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", "dev": true }, - "dedent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.6.0.tgz", - "integrity": "sha1-Dm2o8M5Sg471zsXI+TlrDBtko8s=", - "dev": true + "node_modules/bach": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bach/-/bach-2.0.1.tgz", + "integrity": "sha512-A7bvGMGiTOxGMpNupYl9HQTf0FFDNF4VCmks4PJpFyN1AX2pdKuxuwdvUz2Hu388wcgp+OvGFNsumBfFNkR7eg==", + "dev": true, + "dependencies": { + "async-done": "^2.0.0", + "async-settle": "^2.0.0", + "now-and-later": "^3.0.0" + }, + "engines": { + "node": ">=10.13.0" + } }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true + "node_modules/bare-events": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.4.2.tgz", + "integrity": "sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==", + "dev": true, + "optional": true }, - "defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dev": true, - "requires": { - "clone": "^1.0.2" + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + "node_modules/base/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } }, - "deprecated": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/deprecated/-/deprecated-0.0.1.tgz", - "integrity": "sha1-+cmvVGSvoeepcUWKi97yqpTVuxk=", - "dev": true + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + "node_modules/bcrypt-nodejs": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/bcrypt-nodejs/-/bcrypt-nodejs-0.0.3.tgz", + "integrity": "sha1-xgkX8m3CNWYVZsaBBhwwPCsohCs=", + "deprecated": "bcrypt-nodejs is no longer actively maintained. Please use bcrypt or bcryptjs. See https://github.com/kelektiv/node.bcrypt.js/wiki/bcrypt-vs-brypt.js to learn more about these two options" }, - "detect-file": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-0.1.0.tgz", - "integrity": "sha1-STXe39lIhkjgBrASlWbpOGcR6mM=", - "dev": true, - "requires": { - "fs-exists-sync": "^0.1.0" + "node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "engines": { + "node": "*" } }, - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, - "requires": { - "repeating": "^2.0.0" + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "dicer": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", - "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", - "requires": { - "readable-stream": "1.1.x", - "streamsearch": "0.1.2" + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" } }, - "dns-prefetch-control": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/dns-prefetch-control/-/dns-prefetch-control-0.1.0.tgz", - "integrity": "sha1-YN20V3dOF48flBXwyrsOhbCzALI=" - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, - "requires": { - "esutils": "^2.0.2" + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" } }, - "dom-walk": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", - "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=" + "node_modules/bl/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } }, - "dont-sniff-mimetype": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dont-sniff-mimetype/-/dont-sniff-mimetype-1.0.0.tgz", - "integrity": "sha1-WTKJDcn04vGeXrAqIAJuXl78j1g=" + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } }, - "dot-prop": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", - "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "node_modules/bl/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, - "requires": { - "is-obj": "^1.0.0" + "dependencies": { + "safe-buffer": "~5.2.0" } }, - "dotenv": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-4.0.0.tgz", - "integrity": "sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0=" + "node_modules/bmp-js": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz", + "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==" }, - "duplexer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", - "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", - "dev": true + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } }, - "duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", + "node_modules/body-parser/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "requires": { - "readable-stream": "~1.1.9" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" + "node_modules/bson": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.8.0.tgz", + "integrity": "sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==", + "engines": { + "node": ">=16.20.1" } }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "requires": { - "safe-buffer": "^5.0.1" + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" } }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + "node_modules/buffer-equal": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", + "integrity": "sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA==", + "engines": { + "node": ">=0.4.0" + } }, - "elegant-spinner": { + "node_modules/buffer-equal-constant-time": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", - "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", - "dev": true + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" }, - "encoding": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", - "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", - "dev": true, - "requires": { - "iconv-lite": "~0.4.13" + "node_modules/busboy": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", + "integrity": "sha512-InWFDomvlkEj+xWLBfU3AvnbVYqeTWmQopiW0tWWEy5yehYm2YkGEc59sUmw/4ty5Zj/b0WHGs1LgecuBSBGrg==", + "dependencies": { + "dicer": "0.2.5", + "readable-stream": "1.1.x" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" } }, - "end-of-stream": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-0.1.5.tgz", - "integrity": "sha1-jhdyBsPICDfYVjLouTWd/osvbq8=", + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, - "requires": { - "once": "~1.3.0" - }, "dependencies": { - "once": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", - "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", - "dev": true, - "requires": { - "wrappy": "1" - } - } + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "node_modules/cachedir": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", + "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", "dev": true, - "requires": { - "is-arrayish": "^0.2.1" + "engines": { + "node": ">=6" } }, - "es6-promise": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", - "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=" + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "node_modules/camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/centra": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/centra/-/centra-2.7.0.tgz", + "integrity": "sha512-PbFMgMSrmgx6uxCdm57RUos9Tc3fclMvhLSATYN39XsDV29B89zZ3KA89jmY0vwSGazyU+uerqwa6t+KaodPcg==", + "dependencies": { + "follow-redirects": "^1.15.6" + } }, - "eslint": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", - "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, - "requires": { - "ajv": "^5.3.0", - "babel-code-frame": "^6.22.0", - "chalk": "^2.1.0", - "concat-stream": "^1.6.0", - "cross-spawn": "^5.1.0", - "debug": "^3.1.0", - "doctrine": "^2.1.0", - "eslint-scope": "^3.7.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^3.5.4", - "esquery": "^1.0.0", - "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.0.1", - "ignore": "^3.3.3", - "imurmurhash": "^0.1.4", - "inquirer": "^3.0.6", - "is-resolvable": "^1.0.0", - "js-yaml": "^3.9.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.4", - "minimatch": "^3.0.2", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "pluralize": "^7.0.0", - "progress": "^2.0.0", - "regexpp": "^1.0.1", - "require-uncached": "^1.0.3", - "semver": "^5.3.0", - "strip-ansi": "^4.0.0", - "strip-json-comments": "~2.0.1", - "table": "4.0.2", - "text-table": "~0.2.0" - }, - "dependencies": { - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "dev": true, - "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "external-editor": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", - "dev": true, - "requires": { - "chardet": "^0.4.0", - "iconv-lite": "^0.4.17", - "tmp": "^0.0.33" - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", - "dev": true - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "inquirer": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", - "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", - "dev": true, - "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^2.0.4", - "figures": "^2.0.0", - "lodash": "^4.3.0", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rx-lite": "^4.0.8", - "rx-lite-aggregates": "^4.0.8", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - } + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" } }, - "eslint-config-semistandard": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/eslint-config-semistandard/-/eslint-config-semistandard-12.0.1.tgz", - "integrity": "sha512-4zaPW5uRFasf2uRZkE19Y+W84KBV3q+oyWYOsgUN+5DQXE5HCsh7ZxeWDXxozk7NPycGm0kXcsJzLe5GZ1jCeg==", + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, - "eslint-config-standard": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz", - "integrity": "sha1-wGHk0GbzedwXzVYsZOgZtN1FRZE=", - "dev": true + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=", + "engines": { + "node": "*" + } }, - "eslint-import-resolver-node": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", - "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "requires": { - "debug": "^2.6.9", - "resolve": "^1.5.0" + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, - "eslint-module-utils": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.1.tgz", - "integrity": "sha512-H6DOj+ejw7Tesdgbfs4jeS4YMFrT8uI8xwd1gtQqXssaR0EQ26L+2O/w6wkYFy2MymON0fTwHmXBvvfLNZVZEw==", + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, - "requires": { - "debug": "^2.6.8", - "pkg-dir": "^2.0.0" + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" } }, - "eslint-plugin-import": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.10.0.tgz", - "integrity": "sha1-+gkIPVp1KI35xsfQn+EiVZhWVec=", + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "dev": true, - "requires": { - "builtin-modules": "^1.1.1", - "contains-path": "^0.1.0", - "debug": "^2.6.8", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.1", - "eslint-module-utils": "^2.2.0", - "has": "^1.0.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.3", - "read-pkg-up": "^2.0.0" + "engines": { + "node": ">=6" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "eslint-plugin-node": { + "node_modules/cli-truncate/node_modules/ansi-regex": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-6.0.1.tgz", - "integrity": "sha512-Q/Cc2sW1OAISDS+Ji6lZS2KV4b7ueA/WydVWd1BECTQwVvfQy5JAi3glhINoKzoMnfnuRgNP+ZWKrGAbp3QDxw==", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, - "requires": { - "ignore": "^3.3.6", - "minimatch": "^3.0.4", - "resolve": "^1.3.3", - "semver": "^5.4.1" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "eslint-plugin-promise": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.7.0.tgz", - "integrity": "sha512-2WO+ZFh7vxUKRfR0cOIMrWgYKdR6S1AlOezw6pC52B6oYpd5WFghN+QHxvrRdZMtbo8h3dfUZ2o1rWb0UPbKtg==", + "node_modules/cli-truncate/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", "dev": true }, - "eslint-plugin-standard": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-3.1.0.tgz", - "integrity": "sha512-fVcdyuKRr0EZ4fjWl3c+gp1BANFJD1+RaWa2UPYfMZ6jCtp5RG00kSaXnK/dE5sYzt4kaWJ9qdxqUfc0d9kX0w==", - "dev": true - }, - "eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", + "node_modules/cli-truncate/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "eslint-visitor-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", - "dev": true - }, - "espree": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", - "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "node_modules/cli-truncate/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, - "requires": { - "acorn": "^5.5.0", - "acorn-jsx": "^3.0.0" + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "engines": { + "node": ">= 10" + } }, - "esquery": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "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, - "requires": { - "estraverse": "^4.0.0" + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, - "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", "dev": true, - "requires": { - "estraverse": "^4.1.0" + "engines": { + "node": ">=0.8" } }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true + "node_modules/clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "node_modules/clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==", "dev": true }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "event-stream": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.5.tgz", - "integrity": "sha512-vyibDcu5JL20Me1fP734QBH/kenBGLZap2n0+XXM7mvuUPzJ20Ydqj1aKcIeMdri1p+PU+4yAKugjN8KCVst+g==", + "node_modules/cloneable-readable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", + "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", "dev": true, - "requires": { - "duplexer": "^0.1.1", - "from": "^0.1.7", - "map-stream": "0.0.7", - "pause-stream": "^0.0.11", - "split": "^1.0.1", - "stream-combiner": "^0.2.2", - "through": "^2.3.8" + "dependencies": { + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" } }, - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" - }, - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "node_modules/cloneable-readable/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "exif-parser": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz", - "integrity": "sha1-WKnS1ywCwfbwKg70qRZicrd2CSI=" - }, - "exit-hook": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", - "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", + "node_modules/cloneable-readable/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "node_modules/cloneable-readable/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "requires": { - "is-posix-bracket": "^0.1.0" + "dependencies": { + "safe-buffer": "~5.1.0" } }, - "expand-range": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", "dev": true, - "requires": { - "fill-range": "^2.1.0" + "engines": { + "node": ">=0.10.0" } }, - "expand-tilde": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz", - "integrity": "sha1-C4HrqJflo9MdHD0QL48BRB5VlEk=", + "node_modules/collection-map": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", + "integrity": "sha512-5D2XXSpkOnleOI21TG7p3T0bGAsZ/XknZpKBmGYyluO8pw4zA3K8ZlrBIbC4FXg3m6z/RNFiUFfT2sQK01+UHA==", "dev": true, - "requires": { - "os-homedir": "^1.0.1" - } - }, - "expect-ct": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/expect-ct/-/expect-ct-0.1.0.tgz", - "integrity": "sha1-UnNWeN4YUwiQ2Ne5XwrGNkCVgJQ=" - }, - "express": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.15.3.tgz", - "integrity": "sha1-urZdDwOqgMNYQIly/HAPkWlEtmI=", - "requires": { - "accepts": "~1.3.3", - "array-flatten": "1.1.1", - "content-disposition": "0.5.2", - "content-type": "~1.0.2", - "cookie": "0.3.1", - "cookie-signature": "1.0.6", - "debug": "2.6.7", - "depd": "~1.1.0", - "encodeurl": "~1.0.1", - "escape-html": "~1.0.3", - "etag": "~1.8.0", - "finalhandler": "~1.0.3", - "fresh": "0.5.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.1", - "path-to-regexp": "0.1.7", - "proxy-addr": "~1.1.4", - "qs": "6.4.0", - "range-parser": "~1.2.0", - "send": "0.15.3", - "serve-static": "1.12.3", - "setprototypeof": "1.0.3", - "statuses": "~1.3.1", - "type-is": "~1.6.15", - "utils-merge": "1.0.0", - "vary": "~1.1.1" - }, "dependencies": { - "debug": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz", - "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "setprototypeof": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", - "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" - }, - "statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" - } + "arr-map": "^2.0.2", + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "external-editor": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-1.1.1.tgz", - "integrity": "sha1-Etew24UPf/fnCBuvQAVwAGDEYAs=", + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, - "requires": { - "extend": "^3.0.0", - "spawn-sync": "^1.0.15", - "tmp": "^0.0.29" + "dependencies": { + "color-name": "1.1.3" } }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", "dev": true, - "requires": { - "is-extglob": "^1.0.0" + "bin": { + "color-support": "bin.js" } }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true }, - "fancy-log": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", - "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", "dev": true, - "requires": { - "ansi-gray": "^0.1.1", - "color-support": "^1.1.3", - "parse-node-version": "^1.0.0", - "time-stamp": "^1.0.0" + "engines": { + "node": ">=0.1.90" } }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, + "engines": { + "node": ">=18" + } }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true + "node_modules/commitizen": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.3.0.tgz", + "integrity": "sha512-H0iNtClNEhT0fotHvGV3E9tDejDeS04sN1veIebsKYGMuGscFaswRoYJKmT3eW85eIJAs0F28bG2+a/9wCOfPw==", + "dev": true, + "dependencies": { + "cachedir": "2.3.0", + "cz-conventional-changelog": "3.3.0", + "dedent": "0.7.0", + "detect-indent": "6.1.0", + "find-node-modules": "^2.1.2", + "find-root": "1.1.0", + "fs-extra": "9.1.0", + "glob": "7.2.3", + "inquirer": "8.2.5", + "is-utf8": "^0.2.1", + "lodash": "4.17.21", + "minimist": "1.2.7", + "strip-bom": "4.0.0", + "strip-json-comments": "3.1.1" + }, + "bin": { + "commitizen": "bin/commitizen", + "cz": "bin/git-cz", + "git-cz": "bin/git-cz" + }, + "engines": { + "node": ">= 12" + } }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "node_modules/commitizen/node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "node_modules/commitizen/node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, - "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" + "engines": { + "node": ">=8" } }, - "file-type": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", - "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=" + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "filename-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "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 }, - "fill-range": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", - "dev": true, - "requires": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^3.0.0", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" } }, - "finalhandler": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.6.tgz", - "integrity": "sha1-AHrqM9Gk0+QgF/YkhIrVjSEvgU8=", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.1", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "statuses": "~1.3.1", - "unpipe": "~1.0.0" - }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" - } + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "find-index": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz", - "integrity": "sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ=", - "dev": true + "node_modules/concat-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, - "find-node-modules": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-1.0.4.tgz", - "integrity": "sha1-tt6zzMtpnIcDdne87eLF9YYrJVA=", - "dev": true, - "requires": { - "findup-sync": "0.4.2", - "merge": "^1.2.0" + "node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" } }, - "find-parent-dir": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/find-parent-dir/-/find-parent-dir-0.3.0.tgz", - "integrity": "sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ=", + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/conventional-commit-types": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-3.0.0.tgz", + "integrity": "sha512-SmmCYnOniSsAa9GqWOeLqc179lfr5TRu5b4QFDkbsrJ5TZjPJx85wtOr3zn+1dbeNiXDKGPbZ72IKbPhLXh/Lg==", "dev": true }, - "find-root": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.0.0.tgz", - "integrity": "sha1-li/yEaqyXGUg/u641ih/j26VgHo=", + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" + "node_modules/cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "engines": { + "node": ">= 0.6" } }, - "findup-sync": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.4.2.tgz", - "integrity": "sha1-qBF9D3MST1pFRoOVef5S1xKfteU=", + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", "dev": true, - "requires": { - "detect-file": "^0.1.0", - "is-glob": "^2.0.1", - "micromatch": "^2.3.7", - "resolve-dir": "^0.1.0" + "engines": { + "node": ">=0.10.0" } }, - "fined": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", - "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "node_modules/copy-props": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-4.0.0.tgz", + "integrity": "sha512-bVWtw1wQLzzKiYROtvNlbJgxgBYt2bMJpkCbKmXM3xyijvcjjWXEk5nyrrT3bgJ7ODb19ZohE2T0Y3FgNPyoTw==", "dev": true, - "requires": { - "expand-tilde": "^2.0.2", - "is-plain-object": "^2.0.3", - "object.defaults": "^1.1.0", - "object.pick": "^1.2.0", - "parse-filepath": "^1.0.1" - }, "dependencies": { - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1" - } - } + "each-props": "^3.0.0", + "is-plain-object": "^5.0.0" + }, + "engines": { + "node": ">= 10.13.0" } }, - "first-chunk-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz", - "integrity": "sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=", - "dev": true + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, - "flagged-respawn": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", - "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", - "dev": true + "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" + } }, - "flat-cache": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", - "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dev": true, - "requires": { - "circular-json": "^0.3.1", - "graceful-fs": "^4.1.2", - "rimraf": "~2.6.2", - "write": "^0.2.1" + "optional": true, + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "follow-redirects": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.9.0.tgz", - "integrity": "sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==", - "requires": { - "debug": "^3.0.0" + "node_modules/cosmiconfig-typescript-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-5.0.0.tgz", + "integrity": "sha512-+8cK7jRAReYkMwMiG+bxhcNKiHJDM6bR9FD/nGBXOWdMLuYawjF5cGrtLilJ+LGd3ZjCXnJjR5DkfWPoIVlqJA==", + "dev": true, + "optional": true, + "dependencies": { + "jiti": "^1.19.1" + }, + "engines": { + "node": ">=v16" + }, + "peerDependencies": { + "@types/node": "*", + "cosmiconfig": ">=8.2", + "typescript": ">=4" } }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true + "node_modules/cosmiconfig/node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "optional": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", "dev": true, - "requires": { - "for-in": "^1.0.1" + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" } }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } }, - "form-data": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", - "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "1.0.6", - "mime-types": "^2.1.12" + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=", + "engines": { + "node": "*" } }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + "node_modules/cz-conventional-changelog": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.3.0.tgz", + "integrity": "sha512-U466fIzU5U22eES5lTNiNbZ+d8dfcHcssH4o7QsdWaCcRs/feIPCxKYSWkYBNs5mny7MvEfwpTLWjvbm94hecw==", + "dev": true, + "dependencies": { + "chalk": "^2.4.1", + "commitizen": "^4.0.3", + "conventional-commit-types": "^3.0.0", + "lodash.map": "^4.5.1", + "longest": "^2.0.1", + "word-wrap": "^1.0.3" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@commitlint/load": ">6.1.1" + } }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "node_modules/d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", "dev": true, - "requires": { - "map-cache": "^0.2.2" + "dependencies": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" } }, - "frameguard": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/frameguard/-/frameguard-3.0.0.tgz", - "integrity": "sha1-e8rUae57lukdEs6zlZx4I1qScuk=" + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } }, - "freemail": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/freemail/-/freemail-1.5.0.tgz", - "integrity": "sha1-k7sPZ8SYcUO0eLQH6Y4ybq2O1OA=", - "requires": { - "tldjs": "^1.5.2" + "node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "fresh": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz", - "integrity": "sha1-9HTKXmqSRtb9jglTz6m5yAWvp44=" + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } }, - "from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", "dev": true }, - "fs-exists-sync": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz", - "integrity": "sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=", + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "fs-extra": { + "node_modules/default-compare": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", - "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", + "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0" + "dependencies": { + "kind-of": "^5.0.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "node_modules/default-compare/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "fsevents": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", - "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "node_modules/default-resolution": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", + "integrity": "sha512-2xaP6GiwVwOEbXCGoJ4ufgC76m8cj805jrghScewJC2ZDsb9U0b4BIrba+xt/Uytyd0HvQ6+WymSRTfnYj59GQ==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "dev": true, - "optional": true, - "requires": { - "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" - }, "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "debug": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true, - "optional": true - }, - "minipass": { - "version": "2.3.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "needle": { - "version": "2.3.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "^4.1.0", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.6.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "5.7.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "4.4.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "yallist": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "optional": true - } + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "gaze": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz", - "integrity": "sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8=", + "node_modules/defaults/node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true, - "requires": { - "globule": "~0.1.0" + "engines": { + "node": ">=0.8" } }, - "get-own-enumerable-property-symbols": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.1.tgz", - "integrity": "sha512-09/VS4iek66Dh2bctjRkowueRJbY1JDGR1L/zRxO1Qk8Uxs6PnqaNSqalpizPT+CDjre3hnEsuzvhgomz9qYrA==", - "dev": true - }, - "get-stdin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", - "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", - "dev": true - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "^1.0.0" + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "glob": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", - "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.2", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, - "requires": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" } }, - "glob-parent": { + "node_modules/depd": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "dev": true, - "requires": { - "is-glob": "^2.0.0" - } - }, - "glob-stream": { - "version": "3.1.18", - "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-3.1.18.tgz", - "integrity": "sha1-kXCl8St5Awb9/lmPMT+PeVT9FDs=", - "dev": true, - "requires": { - "glob": "^4.3.1", - "glob2base": "^0.0.12", - "minimatch": "^2.0.1", - "ordered-read-streams": "^0.1.0", - "through2": "^0.6.1", - "unique-stream": "^1.0.0" - }, - "dependencies": { - "glob": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", - "integrity": "sha1-xstz0yJsHv7wTePFbQEvAzd+4V8=", - "dev": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^2.0.1", - "once": "^1.3.0" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "minimatch": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", - "dev": true, - "requires": { - "brace-expansion": "^1.0.0" - } - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", - "dev": true, - "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - } + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" } }, - "glob-watcher": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-0.0.6.tgz", - "integrity": "sha1-uVtKjfdLOcgymLDAXJeLTZo7cQs=", + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", "dev": true, - "requires": { - "gaze": "^0.5.1" + "engines": { + "node": ">=0.10.0" } }, - "glob2base": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", - "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=", + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", "dev": true, - "requires": { - "find-index": "^0.1.1" + "engines": { + "node": ">=8" } }, - "global": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz", - "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=", - "requires": { - "min-document": "^2.19.0", - "process": "~0.5.1" + "node_modules/dicer": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", + "integrity": "sha512-FDvbtnq7dzlPz0wyYlOExifDEZcu8h+rErEXgfxqmLfRfC/kJidEFh4+effJRO3P0xmfqyPbSMG0LveNRfTKVg==", + "dependencies": { + "readable-stream": "1.1.x", + "streamsearch": "0.1.2" + }, + "engines": { + "node": ">=0.8.0" } }, - "global-dirs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", - "dev": true, - "requires": { - "ini": "^1.3.4" + "node_modules/dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" + }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" } }, - "global-modules": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz", - "integrity": "sha1-6lo77ULG1s6ZWk+KEmm12uIjgo0=", + "node_modules/duplexify": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", + "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==", "dev": true, - "requires": { - "global-prefix": "^0.1.4", - "is-windows": "^0.2.0" + "dependencies": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.2" } }, - "global-prefix": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz", - "integrity": "sha1-jTvGuNo8qBEqFg2NSW/wRiv+948=", + "node_modules/duplexify/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, - "requires": { - "homedir-polyfill": "^1.0.0", - "ini": "^1.3.4", - "is-windows": "^0.2.0", - "which": "^1.2.12" + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "globule": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz", - "integrity": "sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU=", - "dev": true, - "requires": { - "glob": "~3.1.21", - "lodash": "~1.0.1", - "minimatch": "~0.2.11" - }, - "dependencies": { - "glob": { - "version": "3.1.21", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", - "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", - "dev": true, - "requires": { - "graceful-fs": "~1.2.0", - "inherits": "1", - "minimatch": "~0.2.11" - } - }, - "graceful-fs": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", - "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", - "dev": true - }, - "inherits": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", - "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=", - "dev": true - }, - "lodash": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", - "integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE=", - "dev": true - }, - "lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", - "dev": true - }, - "minimatch": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", - "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", - "dev": true, - "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" - } - } + "node_modules/duplexify/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" } }, - "glogg": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", - "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", + "node_modules/each-props": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/each-props/-/each-props-3.0.0.tgz", + "integrity": "sha512-IYf1hpuWrdzse/s/YJOrFmU15lyhSzxelNVAHTEG3DtP4QsLTWZUzcUL3HMXmKQxXpa4EIrBPpwRgj0aehdvAw==", "dev": true, - "requires": { - "sparkles": "^1.0.0" + "dependencies": { + "is-plain-object": "^5.0.0", + "object.defaults": "^1.1.0" + }, + "engines": { + "node": ">= 10.13.0" } }, - "google-auth-library": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-0.10.0.tgz", - "integrity": "sha1-bhW6vuhf0d0U2NEoopW2g41SE24=", - "requires": { - "gtoken": "^1.2.1", - "jws": "^3.1.4", - "lodash.noop": "^3.0.1", - "request": "^2.74.0" + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" } }, - "google-p12-pem": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-0.1.2.tgz", - "integrity": "sha1-M8RqsCGqc0+gMys5YKmj/8svMXc=", - "requires": { - "node-forge": "^0.7.1" - } - }, - "got": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", - "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", - "dev": true, - "requires": { - "create-error-class": "^3.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-redirect": "^1.0.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "lowercase-keys": "^1.0.0", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "unzip-response": "^2.0.1", - "url-parse-lax": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "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 }, - "gtoken": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-1.2.3.tgz", - "integrity": "sha512-wQAJflfoqSgMWrSBk9Fg86q+sd6s7y6uJhIvvIPz++RElGlMtEqsdAR2oWwZ/WTEtp7P9xFbJRrT976oRgzJ/w==", - "requires": { - "google-p12-pem": "^0.1.0", - "jws": "^3.0.0", - "mime": "^1.4.1", - "request": "^2.72.0" - }, - "dependencies": { - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - } + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "engines": { + "node": ">= 0.8" } }, - "gulp": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/gulp/-/gulp-3.9.1.tgz", - "integrity": "sha1-VxzkWSjdQK9lFPxAEYZgFsE4RbQ=", + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, - "requires": { - "archy": "^1.0.0", - "chalk": "^1.0.0", - "deprecated": "^0.0.1", - "gulp-util": "^3.0.0", - "interpret": "^1.0.0", - "liftoff": "^2.1.0", - "minimist": "^1.1.0", - "orchestrator": "^0.3.0", - "pretty-hrtime": "^1.0.0", - "semver": "^4.1.0", - "tildify": "^1.0.0", - "v8flags": "^2.0.2", - "vinyl-fs": "^0.3.0" - }, "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "semver": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", - "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", - "dev": true - } + "once": "^1.4.0" } }, - "gulp-eslint": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-4.0.0.tgz", - "integrity": "sha512-+qsePo04v1O3JshpNvww9+bOgZEJ6Cc2/w3mEktfKz0NL0zsh1SWzjyIL2FIM2zzy6IYQYv+j8REZORF8dKX4g==", + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", "dev": true, - "requires": { - "eslint": "^4.0.0", - "gulp-util": "^3.0.8" + "optional": true, + "engines": { + "node": ">=6" } }, - "gulp-nodemon": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/gulp-nodemon/-/gulp-nodemon-2.2.1.tgz", - "integrity": "sha1-2b8Zn1WFRYFZ09KZFT5gtGhotvQ=", - "dev": true, - "requires": { - "colors": "^1.0.3", - "event-stream": "^3.2.1", - "gulp": "^3.9.1", - "nodemon": "^1.10.2" - } - }, - "gulp-util": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", - "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", - "dev": true, - "requires": { - "array-differ": "^1.0.0", - "array-uniq": "^1.0.2", - "beeper": "^1.0.0", - "chalk": "^1.0.0", - "dateformat": "^2.0.0", - "fancy-log": "^1.1.0", - "gulplog": "^1.0.0", - "has-gulplog": "^0.1.0", - "lodash._reescape": "^3.0.0", - "lodash._reevaluate": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.template": "^3.0.0", - "minimist": "^1.1.0", - "multipipe": "^0.1.2", - "object-assign": "^3.0.0", - "replace-ext": "0.0.1", - "through2": "^2.0.0", - "vinyl": "^0.5.0" - }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "object-assign": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", - "dev": true - } + "is-arrayish": "^0.2.1" } }, - "gulplog": { + "node_modules/es-define-property": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", - "dev": true, - "requires": { - "glogg": "^1.0.0" + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" } }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" } }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "node_modules/es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", "dev": true, - "requires": { - "function-bind": "^1.1.1" + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" } }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "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, - "requires": { - "ansi-regex": "^2.0.0" + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" } }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-gulplog": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", - "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", + "node_modules/es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", "dev": true, - "requires": { - "sparkles": "^1.0.0" + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" } }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "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, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" } }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "engines": { + "node": ">=6" } }, - "helmet": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/helmet/-/helmet-3.8.1.tgz", - "integrity": "sha512-HzcpQ74kE1gNFvTd8fI/Nz2N0b0Aa/38dSiSVt/ijkwjc50tUp5siXTE9lTBibQ4JlRzp/35Qf+j2bZgHYwg1g==", - "requires": { - "connect": "3.6.2", - "dns-prefetch-control": "0.1.0", - "dont-sniff-mimetype": "1.0.0", - "expect-ct": "0.1.0", - "frameguard": "3.0.0", - "helmet-csp": "2.5.1", - "hide-powered-by": "1.0.0", - "hpkp": "2.0.0", - "hsts": "2.1.0", - "ienoopen": "1.0.0", - "nocache": "2.0.0", - "referrer-policy": "1.1.0", - "x-xss-protection": "1.0.0" - } - }, - "helmet-csp": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/helmet-csp/-/helmet-csp-2.5.1.tgz", - "integrity": "sha512-PLLch8wVcVF2+ViTtSGHIvXqQVjcwGRtBwrNPggC+j28J7eSoPHxbJBr9SvLgh9V3HZa0C1zZFZ6gYVLIrPD0Q==", - "requires": { - "camelize": "1.0.0", - "content-security-policy-builder": "1.1.0", - "dasherize": "2.0.0", - "lodash.reduce": "4.6.0", - "platform": "1.3.4" - } - }, - "hide-powered-by": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hide-powered-by/-/hide-powered-by-1.0.0.tgz", - "integrity": "sha1-SoWtZYgfYoV/xwr3F0oRhNzM4ys=" - }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" - }, - "homedir-polyfill": { + "node_modules/escape-html": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, - "requires": { - "parse-passwd": "^1.0.0" + "engines": { + "node": ">=0.8.0" } }, - "hosted-git-info": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", - "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", - "dev": true - }, - "hpkp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hpkp/-/hpkp-2.0.0.tgz", - "integrity": "sha1-EOFCJk52IVpdMMROxD3mTe5tFnI=" - }, - "hsts": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hsts/-/hsts-2.1.0.tgz", - "integrity": "sha512-zXhh/DqgrTXJ7erTN6Fh5k/xjMhDGXCqdYN3wvxUvGUQvnxcFfUd8E+6vLg/nk3ss1TYMb+DhRl25fYABioTvA==" + "node_modules/eslint": { + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.7.0.tgz", + "integrity": "sha512-FzJ9D/0nGiCGBf8UXO/IGLTgLVzIxze1zpfA8Ton2mjLovXdAPlYDv+MQDcqj3TmrhAGYfOpz9RfR+ent0AgAw==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.17.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.7.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.0.2", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } }, - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" + "node_modules/eslint-scope": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", + "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "husky": { - "version": "1.0.0-rc.13", - "resolved": "https://registry.npmjs.org/husky/-/husky-1.0.0-rc.13.tgz", - "integrity": "sha512-ZNNoaBgfOHRA05UHS/etBoWFDu65mjPoohPYQwOqb5155KOovBp8LMkMoNK0kn3VYdsm+HWdtuHbD4XjfzlfpQ==", - "dev": true, - "requires": { - "cosmiconfig": "^5.0.2", - "execa": "^0.9.0", - "find-up": "^3.0.0", - "get-stdin": "^6.0.0", - "is-ci": "^1.1.0", - "pkg-dir": "^3.0.0", - "please-upgrade-node": "^3.1.1", - "read-pkg": "^4.0.1", - "run-node": "^1.0.0", - "slash": "^2.0.0" - }, - "dependencies": { - "execa": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.9.0.tgz", - "integrity": "sha512-BbUMBiX4hqiHZUA5+JujIjNb6TyAlp2D5KLheMjMluwOuzcnylDL4AxZYLLn1n2AGB49eSWwyKvvEQoRpnAtmA==", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - }, - "read-pkg": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", - "integrity": "sha1-ljYlN48+HE1IyFhytabsfV0JMjc=", - "dev": true, - "requires": { - "normalize-package-data": "^2.3.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0" - } - } + "node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "iconv-lite": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz", - "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es=" + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } }, - "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } }, - "ienoopen": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ienoopen/-/ienoopen-1.0.0.tgz", - "integrity": "sha1-NGpCj0dKrI9QzzeE6i0PFvYr2ms=" + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } }, - "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", - "dev": true + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } }, - "ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "dev": true, - "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - }, - "dependencies": { - "caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "dev": true, - "requires": { - "caller-callsite": "^2.0.0" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true + "node_modules/eslint/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true } } }, - "import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "dev": true - }, - "inquirer": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-1.2.3.tgz", - "integrity": "sha1-TexvMvN+97sLLtPx0aXD9UUHSRg=", - "dev": true, - "requires": { - "ansi-escapes": "^1.1.0", - "chalk": "^1.0.0", - "cli-cursor": "^1.0.1", - "cli-width": "^2.0.0", - "external-editor": "^1.1.0", - "figures": "^1.3.5", - "lodash": "^4.3.0", - "mute-stream": "0.0.6", - "pinkie-promise": "^2.0.0", - "run-async": "^2.2.0", - "rx": "^4.1.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.0", - "through": "^2.3.6" + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "interpret": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", - "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", - "dev": true - }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" - }, - "ip-regex": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-1.0.3.tgz", - "integrity": "sha1-3FiQdvZZ9BnCIgOaMzFvHHOH7/0=" - }, - "ipaddr.js": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.4.0.tgz", - "integrity": "sha1-KWrKh4qCGBbluF0KKFqZvP9FgvA=" - }, - "is-absolute": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "requires": { - "is-relative": "^1.0.0", - "is-windows": "^1.0.1" - }, - "dependencies": { - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - } + "engines": { + "node": ">=8" } }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true, - "requires": { - "kind-of": "^3.0.2" + "engines": { + "node": ">= 4" } }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, - "requires": { - "binary-extensions": "^1.0.0" + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "is-ci": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", - "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, - "requires": { - "ci-info": "^1.5.0" + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, - "requires": { - "kind-of": "^3.0.2" + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true - }, - "is-dotfile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", - "dev": true - }, - "is-equal-shallow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", "dev": true, - "requires": { - "is-primitive": "^2.0.0" + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" } }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true - }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "node_modules/espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", "dev": true, - "requires": { - "number-is-nan": "^1.0.0" + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, - "requires": { - "number-is-nan": "^1.0.0" + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" } }, - "is-function": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.1.tgz", - "integrity": "sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU=" + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "requires": { - "is-extglob": "^1.0.0" + "engines": { + "node": ">=4.0" } }, - "is-installed-globally": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", - "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, - "requires": { - "global-dirs": "^0.1.0", - "is-path-inside": "^1.0.0" + "engines": { + "node": ">=0.10.0" } }, - "is-npm": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", - "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=", - "dev": true + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } }, - "is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "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, - "requires": { - "kind-of": "^3.0.2" + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" } }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "dev": true }, - "is-observable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz", - "integrity": "sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==", - "dev": true, - "requires": { - "symbol-observable": "^1.1.0" + "node_modules/events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "engines": { + "node": ">=0.4.x" } }, - "is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", "dev": true, - "requires": { - "path-is-inside": "^1.0.1" + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "node_modules/execa/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", "dev": true, - "requires": { - "isobject": "^3.0.1" + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "is-posix-bracket": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", - "dev": true + "node_modules/exif-parser": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz", + "integrity": "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==" }, - "is-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", - "dev": true + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", + "dev": true, + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } }, - "is-redirect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", - "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", - "dev": true + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } }, - "is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", - "dev": true + "node_modules/express/node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "engines": { + "node": ">= 0.6" + } }, - "is-relative": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "node_modules/express/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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, - "requires": { - "is-unc-path": "^1.0.0" + "dependencies": { + "type": "^2.7.2" } }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", - "dev": true + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, - "is-retry-allowed": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", - "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", - "dev": true + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } }, - "is-unc-path": { + "node_modules/extglob/node_modules/define-property": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, - "requires": { - "unc-path-regex": "^0.1.2" + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true + "node_modules/extglob/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } }, - "is-windows": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz", - "integrity": "sha1-3hqm1j6indJIc3tp8f+LgALSEIw=", + "node_modules/fancy-log": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", + "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", + "dev": true, + "dependencies": { + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "parse-node-version": "^1.0.0", + "time-stamp": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true }, - "isemail": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz", - "integrity": "sha1-vgPfjMPineTSxd9lASY/H6RZXpo=" + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", "dev": true, - "requires": { - "isarray": "1.0.0" + "optional": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" } }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } }, - "jest-get-type": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", - "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==", - "dev": true + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "jest-validate": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-23.6.0.tgz", - "integrity": "sha512-OFKapYxe72yz7agrDAWi8v2WL8GIfVqcbKRCLbRG9PAxtzF9b1SEDdTpytNDN12z2fJynoBwpMpvj2R39plI2A==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "jest-get-type": "^22.1.0", - "leven": "^2.1.0", - "pretty-format": "^23.6.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" } }, - "jimp": { - "version": "0.2.28", - "resolved": "https://registry.npmjs.org/jimp/-/jimp-0.2.28.tgz", - "integrity": "sha1-3VKak3GQ9ClXp5N9Gsw6d2KZbqI=", - "requires": { - "bignumber.js": "^2.1.0", - "bmp-js": "0.0.3", - "es6-promise": "^3.0.2", - "exif-parser": "^0.1.9", - "file-type": "^3.1.0", - "jpeg-js": "^0.2.0", - "load-bmfont": "^1.2.3", - "mime": "^1.3.4", - "mkdirp": "0.5.1", - "pixelmatch": "^4.0.0", - "pngjs": "^3.0.0", - "read-chunk": "^1.0.1", - "request": "^2.65.0", - "stream-to-buffer": "^0.1.0", - "tinycolor2": "^1.1.2", - "url-regex": "^3.0.0" - } - }, - "jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" - }, - "joi": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz", - "integrity": "sha1-TVDDGAeRIgAP5fFq8f+OGRe3fgY=", - "requires": { - "hoek": "2.x.x", - "isemail": "1.x.x", - "moment": "2.x.x", - "topo": "1.x.x" - } - }, - "jpeg-js": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.2.0.tgz", - "integrity": "sha1-U+RI7J0mPmgyZkZ+lELSxaLvVII=" + "node_modules/file-type": { + "version": "16.5.4", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz", + "integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==", + "dependencies": { + "readable-web-to-node-stream": "^3.0.0", + "strtok3": "^6.2.4", + "token-types": "^4.1.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", - "dev": true + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + "node_modules/finalhandler/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "node_modules/find-node-modules": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.1.3.tgz", + "integrity": "sha512-UC2I2+nx1ZuOBclWVNdcnbDR5dlrOdVb7xNjmT/lHE+LsgztWks3dG7boJ37yTS/venXw84B/mAW9uHVoC5QRg==", + "dev": true, + "dependencies": { + "findup-sync": "^4.0.0", + "merge": "^2.1.1" + } }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", "dev": true }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", "dev": true, - "requires": { - "graceful-fs": "^4.1.6" + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "jsonwebtoken": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.4.1.tgz", - "integrity": "sha1-fKMk9SFfi+A5zTWmxFu4y3SkSPs=", - "requires": { - "joi": "^6.10.1", - "jws": "^3.1.4", - "lodash.once": "^4.0.0", - "ms": "^2.0.0", - "xtend": "^4.0.1" + "node_modules/find-up/node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", + "dev": true, + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" + "node_modules/findup-sync": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 8" } }, - "jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" + "node_modules/fined": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-2.0.0.tgz", + "integrity": "sha512-OFRzsL6ZMHz5s0JrsEr+TpdGNCtrVtnuG3x1yzGNiQHT0yaDnXAj8V/lWcpJVrnoDpcwXcASxAZYbuXda2Y82A==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^5.0.0", + "object.defaults": "^1.1.0", + "object.pick": "^1.3.0", + "parse-filepath": "^1.0.2" + }, + "engines": { + "node": ">= 10.13.0" } }, - "jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "requires": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" + "node_modules/flagged-respawn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-2.0.0.tgz", + "integrity": "sha512-Gq/a6YCi8zexmGHMuJwahTGzXlAZAOsbCVKduWXC6TlLCjjFRlExMJc4GC2NYPYZ0r/brw9P7CpRgQmlPVeOoA==", + "dev": true, + "engines": { + "node": ">= 10.13.0" } }, - "kareem": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.0.tgz", - "integrity": "sha512-6hHxsp9e6zQU8nXsP+02HGWXwTkOEw6IROhF2ZA28cYbUk4eJ6QbtZvdqZOdD9YPKghG3apk5eOCvs+tLl3lRg==" - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, - "requires": { - "is-buffer": "^1.1.5" + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" } }, - "klaw": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", - "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", "dev": true, - "requires": { - "graceful-fs": "^4.1.9" + "dependencies": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" } }, - "latest-version": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", - "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", + "node_modules/flush-write-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "requires": { - "package-json": "^4.0.0" + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "leven": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", - "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", + "node_modules/flush-write-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "node_modules/flush-write-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "dependencies": { + "safe-buffer": "~5.1.0" } }, - "liftoff": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz", - "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=", - "dev": true, - "requires": { - "extend": "^3.0.0", - "findup-sync": "^2.0.0", - "fined": "^1.0.1", - "flagged-respawn": "^1.0.0", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.0", - "rechoir": "^0.6.2", - "resolve": "^1.1.7" + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "1.1.0", - "array-unique": "0.3.2", - "extend-shallow": "2.0.1", - "fill-range": "4.0.0", - "isobject": "3.0.1", - "repeat-element": "1.1.3", - "snapdragon": "0.8.2", - "snapdragon-node": "2.1.1", - "split-string": "3.1.0", - "to-regex": "3.0.2" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - } - } - }, + "peerDependenciesMeta": { "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", - "dev": true - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "posix-character-classes": "0.1.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "0.1.6" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "dev": true, - "requires": { - "homedir-polyfill": "1.0.3" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "0.3.2", - "define-property": "1.0.0", - "expand-brackets": "2.1.4", - "extend-shallow": "2.0.1", - "fragment-cache": "0.2.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "1.0.2" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "2.0.1", - "is-number": "3.0.0", - "repeat-string": "1.6.1", - "to-regex-range": "2.1.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - } - } - }, - "findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", - "dev": true, - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^3.1.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - } - }, - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "dev": true, - "requires": { - "global-prefix": "1.0.2", - "is-windows": "1.0.2", - "resolve-dir": "1.0.1" - } - }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", - "dev": true, - "requires": { - "expand-tilde": "2.0.2", - "homedir-polyfill": "1.0.3", - "ini": "1.3.5", - "is-windows": "1.0.2", - "which": "1.3.1" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "6.0.2" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "6.0.2" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" - } - }, - "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-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "braces": "2.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "extglob": "2.0.4", - "fragment-cache": "0.2.1", - "kind-of": "6.0.2", - "nanomatch": "1.2.13", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "dev": true, - "requires": { - "expand-tilde": "2.0.2", - "global-modules": "1.0.0" - } + "optional": true } } }, - "lint-staged": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-7.2.2.tgz", - "integrity": "sha512-BWT3kx242hq5oaKJ8QiazPeHwJnEXImvjmgZfjljMI5HX6RrTxI3cTJXywre6GNafMONCD/suFnEiFmC69Gscg==", + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", + "dev": true, + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fork-stream": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/fork-stream/-/fork-stream-0.0.4.tgz", + "integrity": "sha512-Pqq5NnT78ehvUnAk/We/Jr22vSvanRlFTpAmQ88xBY/M1TlHe+P0ILuEyXS595ysdGfaj22634LBkGMA2GTcpA==", + "dev": true + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", + "dev": true, + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/freemail": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/freemail/-/freemail-1.7.0.tgz", + "integrity": "sha512-XzEdol9AxxwDN5ISi+J560MgQRKTiGOTRFakRQLUQDEjr48hBMzU5Eo7c2U13zzz3IwcaD+54jWHJrg6/wqRNA==", + "dependencies": { + "tldjs": "^1.5.2" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "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-mkdirp-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-2.0.1.tgz", + "integrity": "sha512-UTOY+59K6IA94tec8Wjqm0FSh5OVudGNB0NL/P6fB3HiE3bYOY3VYBGijsnOHNkQSwC1FKkU77pmq7xp9CskLw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.8", + "streamx": "^2.12.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.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/gaxios": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.0.tgz", + "integrity": "sha512-DSrkyMTfAnAm4ks9Go20QGOcXEyW/NmZhvTYBU2rb4afBB393WIMQPWPEDMl/k8xqiNN9HYq2zao3oWXsdl2Tg==", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9", + "uuid": "^10.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gaxios/node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/gcp-metadata": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz", + "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==", + "dependencies": { + "gaxios": "^6.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "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-east-asian-width": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", + "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gifwrap": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/gifwrap/-/gifwrap-0.10.1.tgz", + "integrity": "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw==", + "dependencies": { + "image-q": "^4.0.0", + "omggif": "^1.0.10" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-stream": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-8.0.2.tgz", + "integrity": "sha512-R8z6eTB55t3QeZMmU1C+Gv+t5UnNRkA55c5yo67fAVfxODxieTwsjNG7utxS/73NdP1NbDgCrhVEg2h00y4fFw==", + "dev": true, + "dependencies": { + "@gulpjs/to-absolute-glob": "^4.0.0", + "anymatch": "^3.1.3", + "fastq": "^1.13.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "is-negated-glob": "^1.0.0", + "normalize-path": "^3.0.0", + "streamx": "^2.12.5" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-watcher": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-6.0.0.tgz", + "integrity": "sha512-wGM28Ehmcnk2NqRORXFOTOR064L4imSw3EeOqU5bIwUf62eXGwg89WivH6VMahL8zlQHeodzvHpXplrqzrz3Nw==", + "dev": true, + "dependencies": { + "async-done": "^2.0.0", + "chokidar": "^3.5.3" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dependencies": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "node_modules/global-directory": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", + "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", + "dev": true, + "optional": true, + "dependencies": { + "ini": "4.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix/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/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globals": { + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.8.0.tgz", + "integrity": "sha512-VZAJ4cewHTExBWDHR6yptdIBlx9YSSZuwojj9Nt5mBRXQzrKakDsVKQ1J63sklLvzAJm0X5+RpO4i3Y2hcOnFw==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glogg": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-2.2.0.tgz", + "integrity": "sha512-eWv1ds/zAlz+M1ioHsyKJomfY7jbDDPpwSkv14KQj89bycx1nvK5/2Cj/T9g7kzJcX5Bc7Yv22FjfBZS/jl94A==", + "dev": true, + "dependencies": { + "sparkles": "^2.1.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/google-auth-library": { + "version": "9.11.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.11.0.tgz", + "integrity": "sha512-epX3ww/mNnhl6tL45EQ/oixsY8JLEgUFoT4A5E/5iAR4esld9Kqv6IJGk7EmGuOgDvaarwF95hU2+v7Irql9lw==", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^6.1.1", + "gcp-metadata": "^6.1.0", + "gtoken": "^7.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/google-auth-library/node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/google-auth-library/node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/gtoken": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", + "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", + "dependencies": { + "gaxios": "^6.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/gtoken/node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/gtoken/node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/gulp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-5.0.0.tgz", + "integrity": "sha512-S8Z8066SSileaYw1S2N1I64IUc/myI2bqe2ihOBzO6+nKpvNSg7ZcWJt/AwF8LC/NVN+/QZ560Cb/5OPsyhkhg==", + "dev": true, + "dependencies": { + "glob-watcher": "^6.0.0", + "gulp-cli": "^3.0.0", + "undertaker": "^2.0.0", + "vinyl-fs": "^4.0.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gulp-cli": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-3.0.0.tgz", + "integrity": "sha512-RtMIitkT8DEMZZygHK2vEuLPqLPAFB4sntSxg4NoDta7ciwGZ18l7JuhCTiS5deOJi2IoK0btE+hs6R4sfj7AA==", + "dev": true, + "dependencies": { + "@gulpjs/messages": "^1.1.0", + "chalk": "^4.1.2", + "copy-props": "^4.0.0", + "gulplog": "^2.2.0", + "interpret": "^3.1.1", + "liftoff": "^5.0.0", + "mute-stdout": "^2.0.0", + "replace-homedir": "^2.0.0", + "semver-greatest-satisfied-range": "^2.0.0", + "string-width": "^4.2.3", + "v8flags": "^4.0.0", + "yargs": "^16.2.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gulp-cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/gulp-cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/gulp-cli/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/gulp-cli/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/gulp-cli/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/gulp-cli/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/gulp-eslint-new": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/gulp-eslint-new/-/gulp-eslint-new-2.2.0.tgz", + "integrity": "sha512-B9sBfILAW563MQM81vxWOMeeNbkZTgZEYiwEVmv3fndB5zmGINlA4wbc4qjgPd4kTCtq0sTlFZJV0fpxl8b5kg==", + "dev": true, + "dependencies": { + "@types/eslint": "^8.56.10", + "@types/node": ">=12", + "eslint": "8 || 9", + "fancy-log": "^2.0.0", + "plugin-error": "^2.0.1", + "semver": "^7.6.2", + "ternary-stream": "^3.0.0", + "vinyl-fs": "^4.0.0" + }, + "engines": { + "node": "^12.20 || ^14.13 || >=16" + } + }, + "node_modules/gulp-eslint-new/node_modules/fancy-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-2.0.0.tgz", + "integrity": "sha512-9CzxZbACXMUXW13tS0tI8XsGGmxWzO2DmYrGuBJOJ8k8q2K7hwfJA5qHjuPPe8wtsco33YR9wc+Rlr5wYFvhSA==", + "dev": true, + "dependencies": { + "color-support": "^1.1.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gulp-eslint-new/node_modules/plugin-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-2.0.1.tgz", + "integrity": "sha512-zMakqvIDyY40xHOvzXka0kUvf40nYIuwRE8dWhti2WtjQZ31xAgBZBhxsK7vK3QbRXS1Xms/LO7B5cuAsfB2Gg==", + "dev": true, + "dependencies": { + "ansi-colors": "^1.0.1" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gulp-eslint-new/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gulp-nodemon": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/gulp-nodemon/-/gulp-nodemon-2.5.0.tgz", + "integrity": "sha512-vXfaP72xo2C6XOaXrNcLEM3QqDJ1x21S3x97U4YtzN2Rl2kH57++aFkAVxe6BafGRSTxs/xVfE/jNNlCv5Ym2Q==", + "dev": true, + "dependencies": { + "colors": "^1.2.1", + "gulp": "^4.0.0", + "nodemon": "^2.0.2" + } + }, + "node_modules/gulp-nodemon/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "dependencies": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "node_modules/gulp-nodemon/node_modules/anymatch/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "dev": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/async-done": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", + "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.2", + "process-nextick-args": "^2.0.0", + "stream-exhaust": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/async-settle": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", + "integrity": "sha512-VPXfB4Vk49z1LHHodrEQ6Xf7W4gg1w0dAPROHngx7qgDjqmIQ+fXmwgGXTW/ITLai0YLSvWepJOP9EVpMnEAcw==", + "dev": true, + "dependencies": { + "async-done": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/bach": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", + "integrity": "sha512-bZOOfCb3gXBXbTFXq3OZtGR88LwGeJvzu6szttaIzymOTS4ZttBNOWSv7aLZja2EMycKtRYV0Oa8SNKH/zkxvg==", + "dev": true, + "dependencies": { + "arr-filter": "^1.1.1", + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "array-each": "^1.0.0", + "array-initial": "^1.0.0", + "array-last": "^1.1.1", + "async-done": "^1.2.2", + "async-settle": "^1.0.0", + "now-and-later": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "deprecated": "Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies", + "dev": true, + "dependencies": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + }, + "optionalDependencies": { + "fsevents": "^1.2.7" + } + }, + "node_modules/gulp-nodemon/node_modules/cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "node_modules/gulp-nodemon/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/gulp-nodemon/node_modules/copy-props": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.5.tgz", + "integrity": "sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw==", + "dev": true, + "dependencies": { + "each-props": "^1.3.2", + "is-plain-object": "^5.0.0" + } + }, + "node_modules/gulp-nodemon/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/each-props": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", + "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.1", + "object.defaults": "^1.1.0" + } + }, + "node_modules/gulp-nodemon/node_modules/each-props/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/fast-levenshtein": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", + "integrity": "sha512-Ia0sQNrMPXXkqVFt6w6M1n1oKo3NfKs+mvaV811Jwir7vAk9a6PVV9VPYf6X3BU97QiLEmuW3uXH9u87zDFfdw==", + "dev": true + }, + "node_modules/gulp-nodemon/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/fined": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/fined/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/flagged-respawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/fs-mkdirp-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", + "integrity": "sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "deprecated": "The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/gulp-nodemon/node_modules/get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "node_modules/gulp-nodemon/node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "dev": true, + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/gulp-nodemon/node_modules/glob-parent/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/glob-stream": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha512-uMbLGAP3S2aDOHUDfdoYcdIePUCfysbAd0IAoWVZbeGU/oNQ8asHVSshLDJUPWxfzj8zsCG7/XeHPHTtow0nsw==", + "dev": true, + "dependencies": { + "extend": "^3.0.0", + "glob": "^7.1.1", + "glob-parent": "^3.1.0", + "is-negated-glob": "^1.0.0", + "ordered-read-streams": "^1.0.0", + "pumpify": "^1.3.5", + "readable-stream": "^2.1.5", + "remove-trailing-separator": "^1.0.1", + "to-absolute-glob": "^2.0.0", + "unique-stream": "^2.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/glob-watcher": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz", + "integrity": "sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==", + "dev": true, + "dependencies": { + "anymatch": "^2.0.0", + "async-done": "^1.2.0", + "chokidar": "^2.0.0", + "is-negated-glob": "^1.0.0", + "just-debounce": "^1.0.0", + "normalize-path": "^3.0.0", + "object.defaults": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/glogg": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", + "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", + "dev": true, + "dependencies": { + "sparkles": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/gulp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", + "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", + "dev": true, + "dependencies": { + "glob-watcher": "^5.0.3", + "gulp-cli": "^2.2.0", + "undertaker": "^1.2.1", + "vinyl-fs": "^3.0.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/gulp-cli": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz", + "integrity": "sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==", + "dev": true, + "dependencies": { + "ansi-colors": "^1.0.1", + "archy": "^1.0.0", + "array-sort": "^1.0.0", + "color-support": "^1.1.3", + "concat-stream": "^1.6.0", + "copy-props": "^2.0.1", + "fancy-log": "^1.3.2", + "gulplog": "^1.0.0", + "interpret": "^1.4.0", + "isobject": "^3.0.1", + "liftoff": "^3.1.0", + "matchdep": "^2.0.0", + "mute-stdout": "^1.0.0", + "pretty-hrtime": "^1.0.0", + "replace-homedir": "^1.0.0", + "semver-greatest-satisfied-range": "^1.1.0", + "v8flags": "^3.2.0", + "yargs": "^7.1.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/gulplog": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", + "integrity": "sha512-hm6N8nrm3Y08jXie48jsC55eCZz9mnb4OirAStEk2deqeyhXU3C1otDVh+ccttMuc1sBi6RX6ZJ720hs9RCvgw==", + "dev": true, + "dependencies": { + "glogg": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", + "dev": true, + "dependencies": { + "binary-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gulp-nodemon/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/is-extendable/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "dev": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/last-run": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", + "integrity": "sha512-U/VxvpX4N/rFvPzr3qG5EtLKEnNI0emvIQB3/ecEwv+8GHaUKbIB8vxv1Oai5FAF0d0r7LXHhLLe5K/yChm5GQ==", + "dev": true, + "dependencies": { + "default-resolution": "^2.0.0", + "es6-weak-map": "^2.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/lead": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", + "integrity": "sha512-IpSVCk9AYvLHo5ctcIXxOBpMWUe+4TKN3VPWAKUbJikkmsGp0VrSM8IttVc32D6J4WUsiPE6aEFRNmIoF/gdow==", + "dev": true, + "dependencies": { + "flush-write-stream": "^1.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/liftoff": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", + "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", + "dev": true, + "dependencies": { + "extend": "^3.0.0", + "findup-sync": "^3.0.0", + "fined": "^1.0.1", + "flagged-respawn": "^1.0.0", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.0", + "rechoir": "^0.6.2", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/gulp-nodemon/node_modules/liftoff/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/micromatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/micromatch/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/mute-stdout": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", + "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/now-and-later": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", + "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", + "dev": true, + "dependencies": { + "once": "^1.3.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/gulp-nodemon/node_modules/readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/replace-ext": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz", + "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/replace-homedir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", + "integrity": "sha512-CHPV/GAglbIB1tnQgaiysb8H2yCy8WQ7lcEwQ/eT+kLj0QHV8LnJW0zpqpE7RSkrMSRoa+EBoag86clf7WAgSg==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1", + "is-absolute": "^1.0.0", + "remove-trailing-separator": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/resolve-options": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", + "integrity": "sha512-NYDgziiroVeDC29xq7bp/CacZERYsA9bXYd1ZmcJlF3BcrZv5pTb4NG7SjdyKDnXZ84aC4vo2u6sNKIA1LCu/A==", + "dev": true, + "dependencies": { + "value-or-function": "^3.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/gulp-nodemon/node_modules/semver-greatest-satisfied-range": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", + "integrity": "sha512-Ny/iyOzSSa8M5ML46IAx3iXc6tfOsYU2R4AXi2UpHk60Zrgyq6eqPj/xiOfS0rRl/iiQ/rdJkVjw/5cdUyCntQ==", + "dev": true, + "dependencies": { + "sver-compat": "^1.5.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/sparkles": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", + "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/gulp-nodemon/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/to-through": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", + "integrity": "sha512-+QIz37Ly7acM4EMdw2PRN389OneM5+d844tirkGp4dPKzI5OE72V9OsbFp+CIYJDahZ41ZV05hNtcPAQUAm9/Q==", + "dev": true, + "dependencies": { + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/undertaker": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz", + "integrity": "sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "bach": "^1.0.0", + "collection-map": "^1.0.0", + "es6-weak-map": "^2.0.1", + "fast-levenshtein": "^1.0.0", + "last-run": "^1.1.0", + "object.defaults": "^1.0.0", + "object.reduce": "^1.0.0", + "undertaker-registry": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/undertaker-registry": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", + "integrity": "sha512-UR1khWeAjugW3548EfQmL9Z7pGMlBgXteQpr1IZeZBtnkCJQJIJ1Scj0mb9wQaPvUZ9Q17XqW6TIaPchJkyfqw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/v8flags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/value-or-function": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", + "integrity": "sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/vinyl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", + "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==", + "dev": true, + "dependencies": { + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/vinyl-fs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", + "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", + "dev": true, + "dependencies": { + "fs-mkdirp-stream": "^1.0.0", + "glob-stream": "^6.1.0", + "graceful-fs": "^4.0.0", + "is-valid-glob": "^1.0.0", + "lazystream": "^1.0.0", + "lead": "^1.0.0", + "object.assign": "^4.0.4", + "pumpify": "^1.3.5", + "readable-stream": "^2.3.3", + "remove-bom-buffer": "^3.0.0", + "remove-bom-stream": "^1.2.0", + "resolve-options": "^1.1.0", + "through2": "^2.0.0", + "to-through": "^2.0.0", + "value-or-function": "^3.0.0", + "vinyl": "^2.0.0", + "vinyl-sourcemap": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/vinyl-sourcemap": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", + "integrity": "sha512-NiibMgt6VJGJmyw7vtzhctDcfKch4e4n9TBeoWlirb7FMg9/1Ov9k+A5ZRAtywBpRPiyECvQRQllYM8dECegVA==", + "dev": true, + "dependencies": { + "append-buffer": "^1.0.2", + "convert-source-map": "^1.5.0", + "graceful-fs": "^4.1.6", + "normalize-path": "^2.1.1", + "now-and-later": "^2.0.0", + "remove-bom-buffer": "^3.0.0", + "vinyl": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/vinyl-sourcemap/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "dev": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/y18n": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", + "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", + "dev": true + }, + "node_modules/gulp-nodemon/node_modules/yargs": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.2.tgz", + "integrity": "sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==", + "dev": true, + "dependencies": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^5.0.1" + } + }, + "node_modules/gulp-nodemon/node_modules/yargs-parser": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.1.tgz", + "integrity": "sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==", + "dev": true, + "dependencies": { + "camelcase": "^3.0.0", + "object.assign": "^4.1.0" + } + }, + "node_modules/gulplog": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-2.2.0.tgz", + "integrity": "sha512-V2FaKiOhpR3DRXZuYdRLn/qiY0yI5XmqbTKrYbdemJ+xOh2d2MOweI/XFgMzd/9+1twdvMwllnZbWZNJ+BOm4A==", + "dev": true, + "dependencies": { + "glogg": "^2.2.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", + "dev": true, + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/helmet": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.1.0.tgz", + "integrity": "sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg==", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/husky": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.1.tgz", + "integrity": "sha512-fCqlqLXcBnXa/TJXmT93/A36tJsjdJkibQ1MuIiFyCCYUlpYpIaj2mv1w+3KR6Rzu1IC3slFTje5f6DUp2A2rg==", + "dev": true, + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "node_modules/image-q": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/image-q/-/image-q-4.0.0.tgz", + "integrity": "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw==", + "dependencies": { + "@types/node": "16.9.1" + } + }, + "node_modules/image-q/node_modules/@types/node": { + "version": "16.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz", + "integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==" + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/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, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", + "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", + "dev": true, + "optional": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, + "optional": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/inquirer": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/inquirer/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/inquirer/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==" + }, + "node_modules/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==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "dependencies": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", + "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", + "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", + "dev": true, + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", + "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==" + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-negated-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "dependencies": { + "is-unc-path": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "dependencies": { + "unc-path-regex": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "node_modules/is-valid-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", + "integrity": "sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isomorphic-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", + "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", + "dependencies": { + "node-fetch": "^2.6.1", + "whatwg-fetch": "^3.4.1" + } + }, + "node_modules/jimp": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/jimp/-/jimp-0.22.12.tgz", + "integrity": "sha512-R5jZaYDnfkxKJy1dwLpj/7cvyjxiclxU3F4TrI/J4j2rS0niq6YDUMoPn5hs8GDpO+OZGo7Ky057CRtWesyhfg==", + "dependencies": { + "@jimp/custom": "^0.22.12", + "@jimp/plugins": "^0.22.12", + "@jimp/types": "^0.22.12", + "regenerator-runtime": "^0.13.3" + } + }, + "node_modules/jiti": { + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", + "dev": true, + "optional": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/jpeg-js": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz", + "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "optional": 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==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true, - "requires": { - "chalk": "^2.3.1", - "commander": "^2.14.1", - "cosmiconfig": "^5.0.2", - "debug": "^3.1.0", - "dedent": "^0.7.0", - "execa": "^0.9.0", - "find-parent-dir": "^0.3.0", - "is-glob": "^4.0.0", - "is-windows": "^1.0.2", - "jest-validate": "^23.5.0", - "listr": "^0.14.1", - "lodash": "^4.17.5", - "log-symbols": "^2.2.0", - "micromatch": "^3.1.8", - "npm-which": "^3.0.1", - "p-map": "^1.1.1", - "path-is-inside": "^1.0.2", - "pify": "^3.0.0", - "please-upgrade-node": "^3.0.2", - "staged-git-files": "1.1.1", - "string-argv": "^0.0.2", - "stringify-object": "^3.2.2" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true - }, - "execa": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.9.0.tgz", - "integrity": "sha512-BbUMBiX4hqiHZUA5+JujIjNb6TyAlp2D5KLheMjMluwOuzcnylDL4AxZYLLn1n2AGB49eSWwyKvvEQoRpnAtmA==", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "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-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, + "optional": true + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "optional": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "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/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/just-debounce": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.1.0.tgz", + "integrity": "sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==", + "dev": true + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/kareem": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz", + "integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/last-run": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/last-run/-/last-run-2.0.0.tgz", + "integrity": "sha512-j+y6WhTLN4Itnf9j5ZQos1BGPCS8DAwmgMroR3OzfxAsBxam0hMw7J8M3KqZl0pLQJ1jNnwIexg5DYpC/ctwEQ==", + "dev": true, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", + "dev": true, + "dependencies": { + "invert-kv": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lead": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lead/-/lead-4.0.0.tgz", + "integrity": "sha512-DpMa59o5uGUWWjruMp71e6knmwKU3jRBBn1kjuLWN9EeIOxNeSAwvHf03WIl8g/ZMR2oSQC9ej3yeLBwdDc/pg==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/liftoff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-5.0.0.tgz", + "integrity": "sha512-a5BQjbCHnB+cy+gsro8lXJ4kZluzOijzJ1UVVfyJYZC+IP2pLv1h4+aysQeKuTmyO8NAqfyQAk4HWaP/HjcKTg==", + "dev": true, + "dependencies": { + "extend": "^3.0.2", + "findup-sync": "^5.0.0", + "fined": "^2.0.0", + "flagged-respawn": "^2.0.0", + "is-plain-object": "^5.0.0", + "rechoir": "^0.8.0", + "resolve": "^1.20.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/liftoff/node_modules/findup-sync": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-5.0.0.tgz", + "integrity": "sha512-MzwXju70AuyflbgeOhzvQWAvvQdo1XL0A9bVvlXsYcFEBM87WR4OakL4OfZq+QRmr+duJubio+UtNQCPsVESzQ==", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.3", + "micromatch": "^4.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "optional": true + }, + "node_modules/lint-staged": { + "version": "15.2.7", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.7.tgz", + "integrity": "sha512-+FdVbbCZ+yoh7E/RosSdqKJyUM2OEjTciH0TFNkawKgvFp1zbGlEC39RADg+xKBG1R4mhoH2j85myBQZ5wR+lw==", + "dev": true, + "dependencies": { + "chalk": "~5.3.0", + "commander": "~12.1.0", + "debug": "~4.3.4", + "execa": "~8.0.1", + "lilconfig": "~3.1.1", + "listr2": "~8.2.1", + "micromatch": "~4.0.7", + "pidtree": "~0.6.0", + "string-argv": "~0.3.2", + "yaml": "~2.4.2" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/lint-staged/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } + "optional": true } } }, - "listr": { - "version": "0.14.3", - "resolved": "https://registry.npmjs.org/listr/-/listr-0.14.3.tgz", - "integrity": "sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==", - "dev": true, - "requires": { - "@samverschueren/stream-to-observable": "^0.3.0", - "is-observable": "^1.1.0", - "is-promise": "^2.1.0", - "is-stream": "^1.1.0", - "listr-silent-renderer": "^1.1.1", - "listr-update-renderer": "^0.5.0", - "listr-verbose-renderer": "^0.5.0", - "p-map": "^2.0.0", - "rxjs": "^6.3.3" - }, - "dependencies": { - "p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", - "dev": true - } + "node_modules/listr2": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.3.tgz", + "integrity": "sha512-Lllokma2mtoniUOS94CcOErHWAug5iu7HOmDrvWgpw8jyQH2fomgB+7lZS4HWZxytUuQwkGOwe49FvwVaA85Xw==", + "dev": true, + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.0.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/listr2/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/listr2/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/listr2/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "dev": true + }, + "node_modules/listr2/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/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/listr2/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/load-bmfont": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.2.tgz", + "integrity": "sha512-qElWkmjW9Oq1F9EI5Gt7aD9zcdHb9spJCW1L/dmPf7KzCCEJxq8nhHz5eCgI9aMf7vrG/wyaCqdsI+Iy9ZTlog==", + "dependencies": { + "buffer-equal": "0.0.1", + "mime": "^1.3.4", + "parse-bmfont-ascii": "^1.0.3", + "parse-bmfont-binary": "^1.0.5", + "parse-bmfont-xml": "^1.1.4", + "phin": "^3.7.1", + "xhr": "^2.0.1", + "xtend": "^4.0.0" + } + }, + "node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.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.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, + "node_modules/lodash.map": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", + "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=", + "dev": true + }, + "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/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "dev": true, + "optional": true + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true, + "optional": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "listr-silent-renderer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", - "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", - "dev": true - }, - "listr-update-renderer": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz", - "integrity": "sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA==", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "cli-truncate": "^0.2.1", - "elegant-spinner": "^1.0.1", - "figures": "^1.7.0", - "indent-string": "^3.0.0", - "log-symbols": "^1.0.2", - "log-update": "^2.3.0", - "strip-ansi": "^3.0.1" - }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "dependencies": { - "log-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", - "dev": true, - "requires": { - "chalk": "^1.0.0" - } - } + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "listr-verbose-renderer": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz", - "integrity": "sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw==", + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "requires": { - "chalk": "^2.4.1", - "cli-cursor": "^2.1.0", - "date-fns": "^1.27.2", - "figures": "^2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "engines": { + "node": ">=8" } }, - "load-bmfont": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.0.tgz", - "integrity": "sha512-kT63aTAlNhZARowaNYcY29Fn/QYkc52M3l6V1ifRcPewg2lvUZDAj7R6dXjOL9D0sict76op3T5+odumDSF81g==", - "requires": { - "buffer-equal": "0.0.1", - "mime": "^1.3.4", - "parse-bmfont-ascii": "^1.0.3", - "parse-bmfont-binary": "^1.0.5", - "parse-bmfont-xml": "^1.1.4", - "phin": "^2.9.1", - "xhr": "^2.0.1", - "xtend": "^4.0.0" + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "node_modules/log-update": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.0.0.tgz", + "integrity": "sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==", "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" + "dependencies": { + "ansi-escapes": "^6.2.0", + "cli-cursor": "^4.0.0", + "slice-ansi": "^7.0.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "node_modules/log-update/node_modules/ansi-escapes": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", + "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "engines": { + "node": ">=14.16" }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" - }, - "lodash._basecopy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", - "dev": true + "node_modules/log-update/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" + } }, - "lodash._basetostring": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", - "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=", - "dev": true + "node_modules/log-update/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" + } }, - "lodash._basevalues": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", - "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", - "dev": true + "node_modules/log-update/node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "dev": true, + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", "dev": true }, - "lodash._isiterateecall": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", - "dev": true + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", + "dev": true, + "dependencies": { + "get-east-asian-width": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "lodash._reescape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", - "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=", - "dev": true + "node_modules/log-update/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } }, - "lodash._reevaluate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", - "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", - "dev": true + "node_modules/log-update/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", - "dev": true + "node_modules/log-update/node_modules/restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "lodash._root": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", + "node_modules/log-update/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, - "lodash.escape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", - "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", + "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", "dev": true, - "requires": { - "lodash._root": "^3.0.0" + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + "node_modules/log-update/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", - "dev": true + "node_modules/log-update/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" + } }, - "lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", - "dev": true + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } }, - "lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "node_modules/longest": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-2.0.1.tgz", + "integrity": "sha512-Ajzxb8CM6WAnFjgiloPsI3bF+WCxcvhdIG3KNA2KN962+tdBsHcuQ4k4qX/EcS/2CRkcc0iAkR956Nib6aXU/Q==", "dev": true, - "requires": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" + "engines": { + "node": ">=0.10.0" } }, - "lodash.map": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", - "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=", - "dev": true + "node_modules/make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } }, - "lodash.noop": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash.noop/-/lodash.noop-3.0.1.tgz", - "integrity": "sha1-OBiPTWUKOkdCWEObluxFsyYXEzw=" + "node_modules/make-iterator/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "lodash.reduce": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz", - "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs=" + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", + "dev": true, + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "lodash.restparam": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", - "dev": true + "node_modules/matchdep": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", + "integrity": "sha512-LFgVbaHIHMqCRuCZyfCtUOq9/Lnzhi7Z0KFUE2fhD54+JN2jLh3hC02RLkqauJ3U4soU6H1J3tfj/Byk7GoEjA==", + "dev": true, + "dependencies": { + "findup-sync": "^2.0.0", + "micromatch": "^3.0.4", + "resolve": "^1.4.0", + "stack-trace": "0.0.10" + }, + "engines": { + "node": ">= 0.10.0" + } }, - "lodash.template": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", - "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", - "dev": true, - "requires": { - "lodash._basecopy": "^3.0.0", - "lodash._basetostring": "^3.0.0", - "lodash._basevalues": "^3.0.0", - "lodash._isiterateecall": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0", - "lodash.keys": "^3.0.0", - "lodash.restparam": "^3.0.0", - "lodash.templatesettings": "^3.0.0" - } - }, - "lodash.templatesettings": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", - "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", + "node_modules/matchdep/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, - "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0" + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "node_modules/matchdep/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, - "requires": { - "chalk": "^2.0.1" + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "dev": true, "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "log-update": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", - "integrity": "sha1-iDKP19HOeTiykoN0bwsbwSayRwg=", + "node_modules/matchdep/node_modules/findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha512-vs+3unmJT45eczmcAZ6zMJtxN3l/QXeccaXQx5cu/MeJMhewVfoWZqibRkOxPnmoR59+Zy5hjabfQc6JLSah4g==", "dev": true, - "requires": { - "ansi-escapes": "^3.0.0", - "cli-cursor": "^2.0.0", - "wrap-ansi": "^3.0.1" + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/matchdep/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, "dependencies": { - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - } + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" } }, - "longest": { + "node_modules/matchdep/node_modules/is-extendable": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "dev": true + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true + "node_modules/matchdep/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "node_modules/matchdep/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "node_modules/matchdep/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, - "requires": { - "pify": "^3.0.0" + "dependencies": { + "is-buffer": "^1.1.5" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "make-iterator": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "node_modules/matchdep/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, - "requires": { - "kind-of": "^6.0.2" + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/micromatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "node_modules/matchdep/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", "dev": true, - "requires": { - "object-visit": "^1.0.0" + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "math-random": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", - "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==", - "dev": true - }, - "md5": { + "node_modules/md5": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=", - "requires": { + "dependencies": { "charenc": "~0.0.1", "crypt": "~0.0.1", "is-buffer": "~1.1.1" } }, - "media-typer": { + "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } }, - "memory-pager": { + "node_modules/memory-pager": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", - "optional": true + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" }, - "merge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", - "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==", + "node_modules/merge": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", + "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", "dev": true }, - "merge-descriptors": { + "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, - "methods": { + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "dev": true, - "requires": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" - } - }, - "mime": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", - "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=" - }, - "mime-db": { - "version": "1.42.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz", - "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==" - }, - "mime-types": { - "version": "2.1.25", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz", - "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==", - "requires": { - "mime-db": "1.42.0" - } - }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } }, - "min-document": { + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/min-document": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", - "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", - "requires": { + "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", + "dependencies": { "dom-walk": "^0.1.0" } }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "requires": { + "dependencies": { "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "mixin-deep": { + "node_modules/mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, - "requires": { + "dependencies": { "for-in": "^1.0.2", "is-extendable": "^1.0.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" } }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" + "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": "*" } }, - "moment": { - "version": "2.18.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz", - "integrity": "sha1-w2GT3Tzhwu7SrbfIAtu8d6gbHA8=" + "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": "*" + } }, - "moment-timezone": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.21.tgz", - "integrity": "sha512-j96bAh4otsgj3lKydm3K7kdtA3iKf2m6MY2iSYCzCm5a1zmHo1g+aK3068dDEeocLZQIS9kU8bsdQHLqEvgW0A==", - "requires": { - "moment": ">= 2.9.0" + "node_modules/mongodb-connection-string-url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz", + "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==", + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^13.0.0" } }, - "mongodb": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.1.6.tgz", - "integrity": "sha512-E5QJuXQoMlT7KyCYqNNMfAkhfQD79AT4F8Xd+6x37OX+8BL17GyXyWvfm6wuyx4wnzCCPoCSLeMeUN2S7dU9yw==", - "requires": { - "mongodb-core": "3.1.5", - "safe-buffer": "^5.1.2" + "node_modules/mongodb-connection-string-url/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" } }, - "mongodb-core": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.1.5.tgz", - "integrity": "sha512-emT/tM4ZBinqd6RZok+EzDdtN4LjYJIckv71qQVOEFmvXgT5cperZegVmTgox/1cx4XQu6LJ5ZuIwipP/eKdQg==", - "requires": { - "bson": "^1.1.0", - "require_optional": "^1.0.1", - "safe-buffer": "^5.1.2", - "saslprep": "^1.0.0" + "node_modules/mongodb-connection-string-url/node_modules/tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dependencies": { + "punycode": "^2.3.0" }, + "engines": { + "node": ">=14" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/whatwg-url": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", "dependencies": { - "bson": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.3.tgz", - "integrity": "sha512-TdiJxMVnodVS7r0BdL42y/pqC9cL2iKynVwA0Ho3qbsQYr428veL3l7BQyuqiw+Q5SqqoT0m4srSY/BlZ9AxXg==" - } + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=16" } }, - "mongodb-uri": { + "node_modules/mongodb-uri": { "version": "0.9.7", "resolved": "https://registry.npmjs.org/mongodb-uri/-/mongodb-uri-0.9.7.tgz", - "integrity": "sha1-D3ca0W9IOuZfQoeWlCjp+8SqYYE=" + "integrity": "sha1-D3ca0W9IOuZfQoeWlCjp+8SqYYE=", + "engines": { + "node": ">= 0.6.0" + } }, - "mongoose": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.3.2.tgz", - "integrity": "sha512-07fpCMqvCiSdKXIygt3aAeNFJYjQPjDXILbwBEmF0e8gy2hSKMNuP5QG4J6L8m9BhjVxcvoLiPzaGKN7I/7lLg==", - "requires": { - "async": "2.6.1", - "bson": "~1.0.5", - "kareem": "2.3.0", - "lodash.get": "4.4.2", - "mongodb": "3.1.6", - "mongodb-core": "3.1.5", - "mongoose-legacy-pluralize": "1.0.2", - "mpath": "0.5.1", - "mquery": "3.2.0", - "ms": "2.0.0", - "regexp-clone": "0.0.1", - "safe-buffer": "5.1.2", - "sliced": "1.0.1" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } + "node_modules/mongoose": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.5.1.tgz", + "integrity": "sha512-OhVcwVl91A1G6+XpjDcpkGP7l7ikZkxa0DylX7NT/lcEqAjggzSdqDxb48A+xsDxqNAr0ntSJ1yiE3+KJTOd5Q==", + "dependencies": { + "bson": "^6.7.0", + "kareem": "2.6.3", + "mongodb": "6.7.0", + "mpath": "0.9.0", + "mquery": "5.0.0", + "ms": "2.1.3", + "sift": "17.1.3" + }, + "engines": { + "node": ">=16.20.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mongoose" } }, - "mongoose-legacy-pluralize": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz", - "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==" - }, - "morgan": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.8.2.tgz", - "integrity": "sha1-eErHc05KRTqcbm6GgKkyknXItoc=", - "requires": { - "basic-auth": "~1.1.0", - "debug": "2.6.8", - "depd": "~1.1.0", - "on-finished": "~2.3.0", - "on-headers": "~1.0.1" + "node_modules/mongoose/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "optional": true, + "peer": true, + "dependencies": { + "debug": "4" }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/mongoose/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "optional": true, + "peer": true, "dependencies": { - "debug": { - "version": "2.6.8", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", - "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true } } }, - "mpath": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.5.1.tgz", - "integrity": "sha512-H8OVQ+QEz82sch4wbODFOz+3YQ61FYz/z3eJ5pIdbMEaUzDqA268Wd+Vt4Paw9TJfvDgVKaayC0gBzMIw2jhsg==" + "node_modules/mongoose/node_modules/debug/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==", + "optional": true, + "peer": true }, - "mquery": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.0.tgz", - "integrity": "sha512-qPJcdK/yqcbQiKoemAt62Y0BAc0fTEKo1IThodBD+O5meQRJT/2HSe5QpBNwaa4CjskoGrYWsEyjkqgiE0qjhg==", - "requires": { - "bluebird": "3.5.1", - "debug": "3.1.0", - "regexp-clone": "0.0.1", - "safe-buffer": "5.1.2", - "sliced": "1.0.1" + "node_modules/mongoose/node_modules/gaxios": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz", + "integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==", + "optional": true, + "peer": true, + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9" }, + "engines": { + "node": ">=12" + } + }, + "node_modules/mongoose/node_modules/gcp-metadata": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz", + "integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==", + "optional": true, + "peer": true, "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } + "gaxios": "^5.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/mongoose/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "optional": true, + "peer": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/mongoose/node_modules/mongodb": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.7.0.tgz", + "integrity": "sha512-TMKyHdtMcO0fYBNORiYdmM25ijsHs+Njs963r4Tro4OQZzqYigAzYQouwWRg4OIaiLRUEGUh/1UAcH5lxdSLIA==", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.5", + "bson": "^6.7.0", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "socks": { + "optional": true + } + } + }, + "node_modules/mongoose/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "dependencies": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/mpath": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", + "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mquery": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", + "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", + "dependencies": { + "debug": "4.x" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/mquery/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true } } }, - "ms": { + "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==" }, - "multer": { + "node_modules/multer": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/multer/-/multer-1.3.0.tgz", - "integrity": "sha1-CSsmcPaEb6SRSWXvyM+Uwg/sbNI=", - "requires": { + "integrity": "sha512-wbAkTsh0QXkvqvHCU2qSLEXLuRN7IKMEe80+JrXfJzANniPNgrNcDOMKfGgR1EhL7y7MHIbODVwT7uaVY20ggw==", + "deprecated": "Multer 1.x is affected by CVE-2022-24434. This is fixed in v1.4.4-lts.1 which drops support for versions of Node.js before 6. Please upgrade to at least Node.js 6 and version 1.4.4-lts.1 of Multer. If you need support for older versions of Node.js, we are open to accepting patches that would fix the CVE on the main 1.x release line, whilst maintaining compatibility with Node.js 0.10.", + "dependencies": { "append-field": "^0.1.0", "busboy": "^0.2.11", "concat-stream": "^1.5.0", @@ -6534,42 +7829,46 @@ "type-is": "^1.6.4", "xtend": "^4.0.0" }, - "dependencies": { - "object-assign": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=" - } + "engines": { + "node": ">= 0.10.0" } }, - "multipipe": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", - "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", + "node_modules/multer/node_modules/object-assign": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", + "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mute-stdout": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-2.0.0.tgz", + "integrity": "sha512-32GSKM3Wyc8dg/p39lWPKYu8zci9mJFzV1Np9Of0ZEpe6Fhssn/FbI7ywAMd40uX+p3ZKh3T5EeCFv81qS3HmQ==", "dev": true, - "requires": { - "duplexer2": "0.0.2" + "engines": { + "node": ">= 10.13.0" } }, - "mute-stream": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.6.tgz", - "integrity": "sha1-SJYrGeFp/R38JAs/HnMXYnu8R9s=", + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "node_modules/nan": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz", + "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==", "dev": true, "optional": true }, - "nanomatch": { + "node_modules/nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, - "requires": { + "dependencies": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", "define-property": "^2.0.2", @@ -6582,1904 +7881,1872 @@ "snapdragon": "^0.8.1", "to-regex": "^3.0.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "natives": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.6.tgz", - "integrity": "sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA==", - "dev": true + "node_modules/nanomatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/nanomatch/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } }, - "natural-compare": { + "node_modules/nanomatch/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } }, - "nocache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/nocache/-/nocache-2.0.0.tgz", - "integrity": "sha1-ICtIAhoMTL3i34DeFaF0Q8i0OYA=" + "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-fetch": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz", - "integrity": "sha1-3CNO3WSJmC1Y6PDbT2lQKavNjAQ=", - "dev": true, - "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } } }, - "node-forge": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.6.tgz", - "integrity": "sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw==" - }, - "nodemailer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-4.0.1.tgz", - "integrity": "sha1-uVhksH+s7oKH6CMu/9bx1W7HWrI=" + "node_modules/nodemailer": { + "version": "6.9.14", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.14.tgz", + "integrity": "sha512-Dobp/ebDKBvz91sbtRKhcznLThrKxKt97GI2FAlAyy+fk19j73Uz3sBXolVtmcXjaorivqsbbbjDY+Jkt4/bQA==", + "engines": { + "node": ">=6.0.0" + } }, - "nodemon": { - "version": "1.19.4", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.19.4.tgz", - "integrity": "sha512-VGPaqQBNk193lrJFotBU8nvWZPqEZY2eIzymy2jjY0fJ9qIsxA0sxQ8ATPl0gZC645gijYEc1jtZvpS8QWzJGQ==", + "node_modules/nodemon": { + "version": "2.0.22", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", + "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", "dev": true, - "requires": { - "chokidar": "^2.1.8", - "debug": "^3.2.6", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", - "pstree.remy": "^1.1.7", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", "supports-color": "^5.5.0", "touch": "^3.1.0", - "undefsafe": "^2.0.2", - "update-notifier": "^2.5.0" + "undefsafe": "^2.0.5" }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" } }, - "nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "requires": { - "abbrev": "1" + "dependencies": { + "ms": "^2.1.1" } }, - "normalize-package-data": { + "node_modules/normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, - "requires": { + "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" } }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" + "engines": { + "node": ">=0.10.0" } }, - "now": { + "node_modules/now": { "version": "11.4.6", "resolved": "https://registry.npmjs.org/now/-/now-11.4.6.tgz", - "integrity": "sha512-5SMS8lVuCzqD55CPQlGcjvOJJJPuDSLoqKIIGR4uEooCbDhHl//dHZmBpT1uLSwT1MYvhYUMf9OpFQRwXG4KEg==" + "integrity": "sha512-5SMS8lVuCzqD55CPQlGcjvOJJJPuDSLoqKIIGR4uEooCbDhHl//dHZmBpT1uLSwT1MYvhYUMf9OpFQRwXG4KEg==", + "deprecated": "\"now\" is deprecated and will stop receiving updates on December 31, 2020. Please use \"vercel\" instead.", + "hasInstallScript": true, + "bin": { + "now": "download/dist/now" + } }, - "npm-path": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/npm-path/-/npm-path-2.0.4.tgz", - "integrity": "sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw==", + "node_modules/now-and-later": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-3.0.0.tgz", + "integrity": "sha512-pGO4pzSdaxhWTGkfSfHx3hVzJVslFPwBp2Myq9MYN/ChfJZF87ochMAXnvz6/58RJSf5ik2q9tXprBBrk2cpcg==", "dev": true, - "requires": { - "which": "^1.2.10" + "dependencies": { + "once": "^1.4.0" + }, + "engines": { + "node": ">= 10.13.0" } }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", "dev": true, - "requires": { - "path-key": "^2.0.0" + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "npm-which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-which/-/npm-which-3.0.1.tgz", - "integrity": "sha1-kiXybsOihcIJyuZ8OxGmtKtxQKo=", + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "dev": true, - "requires": { - "commander": "^2.9.0", - "npm-path": "^2.0.2", - "which": "^1.2.10" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "number-is-nan": { + "node_modules/number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "object-assign": { + "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } }, - "object-copy": { + "node_modules/object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", "dev": true, - "requires": { + "dependencies": { "copy-descriptor": "^0.1.0", "define-property": "^0.2.5", "kind-of": "^3.0.3" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" } }, - "object-visit": { + "node_modules/object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", "dev": true, - "requires": { + "dependencies": { "isobject": "^3.0.0" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "object.defaults": { + "node_modules/object.defaults": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", "dev": true, - "requires": { + "dependencies": { "array-each": "^1.0.1", "array-slice": "^1.0.0", "for-own": "^1.0.0", "isobject": "^3.0.0" }, - "dependencies": { - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "dev": true, - "requires": { - "for-in": "^1.0.1" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } + "engines": { + "node": ">=0.10.0" } }, - "object.map": { + "node_modules/object.map": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==", "dev": true, - "requires": { + "dependencies": { "for-own": "^1.0.0", "make-iterator": "^1.0.0" }, - "dependencies": { - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "dev": true, - "requires": { - "for-in": "^1.0.1" - } - } - } - }, - "object.omit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", - "dev": true, - "requires": { - "for-own": "^0.1.4", - "is-extendable": "^0.1.1" + "engines": { + "node": ">=0.10.0" } }, - "object.pick": { + "node_modules/object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", "dev": true, - "requires": { + "dependencies": { "isobject": "^3.0.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.reduce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", + "integrity": "sha512-naLhxxpUESbNkRqc35oQ2scZSJueHGQNUfMW/0U37IgN6tE2dgDWg3whf+NEliy3F/QysrO48XKUz/nGPe+AQw==", + "dev": true, "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "on-finished": { + "node_modules/omggif": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/omggif/-/omggif-1.0.10.tgz", + "integrity": "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==" + }, + "node_modules/on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { + "dependencies": { "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" } }, - "on-headers": { + "node_modules/on-headers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } }, - "once": { + "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, - "requires": { + "dependencies": { "wrappy": "1" } }, - "onetime": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", - "dev": true - }, - "opencollective": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/opencollective/-/opencollective-1.0.3.tgz", - "integrity": "sha1-ruY3K8KBRFg2kMPKja7PwSDdDvE=", - "dev": true, - "requires": { - "babel-polyfill": "6.23.0", - "chalk": "1.1.3", - "inquirer": "3.0.6", - "minimist": "1.2.0", - "node-fetch": "1.6.3", - "opn": "4.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "external-editor": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", - "dev": true, - "requires": { - "chardet": "^0.4.0", - "iconv-lite": "^0.4.17", - "tmp": "^0.0.33" - } - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "inquirer": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.0.6.tgz", - "integrity": "sha1-4EqqnQW3o8ubD0B9BDdfBEcZA0c=", - "dev": true, - "requires": { - "ansi-escapes": "^1.1.0", - "chalk": "^1.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^2.0.1", - "figures": "^2.0.0", - "lodash": "^4.3.0", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rx": "^4.1.0", - "string-width": "^2.0.0", - "strip-ansi": "^3.0.0", - "through": "^2.3.6" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - } + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "opn": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz", - "integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=", + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, - "requires": { - "object-assign": "^4.0.1", - "pinkie-promise": "^2.0.0" + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" } }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "orchestrator": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/orchestrator/-/orchestrator-0.3.8.tgz", - "integrity": "sha1-FOfp4nZPcxX7rBhOUGx6pt+UrX4=", + "node_modules/ora/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "requires": { - "end-of-stream": "~0.1.5", - "sequencify": "~0.0.7", - "stream-consume": "~0.1.0" + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "ordered-read-streams": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz", - "integrity": "sha1-/VZamvjrRHO6abbtijQ1LLVS8SY=", - "dev": true + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true + "node_modules/ora/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } }, - "os-shim": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz", - "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=", + "node_modules/ora/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true + "node_modules/ora/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true + "node_modules/ora/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "node_modules/ordered-read-streams": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", + "integrity": "sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==", "dev": true, - "requires": { - "p-try": "^1.0.0" + "dependencies": { + "readable-stream": "^2.0.1" } }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "node_modules/ordered-read-streams/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "requires": { - "p-limit": "^1.1.0" + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "p-map": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", - "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", + "node_modules/ordered-read-streams/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true + "node_modules/ordered-read-streams/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } }, - "package-json": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", - "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", + "node_modules/os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", "dev": true, - "requires": { - "got": "^6.7.1", - "registry-auth-token": "^3.0.1", - "registry-url": "^3.0.3", - "semver": "^5.1.0" + "dependencies": { + "lcid": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "pad-right": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/pad-right/-/pad-right-0.2.2.tgz", - "integrity": "sha1-b7ySQEXSRPKiokRQMGDTv8YAl3Q=", + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, - "requires": { - "repeat-string": "^1.5.2" + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "parse-bmfont-ascii": { + "node_modules/parse-bmfont-ascii": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz", - "integrity": "sha1-Eaw8P/WPfCAgqyJ2kHkQjU36AoU=" + "integrity": "sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA==" }, - "parse-bmfont-binary": { + "node_modules/parse-bmfont-binary": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/parse-bmfont-binary/-/parse-bmfont-binary-1.0.6.tgz", - "integrity": "sha1-0Di0dtPp3Z2x4RoLDlOiJ5K2kAY=" + "integrity": "sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA==" }, - "parse-bmfont-xml": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/parse-bmfont-xml/-/parse-bmfont-xml-1.1.4.tgz", - "integrity": "sha512-bjnliEOmGv3y1aMEfREMBJ9tfL3WR0i0CKPj61DnSLaoxWR3nLrsQrEbCId/8rF4NyRF0cCqisSVXyQYWM+mCQ==", - "requires": { + "node_modules/parse-bmfont-xml": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/parse-bmfont-xml/-/parse-bmfont-xml-1.1.6.tgz", + "integrity": "sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA==", + "dependencies": { "xml-parse-from-string": "^1.0.0", - "xml2js": "^0.4.5" + "xml2js": "^0.5.0" + } + }, + "node_modules/parse-bmfont-xml/node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" } }, - "parse-filepath": { + "node_modules/parse-filepath": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", "dev": true, - "requires": { + "dependencies": { "is-absolute": "^1.0.0", "map-cache": "^0.2.0", "path-root": "^0.1.1" + }, + "engines": { + "node": ">=0.8" } }, - "parse-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "dev": true, - "requires": { - "glob-base": "^0.3.0", - "is-dotfile": "^1.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.0" - } - }, - "parse-headers": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.3.tgz", - "integrity": "sha512-QhhZ+DCCit2Coi2vmAKbq5RGTRcQUOE2+REgv8vdyu7MnYx2eZztegqtTx99TZ86GTIwqiy3+4nQTWZ2tgmdCA==" + "node_modules/parse-headers": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", + "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==" }, - "parse-json": { + "node_modules/parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", "dev": true, - "requires": { + "dependencies": { "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "parse-node-version": { + "node_modules/parse-node-version": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.10" + } }, - "parse-passwd": { + "node_modules/parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "dev": true + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "parseurl": { + "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } }, - "pascalcase": { + "node_modules/pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "path-dirname": { + "node_modules/path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", "dev": true }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" + "engines": { + "node": ">=8" } }, - "path-is-absolute": { + "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "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 }, - "path-root": { + "node_modules/path-root": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", "dev": true, - "requires": { + "dependencies": { "path-root-regex": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "path-root-regex": { + "node_modules/path-root-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", - "dev": true + "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "path-to-regexp": { + "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=" }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "node_modules/path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", "dev": true, - "requires": { - "pify": "^2.0.0" + "dependencies": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", - "dev": true, - "requires": { - "through": "~2.3" + "node_modules/peek-readable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz", + "integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==", + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" } }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + "node_modules/phin": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/phin/-/phin-3.7.1.tgz", + "integrity": "sha512-GEazpTWwTZaEQ9RhL7Nyz0WwqilbqgLahDM3D0hxWwmVDI52nXEybHqiN6/elwpkJBhcuj+WbBu+QfT0uhPGfQ==", + "dependencies": { + "centra": "^2.7.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true, + "optional": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, - "phin": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/phin/-/phin-2.9.3.tgz", - "integrity": "sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA==" + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } }, - "pify": { + "node_modules/pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "pinkie": { + "node_modules/pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "pinkie-promise": { + "node_modules/pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", "dev": true, - "requires": { + "dependencies": { "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "pixelmatch": { + "node_modules/pixelmatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz", - "integrity": "sha1-j0fc7FARtHe2fbA8JDvB8wheiFQ=", - "requires": { + "integrity": "sha512-J8B6xqiO37sU/gkcMglv6h5Jbd9xNER7aHzpfRdNmV4IbQBzBpe4l9XmbG+xPF/znacgu2jfEw+wHffaq/YkXA==", + "dependencies": { "pngjs": "^3.0.0" + }, + "bin": { + "pixelmatch": "bin/pixelmatch" } }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "requires": { - "find-up": "^2.1.0" - } - }, - "platform": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.4.tgz", - "integrity": "sha1-bw+xftqqSPIUQrOpdcBjEw8cPr0=" - }, - "please-upgrade-node": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", - "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", - "dev": true, - "requires": { - "semver-compare": "^1.0.0" - } - }, - "pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", - "dev": true - }, - "pngjs": { + "node_modules/pixelmatch/node_modules/pngjs": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", - "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==" + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", + "engines": { + "node": ">=4.0.0" + } }, - "posix-character-classes": { + "node_modules/pngjs": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", + "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", - "dev": true + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "preserve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", - "dev": true + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "engines": { + "node": ">= 0.4" + } }, - "prettier": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.14.2.tgz", - "integrity": "sha512-McHPg0n1pIke+A/4VcaS2en+pTNjy4xF+Uuq86u/5dyDO59/TtFZtQ708QIRkEZ3qwKz3GVkVa6mpxK/CpB8Rg==", - "dev": true + "node_modules/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, + "engines": { + "node": ">= 0.8.0" + } }, - "pretty-format": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", - "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", + "node_modules/prettier": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true, - "requires": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" + "bin": { + "prettier": "bin/prettier.cjs" }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - } + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "pretty-hrtime": { + "node_modules/pretty-hrtime": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", - "dev": true + "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", + "dev": true, + "engines": { + "node": ">= 0.8" + } }, - "process": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz", - "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=" + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "engines": { + "node": ">= 0.6.0" + } }, - "process-nextick-args": { + "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", "dev": true }, - "proxy-addr": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.5.tgz", - "integrity": "sha1-ccDuOxAt4/IC87ZPYI0XP8uhqRg=", - "requires": { - "forwarded": "~0.1.0", - "ipaddr.js": "1.4.0" + "node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true + "node_modules/pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "dependencies": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } }, - "psl": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.5.0.tgz", - "integrity": "sha512-4vqUjKi2huMu1OJiLhi3jN6jeeKvMZdI1tYgi/njW5zV52jNLgSAZSdN16m9bJFe61/cT8ulmw4qFitV9QRsEA==" + "node_modules/pumpify/node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/pumpify/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } }, - "pstree.remy": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.7.tgz", - "integrity": "sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==", + "node_modules/pumpify/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "punycode": { + "node_modules/pumpify/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" }, - "qs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", - "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "querystring": { + "node_modules/querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" + } }, - "randomatic": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", - "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, - "requires": { - "is-number": "^4.0.0", - "kind-of": "^6.0.0", - "math-random": "^1.0.1" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true + { + "type": "consulting", + "url": "https://feross.org/support" } - } + ] + }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true + }, + "node_modules/randombytes": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.3.tgz", + "integrity": "sha512-lDVjxQQFoCG1jcrP06LNo2lbWp4QTShEXnhActFBwYuHprllQV6VUpwreApsYqCgD+N1mHoqJ/BI/4eV4R2GYg==" }, - "randomstring": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/randomstring/-/randomstring-1.1.5.tgz", - "integrity": "sha1-bfBij3XL1ZMpMNn+OrTpVqGFGMM=", - "requires": { - "array-uniq": "1.0.2" + "node_modules/randomstring": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/randomstring/-/randomstring-1.3.0.tgz", + "integrity": "sha512-gY7aQ4i1BgwZ8I1Op4YseITAyiDiajeZOPQUbIq9TPGPhUm5FX59izIaOpmKbME1nmnEiABf28d9K2VSii6BBg==", + "dependencies": { + "randombytes": "2.0.3" + }, + "bin": { + "randomstring": "bin/randomstring" + }, + "engines": { + "node": "*" } }, - "range-parser": { + "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } }, - "raven": { + "node_modules/raven": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/raven/-/raven-2.6.0.tgz", "integrity": "sha1-OAaoLJ7ozT51w7fqe7GTWq0JLQw=", - "requires": { + "deprecated": "Please upgrade to @sentry/node. See the migration guide https://bit.ly/3ybOlo7", + "dependencies": { "cookie": "0.3.1", "md5": "^2.2.1", "stack-trace": "0.0.10", "timed-out": "4.0.1", "uuid": "3.0.0" }, - "dependencies": { - "uuid": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.0.tgz", - "integrity": "sha1-Zyj8BFnEUNeWqZwxg3VpvfZy1yg=" - } + "bin": { + "raven": "bin/raven" + }, + "engines": { + "node": ">= 4.0.0" } }, - "raw-body": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.2.0.tgz", - "integrity": "sha1-mUl2z2pQlqQRYoQEkvC9xdbn+5Y=", - "requires": { - "bytes": "2.4.0", - "iconv-lite": "0.4.15", - "unpipe": "1.0.0" + "node_modules/raven/node_modules/uuid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.0.tgz", + "integrity": "sha1-Zyj8BFnEUNeWqZwxg3VpvfZy1yg=", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" } }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" } }, - "read-chunk": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-1.0.1.tgz", - "integrity": "sha1-X2jKswfmY/GZk1J9m1icrORmEZQ=" - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "node_modules/read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", "dev": true, - "requires": { - "load-json-file": "^2.0.0", + "dependencies": { + "load-json-file": "^1.0.0", "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" + "path-type": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "node_modules/read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" + "dependencies": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "readable-stream": { + "node_modules/readable-stream": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { + "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", "isarray": "0.0.1", "string_decoder": "~0.10.x" - }, + } + }, + "node_modules/readable-stream/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "node_modules/readable-web-to-node-stream": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", + "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - } + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" } }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" + "node_modules/readable-web-to-node-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readable-web-to-node-stream/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + "safe-buffer": "~5.2.0" } }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, - "requires": { - "resolve": "^1.1.6" + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" } }, - "referrer-policy": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.1.0.tgz", - "integrity": "sha1-NXdOtzW/UPtsB46DM0tHI1AgfXk=" - }, - "regenerator-runtime": { - "version": "0.10.5", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", - "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=", - "dev": true - }, - "regex-cache": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", "dev": true, - "requires": { - "is-equal-shallow": "^0.1.3" + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" } }, - "regex-not": { + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "node_modules/regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, - "requires": { + "dependencies": { "extend-shallow": "^3.0.2", "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "regexp-clone": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-0.0.1.tgz", - "integrity": "sha1-p8LgmJH9vzj7sQ03b7cwA+aKxYk=" + "node_modules/regex-not/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } }, - "regexpp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", - "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", - "dev": true + "node_modules/regex-not/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } }, - "registry-auth-token": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", - "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", + "node_modules/regex-not/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, - "requires": { - "rc": "^1.1.6", - "safe-buffer": "^5.0.1" + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "registry-url": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", - "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", + "node_modules/remove-bom-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", + "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5", + "is-utf8": "^0.2.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/remove-bom-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", + "integrity": "sha512-wigO8/O08XHb8YPzpDDT+QmRANfW6vLqxfaXm1YXhnFf3AkSLyjfG3GEFg4McZkmgL7KvCj5u2KczkvSP6NfHA==", "dev": true, - "requires": { - "rc": "^1.0.1" + "dependencies": { + "remove-bom-buffer": "^3.0.0", + "safe-buffer": "^5.1.0", + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" } }, - "remove-trailing-separator": { + "node_modules/remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", "dev": true }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true + "node_modules/repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "repeat-string": { + "node_modules/repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "engines": { + "node": ">=0.10" + } }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "node_modules/replace-ext": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz", + "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==", "dev": true, - "requires": { - "is-finite": "^1.0.0" + "engines": { + "node": ">= 10" } }, - "replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", - "dev": true + "node_modules/replace-homedir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-2.0.0.tgz", + "integrity": "sha512-bgEuQQ/BHW0XkkJtawzrfzHFSN70f/3cNOiHa2QsYxqrjaC30X1k74FJ6xswVBP0sr0SpGIdVFuPwfrYziVeyw==", + "dev": true, + "engines": { + "node": ">= 10.13.0" + } }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" - }, - "uuid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", - "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" - } + "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" } }, - "require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true, - "requires": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", - "dev": true - } + "optional": true, + "engines": { + "node": ">=0.10.0" } }, - "require_optional": { + "node_modules/require-main-filename": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", - "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", - "requires": { - "resolve-from": "^2.0.0", - "semver": "^5.1.0" + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", + "dev": true + }, + "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" } }, - "resolve": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.13.1.tgz", - "integrity": "sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w==", + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", "dev": true, - "requires": { - "path-parse": "^1.0.6" + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "resolve-dir": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz", - "integrity": "sha1-shklmlYC+sXFxJatiUpujMQwJh4=", + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, - "requires": { - "expand-tilde": "^1.2.2", - "global-modules": "^0.2.3" + "optional": true, + "engines": { + "node": ">=8" } }, - "resolve-from": { + "node_modules/resolve-options": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", - "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" + "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-2.0.0.tgz", + "integrity": "sha512-/FopbmmFOQCfsCx77BRFdKOniglTiHumLgwvd6IDPihy1GKkadZbgQJBcTb2lMzSR1pndzd96b1nZrreZ7+9/A==", + "dev": true, + "dependencies": { + "value-or-function": "^4.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } }, - "resolve-url": { + "node_modules/resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", + "deprecated": "https://github.com/lydell/resolve-url#deprecated", "dev": true }, - "restore-cursor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/restore-cursor/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, - "requires": { - "exit-hook": "^1.0.0", - "onetime": "^1.0.0" + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "ret": { + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, - "right-pad": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/right-pad/-/right-pad-1.0.1.tgz", - "integrity": "sha1-jKCMLLtbVedNr6lr9/0aJ9VoyNA=", - "dev": true - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - }, - "dependencies": { - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } + "dev": true, + "engines": { + "node": ">=0.12" } }, - "run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, - "requires": { - "is-promise": "^2.1.0" + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" } }, - "run-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz", - "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==", - "dev": true - }, - "rx": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", - "integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=", + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "dev": true }, - "rx-lite": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", - "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", - "dev": true + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } }, - "rx-lite-aggregates": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", - "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, - "requires": { - "rx-lite": "*" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" } }, - "rxjs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", - "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, - "requires": { - "tslib": "^1.9.0" + "dependencies": { + "tslib": "^2.1.0" } }, - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "safe-regex": { + "node_modules/safe-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", "dev": true, - "requires": { + "dependencies": { "ret": "~0.1.10" } }, - "safer-buffer": { + "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "saslprep": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", - "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", - "optional": true, - "requires": { - "sparse-bitfield": "^3.0.3" - } - }, - "sax": { + "node_modules/sax": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } }, - "semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", - "dev": true + "node_modules/semver-greatest-satisfied-range": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-2.0.0.tgz", + "integrity": "sha512-lH3f6kMbwyANB7HuOWRMlLCa2itaCrZJ+SAqqkSZrZKO/cAsk2EOyaKHUtNkVLFyFW9pct22SFesFp3Z7zpA0g==", + "dev": true, + "dependencies": { + "sver": "^1.8.3" + }, + "engines": { + "node": ">= 10.13.0" + } }, - "semver-diff": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", - "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", - "dev": true, - "requires": { - "semver": "^5.0.3" - } - }, - "send": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/send/-/send-0.15.3.tgz", - "integrity": "sha1-UBP5+ZAj31DRvZiSwZ4979HVMwk=", - "requires": { - "debug": "2.6.7", - "depd": "~1.1.0", - "destroy": "~1.0.4", - "encodeurl": "~1.0.1", + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "etag": "~1.8.0", - "fresh": "0.5.0", - "http-errors": "~1.6.1", - "mime": "1.3.4", - "ms": "2.0.0", - "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.3.1" + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dependencies": { - "debug": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz", - "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" - } + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" } }, - "sequencify": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/sequencify/-/sequencify-0.0.7.tgz", - "integrity": "sha1-kM/xnQLgcCf9dn9erT57ldHnOAw=", + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "dev": true }, - "serve-static": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.12.3.tgz", - "integrity": "sha1-n0uhni8wMMVH+K+ZEHg47DjVseI=", - "requires": { - "encodeurl": "~1.0.1", - "escape-html": "~1.0.3", - "parseurl": "~1.3.1", - "send": "0.15.3" + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" } }, - "set-value": { + "node_modules/set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "dev": true, - "requires": { + "dependencies": { "extend-shallow": "^2.0.1", "is-extendable": "^0.1.1", "is-plain-object": "^2.0.3", "split-string": "^3.0.1" }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "engines": { + "node": ">=0.10.0" } }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + "node_modules/set-value/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } }, - "shebang-command": { + "node_modules/setprototypeof": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, - "requires": { - "shebang-regex": "^1.0.0" + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "shelljs": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.6.tgz", - "integrity": "sha1-N5zM+1a5HIYB5HkzVutTgpJN6a0=", + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" + "engines": { + "node": ">=8" } }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true + "node_modules/sift": { + "version": "17.1.3", + "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz", + "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==" }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true + "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" + } }, - "slice-ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "node_modules/simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0" + "dependencies": { + "semver": "~7.0.0" }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - } + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "sliced": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", - "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" + "node_modules/slice-ansi/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" + } }, - "snapdragon": { + "node_modules/snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, - "requires": { + "dependencies": { "base": "^0.11.1", "debug": "^2.2.0", "define-property": "^0.2.5", @@ -8489,1269 +9756,1558 @@ "source-map-resolve": "^0.5.0", "use": "^3.1.0" }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } + "engines": { + "node": ">=0.10.0" } }, - "snapdragon-node": { + "node_modules/snapdragon-node": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "dev": true, - "requires": { + "dependencies": { "define-property": "^1.0.0", "isobject": "^3.0.0", "snapdragon-util": "^3.0.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" } }, - "snapdragon-util": { + "node_modules/snapdragon-util": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, - "requires": { + "dependencies": { "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" } }, - "source-map": { + "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "source-map-resolve": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "node_modules/source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", "dev": true, - "requires": { - "atob": "^2.1.1", + "dependencies": { + "atob": "^2.1.2", "decode-uri-component": "^0.2.0", "resolve-url": "^0.2.1", "source-map-url": "^0.4.0", "urix": "^0.1.0" } }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "node_modules/source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "deprecated": "See https://github.com/lydell/source-map-url#deprecated", "dev": true }, - "sparkles": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", - "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", - "dev": true + "node_modules/sparkles": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-2.1.0.tgz", + "integrity": "sha512-r7iW1bDw8R/cFifrD3JnQJX0K1jqT0kprL48BiBpLZLJPmAm34zsVBsK5lc7HirZYZqMW65dOXZgbAGt/I6frg==", + "dev": true, + "engines": { + "node": ">= 10.13.0" + } }, - "sparse-bitfield": { + "node_modules/sparse-bitfield": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", - "optional": true, - "requires": { + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "dependencies": { "memory-pager": "^1.0.2" } }, - "spawn-sync": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", - "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=", + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.18", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", + "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", + "dev": true + }, + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "engines": { + "node": "*" + } + }, + "node_modules/static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", + "dev": true, + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stream-composer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-composer/-/stream-composer-1.0.2.tgz", + "integrity": "sha512-bnBselmwfX5K10AH6L4c8+S5lgZMWI7ZYrz2rvYjCPB2DIMC4Ig8OpxGpNJSxRZ58oti7y1IcNvjBAz9vW5m4w==", + "dev": true, + "dependencies": { + "streamx": "^2.13.2" + } + }, + "node_modules/stream-exhaust": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", + "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", + "dev": true + }, + "node_modules/stream-shift": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", + "dev": true + }, + "node_modules/streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/streamx": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.18.0.tgz", + "integrity": "sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==", "dev": true, - "requires": { - "concat-stream": "^1.4.7", - "os-shim": "^0.1.2" + "dependencies": { + "fast-fifo": "^1.3.2", + "queue-tick": "^1.0.1", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" } }, - "spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "engines": { + "node": ">=0.6.19" } }, - "spdx-exceptions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", - "dev": true + "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" + } }, - "spdx-expression-parse": { + "node_modules/string-width/node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "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, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "engines": { + "node": ">=8" } }, - "spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", - "dev": true - }, - "speakingurl": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.0.tgz", - "integrity": "sha512-70UD8Mm2cMkufkiUJ6tt7DLdLytYxTc1OwzXYJ9LVutfIoNx/Dmuj6vj/x0qAbUEFdyYKaHza1K/B1sI4hEk1A==" - }, - "split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "node_modules/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, - "requires": { - "through": "2" + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "node_modules/strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", "dev": true, - "requires": { - "extend-shallow": "^3.0.0" + "dependencies": { + "is-utf8": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" - }, - "staged-git-files": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/staged-git-files/-/staged-git-files-1.1.1.tgz", - "integrity": "sha512-H89UNKr1rQJvI1c/PIR3kiAMBV23yvR7LItZiV74HWZwzt7f3YHuujJ9nJZlt58WlFox7XQsOahexwk7nTe69A==", - "dev": true - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" + "engines": { + "node": ">=12" }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" - }, - "stream-combiner": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", - "integrity": "sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg=", + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, - "requires": { - "duplexer": "~0.1.1", - "through": "~2.3.4" + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "stream-consume": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz", - "integrity": "sha512-tNa3hzgkjEP7XbCkbRXe1jpg+ievoa0O4SCFlMOYEscGSS4JJsckGL8swUyAa/ApGU3Ae4t6Honor4HhL+tRyg==", - "dev": true - }, - "stream-to": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stream-to/-/stream-to-0.2.2.tgz", - "integrity": "sha1-hDBgmNhf25kLn6MAsbPM9V6O8B0=" - }, - "stream-to-buffer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/stream-to-buffer/-/stream-to-buffer-0.1.0.tgz", - "integrity": "sha1-JnmdkDqyAlyb1VCsRxcbAPjdgKk=", - "requires": { - "stream-to": "~0.2.0" + "node_modules/strtok3": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz", + "integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "peek-readable": "^4.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" } }, - "streamsearch": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", - "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } }, - "string-argv": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.0.2.tgz", - "integrity": "sha1-2sMECGkMIfPDYwo/86BYd73L1zY=", - "dev": true + "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" + } }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "node_modules/sver": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/sver/-/sver-1.8.4.tgz", + "integrity": "sha512-71o1zfzyawLfIWBOmw8brleKyvnbn73oVHNCsu51uPMz/HWiKkkXsI31JjHW5zqXEqnPYkIiHd8ZmL7FCimLEA==", "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "optionalDependencies": { + "semver": "^6.3.0" } }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + "node_modules/sver-compat": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", + "integrity": "sha512-aFTHfmjwizMNlNE6dsGmoAM4lHjL0CyiobWaFiXWSlD7cIxshW422Nb8KbXCmR6z+0ZEPY+daXJrDyh/vuwTyg==", + "dev": true, + "dependencies": { + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" + } }, - "stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "node_modules/sver/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "requires": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" + "optional": true, + "bin": { + "semver": "bin/semver.js" } }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", "dev": true, - "requires": { - "ansi-regex": "^2.0.0" + "dependencies": { + "streamx": "^2.12.5" } }, - "strip-bom": { + "node_modules/ternary-stream": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true + "resolved": "https://registry.npmjs.org/ternary-stream/-/ternary-stream-3.0.0.tgz", + "integrity": "sha512-oIzdi+UL/JdktkT+7KU5tSIQjj8pbShj3OASuvDEhm0NT5lppsm7aXWAmAq4/QMaBIyfuEcNLbAQA+HpaISobQ==", + "dev": true, + "dependencies": { + "duplexify": "^4.1.1", + "fork-stream": "^0.0.4", + "merge-stream": "^2.0.0", + "through2": "^3.0.1" + } }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true + "node_modules/ternary-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } }, - "symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", - "dev": true + "node_modules/ternary-stream/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } }, - "table": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", - "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", - "dev": true, - "requires": { - "ajv": "^5.2.3", - "ajv-keywords": "^2.1.0", - "chalk": "^2.1.0", - "lodash": "^4.17.4", - "slice-ansi": "1.0.0", - "string-width": "^2.1.1" - }, - "dependencies": { - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "dev": true, - "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "node_modules/ternary-stream/node_modules/through2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "2 || 3" } }, - "term-size": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", - "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", + "node_modules/text-decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.1.tgz", + "integrity": "sha512-8zll7REEv4GDD3x4/0pW+ppIxSNs7H1J10IKFZsuOMscumCdM2a+toDGLPA3T+1+fLBql4zbt5z83GEQGGV5VA==", "dev": true, - "requires": { - "execa": "^0.7.0" + "dependencies": { + "b4a": "^1.6.4" } }, - "text-table": { + "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 }, - "through": { + "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true }, - "through2": { + "node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "dev": true, - "requires": { + "dependencies": { "readable-stream": "~2.3.6", "xtend": "~4.0.1" - }, + } + }, + "node_modules/through2-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", + "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", + "dev": true, "dependencies": { - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + "through2": "~2.0.0", + "xtend": "~4.0.0" } }, - "tildify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz", - "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", + "node_modules/through2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/through2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/through2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "requires": { - "os-homedir": "^1.0.0" + "dependencies": { + "safe-buffer": "~5.1.0" } }, - "time-stamp": { + "node_modules/time-stamp": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", - "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", - "dev": true + "integrity": "sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "timed-out": { + "node_modules/timed-out": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "engines": { + "node": ">=0.10.0" + } }, - "tinycolor2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz", - "integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=" + "node_modules/timm": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/timm/-/timm-1.7.1.tgz", + "integrity": "sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw==" + }, + "node_modules/tinycolor2": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", + "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==" }, - "tldjs": { + "node_modules/tldjs": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/tldjs/-/tldjs-1.8.0.tgz", "integrity": "sha1-ucFr1t41e1X/y+fVvkH2s8p24/o=", - "requires": { + "hasInstallScript": true, + "dependencies": { "punycode": "^1.4.1" }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/tldjs/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - } + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" } }, - "tmp": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz", - "integrity": "sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA=", + "node_modules/to-absolute-glob": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", + "integrity": "sha512-rtwLUQEwT8ZeKQbyFJyomBRYXyE16U5VKuy0ftxLMK/PZb2fkOsg5r9kHdauuVDbsNdIBoC/HCthpidamQFXYA==", "dev": true, - "requires": { - "os-tmpdir": "~1.0.1" + "dependencies": { + "is-absolute": "^1.0.0", + "is-negated-glob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "to-object-path": { + "node_modules/to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", "dev": true, - "requires": { + "dependencies": { "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" } }, - "to-regex": { + "node_modules/to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, - "requires": { + "dependencies": { "define-property": "^2.0.2", "extend-shallow": "^3.0.2", "regex-not": "^1.0.2", "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "dependencies": { + "is-number": "^7.0.0" }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/to-regex/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - } + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "topo": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz", - "integrity": "sha1-6ddRYV0buH3IZdsYL6HKCl71NtU=", - "requires": { - "hoek": "2.x.x" + "node_modules/to-regex/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "node_modules/to-regex/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, - "requires": { - "nopt": "~1.0.10" + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" } }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" + "node_modules/to-regex/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-through": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/to-through/-/to-through-3.0.0.tgz", + "integrity": "sha512-y8MN937s/HVhEoBU1SxfHC+wxCHkV1a9gW8eAdTadYh/bGyesZIVcbjI+mSpFbSVwQici/XjBjuUyri1dnXwBw==", + "dev": true, + "dependencies": { + "streamx": "^2.12.5" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/token-types": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz", + "integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==", "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/token-types/node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" } + ] + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "bin": { + "nodetouch": "bin/nodetouch.js" } }, - "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, + "node_modules/type": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", "dev": true }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "^5.0.1" + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" } }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, - "requires": { - "prelude-ls": "~1.1.2" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "type-is": { + "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { + "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" } }, - "typedarray": { + "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, - "unc-path-regex": { + "node_modules/typescript": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "dev": true, + "optional": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", "dev": true }, - "undefsafe": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.2.tgz", - "integrity": "sha1-Il9rngM3Zj4Njnz9aG/Cg2zKznY=", + "node_modules/undertaker": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-2.0.0.tgz", + "integrity": "sha512-tO/bf30wBbTsJ7go80j0RzA2rcwX6o7XPBpeFcb+jzoeb4pfMM2zUeSDIkY1AWqeZabWxaQZ/h8N9t35QKDLPQ==", "dev": true, - "requires": { - "debug": "^2.2.0" + "dependencies": { + "bach": "^2.0.1", + "fast-levenshtein": "^3.0.0", + "last-run": "^2.0.0", + "undertaker-registry": "^2.0.0" }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/undertaker-registry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-2.0.0.tgz", + "integrity": "sha512-+hhVICbnp+rlzZMgxXenpvTxpuvA67Bfgtt+O9WOE5jo7w/dyiF1VmoZVIHvP2EkUjsyKyTwYKlLhA+j47m1Ew==", + "dev": true, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/undertaker/node_modules/fast-levenshtein": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-3.0.0.tgz", + "integrity": "sha512-hKKNajm46uNmTlhHSyZkmToAc56uZJwYq7yrciZjqOxnlfQwERDQJmHPUp7m1m9wx8vgOe8IaCKZ5Kv2k1DdCQ==", + "dev": true, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } + "fastest-levenshtein": "^1.0.7" } }, - "union-value": { + "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==", + "dev": true + }, + "node_modules/union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dev": true, - "requires": { + "dependencies": { "arr-union": "^3.1.0", "get-value": "^2.0.6", "is-extendable": "^0.1.1", "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "unique-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-1.0.0.tgz", - "integrity": "sha1-1ZpKdUJ0R9mqbJHnAmP40mpLEEs=", - "dev": true + "node_modules/unique-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", + "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", + "dev": true, + "dependencies": { + "json-stable-stringify-without-jsonify": "^1.0.1", + "through2-filter": "^3.0.0" + } }, - "unique-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", - "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "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, - "requires": { - "crypto-random-string": "^1.0.0" + "engines": { + "node": ">= 10.0.0" } }, - "unpipe": { + "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } }, - "unset-value": { + "node_modules/unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", "dev": true, - "requires": { + "dependencies": { "has-value": "^0.3.1", "isobject": "^3.0.0" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", + "dev": true, "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "unzip-response": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", - "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", - "dev": true + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "dev": true, + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "upath": { + "node_modules/upath": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true - }, - "update-notifier": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", - "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", - "dev": true, - "requires": { - "boxen": "^1.2.1", - "chalk": "^2.0.1", - "configstore": "^3.0.0", - "import-lazy": "^2.1.0", - "is-ci": "^1.0.10", - "is-installed-globally": "^0.1.0", - "is-npm": "^1.0.0", - "latest-version": "^3.0.0", - "semver-diff": "^2.0.0", - "xdg-basedir": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "dev": true, + "engines": { + "node": ">=4", + "yarn": "*" } }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "requires": { - "punycode": "^2.1.0" - }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - } + "punycode": "^2.1.0" } }, - "urix": { + "node_modules/uri-js/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", + "deprecated": "Please see https://github.com/lydell/urix#deprecated", "dev": true }, - "url": { + "node_modules/url": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", - "requires": { + "dependencies": { "punycode": "1.3.2", "querystring": "0.2.0" } }, - "url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "node_modules/use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true, - "requires": { - "prepend-http": "^1.0.1" + "engines": { + "node": ">=0.10.0" } }, - "url-regex": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/url-regex/-/url-regex-3.2.0.tgz", - "integrity": "sha1-260eDJ4p4QXdCx8J9oYvf9tIJyQ=", - "requires": { - "ip-regex": "^1.0.1" + "node_modules/utif2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/utif2/-/utif2-4.1.0.tgz", + "integrity": "sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w==", + "dependencies": { + "pako": "^1.0.11" } }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, - "user-home": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", - "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", - "dev": true + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } }, - "util-deprecate": { + "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, - "utils-merge": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", - "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=" + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } }, - "uuid": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz", - "integrity": "sha1-ZUS7ot/ajBzxfmKaOjBeK7H+5sE=" + "node_modules/uuid": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", + "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", + "bin": { + "uuid": "dist/bin/uuid" + } }, - "v8flags": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz", - "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", + "node_modules/v8flags": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-4.0.1.tgz", + "integrity": "sha512-fcRLaS4H/hrZk9hYwbdRM35D0U8IYMfEClhXxCivOojl+yTRAZH3Zy2sSy6qVCiGbV9YAtPssP6jaChqC9vPCg==", "dev": true, - "requires": { - "user-home": "^1.1.1" + "engines": { + "node": ">= 10.13.0" } }, - "validate-npm-package-license": { + "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, - "requires": { + "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, - "validator": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/validator/-/validator-9.4.1.tgz", - "integrity": "sha512-YV5KjzvRmSyJ1ee/Dm5UED0G+1L4GZnLN3w6/T+zZm8scVua4sOhYKWTUrKa0H/tMiJyO9QLHMPN+9mB/aMunA==" + "node_modules/validator": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz", + "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/value-or-function": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-4.0.0.tgz", + "integrity": "sha512-aeVK81SIuT6aMJfNo9Vte8Dw0/FZINGBV8BfCraGtqVxIeLAEhJyoWs8SmvRVmXfGss2PmmOwZCuBPbZR+IYWg==", + "dev": true, + "engines": { + "node": ">= 10.13.0" + } }, - "vary": { + "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "node_modules/vinyl": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-3.0.0.tgz", + "integrity": "sha512-rC2VRfAVVCGEgjnxHUnpIVh3AGuk62rP3tqVrn+yab0YH7UULisC085+NYH+mnqf3Wx4SpSi1RQMwudL89N03g==", + "dev": true, + "dependencies": { + "clone": "^2.1.2", + "clone-stats": "^1.0.0", + "remove-trailing-separator": "^1.1.0", + "replace-ext": "^2.0.0", + "teex": "^1.0.1" + }, + "engines": { + "node": ">=10.13.0" } }, - "vinyl": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", - "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", - "dev": true, - "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - } - }, - "vinyl-fs": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-0.3.14.tgz", - "integrity": "sha1-mmhRzhysHBzqX+hsCTHWIMLPqeY=", - "dev": true, - "requires": { - "defaults": "^1.0.0", - "glob-stream": "^3.1.5", - "glob-watcher": "^0.0.6", - "graceful-fs": "^3.0.0", - "mkdirp": "^0.5.0", - "strip-bom": "^1.0.0", - "through2": "^0.6.1", - "vinyl": "^0.4.0" - }, - "dependencies": { - "clone": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", - "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", - "dev": true - }, - "graceful-fs": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.12.tgz", - "integrity": "sha512-J55gaCS4iTTJfTXIxSVw3EMQckcqkpdRv3IR7gu6sq0+tbC363Zx6KH/SEwXASK9JRbhyZmVjJEVJIOxYsB3Qg==", - "dev": true, - "requires": { - "natives": "^1.1.3" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true + "node_modules/vinyl-contents": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vinyl-contents/-/vinyl-contents-2.0.0.tgz", + "integrity": "sha512-cHq6NnGyi2pZ7xwdHSW1v4Jfnho4TEGtxZHw01cmnc8+i7jgR6bRnED/LbrKan/Q7CvVLbnvA5OepnhbpjBZ5Q==", + "dev": true, + "dependencies": { + "bl": "^5.0.0", + "vinyl": "^3.0.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/vinyl-contents/node_modules/bl": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", + "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/vinyl-contents/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } + { + "type": "patreon", + "url": "https://www.patreon.com/feross" }, - "strip-bom": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-1.0.0.tgz", - "integrity": "sha1-hbiGLzhEtabV7IRnqTWYFzo295Q=", - "dev": true, - "requires": { - "first-chunk-stream": "^1.0.0", - "is-utf8": "^0.2.0" - } + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/vinyl-contents/node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" }, - "through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", - "dev": true, - "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } + { + "type": "patreon", + "url": "https://www.patreon.com/feross" }, - "vinyl": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", - "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", - "dev": true, - "requires": { - "clone": "^0.2.0", - "clone-stats": "^0.0.1" - } + { + "type": "consulting", + "url": "https://feross.org/support" } + ] + }, + "node_modules/vinyl-contents/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "node_modules/vinyl-contents/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, - "requires": { - "isexe": "^2.0.0" + "dependencies": { + "safe-buffer": "~5.2.0" } }, - "widest-line": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", - "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", + "node_modules/vinyl-fs": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-4.0.0.tgz", + "integrity": "sha512-7GbgBnYfaquMk3Qu9g22x000vbYkOex32930rBnc3qByw6HfMEAoELjCjoJv4HuEQxHAurT+nvMHm6MnJllFLw==", + "dev": true, + "dependencies": { + "fs-mkdirp-stream": "^2.0.1", + "glob-stream": "^8.0.0", + "graceful-fs": "^4.2.11", + "iconv-lite": "^0.6.3", + "is-valid-glob": "^1.0.0", + "lead": "^4.0.0", + "normalize-path": "3.0.0", + "resolve-options": "^2.0.0", + "stream-composer": "^1.0.2", + "streamx": "^2.14.0", + "to-through": "^3.0.0", + "value-or-function": "^4.0.0", + "vinyl": "^3.0.0", + "vinyl-sourcemap": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/vinyl-fs/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, - "requires": { - "string-width": "^2.1.1" + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/vinyl-sourcemap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-2.0.0.tgz", + "integrity": "sha512-BAEvWxbBUXvlNoFQVFVHpybBbjW1r03WhohJzJDSfgrrK5xVYIDTan6xN14DlyImShgDRv2gl9qhM6irVMsV0Q==", + "dev": true, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } + "convert-source-map": "^2.0.0", + "graceful-fs": "^4.2.10", + "now-and-later": "^3.0.0", + "streamx": "^2.12.5", + "vinyl": "^3.0.0", + "vinyl-contents": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" } }, - "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==", - "dev": true + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } }, - "wrap-ansi": { + "node_modules/webidl-conversions": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", - "integrity": "sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo=", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0" - }, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "node_modules/which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", "dev": true }, - "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, - "requires": { - "mkdirp": "^0.5.1" + "engines": { + "node": ">=0.10.0" } }, - "write-file-atomic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "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, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" + "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" } }, - "x-xss-protection": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/x-xss-protection/-/x-xss-protection-1.0.0.tgz", - "integrity": "sha1-iYr7k4abJGYc+cUvnujbjtB2Tdk=" + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } }, - "xdg-basedir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", - "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "xhr": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.5.0.tgz", - "integrity": "sha512-4nlO/14t3BNUZRXIXfXe+3N6w3s1KoxcJUUURctd64BLRe67E4gRwp4PjywtDY72fXpZ1y6Ch0VZQRY/gMPzzQ==", - "requires": { - "global": "~4.3.0", + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/xhr": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", + "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==", + "dependencies": { + "global": "~4.4.0", "is-function": "^1.0.1", "parse-headers": "^2.0.0", "xtend": "^4.0.0" } }, - "xml-parse-from-string": { + "node_modules/xml-parse-from-string": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz", - "integrity": "sha1-qQKekp09vN7RafPG4oI42VpdWig=" + "integrity": "sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g==" }, - "xml2js": { - "version": "0.4.17", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz", - "integrity": "sha1-F76T6q4/O3eTWceVtBlwWogX6Gg=", - "requires": { + "node_modules/xml2js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "dependencies": { "sax": ">=0.6.0", - "xmlbuilder": "^4.1.0" + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" } }, - "xmlbuilder": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz", - "integrity": "sha1-qlijBBoGb5DqoWwvU4n/GfP0YaU=", - "requires": { - "lodash": "^4.0.0" + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" } }, - "xtend": { + "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true + "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/yaml": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", + "integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==", + "dev": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "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" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 392caf0..4f2f5df 100644 --- a/package.json +++ b/package.json @@ -10,54 +10,51 @@ "cmt": "git-cz", "deploy": "now && now alias", "serve": "cross-env NODE_ENV=development gulp", - "start": "node src/index.js" + "start": "node src/index.js", + "format": "prettier --single-quote --trailing-comma none --tab-width=2 --write \"src/**/*.js\"" }, "devDependencies": { - "commitizen": "2.10.1", - "cross-env": "5.0.5", - "cz-conventional-changelog": "2.1.0", - "eslint": "4.19.1", - "eslint-config-semistandard": "12.0.1", - "eslint-config-standard": "10.2.1", - "eslint-plugin-import": "2.10.0", - "eslint-plugin-node": "6.0.1", - "eslint-plugin-promise": "3.7.0", - "eslint-plugin-standard": "3.1.0", - "gulp": "3.9.1", - "gulp-eslint": "4.0.0", - "gulp-nodemon": "2.2.1", - "husky": "1.0.0-rc.13", - "lint-staged": "7.2.2", - "prettier": "1.14.2" + "@eslint/js": "^9.7.0", + "commitizen": "4.3.0", + "cross-env": "7.0.3", + "cz-conventional-changelog": "3.3.0", + "eslint": "^9.7.0", + "globals": "^15.8.0", + "gulp": "5.0.0", + "gulp-eslint-new": "^2.2.0", + "gulp-nodemon": "^2.2.1", + "husky": "9.1.1", + "lint-staged": "15.2.7", + "prettier": "3.3.3" }, "dependencies": { - "aws-sdk": "2.94.0", - "axios": "0.18.0", + "aws-sdk": "2.1660.0", + "axios": "1.7.2", "bcrypt-nodejs": "0.0.3", - "body-parser": "1.17.2", - "cors": "2.8.4", - "dotenv": "4.0.0", - "express": "4.15.3", - "form-data": "2.3.2", - "freemail": "1.5.0", - "google-auth-library": "0.10.0", - "helmet": "3.8.1", - "ip": "1.1.5", - "jimp": "0.2.28", - "jsonwebtoken": "7.4.1", - "lodash": "4.17.4", - "moment": "2.18.1", - "moment-timezone": "0.5.21", + "body-parser": "1.20.2", + "cors": "2.8.5", + "dotenv": "16.4.5", + "express": "4.19.2", + "form-data": "4.0.0", + "freemail": "1.7.0", + "google-auth-library": "9.11.0", + "helmet": "7.1.0", + "ip": "2.0.1", + "jimp": "0.22.12", + "jsonwebtoken": "9.0.2", + "lodash": "4.17.21", + "moment": "2.30.1", + "moment-timezone": "0.5.45", "mongodb-uri": "0.9.7", - "mongoose": "5.3.2", - "morgan": "1.8.2", + "mongoose": "8.5.1", + "morgan": "1.10.0", "multer": "1.3.0", - "nodemailer": "4.0.1", + "nodemailer": "6.9.14", "now": "11.4.6", - "randomstring": "1.1.5", + "randomstring": "1.3.0", "raven": "2.6.0", - "speakingurl": "14.0.0", - "validator": "9.4.1" + "speakingurl": "14.0.1", + "validator": "13.12.0" }, "lint-staged": { "src/**/*.{js}": [ @@ -78,5 +75,8 @@ "hooks": { "pre-commit": "lint-staged" } + }, + "overrides": { + "graceful-fs": "^4.2.11" } } diff --git a/src/helpers/constants.js b/src/helpers/constants.js index 53eeef5..72f82c7 100644 --- a/src/helpers/constants.js +++ b/src/helpers/constants.js @@ -1,129 +1,129 @@ -module.exports = { - languages: ['en', 'es'], - placesTypes: [ - 'accounting', - 'airport', - 'amusement_park', - 'aquarium', - 'art_gallery', - 'atm', - 'bakery', - 'bank', - 'bar', - 'beauty_salon', - 'bicycle_store', - 'book_store', - 'bowling_alley', - 'bus_station', - 'cafe', - 'campground', - 'car_dealer', - 'car_rental', - 'car_repair', - 'car_wash', - 'casino', - 'cemetery', - 'church', - 'city_hall', - 'clothing_store', - 'convenience_store', - 'courthouse', - 'dentist', - 'department_store', - 'doctor', - 'electrician', - 'electronics_store', - 'embassy', - 'establishment', - 'fire_station', - 'florist', - 'funeral_home', - 'furniture_store', - 'gas_station', - 'gym', - 'hair_care', - 'hardware_store', - 'hindu_temple', - 'home_goods_store', - 'hospital', - 'insurance_agency', - 'jewelry_store', - 'laundry', - 'lawyer', - 'library', - 'liquor_store', - 'local_government_office', - 'locksmith', - 'lodging', - 'meal_delivery', - 'meal_takeaway', - 'mosque', - 'movie_rental', - 'movie_theater', - 'moving_company', - 'museum', - 'night_club', - 'painter', - 'park', - 'parking', - 'pet_store', - 'pharmacy', - 'physiotherapist', - 'plumber', - 'police', - 'post_office', - 'real_estate_agency', - 'restaurant', - 'roofing_contractor', - 'rv_park', - 'school', - 'shoe_store', - 'shopping_mall', - 'spa', - 'stadium', - 'storage', - 'store', - 'subway_station', - 'synagogue', - 'taxi_stand', - 'train_station', - 'transit_station', - 'travel_agency', - 'university', - 'veterinary_care', - 'zoo' - ], - directionsTypes: [ - 'administrative_area_level_1', - 'administrative_area_level_2', - 'administrative_area_level_3', - 'administrative_area_level_4', - 'administrative_area_level_5', - 'colloquial_area', - 'country', - 'finance', - 'floor', - 'geocode', - 'intersection', - 'locality', - 'natural_feature', - 'neighborhood', - 'place_of_worship', - 'political', - 'postal_code', - 'postal_code_prefix', - 'postal_code_suffix', - 'postal_town', - 'premise', - 'route', - 'street_address', - 'street_number', - 'sublocality', - 'sublocality_level_5', - 'sublocality_level_4', - 'sublocality_level_3', - 'sublocality_level_2', - 'sublocality_level_1', - 'subpremise' - ] -}; +module.exports = { + languages: ['en', 'es'], + placesTypes: [ + 'accounting', + 'airport', + 'amusement_park', + 'aquarium', + 'art_gallery', + 'atm', + 'bakery', + 'bank', + 'bar', + 'beauty_salon', + 'bicycle_store', + 'book_store', + 'bowling_alley', + 'bus_station', + 'cafe', + 'campground', + 'car_dealer', + 'car_rental', + 'car_repair', + 'car_wash', + 'casino', + 'cemetery', + 'church', + 'city_hall', + 'clothing_store', + 'convenience_store', + 'courthouse', + 'dentist', + 'department_store', + 'doctor', + 'electrician', + 'electronics_store', + 'embassy', + 'establishment', + 'fire_station', + 'florist', + 'funeral_home', + 'furniture_store', + 'gas_station', + 'gym', + 'hair_care', + 'hardware_store', + 'hindu_temple', + 'home_goods_store', + 'hospital', + 'insurance_agency', + 'jewelry_store', + 'laundry', + 'lawyer', + 'library', + 'liquor_store', + 'local_government_office', + 'locksmith', + 'lodging', + 'meal_delivery', + 'meal_takeaway', + 'mosque', + 'movie_rental', + 'movie_theater', + 'moving_company', + 'museum', + 'night_club', + 'painter', + 'park', + 'parking', + 'pet_store', + 'pharmacy', + 'physiotherapist', + 'plumber', + 'police', + 'post_office', + 'real_estate_agency', + 'restaurant', + 'roofing_contractor', + 'rv_park', + 'school', + 'shoe_store', + 'shopping_mall', + 'spa', + 'stadium', + 'storage', + 'store', + 'subway_station', + 'synagogue', + 'taxi_stand', + 'train_station', + 'transit_station', + 'travel_agency', + 'university', + 'veterinary_care', + 'zoo' + ], + directionsTypes: [ + 'administrative_area_level_1', + 'administrative_area_level_2', + 'administrative_area_level_3', + 'administrative_area_level_4', + 'administrative_area_level_5', + 'colloquial_area', + 'country', + 'finance', + 'floor', + 'geocode', + 'intersection', + 'locality', + 'natural_feature', + 'neighborhood', + 'place_of_worship', + 'political', + 'postal_code', + 'postal_code_prefix', + 'postal_code_suffix', + 'postal_town', + 'premise', + 'route', + 'street_address', + 'street_number', + 'sublocality', + 'sublocality_level_5', + 'sublocality_level_4', + 'sublocality_level_3', + 'sublocality_level_2', + 'sublocality_level_1', + 'subpremise' + ] +}; diff --git a/src/helpers/db-connector.js b/src/helpers/db-connector.js index 9ee3db3..183145d 100644 --- a/src/helpers/db-connector.js +++ b/src/helpers/db-connector.js @@ -1,106 +1,97 @@ -const mongoose = require('mongoose'); -const mongoUri = require('mongodb-uri'); - -mongoose.Promise = global.Promise; - -const delayToReconnect = 1000; -let disconnecting; -let initialized = false; -const mongodbURI = process.env.MONGODB_URI; -const dbName = mongoUri.parse(mongodbURI).database; -const options = { - connectTimeoutMS: 30000, - keepAlive: 120, - useCreateIndex: true, - useNewUrlParser: true -}; - -function logging(db) { - db.on('connected', () => - console.log(`Database connection to ${dbName} established`) - ); - db.on('open', () => console.log(`Database connection to ${dbName} opened`)); - db.on('disconnected', () => { - if (disconnecting !== true) { - console.log(`Database connection to ${dbName} lost`); - } - }); - db.on('error', err => { - console.log(`Database connection to ${dbName} error`); - throw err; - }); -} - -function open() { - console.log(`Opening database connection to ${dbName}...`); - mongoose.connect( - mongodbURI, - options - ); -} - -function reconnection(db) { - let timer; - - function reconnect() { - timer = false; - open(db); - } - - function clear() { - if (timer) { - clearTimeout(timer); - } - timer = false; - } - - function schedule() { - if (disconnecting) { - console.log(`Database connection to ${dbName} explicitly shut down`); - return; - } - - if (timer) { - clearTimeout(timer); - } - timer = setTimeout(reconnect, delayToReconnect); - } - - db.on('disconnected', schedule); - db.on('connected', clear); -} - -function connect(done) { - const db = mongoose.connection; - - if (initialized === false) { - initialized = true; - logging(db); - reconnection(db); - } - - open(); - - db.once('connected', done); -} - -function disconnect(done) { - const db = mongoose.connection; - - function disconnected() { - disconnecting = false; - if (done) { - done(); - } - } - - if (db.readyState !== 0) { - disconnecting = true; - db.once('disconnected', disconnected); - db.close(); - } -} - -connect.disconnect = disconnect; - -module.exports = connect; +const mongoose = require('mongoose'); +const mongoUri = require('mongodb-uri'); + +mongoose.Promise = global.Promise; + +const delayToReconnect = 1000; +let disconnecting; +let initialized = false; +const mongodbURI = process.env.MONGODB_URI; +const dbName = mongoUri.parse(mongodbURI).database; + +function logging(db) { + db.on('connected', () => + console.log(`Database connection to ${dbName} established`) + ); + db.on('open', () => console.log(`Database connection to ${dbName} opened`)); + db.on('disconnected', () => { + if (disconnecting !== true) { + console.log(`Database connection to ${dbName} lost`); + } + }); + db.on('error', (err) => { + console.log(`Database connection to ${dbName} error`); + throw err; + }); +} + +function open() { + console.log(`Opening database connection to ${dbName}...`); + mongoose.connect(mongodbURI); +} + +function reconnection(db) { + let timer; + + function reconnect() { + timer = false; + open(db); + } + + function clear() { + if (timer) { + clearTimeout(timer); + } + timer = false; + } + + function schedule() { + if (disconnecting) { + console.log(`Database connection to ${dbName} explicitly shut down`); + return; + } + + if (timer) { + clearTimeout(timer); + } + timer = setTimeout(reconnect, delayToReconnect); + } + + db.on('disconnected', schedule); + db.on('connected', clear); +} + +function connect(done) { + const db = mongoose.connection; + + if (initialized === false) { + initialized = true; + logging(db); + reconnection(db); + } + + open(); + + db.once('connected', done); +} + +function disconnect(done) { + const db = mongoose.connection; + + function disconnected() { + disconnecting = false; + if (done) { + done(); + } + } + + if (db.readyState !== 0) { + disconnecting = true; + db.once('disconnected', disconnected); + db.close(); + } +} + +connect.disconnect = disconnect; + +module.exports = connect; diff --git a/src/helpers/index.js b/src/helpers/index.js index 3445d7f..94f26fc 100644 --- a/src/helpers/index.js +++ b/src/helpers/index.js @@ -1,106 +1,109 @@ -const aws = require('aws-sdk'); -const { camelCase } = require('lodash'); -const jwt = require('jsonwebtoken'); -const { mapKeys, pickBy } = require('lodash'); -const nodemailer = require('nodemailer'); -const { snakeCase } = require('lodash'); - -const { User } = require('../models/user'); - -module.exports = { - cleanSpaces(string) { - return string.replace(/\s+/g, ' ').trim(); - }, - deleteUnusedProperties(obj) { - return pickBy(obj, prop => prop); - }, - isAuthenticated: ({ isOptional }) => async (req, res, next) => { - const authorizationHeader = req.headers.authorization; - let token; - - if (authorizationHeader) { - token = authorizationHeader.split(' ')[1]; - } - - if (token) { - let decoded; - try { - decoded = await jwt.verify(token, process.env.JWT_SECRET); - } catch (err) { - return res.status(401).json({ general: 'Failed to authenticate' }); - } - - let user; - try { - user = await User.findOne({ - _id: decoded.userId, - isArchived: false - }).select( - '-__v -createdAt -isAdmin -isArchived -isBlocked -hashedPassword -updatedAt' - ); - } catch (err) { - console.log( - `User ${decoded.userId} failed to be found at authenticate` - ); - return next(err); - } - - if (user) { - req.user = user; - - if ( - (isOptional && req.user && req.user.isBlocked) || - (!isOptional && req.user.isBlocked) - ) { - return res.status(423).json({ general: 'You are blocked' }); - } - - return next(); - } - - return res.status(404).json({ general: 'User not found' }); - } - - if (isOptional) { - return next(); - } - - return res.status(401).json({ general: 'No token provided' }); - }, - isNumber(number) { - return !isNaN(parseFloat(number)) && isFinite(number); - }, - mapCamelCaseKeys(obj) { - return mapKeys(obj, (value, key) => camelCase(key)); - }, - mapSnakeCaseKeys(obj) { - return mapKeys(obj, (value, key) => snakeCase(key)); - }, - removeSpaces(string) { - return string.replace(/\s/g, ''); - }, - sendEmail({ - senderEmail = process.env.SENDER_EMAIL, - receiversEmails, - subject, - htmlContent, - textContent - }) { - const transporter = nodemailer.createTransport({ - SES: new aws.SES({ - apiVersion: '2010-12-01' - }) - }); - - return transporter.sendMail({ - from: `"AXS Map" <${senderEmail}>`, - to: receiversEmails.join(', '), - subject, - text: textContent, - html: htmlContent - }); - }, - toJSON(obj) { - return JSON.parse(JSON.stringify(obj)); - } -}; +const aws = require('aws-sdk'); +const { camelCase } = require('lodash'); +const jwt = require('jsonwebtoken'); +const { mapKeys, pickBy } = require('lodash'); +const nodemailer = require('nodemailer'); +const { snakeCase } = require('lodash'); + +const { User } = require('../models/user'); + +module.exports = { + cleanSpaces(string) { + return string.replace(/\s+/g, ' ').trim(); + }, + deleteUnusedProperties(obj) { + return pickBy(obj, (prop) => prop); + }, + isAuthenticated: + ({ isOptional }) => + async (req, res, next) => { + const authorizationHeader = req.headers.authorization; + let token; + + if (authorizationHeader) { + token = authorizationHeader.split(' ')[1]; + } + + if (token) { + let decoded; + try { + decoded = await jwt.verify(token, process.env.JWT_SECRET); + } catch (err) { + console.log(err); + return res.status(401).json({ general: 'Failed to authenticate' }); + } + + let user; + try { + user = await User.findOne({ + _id: decoded.userId, + isArchived: false + }).select( + '-__v -createdAt -isAdmin -isArchived -isBlocked -hashedPassword -updatedAt' + ); + } catch (err) { + console.log( + `User ${decoded.userId} failed to be found at authenticate` + ); + return next(err); + } + + if (user) { + req.user = user; + + if ( + (isOptional && req.user && req.user.isBlocked) || + (!isOptional && req.user.isBlocked) + ) { + return res.status(423).json({ general: 'You are blocked' }); + } + + return next(); + } + + return res.status(404).json({ general: 'User not found' }); + } + + if (isOptional) { + return next(); + } + + return res.status(401).json({ general: 'No token provided' }); + }, + isNumber(number) { + return !isNaN(parseFloat(number)) && isFinite(number); + }, + mapCamelCaseKeys(obj) { + return mapKeys(obj, (value, key) => camelCase(key)); + }, + mapSnakeCaseKeys(obj) { + return mapKeys(obj, (value, key) => snakeCase(key)); + }, + removeSpaces(string) { + return string.replace(/\s/g, ''); + }, + sendEmail({ + senderEmail = process.env.SENDER_EMAIL, + receiversEmails, + subject, + htmlContent, + textContent + }) { + const transporter = nodemailer.createTransport({ + SES: new aws.SES({ + apiVersion: '2010-12-01' + }) + }); + + return transporter.sendMail({ + from: `"AXS Map" <${senderEmail}>`, + to: receiversEmails.join(', '), + subject, + text: textContent, + html: htmlContent + }); + }, + toJSON(obj) { + return JSON.parse(JSON.stringify(obj)); + } +}; diff --git a/src/helpers/venue-review-summary.js b/src/helpers/venue-review-summary.js index e752584..6fc30b5 100644 --- a/src/helpers/venue-review-summary.js +++ b/src/helpers/venue-review-summary.js @@ -8,8 +8,8 @@ function assignFromYesNo(venueField) { // Mongoose hasOwnProperty test issues if ( venueField && - venueField.hasOwnProperty('yes') && - venueField.hasOwnProperty('no') && + 'yes' in venueField && + 'no' in venueField && !(venueField.yes === 0 && venueField.no === 0) ) { if (venueField.yes >= venueField.no) { @@ -23,12 +23,10 @@ function assignFromYesNo(venueField) { } function assignFromSteps(stepField) { - let moreThanTwo = stepField.hasOwnProperty('moreThanTwo') - ? stepField.moreThanTwo - : 0; - let two = stepField.hasOwnProperty('two') ? stepField.two : 0; - let one = stepField.hasOwnProperty('one') ? stepField.one : 0; - let zero = stepField.hasOwnProperty('zero') ? stepField.zero : 0; + let moreThanTwo = 'moreThanTwo' in stepField ? stepField.moreThanTwo : 0; + let two = 'two' in stepField ? stepField.two : 0; + let one = 'one' in stepField ? stepField.one : 0; + let zero = 'zero' in stepField ? stepField.zero : 0; if (moreThanTwo === 0 && two === 0 && one === 0 && zero === 0) { return null; @@ -95,7 +93,7 @@ module.exports = { //console.log('in calculateRatingLevel, select venue data: ', venueData); let sectionLogic, ratingDefinition; - if (reviewSummaryLogic.hasOwnProperty(sectionName)) { + if (sectionName in reviewSummaryLogic) { //valid values: entrance, restroom, interior sectionLogic = reviewSummaryLogic[sectionName]; } else { @@ -108,37 +106,37 @@ module.exports = { let ratingLevel, ratingGlyphs; const ratingLevels = ['alert', 'caution', 'accessible']; - for (rl = 0; rl < ratingLevels.length; rl++) { + for (let rl = 0; rl < ratingLevels.length; rl++) { if ( - sectionLogic.hasOwnProperty(ratingLevels[rl]) && + ratingLevels[rl] in sectionLogic && sectionLogic[ratingLevels[rl]].length > 0 ) { //level loop - for (idx = 0; idx < sectionLogic[ratingLevels[rl]].length; idx++) { + for (let idx = 0; idx < sectionLogic[ratingLevels[rl]].length; idx++) { ratingDefinition = sectionLogic[ratingLevels[rl]][idx]; let ratingDefinitionMatch = false; if ( - ratingDefinition.hasOwnProperty('field') && - venueData.hasOwnProperty(ratingDefinition.field) + 'field' in ratingDefinition && + ratingDefinition.field in venueData ) { if ( - (ratingDefinition.hasOwnProperty('matchValue') && + ('matchValue' in ratingDefinition && venueData[ratingDefinition.field] === ratingDefinition.matchValue) || - (ratingDefinition.hasOwnProperty('notMatchValue') && + ('notMatchValue' in ratingDefinition && venueData[ratingDefinition.field] !== ratingDefinition.notMatchValue) ) { ratingDefinitionMatch = true; } - } else if (ratingDefinition.hasOwnProperty('fields')) { + } else if ('fields' in ratingDefinition) { let fieldMatchCount = 0; - for (field of ratingDefinition.fields) { + for (let field of ratingDefinition.fields) { if ( - (ratingDefinition.hasOwnProperty('matchValue') && + ('matchValue' in ratingDefinition && venueData[field] === ratingDefinition.matchValue) || - (ratingDefinition.hasOwnProperty('notMatchValue') && + ('notMatchValue' in ratingDefinition && venueData[field] !== ratingDefinition.notMatchValue) ) { fieldMatchCount++; @@ -150,21 +148,18 @@ module.exports = { } } - if ( - ratingDefinitionMatch === true && - ratingDefinition.hasOwnProperty('and') - ) { + if (ratingDefinitionMatch === true && 'and' in ratingDefinition) { //console.log('Evaluate AND condition in ' + sectionName); if ( - ratingDefinition.and.hasOwnProperty('field') && - venueData.hasOwnProperty(ratingDefinition.and.field) + 'field' in ratingDefinition.and && + ratingDefinition.and.field in venueData ) { //evaluate 'and' condition depending on match or noMatch value - if (ratingDefinition.and.hasOwnProperty('matchValue')) { + if ('matchValue' in ratingDefinition.and) { ratingDefinitionMatch = venueData[ratingDefinition.and.field] == ratingDefinition.and.matchValue; - } else if (ratingDefinition.and.hasOwnProperty('notMatchValue')) { + } else if ('notMatchValue' in ratingDefinition.and) { ratingDefinitionMatch = venueData[ratingDefinition.and.field] !== ratingDefinition.and.notMatchValue; @@ -202,9 +197,9 @@ module.exports = { //console.log('ratingLevel not set: ', sectionLogic); ratingLevel = 0; ratingGlyphs = - sectionLogic.hasOwnProperty('default') && + 'default' in sectionLogic && sectionLogic.default.length > 0 && - sectionLogic.default[0].hasOwnProperty('showGlyph') + 'showGlyph' in sectionLogic.default[0] ? sectionLogic.default[0].showGlyph : ''; } diff --git a/src/index.js b/src/index.js index f75263b..6c650e1 100644 --- a/src/index.js +++ b/src/index.js @@ -1,81 +1,81 @@ -const fs = require('fs'); -const https = require('https'); - -const bodyParser = require('body-parser'); -const cors = require('cors'); -const express = require('express'); -const helmet = require('helmet'); -const ip = require('ip'); -const morgan = require('morgan'); -const raven = require('raven'); - -// Fill process.env with environment variables -require('dotenv').config(); -//console.log(process.env) - -const port = process.env.PORT || 8000; - -const connectToDB = require('./helpers/db-connector'); -const routes = require('./routes'); - -function connectedToDB() { - const app = express(); - - raven - .config(process.env.SENTRY_URL, { - captureUnhandledRejections: true - }) - .install(); - - // Middlewares - app.use(raven.requestHandler()); - app.use(cors()); - app.use(morgan('dev')); - app.use(bodyParser.json()); - app.use(helmet()); - - // Routes - app.set('strict routing', true); - app.use('/', routes); - - // Error handling - app.use(raven.errorHandler()); - app.use((req, res, _next) => res.status(404).json({ general: 'Not found' })); - app.use((err, req, res, _next) => { - if (err instanceof SyntaxError) { - return res.status(400).json({ general: 'Invalid JSON format' }); - } - - console.error(err.stack); - return res.status(500).json({ general: 'Something went wrong' }); - }); - - process.on('uncaughtException', err => { - console.error(err); - raven.captureException(err); - }); - process.on('unhandledRejection', err => { - console.error(err); - raven.captureException(err); - }); - - // App Initialization - if (process.env.NODE_ENV === 'production') { - console.log(`Listening on http://${ip.address()}:${port}`); - app.listen(port); - } else { - https - .createServer( - { - key: fs.readFileSync('./certificates/server.key'), - cert: fs.readFileSync('./certificates/server.crt') - }, - app - ) - .listen(port, () => - console.log(`Listening on https://${ip.address()}:${port}`) - ); - } -} - -connectToDB(connectedToDB); +const fs = require('fs'); +const https = require('https'); + +const bodyParser = require('body-parser'); +const cors = require('cors'); +const express = require('express'); +const helmet = require('helmet'); +const ip = require('ip'); +const morgan = require('morgan'); +const raven = require('raven'); + +// Fill process.env with environment variables +require('dotenv').config(); +//console.log(process.env) + +const port = process.env.PORT || 8000; + +const connectToDB = require('./helpers/db-connector'); +const routes = require('./routes'); + +function connectedToDB() { + const app = express(); + + raven + .config(process.env.SENTRY_URL, { + captureUnhandledRejections: true + }) + .install(); + + // Middlewares + app.use(raven.requestHandler()); + app.use(cors()); + app.use(morgan('dev')); + app.use(bodyParser.json()); + app.use(helmet()); + + // Routes + app.set('strict routing', true); + app.use('/', routes); + + // Error handling + app.use(raven.errorHandler()); + app.use((req, res) => res.status(404).json({ general: 'Not found' })); + app.use((err, req, res) => { + if (err instanceof SyntaxError) { + return res.status(400).json({ general: 'Invalid JSON format' }); + } + + console.error(err.stack); + return res.status(500).json({ general: 'Something went wrong' }); + }); + + process.on('uncaughtException', (err) => { + console.error(err); + raven.captureException(err); + }); + process.on('unhandledRejection', (err) => { + console.error(err); + raven.captureException(err); + }); + + // App Initialization + if (process.env.NODE_ENV === 'production') { + console.log(`Listening on http://${ip.address()}:${port}`); + app.listen(port); + } else { + https + .createServer( + { + key: fs.readFileSync('./certificates/server.key'), + cert: fs.readFileSync('./certificates/server.crt') + }, + app + ) + .listen(port, () => + console.log(`Listening on https://${ip.address()}:${port}`) + ); + } +} + +connectToDB(connectedToDB); diff --git a/src/models/activation-ticket.js b/src/models/activation-ticket.js index 621d2c0..1fa8760 100644 --- a/src/models/activation-ticket.js +++ b/src/models/activation-ticket.js @@ -1,48 +1,48 @@ -const mongoose = require('mongoose'); - -const activationTicketSchema = new mongoose.Schema( - { - email: { - type: String, - maxlength: [254, 'Should have less than 255 characters'], - required: [true, 'Is required'] - }, - expiresAt: { - type: Date, - required: [true, 'Is required'] - }, - key: { - type: String, - maxlength: [75, 'Should have less than 76 characters'], - required: [true, 'Is required'] - }, - userData: { - firstName: { - type: String, - maxlength: [24, 'Should have less than 25 characters'] - }, - isSubscribed: { - type: Boolean - }, - lastName: { - type: String, - maxlength: [36, 'Should have less than 37 characters'] - }, - password: { - type: String, - maxlength: [30, 'Should have less than 31 characters'], - minlength: [8, 'Should have more than 7 characters'] - }, - username: { - type: String, - maxlength: [67, 'Should have less than 68 characters'] - } - } - }, - { timestamps: true } -); - -module.exports = { - ActivationTicket: mongoose.model('ActivationTicket', activationTicketSchema), - activationTicketSchema -}; +const mongoose = require('mongoose'); + +const activationTicketSchema = new mongoose.Schema( + { + email: { + type: String, + maxlength: [254, 'Should have less than 255 characters'], + required: [true, 'Is required'] + }, + expiresAt: { + type: Date, + required: [true, 'Is required'] + }, + key: { + type: String, + maxlength: [75, 'Should have less than 76 characters'], + required: [true, 'Is required'] + }, + userData: { + firstName: { + type: String, + maxlength: [24, 'Should have less than 25 characters'] + }, + isSubscribed: { + type: Boolean + }, + lastName: { + type: String, + maxlength: [36, 'Should have less than 37 characters'] + }, + password: { + type: String, + maxlength: [30, 'Should have less than 31 characters'], + minlength: [8, 'Should have more than 7 characters'] + }, + username: { + type: String, + maxlength: [67, 'Should have less than 68 characters'] + } + } + }, + { timestamps: true } +); + +module.exports = { + ActivationTicket: mongoose.model('ActivationTicket', activationTicketSchema), + activationTicketSchema +}; diff --git a/src/models/event.js b/src/models/event.js index a767260..8c4b586 100644 --- a/src/models/event.js +++ b/src/models/event.js @@ -1,141 +1,141 @@ -const mongoose = require('mongoose'); - -const eventSchema = new mongoose.Schema( - { - address: { - type: String, - maxlength: [200, 'Should be less than 201 characters'], - required: [true, 'Is required'] - }, - description: { - type: String, - maxlength: [300, 'Should be less than 301 characters'] - }, - donationAmounts: { - type: [ - { - value: { - type: Number, - default: 5, - max: [10000, 'Should be less than 10001'], - min: [5, 'Should be greater than 4'] - } - } - ] - }, - donationEnabled: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - donationGoal: { - type: Number, - default: 10, - max: [100000, 'Should be less than 100001'], - min: [10, 'Should be greater than 9'] - }, - donationId: { - type: String, - default: '' - }, - endDate: { - type: Date, - required: [true, 'Is required'] - }, - isArchived: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - isOpen: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - location: { - type: { - type: String, - default: 'Point' - }, - coordinates: [Number] - }, - managers: { - type: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'User' - } - ], - required: [true, 'Is required'] - }, - name: { - type: String, - maxlength: [100, 'Should be less than 101 characters'], - required: [true, 'Is required'] - }, - participants: { - type: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'User' - } - ] - }, - participantsGoal: { - type: Number, - max: [1000, 'Should be less than 1001'], - min: [1, 'Should be greater than 0'], - required: [true, 'Is required'] - }, - poster: { - type: String, - default: `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/events/posters/default.png`, - maxlength: [2000, 'Should be less than 2001 characters'], - required: [true, 'Is required'] - }, - reviewsAmount: { - type: Number, - default: 0, - required: [true, 'Is required'] - }, - reviewsGoal: { - type: Number, - max: [10000, 'Should be less than 10001'], - min: [1, 'Should be greater than 0'] - }, - startDate: { - type: Date, - required: [true, 'Is required'] - }, - teamManager: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Team' - }, - teams: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'Team' - } - ], - venue: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Venue' - } - }, - { timestamps: true } -); - -eventSchema.index({ - address: 'text', - name: 'text', - endDate: 1, - reviewsAmount: 1, - startDate: 1 -}); - -module.exports = { - Event: mongoose.model('Event', eventSchema), - eventSchema -}; +const mongoose = require('mongoose'); + +const eventSchema = new mongoose.Schema( + { + address: { + type: String, + maxlength: [200, 'Should be less than 201 characters'], + required: [true, 'Is required'] + }, + description: { + type: String, + maxlength: [300, 'Should be less than 301 characters'] + }, + donationAmounts: { + type: [ + { + value: { + type: Number, + default: 5, + max: [10000, 'Should be less than 10001'], + min: [5, 'Should be greater than 4'] + } + } + ] + }, + donationEnabled: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + donationGoal: { + type: Number, + default: 10, + max: [100000, 'Should be less than 100001'], + min: [10, 'Should be greater than 9'] + }, + donationId: { + type: String, + default: '' + }, + endDate: { + type: Date, + required: [true, 'Is required'] + }, + isArchived: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + isOpen: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + location: { + type: { + type: String, + default: 'Point' + }, + coordinates: [Number] + }, + managers: { + type: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'User' + } + ], + required: [true, 'Is required'] + }, + name: { + type: String, + maxlength: [100, 'Should be less than 101 characters'], + required: [true, 'Is required'] + }, + participants: { + type: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'User' + } + ] + }, + participantsGoal: { + type: Number, + max: [1000, 'Should be less than 1001'], + min: [1, 'Should be greater than 0'], + required: [true, 'Is required'] + }, + poster: { + type: String, + default: `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/events/posters/default.png`, + maxlength: [2000, 'Should be less than 2001 characters'], + required: [true, 'Is required'] + }, + reviewsAmount: { + type: Number, + default: 0, + required: [true, 'Is required'] + }, + reviewsGoal: { + type: Number, + max: [10000, 'Should be less than 10001'], + min: [1, 'Should be greater than 0'] + }, + startDate: { + type: Date, + required: [true, 'Is required'] + }, + teamManager: { + type: mongoose.Schema.Types.ObjectId, + ref: 'Team' + }, + teams: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'Team' + } + ], + venue: { + type: mongoose.Schema.Types.ObjectId, + ref: 'Venue' + } + }, + { timestamps: true } +); + +eventSchema.index({ + address: 'text', + name: 'text', + endDate: 1, + reviewsAmount: 1, + startDate: 1 +}); + +module.exports = { + Event: mongoose.model('Event', eventSchema), + eventSchema +}; diff --git a/src/models/password-ticket.js b/src/models/password-ticket.js index 00a4ced..ca98254 100644 --- a/src/models/password-ticket.js +++ b/src/models/password-ticket.js @@ -1,26 +1,26 @@ -const mongoose = require('mongoose'); - -const passwordTicketSchema = new mongoose.Schema( - { - email: { - type: String, - maxlength: [254, 'Should have less than 255 characters'], - required: [true, 'Is required'] - }, - expiresAt: { - type: Date, - required: [true, 'Is required'] - }, - key: { - type: String, - maxlength: [75, 'Should have less than 76 characters'], - required: [true, 'Is required'] - } - }, - { timestamps: true } -); - -module.exports = { - PasswordTicket: mongoose.model('PasswordTicket', passwordTicketSchema), - passwordTicketSchema -}; +const mongoose = require('mongoose'); + +const passwordTicketSchema = new mongoose.Schema( + { + email: { + type: String, + maxlength: [254, 'Should have less than 255 characters'], + required: [true, 'Is required'] + }, + expiresAt: { + type: Date, + required: [true, 'Is required'] + }, + key: { + type: String, + maxlength: [75, 'Should have less than 76 characters'], + required: [true, 'Is required'] + } + }, + { timestamps: true } +); + +module.exports = { + PasswordTicket: mongoose.model('PasswordTicket', passwordTicketSchema), + passwordTicketSchema +}; diff --git a/src/models/petition.js b/src/models/petition.js index af49041..01f3423 100644 --- a/src/models/petition.js +++ b/src/models/petition.js @@ -1,59 +1,59 @@ -const mongoose = require('mongoose'); - -const petitionSchema = new mongoose.Schema( - { - event: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Event' - }, - message: { - type: String, - maxlength: [300, 'Should be less than 301 characters'] - }, - sender: { - type: mongoose.Schema.Types.ObjectId, - ref: 'User', - required: [true, 'Is required'] - }, - state: { - type: String, - default: 'pending', - enum: { - values: ['accepted', 'canceled', 'pending', 'rejected'], - message: 'Should be a valid state' - }, - required: [true, 'Is required'] - }, - team: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Team' - }, - type: { - type: String, - enum: { - values: [ - 'invite-team-event', - 'invite-user-event', - 'invite-user-team', - 'request-team-event', - 'request-user-event', - 'request-user-team' - ], - message: 'Should be a valid type' - }, - required: [true, 'Is required'] - }, - user: { - type: mongoose.Schema.Types.ObjectId, - ref: 'User' - } - }, - { timestamps: true } -); - -petitionSchema.index({ createdAt: -1 }); - -module.exports = { - Petition: mongoose.model('Petition', petitionSchema), - petitionSchema -}; +const mongoose = require('mongoose'); + +const petitionSchema = new mongoose.Schema( + { + event: { + type: mongoose.Schema.Types.ObjectId, + ref: 'Event' + }, + message: { + type: String, + maxlength: [300, 'Should be less than 301 characters'] + }, + sender: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + required: [true, 'Is required'] + }, + state: { + type: String, + default: 'pending', + enum: { + values: ['accepted', 'canceled', 'pending', 'rejected'], + message: 'Should be a valid state' + }, + required: [true, 'Is required'] + }, + team: { + type: mongoose.Schema.Types.ObjectId, + ref: 'Team' + }, + type: { + type: String, + enum: { + values: [ + 'invite-team-event', + 'invite-user-event', + 'invite-user-team', + 'request-team-event', + 'request-user-event', + 'request-user-team' + ], + message: 'Should be a valid type' + }, + required: [true, 'Is required'] + }, + user: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User' + } + }, + { timestamps: true } +); + +petitionSchema.index({ createdAt: -1 }); + +module.exports = { + Petition: mongoose.model('Petition', petitionSchema), + petitionSchema +}; diff --git a/src/models/photo.js b/src/models/photo.js index 6a277a8..37d7049 100644 --- a/src/models/photo.js +++ b/src/models/photo.js @@ -1,66 +1,66 @@ -const mongoose = require('mongoose'); - -const photoSchema = new mongoose.Schema( - { - complaints: [ - { - comments: { - type: String, - maxlength: [300, 'Should be less than 301 characters'] - }, - createdAt: { - type: Date, - default: Date.now, - required: [true, 'Is required'] - }, - type: { - type: String, - enum: { - values: [ - 'biased', - 'copyright', - 'inconsistent', - 'offensive', - 'offtopic', - 'other', - 'spam' - ], - general: 'Invalid type of complaint' - }, - required: [true, 'Is required'] - }, - user: { - type: mongoose.Schema.Types.ObjectId, - ref: 'User', - required: [true, 'Is required'] - } - } - ], - fileName: { - type: String, - maxlength: [25, 'Should be less than 26 characters'], - required: [true, 'Is required'] - }, - isAllowed: { - type: Boolean, - default: true, - required: [true, 'Is required'] - }, - url: { - type: String, - maxlength: [2000, 'Should be less than 2001 characters'], - required: [true, 'Is required'] - }, - user: { - type: mongoose.Schema.Types.ObjectId, - ref: 'User', - required: [true, 'Is required'] - } - }, - { timestamps: true } -); - -module.exports = { - Photo: mongoose.model('Photo', photoSchema), - photoSchema -}; +const mongoose = require('mongoose'); + +const photoSchema = new mongoose.Schema( + { + complaints: [ + { + comments: { + type: String, + maxlength: [300, 'Should be less than 301 characters'] + }, + createdAt: { + type: Date, + default: Date.now, + required: [true, 'Is required'] + }, + type: { + type: String, + enum: { + values: [ + 'biased', + 'copyright', + 'inconsistent', + 'offensive', + 'offtopic', + 'other', + 'spam' + ], + general: 'Invalid type of complaint' + }, + required: [true, 'Is required'] + }, + user: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + required: [true, 'Is required'] + } + } + ], + fileName: { + type: String, + maxlength: [25, 'Should be less than 26 characters'], + required: [true, 'Is required'] + }, + isAllowed: { + type: Boolean, + default: true, + required: [true, 'Is required'] + }, + url: { + type: String, + maxlength: [2000, 'Should be less than 2001 characters'], + required: [true, 'Is required'] + }, + user: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + required: [true, 'Is required'] + } + }, + { timestamps: true } +); + +module.exports = { + Photo: mongoose.model('Photo', photoSchema), + photoSchema +}; diff --git a/src/models/refresh-token.js b/src/models/refresh-token.js index ac74a06..3ddeffe 100644 --- a/src/models/refresh-token.js +++ b/src/models/refresh-token.js @@ -1,27 +1,27 @@ -const mongoose = require('mongoose'); - -const refreshTokenSchema = new mongoose.Schema( - { - expiresAt: { - type: Date, - required: [true, 'Is required'] - }, - key: { - type: String, - maxlength: [80, 'Should have less than 81 characters'], - required: [true, 'Is required'], - unique: true - }, - userId: { - type: String, - maxlength: [24, 'Should have less than 25 characters'], - required: [true, 'Is required'] - } - }, - { timestamps: true } -); - -module.exports = { - RefreshToken: mongoose.model('RefreshToken', refreshTokenSchema), - refreshTokenSchema -}; +const mongoose = require('mongoose'); + +const refreshTokenSchema = new mongoose.Schema( + { + expiresAt: { + type: Date, + required: [true, 'Is required'] + }, + key: { + type: String, + maxlength: [80, 'Should have less than 81 characters'], + required: [true, 'Is required'], + unique: true + }, + userId: { + type: String, + maxlength: [24, 'Should have less than 25 characters'], + required: [true, 'Is required'] + } + }, + { timestamps: true } +); + +module.exports = { + RefreshToken: mongoose.model('RefreshToken', refreshTokenSchema), + refreshTokenSchema +}; diff --git a/src/models/review.js b/src/models/review.js index 7ed9617..f719643 100644 --- a/src/models/review.js +++ b/src/models/review.js @@ -1,122 +1,122 @@ -const mongoose = require('mongoose'); - -const reviewSchema = new mongoose.Schema( - { - //new expanded fields - hasPermanentRamp: Boolean, - hasPortableRamp: Boolean, - hasWideEntrance: Boolean, - hasAccessibleTableHeight: Boolean, - hasAccessibleElevator: Boolean, - hasInteriorRamp: Boolean, - hasSwingOutDoor: Boolean, - hasLargeStall: Boolean, - hasSupportAroundToilet: Boolean, - hasLoweredSinks: Boolean, - - //original fields - allowsGuideDog: Boolean, - comments: { - type: String, - maxlength: [300, 'Should be less than 301 characters'] - }, - complaints: [ - { - comments: { - type: String, - maxlength: [300, 'Should be less than 30 characters'] - }, - createdAt: { - type: Date, - default: Date.now, - required: [true, 'Is required'] - }, - type: { - type: String, - enum: { - values: [ - 'biased', - 'copyright', - 'inconsistent', - 'offensive', - 'offtopic', - 'other', - 'spam' - ], - general: 'Invalid type of complaint' - }, - required: [true, 'Is required'] - }, - user: { - type: mongoose.Schema.Types.ObjectId, - ref: 'User', - required: [true, 'Is required'] - } - } - ], - - /* - * deprecated 5-star scoring - */ - _entryScore: { - type: Number - //max: [9, 'Should be less than 10'], - //min: [1, 'Should be more than 0'] - }, - _bathroomScore: { - type: Number - //max: [4, 'Should be less than 5'], - //min: [1, 'Should be more than 0'] - }, - _isScoreConverted: { - type: Boolean, - default: false - }, - - event: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Event' - }, - hasParking: Boolean, - hasSecondEntry: Boolean, - hasWellLit: Boolean, - isBanned: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - isQuiet: Boolean, - isSpacious: Boolean, - steps: { - type: Number, - max: [3, 'Should be less than 4'], - min: [0, 'Should be more than -1'] - }, - team: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Team' - }, - user: { - type: mongoose.Schema.Types.ObjectId, - ref: 'User', - required: [true, 'Is required'] - }, - venue: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Venue', - required: [true, 'Is required'] - }, - voters: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'User' - } - ] - }, - { timestamps: true } -); - -module.exports = { - Review: mongoose.model('Review', reviewSchema), - reviewSchema -}; +const mongoose = require('mongoose'); + +const reviewSchema = new mongoose.Schema( + { + //new expanded fields + hasPermanentRamp: Boolean, + hasPortableRamp: Boolean, + hasWideEntrance: Boolean, + hasAccessibleTableHeight: Boolean, + hasAccessibleElevator: Boolean, + hasInteriorRamp: Boolean, + hasSwingOutDoor: Boolean, + hasLargeStall: Boolean, + hasSupportAroundToilet: Boolean, + hasLoweredSinks: Boolean, + + //original fields + allowsGuideDog: Boolean, + comments: { + type: String, + maxlength: [300, 'Should be less than 301 characters'] + }, + complaints: [ + { + comments: { + type: String, + maxlength: [300, 'Should be less than 30 characters'] + }, + createdAt: { + type: Date, + default: Date.now, + required: [true, 'Is required'] + }, + type: { + type: String, + enum: { + values: [ + 'biased', + 'copyright', + 'inconsistent', + 'offensive', + 'offtopic', + 'other', + 'spam' + ], + general: 'Invalid type of complaint' + }, + required: [true, 'Is required'] + }, + user: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + required: [true, 'Is required'] + } + } + ], + + /* + * deprecated 5-star scoring + */ + _entryScore: { + type: Number + //max: [9, 'Should be less than 10'], + //min: [1, 'Should be more than 0'] + }, + _bathroomScore: { + type: Number + //max: [4, 'Should be less than 5'], + //min: [1, 'Should be more than 0'] + }, + _isScoreConverted: { + type: Boolean, + default: false + }, + + event: { + type: mongoose.Schema.Types.ObjectId, + ref: 'Event' + }, + hasParking: Boolean, + hasSecondEntry: Boolean, + hasWellLit: Boolean, + isBanned: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + isQuiet: Boolean, + isSpacious: Boolean, + steps: { + type: Number, + max: [3, 'Should be less than 4'], + min: [0, 'Should be more than -1'] + }, + team: { + type: mongoose.Schema.Types.ObjectId, + ref: 'Team' + }, + user: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + required: [true, 'Is required'] + }, + venue: { + type: mongoose.Schema.Types.ObjectId, + ref: 'Venue', + required: [true, 'Is required'] + }, + voters: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'User' + } + ] + }, + { timestamps: true } +); + +module.exports = { + Review: mongoose.model('Review', reviewSchema), + reviewSchema +}; diff --git a/src/models/team.js b/src/models/team.js index 0d61217..9d96722 100644 --- a/src/models/team.js +++ b/src/models/team.js @@ -1,62 +1,62 @@ -const mongoose = require('mongoose'); - -const teamSchema = new mongoose.Schema( - { - avatar: { - type: String, - default: `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/teams/avatars/default.png`, - maxlength: [2000, 'Should be less than 2001 characters'], - required: [true, 'Is required'] - }, - description: { - type: String, - maxlength: [300, 'Should be less than 301 characters'] - }, - events: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'Event' - } - ], - isArchived: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - managers: { - type: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'User' - } - ], - required: [true, 'Is required'] - }, - members: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'User' - } - ], - name: { - type: String, - maxlength: [35, 'Should be less than 36 characters'], - required: [true, 'Is required'] - }, - reviewsAmount: { - type: Number, - default: 0, - required: [true, 'Is required'] - } - }, - { timestamps: true } -); - -teamSchema.index({ name: 'text', reviewsAmount: 1 }); - -module.exports = { - Team: mongoose.model('Team', teamSchema), - teamSchema -}; +const mongoose = require('mongoose'); + +const teamSchema = new mongoose.Schema( + { + avatar: { + type: String, + default: `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/teams/avatars/default.png`, + maxlength: [2000, 'Should be less than 2001 characters'], + required: [true, 'Is required'] + }, + description: { + type: String, + maxlength: [300, 'Should be less than 301 characters'] + }, + events: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'Event' + } + ], + isArchived: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + managers: { + type: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'User' + } + ], + required: [true, 'Is required'] + }, + members: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'User' + } + ], + name: { + type: String, + maxlength: [35, 'Should be less than 36 characters'], + required: [true, 'Is required'] + }, + reviewsAmount: { + type: Number, + default: 0, + required: [true, 'Is required'] + } + }, + { timestamps: true } +); + +teamSchema.index({ name: 'text', reviewsAmount: 1 }); + +module.exports = { + Team: mongoose.model('Team', teamSchema), + teamSchema +}; diff --git a/src/models/user.js b/src/models/user.js index e0c9cb9..949b077 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -1,193 +1,193 @@ -const bcrypt = require('bcrypt-nodejs'); -const mongoose = require('mongoose'); - -const userSchema = new mongoose.Schema( - { - avatar: { - type: String, - default: `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/users/avatars/default.png`, - maxlength: [2000, 'Should be less than 2001 characters'], - required: [true, 'Is required'] - }, - description: { - type: String, - maxlength: [2000, 'Should be less than 2001 characters'] - }, - disabilities: { - type: [String], - default: ['none'], - enum: { - values: [ - 'brain', - 'cognitive', - 'hearing', - 'invisible', - 'none', - 'other', - 'physical', - 'private', - 'psychological', - 'spinal-cord', - 'vision' - ], - general: 'Invalid type of disability' - }, - required: [true, 'Is required'] - }, - email: { - type: String, - maxlength: [254, 'Should be less than 255 characters'] - }, - events: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'Event' - } - ], - facebookId: String, - firstName: { - type: String, - maxlength: [24, 'Should be less than 25 characters'], - required: [true, 'Is required'] - }, - gender: { - type: String, - default: 'private', - enum: { - values: ['female', 'male', 'other', 'private', 'transgender'], - general: 'Invalid type of gender' - }, - required: [true, 'Is required'] - }, - googleId: String, - hashedPassword: { - type: String, - maxlength: [256, 'Should be less than 255 characters'] - }, - isAdmin: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - isArchived: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - isBlocked: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - isSubscribed: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - lastName: { - type: String, - maxlength: [36, 'Should be less than 37 characters'], - required: [true, 'Is required'] - }, - language: { - type: String, - default: 'en', - enum: { - values: ['en', 'es'], - general: 'Invalid type of language' - }, - required: [true, 'Is required'] - }, - phone: { - type: String, - maxlength: [50, 'Should be less than 51 characters'] - }, - reviewFieldsAmount: { - type: Number, - default: 0, - required: [true, 'Is required'] - }, - reviewsAmount: { - type: Number, - default: 0, - required: [true, 'Is required'] - }, - showDisabilities: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - showEmail: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - showPhone: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - teams: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'Team' - } - ], - username: { - type: String, - maxlength: [67, 'Should be less than 68 characters'] - }, - zip: { - type: String, - maxlength: [32, 'Should be less than 33 characters'] - } - }, - { timestamps: true } -); - -userSchema.index( - { - email: 'text', - firstName: 'text', - lastName: 'text', - username: 'text', - reviewsAmount: 1 - }, - { weights: { email: 5, username: 5 } } -); - -function hashPassword(password) { - bcrypt.genSalt(10, (errorOnSaltGeneration, salt) => { - if (errorOnSaltGeneration) { - return false; - } - - bcrypt.hash( - password, - salt, - null, - (errorOnHashingPassword, hashedPassword) => { - if (errorOnHashingPassword) { - return false; - } - - this.hashedPassword = hashedPassword; - return true; - } - ); - }); -} - -function comparePassword(password) { - return bcrypt.compareSync(password, this.hashedPassword); -} - -userSchema.virtual('password').set(hashPassword); -userSchema.methods.comparePassword = comparePassword; - -module.exports = { - User: mongoose.model('User', userSchema), - userSchema -}; +const bcrypt = require('bcrypt-nodejs'); +const mongoose = require('mongoose'); + +const userSchema = new mongoose.Schema( + { + avatar: { + type: String, + default: `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/users/avatars/default.png`, + maxlength: [2000, 'Should be less than 2001 characters'], + required: [true, 'Is required'] + }, + description: { + type: String, + maxlength: [2000, 'Should be less than 2001 characters'] + }, + disabilities: { + type: [String], + default: ['none'], + enum: { + values: [ + 'brain', + 'cognitive', + 'hearing', + 'invisible', + 'none', + 'other', + 'physical', + 'private', + 'psychological', + 'spinal-cord', + 'vision' + ], + general: 'Invalid type of disability' + }, + required: [true, 'Is required'] + }, + email: { + type: String, + maxlength: [254, 'Should be less than 255 characters'] + }, + events: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'Event' + } + ], + facebookId: String, + firstName: { + type: String, + maxlength: [24, 'Should be less than 25 characters'], + required: [true, 'Is required'] + }, + gender: { + type: String, + default: 'private', + enum: { + values: ['female', 'male', 'other', 'private', 'transgender'], + general: 'Invalid type of gender' + }, + required: [true, 'Is required'] + }, + googleId: String, + hashedPassword: { + type: String, + maxlength: [256, 'Should be less than 255 characters'] + }, + isAdmin: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + isArchived: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + isBlocked: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + isSubscribed: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + lastName: { + type: String, + maxlength: [36, 'Should be less than 37 characters'], + required: [true, 'Is required'] + }, + language: { + type: String, + default: 'en', + enum: { + values: ['en', 'es'], + general: 'Invalid type of language' + }, + required: [true, 'Is required'] + }, + phone: { + type: String, + maxlength: [50, 'Should be less than 51 characters'] + }, + reviewFieldsAmount: { + type: Number, + default: 0, + required: [true, 'Is required'] + }, + reviewsAmount: { + type: Number, + default: 0, + required: [true, 'Is required'] + }, + showDisabilities: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + showEmail: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + showPhone: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + teams: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'Team' + } + ], + username: { + type: String, + maxlength: [67, 'Should be less than 68 characters'] + }, + zip: { + type: String, + maxlength: [32, 'Should be less than 33 characters'] + } + }, + { timestamps: true } +); + +userSchema.index( + { + email: 'text', + firstName: 'text', + lastName: 'text', + username: 'text', + reviewsAmount: 1 + }, + { weights: { email: 5, username: 5 } } +); + +function hashPassword(password) { + bcrypt.genSalt(10, (errorOnSaltGeneration, salt) => { + if (errorOnSaltGeneration) { + return false; + } + + bcrypt.hash( + password, + salt, + null, + (errorOnHashingPassword, hashedPassword) => { + if (errorOnHashingPassword) { + return false; + } + + this.hashedPassword = hashedPassword; + return true; + } + ); + }); +} + +function comparePassword(password) { + return bcrypt.compareSync(password, this.hashedPassword); +} + +userSchema.virtual('password').set(hashPassword); +userSchema.methods.comparePassword = comparePassword; + +module.exports = { + User: mongoose.model('User', userSchema), + userSchema +}; diff --git a/src/models/venue.js b/src/models/venue.js index 9c473f4..e0c475d 100644 --- a/src/models/venue.js +++ b/src/models/venue.js @@ -1,315 +1,315 @@ -const mongoose = require('mongoose'); - -const venueSchema = new mongoose.Schema( - { - //new expanded fields - hasPermanentRamp: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasPortableRamp: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasWideEntrance: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasAccessibleTableHeight: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasAccessibleElevator: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasInteriorRamp: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasSwingOutDoor: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasLargeStall: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasSupportAroundToilet: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasLoweredSinks: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - entranceScore: { - //enum: ['alert', 'caution', 'accessible', 'default'], - //description: 'can only be one of the enum values and is required', - //default: 'default' - type: Number, - default: 0 - }, - entranceGlyphs: { - type: String, - maxlength: [32, 'Should be less than 256 characters'] - }, - interiorScore: { - //enum: ['alert', 'caution', 'accessible', 'default'], - //description: 'can only be one of the enum values and is required', - //: 'default' - type: Number, - default: 0 - }, - interiorGlyphs: { - type: String, - maxlength: [32, 'Should be less than 256 characters'] - }, - restroomScore: { - //enum: ['alert', 'caution', 'accessible', 'default'], - //: 'can only be one of the enum values and is required', - //default: 'default' - type: Number, - default: 0 - }, - restroomGlyphs: { - type: String, - maxlength: [32, 'Should be less than 256 characters'] - }, - mapMarkerScore: { - type: Number, - default: 0 - }, - - //original fields - address: { - type: String, - maxlength: [255, 'Should be less than 256 characters'] - }, - allowsGuideDog: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - - /* - * deprecated 5-star scoring - */ - _bathroomReviews: { - type: Number, - default: 0 - //min: [0, 'Should be more than 1'] - }, - _bathroomScore: { - type: Number - //max: [4, 'Should be less than 5'], - //min: [1, 'Should be more than 0'] - }, - _entryReviews: { - type: Number, - default: 0 - //min: [0, 'Should be more than -1'] - }, - _entryScore: { - type: Number - //max: [9, 'Should be less than 10'], - //min: [1, 'Should be more than 0'] - }, - _isScoreConverted: { - type: Boolean, - default: false - }, - - hasParking: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasSecondEntry: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasWellLit: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - isArchived: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - isQuiet: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - isSpacious: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - location: { - type: { - type: String, - default: 'Point' - }, - coordinates: [Number] - }, - name: { - type: String, - maxlength: [255, 'Should be less than 256 characters'] - }, - photos: [ - { - type: mongoose.Schema.ObjectId, - ref: 'Photo' - } - ], - placeId: { - type: String, - maxlength: [255, 'Should be less than 256 characters'], - required: [true, 'Is required'] - }, - reviews: [ - { - type: mongoose.Schema.ObjectId, - ref: 'Review' - } - ], - steps: { - zero: { - type: Number, - default: 0 - }, - one: { - type: Number, - default: 0 - }, - two: { - type: Number, - default: 0 - }, - moreThanTwo: { - type: Number, - default: 0 - } - }, - types: [ - { - type: String, - maxlength: [50, 'Should be less than 51 characters'] - } - ] - }, - { timestamps: true } -); - -venueSchema.index({ location: '2dsphere', placeId: 1 }); - -venueSchema.virtual('coordinates').get(function() { - return { - lat: this.location.coordinates[1], - lng: this.location.coordinates[0] - }; -}); - -venueSchema.virtual('photo').get(function() { - return undefined; -}); - -module.exports = { - Venue: mongoose.model('Venue', venueSchema), - venueSchema -}; +const mongoose = require('mongoose'); + +const venueSchema = new mongoose.Schema( + { + //new expanded fields + hasPermanentRamp: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasPortableRamp: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasWideEntrance: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasAccessibleTableHeight: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasAccessibleElevator: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasInteriorRamp: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasSwingOutDoor: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasLargeStall: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasSupportAroundToilet: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasLoweredSinks: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + entranceScore: { + //enum: ['alert', 'caution', 'accessible', 'default'], + //description: 'can only be one of the enum values and is required', + //default: 'default' + type: Number, + default: 0 + }, + entranceGlyphs: { + type: String, + maxlength: [32, 'Should be less than 256 characters'] + }, + interiorScore: { + //enum: ['alert', 'caution', 'accessible', 'default'], + //description: 'can only be one of the enum values and is required', + //: 'default' + type: Number, + default: 0 + }, + interiorGlyphs: { + type: String, + maxlength: [32, 'Should be less than 256 characters'] + }, + restroomScore: { + //enum: ['alert', 'caution', 'accessible', 'default'], + //: 'can only be one of the enum values and is required', + //default: 'default' + type: Number, + default: 0 + }, + restroomGlyphs: { + type: String, + maxlength: [32, 'Should be less than 256 characters'] + }, + mapMarkerScore: { + type: Number, + default: 0 + }, + + //original fields + address: { + type: String, + maxlength: [255, 'Should be less than 256 characters'] + }, + allowsGuideDog: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + + /* + * deprecated 5-star scoring + */ + _bathroomReviews: { + type: Number, + default: 0 + //min: [0, 'Should be more than 1'] + }, + _bathroomScore: { + type: Number + //max: [4, 'Should be less than 5'], + //min: [1, 'Should be more than 0'] + }, + _entryReviews: { + type: Number, + default: 0 + //min: [0, 'Should be more than -1'] + }, + _entryScore: { + type: Number + //max: [9, 'Should be less than 10'], + //min: [1, 'Should be more than 0'] + }, + _isScoreConverted: { + type: Boolean, + default: false + }, + + hasParking: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasSecondEntry: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasWellLit: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + isArchived: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + isQuiet: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + isSpacious: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + location: { + type: { + type: String, + default: 'Point' + }, + coordinates: [Number] + }, + name: { + type: String, + maxlength: [255, 'Should be less than 256 characters'] + }, + photos: [ + { + type: mongoose.Schema.ObjectId, + ref: 'Photo' + } + ], + placeId: { + type: String, + maxlength: [255, 'Should be less than 256 characters'], + required: [true, 'Is required'] + }, + reviews: [ + { + type: mongoose.Schema.ObjectId, + ref: 'Review' + } + ], + steps: { + zero: { + type: Number, + default: 0 + }, + one: { + type: Number, + default: 0 + }, + two: { + type: Number, + default: 0 + }, + moreThanTwo: { + type: Number, + default: 0 + } + }, + types: [ + { + type: String, + maxlength: [50, 'Should be less than 51 characters'] + } + ] + }, + { timestamps: true } +); + +venueSchema.index({ location: '2dsphere', placeId: 1 }); + +venueSchema.virtual('coordinates').get(function () { + return { + lat: this.location.coordinates[1], + lng: this.location.coordinates[0] + }; +}); + +venueSchema.virtual('photo').get(function () { + return undefined; +}); + +module.exports = { + Venue: mongoose.model('Venue', venueSchema), + venueSchema +}; diff --git a/src/routes/auth/activate-account.js b/src/routes/auth/activate-account.js index b78caf7..e5a0655 100644 --- a/src/routes/auth/activate-account.js +++ b/src/routes/auth/activate-account.js @@ -1,139 +1,139 @@ -const crypto = require('crypto'); - -const moment = require('moment'); -const randomstring = require('randomstring'); -const slugify = require('speakingurl'); - -const { ActivationTicket } = require('../../models/activation-ticket'); -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); - -module.exports = async (req, res, next) => { - const key = req.params.key; - - let activationTicket; - try { - activationTicket = await ActivationTicket.findOne({ key }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Activation ticket not found' }); - } - - console.log( - `Activation ticket with key ${key} failed to be found at activate-account.` - ); - return next(err); - } - - if (!activationTicket) { - return res.status(404).json({ general: 'Activation ticket not found' }); - } - - let expiresAt = moment(activationTicket.expiresAt).utc(); - const now = moment.utc(); - if (expiresAt.isBefore(now)) { - try { - await activationTicket.remove(); - } catch (err) { - console.log( - `Activation ticket with key ${ - activationTicket.key - } failed to be deleted at activate-account.` - ); - return next(err); - } - - return res.status(400).json({ general: 'Activation ticket expired' }); - } - - const userData = Object.assign({}, activationTicket.userData, { - email: activationTicket.email - }); - - let repeatedUsers; - try { - repeatedUsers = await User.find({ - $or: [{ email: userData.email }, { username: userData.username }], - isArchived: false - }); - } catch (err) { - console.log('Users failed to be found at activate-account.'); - return next(err); - } - - if (repeatedUsers && repeatedUsers.length > 0) { - for (const user of repeatedUsers) { - if (user.email === userData.email) { - return res.status(400).json({ email: 'Is already taken' }); - } - - let repeatedUser; - do { - userData.username = `${slugify(userData.firstName)}-${slugify( - userData.lastName - )}-${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}`; - - try { - repeatedUser = await User.findOne({ - username: userData.username, - isArchived: false - }); - } catch (err) { - console.log( - `User with username ${ - userData.username - } failed to be found at activate-account.` - ); - return next(err); - } - } while (repeatedUser && repeatedUser.username === userData.username); - } - } - - let user; - try { - user = await User.create(userData); - } catch (err) { - console.log( - `User failed to be created at activate-account.\nData: ${JSON.stringify( - userData - )}` - ); - return next(err); - } - - const today = moment.utc(); - expiresAt = today.add(14, 'days').toDate(); - const refreshTokenData = { - expiresAt, - key: `${user.id}${crypto.randomBytes(28).toString('hex')}`, - userId: user.id - }; - - try { - await RefreshToken.create(refreshTokenData); - } catch (err) { - console.log( - `Refresh token failed to be created at activate-account.\nData: ${JSON.stringify( - refreshTokenData - )}` - ); - return next(err); - } - - try { - await activationTicket.remove(); - } catch (err) { - console.log( - `Activation ticket with key ${ - activationTicket.key - } failed to be deleted at activate-account.` - ); - return next(err); - } - - return res.redirect(`${process.env.APP_URL}/sign-in`); -}; +const crypto = require('crypto'); + +const moment = require('moment'); +const randomstring = require('randomstring'); +const slugify = require('speakingurl'); + +const { ActivationTicket } = require('../../models/activation-ticket'); +const { RefreshToken } = require('../../models/refresh-token'); +const { User } = require('../../models/user'); + +module.exports = async (req, res, next) => { + const key = req.params.key; + + let activationTicket; + try { + activationTicket = await ActivationTicket.findOne({ key }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Activation ticket not found' }); + } + + console.log( + `Activation ticket with key ${key} failed to be found at activate-account.` + ); + return next(err); + } + + if (!activationTicket) { + return res.status(404).json({ general: 'Activation ticket not found' }); + } + + let expiresAt = moment(activationTicket.expiresAt).utc(); + const now = moment.utc(); + if (expiresAt.isBefore(now)) { + try { + await activationTicket.remove(); + } catch (err) { + console.log( + `Activation ticket with key ${ + activationTicket.key + } failed to be deleted at activate-account.` + ); + return next(err); + } + + return res.status(400).json({ general: 'Activation ticket expired' }); + } + + const userData = Object.assign({}, activationTicket.userData, { + email: activationTicket.email + }); + + let repeatedUsers; + try { + repeatedUsers = await User.find({ + $or: [{ email: userData.email }, { username: userData.username }], + isArchived: false + }); + } catch (err) { + console.log('Users failed to be found at activate-account.'); + return next(err); + } + + if (repeatedUsers && repeatedUsers.length > 0) { + for (const user of repeatedUsers) { + if (user.email === userData.email) { + return res.status(400).json({ email: 'Is already taken' }); + } + + let repeatedUser; + do { + userData.username = `${slugify(userData.firstName)}-${slugify( + userData.lastName + )}-${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}`; + + try { + repeatedUser = await User.findOne({ + username: userData.username, + isArchived: false + }); + } catch (err) { + console.log( + `User with username ${ + userData.username + } failed to be found at activate-account.` + ); + return next(err); + } + } while (repeatedUser && repeatedUser.username === userData.username); + } + } + + let user; + try { + user = await User.create(userData); + } catch (err) { + console.log( + `User failed to be created at activate-account.\nData: ${JSON.stringify( + userData + )}` + ); + return next(err); + } + + const today = moment.utc(); + expiresAt = today.add(14, 'days').toDate(); + const refreshTokenData = { + expiresAt, + key: `${user.id}${crypto.randomBytes(28).toString('hex')}`, + userId: user.id + }; + + try { + await RefreshToken.create(refreshTokenData); + } catch (err) { + console.log( + `Refresh token failed to be created at activate-account.\nData: ${JSON.stringify( + refreshTokenData + )}` + ); + return next(err); + } + + try { + await activationTicket.remove(); + } catch (err) { + console.log( + `Activation ticket with key ${ + activationTicket.key + } failed to be deleted at activate-account.` + ); + return next(err); + } + + return res.redirect(`${process.env.APP_URL}/sign-in`); +}; diff --git a/src/routes/auth/facebook-sign-in.js b/src/routes/auth/facebook-sign-in.js index bc68c5e..d5477ac 100644 --- a/src/routes/auth/facebook-sign-in.js +++ b/src/routes/auth/facebook-sign-in.js @@ -1,200 +1,201 @@ -const crypto = require('crypto'); - -const axios = require('axios'); -const jwt = require('jsonwebtoken'); -const moment = require('moment'); -const randomstring = require('randomstring'); -const slugify = require('speakingurl'); - -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); - -const { validateFacebookSignIn } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateFacebookSignIn(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const code = req.body.code; - - const getTokenUrl = 'https://graph.facebook.com/v2.10/oauth/access_token'; - const getTokenParams = { - code, - client_id: process.env.FACEBOOK_CLIENT_ID, - client_secret: process.env.FACEBOOK_CLIENT_SECRET, - redirect_uri: `${process.env.APP_URL}/auth/facebook` - }; - let getTokenResponse; - try { - getTokenResponse = await axios.get(getTokenUrl, { params: getTokenParams }); - } catch (err) { - return res.status(400).json({ general: 'Invalid code' }); - } - - const facebookToken = getTokenResponse.data.access_token; - - const getProfileUrl = - 'https://graph.facebook.com/v2.10/me?fields=id,email,first_name,last_name,locale'; - const getProfileOptions = { - params: { - access_token: facebookToken - } - }; - let getProfileResponse; - try { - getProfileResponse = await axios.get(getProfileUrl, getProfileOptions); - } catch (err) { - console.log('Profile data failed to be found at facebook-sign-in.'); - return next(err); - } - - const email = getProfileResponse.data.email - ? getProfileResponse.data.email - : ''; - const facebookId = getProfileResponse.data.id; - let user; - try { - user = await User.findOne({ - $or: [{ email }, { facebookId }], - isArchived: false - }); - } catch (err) { - console.log( - `User with facebookId ${facebookId} and email ${email} failed to be found at facebook-sign-in.` - ); - return next(err); - } - - let accessToken; - let refreshToken; - - if (!user) { - console.log(getProfileResponse.data); - const userData = { - email: getProfileResponse.data.email ? getProfileResponse.data.email : '', - facebookId: getProfileResponse.data.id, - firstName: getProfileResponse.data.first_name, - lastName: getProfileResponse.data.last_name - }; - userData.username = `${slugify(userData.firstName)}-${slugify( - userData.lastName - )}`; - - let repeatedUsers; - try { - repeatedUsers = await User.find({ - username: userData.username, - isArchived: false - }); - } catch (err) { - console.log('Users failed to be found at facebook-sign-in.'); - return next(err); - } - - if (repeatedUsers && repeatedUsers.length > 0) { - let repeatedUser; - do { - userData.username = `${slugify(userData.firstName)}-${slugify( - userData.lastName - )}-${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}`; - - try { - repeatedUser = await User.findOne({ - username: userData.username, - isArchived: false - }); - } catch (err) { - console.log( - `User with username ${ - userData.username - } failed to be found at facebook-sign-in.` - ); - return next(err); - } - } while (repeatedUser && repeatedUser.username === userData.username); - } - - const getPictureUrl = `https://graph.facebook.com/v2.10/${ - userData.facebookId - }/picture`; - const getPictureOptions = { - params: { - access_token: accessToken, - redirect: false, - type: 'large' - } - }; - let getPictureResponse; - try { - getPictureResponse = await axios.get(getPictureUrl, getPictureOptions); - } catch (err) { - console.log('User picture failed to be found at facebook-sign-in.'); - return next(err); - } - - const isSilhouette = getPictureResponse.data.data.is_silhouette; - if (!isSilhouette) { - userData.avatar = getPictureResponse.data.data.url; - } - - try { - user = await User.create(userData); - } catch (err) { - console.log( - `User failed to be created at facebook-sign-in.\nData: ${JSON.stringify( - userData - )}` - ); - return next(err); - } - - const today = moment.utc(); - const expiresAt = today.add(14, 'days').toDate(); - const refreshTokenData = { - expiresAt, - key: `${user.id}${crypto.randomBytes(28).toString('hex')}`, - userId: user.id - }; - - try { - refreshToken = await RefreshToken.create(refreshTokenData); - } catch (err) { - console.log( - `Refresh token failed to be created at facebook-sign-in.\nData: ${JSON.stringify( - refreshTokenData - )}` - ); - return next(err); - } - } else { - const userId = user.id; - const today = moment.utc(); - const expiresAt = today.add(14, 'days').toDate(); - const key = `${userId}${crypto.randomBytes(28).toString('hex')}`; - - try { - refreshToken = await RefreshToken.findOneAndUpdate( - { userId }, - { expiresAt, key, userId }, - { new: true, setDefaultsOnInsert: true, upsert: true } - ); - } catch (err) { - console.log( - `Refresh Token for userId ${userId} failed to be created or updated at facebook-sign-in.` - ); - return next(err); - } - } - - const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { - expiresIn: 3600 - }); - refreshToken = refreshToken.key; - - return res.status(200).json({ token, refreshToken }); -}; +const crypto = require('crypto'); + +const axios = require('axios'); +const jwt = require('jsonwebtoken'); +const moment = require('moment'); +const randomstring = require('randomstring'); +const slugify = require('speakingurl'); + +const { RefreshToken } = require('../../models/refresh-token'); +const { User } = require('../../models/user'); + +const { validateFacebookSignIn } = require('./validations'); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateFacebookSignIn(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const code = req.body.code; + + const getTokenUrl = 'https://graph.facebook.com/v2.10/oauth/access_token'; + const getTokenParams = { + code, + client_id: process.env.FACEBOOK_CLIENT_ID, + client_secret: process.env.FACEBOOK_CLIENT_SECRET, + redirect_uri: `${process.env.APP_URL}/auth/facebook` + }; + let getTokenResponse; + try { + getTokenResponse = await axios.get(getTokenUrl, { params: getTokenParams }); + } catch (err) { + console.err(err); + return res.status(400).json({ general: 'Invalid code' }); + } + + const facebookToken = getTokenResponse.data.access_token; + + const getProfileUrl = + 'https://graph.facebook.com/v2.10/me?fields=id,email,first_name,last_name,locale'; + const getProfileOptions = { + params: { + access_token: facebookToken + } + }; + let getProfileResponse; + try { + getProfileResponse = await axios.get(getProfileUrl, getProfileOptions); + } catch (err) { + console.log('Profile data failed to be found at facebook-sign-in.'); + return next(err); + } + + const email = getProfileResponse.data.email + ? getProfileResponse.data.email + : ''; + const facebookId = getProfileResponse.data.id; + let user; + try { + user = await User.findOne({ + $or: [{ email }, { facebookId }], + isArchived: false + }); + } catch (err) { + console.log( + `User with facebookId ${facebookId} and email ${email} failed to be found at facebook-sign-in.` + ); + return next(err); + } + + let accessToken; + let refreshToken; + + if (!user) { + console.log(getProfileResponse.data); + const userData = { + email: getProfileResponse.data.email ? getProfileResponse.data.email : '', + facebookId: getProfileResponse.data.id, + firstName: getProfileResponse.data.first_name, + lastName: getProfileResponse.data.last_name + }; + userData.username = `${slugify(userData.firstName)}-${slugify( + userData.lastName + )}`; + + let repeatedUsers; + try { + repeatedUsers = await User.find({ + username: userData.username, + isArchived: false + }); + } catch (err) { + console.log('Users failed to be found at facebook-sign-in.'); + return next(err); + } + + if (repeatedUsers && repeatedUsers.length > 0) { + let repeatedUser; + do { + userData.username = `${slugify(userData.firstName)}-${slugify( + userData.lastName + )}-${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}`; + + try { + repeatedUser = await User.findOne({ + username: userData.username, + isArchived: false + }); + } catch (err) { + console.log( + `User with username ${ + userData.username + } failed to be found at facebook-sign-in.` + ); + return next(err); + } + } while (repeatedUser && repeatedUser.username === userData.username); + } + + const getPictureUrl = `https://graph.facebook.com/v2.10/${ + userData.facebookId + }/picture`; + const getPictureOptions = { + params: { + access_token: accessToken, + redirect: false, + type: 'large' + } + }; + let getPictureResponse; + try { + getPictureResponse = await axios.get(getPictureUrl, getPictureOptions); + } catch (err) { + console.log('User picture failed to be found at facebook-sign-in.'); + return next(err); + } + + const isSilhouette = getPictureResponse.data.data.is_silhouette; + if (!isSilhouette) { + userData.avatar = getPictureResponse.data.data.url; + } + + try { + user = await User.create(userData); + } catch (err) { + console.log( + `User failed to be created at facebook-sign-in.\nData: ${JSON.stringify( + userData + )}` + ); + return next(err); + } + + const today = moment.utc(); + const expiresAt = today.add(14, 'days').toDate(); + const refreshTokenData = { + expiresAt, + key: `${user.id}${crypto.randomBytes(28).toString('hex')}`, + userId: user.id + }; + + try { + refreshToken = await RefreshToken.create(refreshTokenData); + } catch (err) { + console.log( + `Refresh token failed to be created at facebook-sign-in.\nData: ${JSON.stringify( + refreshTokenData + )}` + ); + return next(err); + } + } else { + const userId = user.id; + const today = moment.utc(); + const expiresAt = today.add(14, 'days').toDate(); + const key = `${userId}${crypto.randomBytes(28).toString('hex')}`; + + try { + refreshToken = await RefreshToken.findOneAndUpdate( + { userId }, + { expiresAt, key, userId }, + { new: true, setDefaultsOnInsert: true, upsert: true } + ); + } catch (err) { + console.log( + `Refresh Token for userId ${userId} failed to be created or updated at facebook-sign-in.` + ); + return next(err); + } + } + + const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { + expiresIn: 3600 + }); + refreshToken = refreshToken.key; + + return res.status(200).json({ token, refreshToken }); +}; diff --git a/src/routes/auth/forgotten-password.js b/src/routes/auth/forgotten-password.js index ed3039f..e1e18f7 100644 --- a/src/routes/auth/forgotten-password.js +++ b/src/routes/auth/forgotten-password.js @@ -1,88 +1,88 @@ -const crypto = require('crypto'); - -const moment = require('moment'); - -const { PasswordTicket } = require('../../models/password-ticket'); -const { sendEmail } = require('../../helpers'); -const { User } = require('../../models/user'); - -const { validateForgottenPassword } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateForgottenPassword(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const email = req.body.email; - - let user; - try { - user = await User.findOne({ email, isArchived: false }); - } catch (err) { - console.log( - `User with email ${email} failed to be found at forgotten-password.` - ); - return next(err); - } - - if (!user) { - return res.status(200).json({ general: 'Success' }); - } - - try { - await PasswordTicket.remove({ email }); - } catch (err) { - console.log( - `Password ticket with email ${email} failed to be removed at forgotten-password.` - ); - return next(err); - } - - const today = moment.utc(); - const expiresAt = today.add(1, 'days').toDate(); - const key = `${crypto - .randomBytes(31) - .toString('hex')}${new Date().getTime().toString()}`; - - let passwordTicket; - try { - passwordTicket = await PasswordTicket.create({ email, expiresAt, key }); - } catch (err) { - console.log( - `Password ticket failed to be created at forgotten-password.\nData: ${JSON.stringify( - { email, expiresAt, key } - )}` - ); - return next(err); - } - - const htmlContent = ` -
To reset your password use the link below:
-Stay awesome.
- `; - const receiversEmails = [passwordTicket.email]; - const subject = 'Reset Password'; - const textContent = ` - Hi from AXS Map! - To reset your password use the link below: - ${process.env.APP_URL}/reset-password?key=${passwordTicket.key} - Stay awesome. - `; - - sendEmail({ - receiversEmails, - subject, - htmlContent, - textContent - }); - - return res.status(200).json({ general: 'Success' }); -}; +const crypto = require('crypto'); + +const moment = require('moment'); + +const { PasswordTicket } = require('../../models/password-ticket'); +const { sendEmail } = require('../../helpers'); +const { User } = require('../../models/user'); + +const { validateForgottenPassword } = require('./validations'); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateForgottenPassword(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const email = req.body.email; + + let user; + try { + user = await User.findOne({ email, isArchived: false }); + } catch (err) { + console.log( + `User with email ${email} failed to be found at forgotten-password.` + ); + return next(err); + } + + if (!user) { + return res.status(200).json({ general: 'Success' }); + } + + try { + await PasswordTicket.remove({ email }); + } catch (err) { + console.log( + `Password ticket with email ${email} failed to be removed at forgotten-password.` + ); + return next(err); + } + + const today = moment.utc(); + const expiresAt = today.add(1, 'days').toDate(); + const key = `${crypto + .randomBytes(31) + .toString('hex')}${new Date().getTime().toString()}`; + + let passwordTicket; + try { + passwordTicket = await PasswordTicket.create({ email, expiresAt, key }); + } catch (err) { + console.log( + `Password ticket failed to be created at forgotten-password.\nData: ${JSON.stringify( + { email, expiresAt, key } + )}` + ); + return next(err); + } + + const htmlContent = ` +To reset your password use the link below:
+Stay awesome.
+ `; + const receiversEmails = [passwordTicket.email]; + const subject = 'Reset Password'; + const textContent = ` + Hi from AXS Map! + To reset your password use the link below: + ${process.env.APP_URL}/reset-password?key=${passwordTicket.key} + Stay awesome. + `; + + sendEmail({ + receiversEmails, + subject, + htmlContent, + textContent + }); + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/auth/generate-token.js b/src/routes/auth/generate-token.js index ba1016f..689e2d2 100644 --- a/src/routes/auth/generate-token.js +++ b/src/routes/auth/generate-token.js @@ -1,55 +1,55 @@ -const jwt = require('jsonwebtoken'); -const moment = require('moment'); - -const { RefreshToken } = require('../../models/refresh-token'); - -const { validateGenerateToken } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateGenerateToken(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const key = req.body.key; - - let refreshToken; - try { - refreshToken = await RefreshToken.findOne({ key }); - } catch (err) { - console.log( - `Refresh Token with key ${key} failed to be found at generate-token.` - ); - return next(err); - } - - if (!refreshToken) { - return res.status(404).json({ general: 'Refresh Token not found' }); - } - - const expiresAt = moment(refreshToken.expiresAt).utc(); - const today = moment.utc(); - if (expiresAt.isBefore(today)) { - try { - await refreshToken.remove(); - } catch (err) { - console.log( - `Refresh Token with key ${ - refreshToken.key - } failed to be removed at generate-token.` - ); - return next(err); - } - - return res.status(401).json({ general: 'Refresh Token expired' }); - } - - const token = jwt.sign( - { userId: refreshToken.userId }, - process.env.JWT_SECRET, - { - expiresIn: 3600 - } - ); - return res.status(200).json({ token }); -}; +const jwt = require('jsonwebtoken'); +const moment = require('moment'); + +const { RefreshToken } = require('../../models/refresh-token'); + +const { validateGenerateToken } = require('./validations'); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateGenerateToken(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const key = req.body.key; + + let refreshToken; + try { + refreshToken = await RefreshToken.findOne({ key }); + } catch (err) { + console.log( + `Refresh Token with key ${key} failed to be found at generate-token.` + ); + return next(err); + } + + if (!refreshToken) { + return res.status(404).json({ general: 'Refresh Token not found' }); + } + + const expiresAt = moment(refreshToken.expiresAt).utc(); + const today = moment.utc(); + if (expiresAt.isBefore(today)) { + try { + await refreshToken.remove(); + } catch (err) { + console.log( + `Refresh Token with key ${ + refreshToken.key + } failed to be removed at generate-token.` + ); + return next(err); + } + + return res.status(401).json({ general: 'Refresh Token expired' }); + } + + const token = jwt.sign( + { userId: refreshToken.userId }, + process.env.JWT_SECRET, + { + expiresIn: 3600 + } + ); + return res.status(200).json({ token }); +}; diff --git a/src/routes/auth/google-sign-in.js b/src/routes/auth/google-sign-in.js index 6031188..14c2a84 100644 --- a/src/routes/auth/google-sign-in.js +++ b/src/routes/auth/google-sign-in.js @@ -1,188 +1,189 @@ -const crypto = require('crypto'); -const querystring = require('querystring'); - -const axios = require('axios'); -const GoogleAuth = require('google-auth-library'); -const jwt = require('jsonwebtoken'); -const moment = require('moment'); -const randomstring = require('randomstring'); -const slugify = require('speakingurl'); - -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); - -const { validateGoogleSignIn } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateGoogleSignIn(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const code = req.body.code; - - const getTokenUrl = 'https://www.googleapis.com/oauth2/v4/token'; - const getTokenParams = { - code, - client_id: process.env.GOOGLE_CLIENT_ID, - client_secret: process.env.GOOGLE_CLIENT_SECRET, - redirect_uri: `${process.env.APP_URL}/auth/google`, - grant_type: 'authorization_code' - }; - let getTokenResponse; - try { - getTokenResponse = await axios.post( - getTokenUrl, - querystring.stringify(getTokenParams) - ); - } catch (err) { - return res.status(400).json({ general: 'Invalid code' }); - } - - const auth = new GoogleAuth(); - const client = new auth.OAuth2(process.env.GOOGLE_CLIENT_ID, '', ''); - const idToken = getTokenResponse.data.id_token; - client.verifyIdToken( - idToken, - process.env.GOOGLE_CLIENT_ID, - async (err, login) => { - if (err) { - return res.status(400).json({ general: 'Invalid token id' }); - } - - const payload = login.getPayload(); - - const email = payload.email; - const googleId = payload.sub; - let user; - try { - user = await User.findOne({ - $or: [{ email }, { googleId }], - isArchived: false - }); - } catch (err) { - console.log( - `User with googleId ${googleId} and email ${email} failed to be found at google-sign-in.` - ); - return next(err); - } - - let refreshToken; - - if (!user) { - const userData = { - email: payload.email, - googleId: payload.sub, - firstName: payload.given_name, - lastName: payload.family_name - }; - - if (payload.locale === 'en') { - userData.language = 'en'; - } else if (payload.locale === 'es') { - userData.language = 'es'; - } - - if (payload.picture) { - userData.avatar = payload.picture; - } - - userData.username = `${slugify(userData.firstName)}-${slugify( - userData.lastName - )}`; - - let repeatedUsers; - try { - repeatedUsers = await User.find({ - username: userData.username, - isArchived: false - }); - } catch (err) { - console.log('Users failed to be found at google-sign-in.'); - return next(err); - } - - if (repeatedUsers && repeatedUsers.length > 0) { - let repeatedUser; - do { - userData.username = `${slugify(userData.firstName)}-${slugify( - userData.lastName - )}-${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}`; - - try { - repeatedUser = await User.findOne({ - username: userData.username, - isArchived: false - }); - } catch (err) { - console.log( - `User with username ${ - userData.username - } failed to be found at google-sign-in.` - ); - return next(err); - } - } while (repeatedUser && repeatedUser.username === userData.username); - } - - try { - user = await User.create(userData); - } catch (err) { - console.log( - `User failed to be created at google-sign-in.\nData: ${JSON.stringify( - userData - )}` - ); - return next(err); - } - - const today = moment.utc(); - const expiresAt = today.add(14, 'days').toDate(); - const refreshTokenData = { - expiresAt, - key: `${user.id}${crypto.randomBytes(28).toString('hex')}`, - userId: user.id - }; - - try { - refreshToken = await RefreshToken.create(refreshTokenData); - } catch (err) { - console.log( - `Refresh token failed to be created at google-sign-in.\nData: ${JSON.stringify( - refreshTokenData - )}` - ); - return next(err); - } - } else { - const userId = user.id; - const today = moment.utc(); - const expiresAt = today.add(14, 'days').toDate(); - const key = `${userId}${crypto.randomBytes(28).toString('hex')}`; - - try { - refreshToken = await RefreshToken.findOneAndUpdate( - { userId }, - { expiresAt, key, userId }, - { new: true, setDefaultsOnInsert: true, upsert: true } - ); - } catch (err) { - console.log( - `Refresh Token for userId ${userId} failed to be created or updated at google-sign-in.` - ); - return next(err); - } - } - - const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { - expiresIn: 3600 - }); - refreshToken = refreshToken.key; - - return res.status(200).json({ token, refreshToken }); - } - ); -}; +const crypto = require('crypto'); +const querystring = require('querystring'); + +const axios = require('axios'); +const GoogleAuth = require('google-auth-library'); +const jwt = require('jsonwebtoken'); +const moment = require('moment'); +const randomstring = require('randomstring'); +const slugify = require('speakingurl'); + +const { RefreshToken } = require('../../models/refresh-token'); +const { User } = require('../../models/user'); + +const { validateGoogleSignIn } = require('./validations'); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateGoogleSignIn(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const code = req.body.code; + + const getTokenUrl = 'https://www.googleapis.com/oauth2/v4/token'; + const getTokenParams = { + code, + client_id: process.env.GOOGLE_CLIENT_ID, + client_secret: process.env.GOOGLE_CLIENT_SECRET, + redirect_uri: `${process.env.APP_URL}/auth/google`, + grant_type: 'authorization_code' + }; + let getTokenResponse; + try { + getTokenResponse = await axios.post( + getTokenUrl, + querystring.stringify(getTokenParams) + ); + } catch (err) { + console.error(err); + return res.status(400).json({ general: 'Invalid code' }); + } + + const auth = new GoogleAuth(); + const client = new auth.OAuth2(process.env.GOOGLE_CLIENT_ID, '', ''); + const idToken = getTokenResponse.data.id_token; + client.verifyIdToken( + idToken, + process.env.GOOGLE_CLIENT_ID, + async (err, login) => { + if (err) { + return res.status(400).json({ general: 'Invalid token id' }); + } + + const payload = login.getPayload(); + + const email = payload.email; + const googleId = payload.sub; + let user; + try { + user = await User.findOne({ + $or: [{ email }, { googleId }], + isArchived: false + }); + } catch (err) { + console.log( + `User with googleId ${googleId} and email ${email} failed to be found at google-sign-in.` + ); + return next(err); + } + + let refreshToken; + + if (!user) { + const userData = { + email: payload.email, + googleId: payload.sub, + firstName: payload.given_name, + lastName: payload.family_name + }; + + if (payload.locale === 'en') { + userData.language = 'en'; + } else if (payload.locale === 'es') { + userData.language = 'es'; + } + + if (payload.picture) { + userData.avatar = payload.picture; + } + + userData.username = `${slugify(userData.firstName)}-${slugify( + userData.lastName + )}`; + + let repeatedUsers; + try { + repeatedUsers = await User.find({ + username: userData.username, + isArchived: false + }); + } catch (err) { + console.log('Users failed to be found at google-sign-in.'); + return next(err); + } + + if (repeatedUsers && repeatedUsers.length > 0) { + let repeatedUser; + do { + userData.username = `${slugify(userData.firstName)}-${slugify( + userData.lastName + )}-${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}`; + + try { + repeatedUser = await User.findOne({ + username: userData.username, + isArchived: false + }); + } catch (err) { + console.log( + `User with username ${ + userData.username + } failed to be found at google-sign-in.` + ); + return next(err); + } + } while (repeatedUser && repeatedUser.username === userData.username); + } + + try { + user = await User.create(userData); + } catch (err) { + console.log( + `User failed to be created at google-sign-in.\nData: ${JSON.stringify( + userData + )}` + ); + return next(err); + } + + const today = moment.utc(); + const expiresAt = today.add(14, 'days').toDate(); + const refreshTokenData = { + expiresAt, + key: `${user.id}${crypto.randomBytes(28).toString('hex')}`, + userId: user.id + }; + + try { + refreshToken = await RefreshToken.create(refreshTokenData); + } catch (err) { + console.log( + `Refresh token failed to be created at google-sign-in.\nData: ${JSON.stringify( + refreshTokenData + )}` + ); + return next(err); + } + } else { + const userId = user.id; + const today = moment.utc(); + const expiresAt = today.add(14, 'days').toDate(); + const key = `${userId}${crypto.randomBytes(28).toString('hex')}`; + + try { + refreshToken = await RefreshToken.findOneAndUpdate( + { userId }, + { expiresAt, key, userId }, + { new: true, setDefaultsOnInsert: true, upsert: true } + ); + } catch (err) { + console.log( + `Refresh Token for userId ${userId} failed to be created or updated at google-sign-in.` + ); + return next(err); + } + } + + const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { + expiresIn: 3600 + }); + refreshToken = refreshToken.key; + + return res.status(200).json({ token, refreshToken }); + } + ); +}; diff --git a/src/routes/auth/index.js b/src/routes/auth/index.js index d1cb782..431d0c8 100644 --- a/src/routes/auth/index.js +++ b/src/routes/auth/index.js @@ -1,27 +1,27 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const activateAccount = require('./activate-account'); -const facebookSignIn = require('./facebook-sign-in'); -const forgottenPassword = require('./forgotten-password'); -const generateToken = require('./generate-token'); -const googleSignIn = require('./google-sign-in'); -const resetPassword = require('./reset-password'); -const signIn = require('./sign-in'); -const signOut = require('./sign-out'); -const signUp = require('./sign-up'); - -const router = new express.Router(); - -router.get('/activate-account/:key', activateAccount); -router.post('/facebook', facebookSignIn); -router.post('/forgotten-password', forgottenPassword); -router.post('/google', googleSignIn); -router.put('/reset-password', resetPassword); -router.post('/sign-in', signIn); -router.delete('/sign-out', isAuthenticated({ isOptional: false }), signOut); -router.post('/sign-up', signUp); -router.post('/token', generateToken); - -module.exports = router; +const express = require('express'); + +const { isAuthenticated } = require('../../helpers'); + +const activateAccount = require('./activate-account'); +const facebookSignIn = require('./facebook-sign-in'); +const forgottenPassword = require('./forgotten-password'); +const generateToken = require('./generate-token'); +const googleSignIn = require('./google-sign-in'); +const resetPassword = require('./reset-password'); +const signIn = require('./sign-in'); +const signOut = require('./sign-out'); +const signUp = require('./sign-up'); + +const router = new express.Router(); + +router.get('/activate-account/:key', activateAccount); +router.post('/facebook', facebookSignIn); +router.post('/forgotten-password', forgottenPassword); +router.post('/google', googleSignIn); +router.put('/reset-password', resetPassword); +router.post('/sign-in', signIn); +router.delete('/sign-out', isAuthenticated({ isOptional: false }), signOut); +router.post('/sign-up', signUp); +router.post('/token', generateToken); + +module.exports = router; diff --git a/src/routes/auth/reset-password.js b/src/routes/auth/reset-password.js index 5e69206..51f6a90 100644 --- a/src/routes/auth/reset-password.js +++ b/src/routes/auth/reset-password.js @@ -1,133 +1,133 @@ -const moment = require('moment'); - -const { PasswordTicket } = require('../../models/password-ticket'); -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); - -const { validateResetPassword } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateResetPassword(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const key = req.body.key; - const password = req.body.password; - - let passwordTicket; - try { - passwordTicket = await PasswordTicket.findOne({ key }); - } catch (err) { - console.log( - `Password ticket with key ${key} failed to be found at reset-password.` - ); - return next(err); - } - - if (!passwordTicket) { - return res.status(404).json({ general: 'Password Ticket not found' }); - } - - const expiresAt = moment(passwordTicket.expiresAt).utc(); - const today = moment.utc(); - if (expiresAt.isBefore(today)) { - try { - await passwordTicket.remove(); - } catch (err) { - console.log( - `Password Ticket with key ${ - passwordTicket.key - } failed to be removed at reset-password.` - ); - return next(err); - } - - return res.status(400).json({ general: 'Password Ticket expired' }); - } - - let user; - try { - user = await User.findOne({ - email: passwordTicket.email, - isArchived: false - }); - } catch (err) { - console.log( - `User with email ${ - passwordTicket.email - } failed to be found at reset-password.` - ); - return next(err); - } - - if (!user) { - try { - await passwordTicket.remove(); - } catch (err) { - console.log( - `Password Ticket with key ${ - passwordTicket.key - } failed to be removed at reset-password.` - ); - return next(err); - } - - return res.status(400).json({ general: 'User not found' }); - } - - const passwordMatches = user.comparePassword(password); - if (passwordMatches) { - return res.status(400).json({ password: 'Is already used' }); - } - - user.password = password; - user.updatedAt = moment.utc().toDate(); - - try { - await user.save(); - } catch (err) { - console.log( - `User with email ${user.email} failed to be updated at reset-password.` - ); - return next(err); - } - - let refreshToken; - try { - refreshToken = await RefreshToken.findOne({ userId: user.id }); - } catch (err) { - console.log( - `Refresh token with userId ${ - user.id - } failed to be found at reset-password.` - ); - return next(err); - } - - if (refreshToken) { - try { - await refreshToken.remove(); - } catch (err) { - console.log( - `Refresh Token with userId ${ - refreshToken.userId - } failed to be removed at reset-password.` - ); - return next(err); - } - } - - try { - await passwordTicket.remove(); - } catch (err) { - console.log( - `Password Ticket with key ${ - passwordTicket.key - } failed to be removed at reset-password.` - ); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { PasswordTicket } = require('../../models/password-ticket'); +const { RefreshToken } = require('../../models/refresh-token'); +const { User } = require('../../models/user'); + +const { validateResetPassword } = require('./validations'); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateResetPassword(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const key = req.body.key; + const password = req.body.password; + + let passwordTicket; + try { + passwordTicket = await PasswordTicket.findOne({ key }); + } catch (err) { + console.log( + `Password ticket with key ${key} failed to be found at reset-password.` + ); + return next(err); + } + + if (!passwordTicket) { + return res.status(404).json({ general: 'Password Ticket not found' }); + } + + const expiresAt = moment(passwordTicket.expiresAt).utc(); + const today = moment.utc(); + if (expiresAt.isBefore(today)) { + try { + await passwordTicket.remove(); + } catch (err) { + console.log( + `Password Ticket with key ${ + passwordTicket.key + } failed to be removed at reset-password.` + ); + return next(err); + } + + return res.status(400).json({ general: 'Password Ticket expired' }); + } + + let user; + try { + user = await User.findOne({ + email: passwordTicket.email, + isArchived: false + }); + } catch (err) { + console.log( + `User with email ${ + passwordTicket.email + } failed to be found at reset-password.` + ); + return next(err); + } + + if (!user) { + try { + await passwordTicket.remove(); + } catch (err) { + console.log( + `Password Ticket with key ${ + passwordTicket.key + } failed to be removed at reset-password.` + ); + return next(err); + } + + return res.status(400).json({ general: 'User not found' }); + } + + const passwordMatches = user.comparePassword(password); + if (passwordMatches) { + return res.status(400).json({ password: 'Is already used' }); + } + + user.password = password; + user.updatedAt = moment.utc().toDate(); + + try { + await user.save(); + } catch (err) { + console.log( + `User with email ${user.email} failed to be updated at reset-password.` + ); + return next(err); + } + + let refreshToken; + try { + refreshToken = await RefreshToken.findOne({ userId: user.id }); + } catch (err) { + console.log( + `Refresh token with userId ${ + user.id + } failed to be found at reset-password.` + ); + return next(err); + } + + if (refreshToken) { + try { + await refreshToken.remove(); + } catch (err) { + console.log( + `Refresh Token with userId ${ + refreshToken.userId + } failed to be removed at reset-password.` + ); + return next(err); + } + } + + try { + await passwordTicket.remove(); + } catch (err) { + console.log( + `Password Ticket with key ${ + passwordTicket.key + } failed to be removed at reset-password.` + ); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/auth/sign-in.js b/src/routes/auth/sign-in.js index f0ac99d..3582e2f 100644 --- a/src/routes/auth/sign-in.js +++ b/src/routes/auth/sign-in.js @@ -1,69 +1,70 @@ -const crypto = require('crypto'); - -const jwt = require('jsonwebtoken'); -const moment = require('moment'); - -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); - -const { validateSignIn } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateSignIn(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const email = req.body.email; - const password = req.body.password; - - let user; - try { - user = await User.findOne({ email, isArchived: false }); - } catch (err) { - console.log(`User with email ${email} failed to be found at sign-in.`); - return next(err); - } - - if (!user) { - return res.status(400).json({ general: 'Email or password incorrect' }); - } - - if (user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - if (!user.hashedPassword) { - return res.status(400).json({ general: 'Email or password incorrect' }); - } - - const passwordMatches = user.comparePassword(password); - - if (!passwordMatches) { - return res.status(400).json({ general: 'Email or password incorrect' }); - } - - const userId = user.id; - const today = moment.utc(); - const expiresAt = today.add(14, 'days').toDate(); - const key = `${userId}${crypto.randomBytes(28).toString('hex')}`; - - let refreshToken; - try { - refreshToken = await RefreshToken.findOneAndUpdate( - { userId }, - { expiresAt, key, userId }, - { new: true, setDefaultsOnInsert: true, upsert: true } - ); - } catch (err) { - console.log( - `Refresh Token for userId ${userId} failed to be created or updated at sign-in.` - ); - return next(err); - } - - const token = jwt.sign({ userId }, process.env.JWT_SECRET, { - expiresIn: 36000 - }); - return res.status(200).json({ refreshToken: refreshToken.key, token }); -}; +const crypto = require("crypto"); + +const jwt = require("jsonwebtoken"); +const moment = require("moment"); + +const { RefreshToken } = require("../../models/refresh-token"); +const { User } = require("../../models/user"); + +const { validateSignIn } = require("./validations"); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateSignIn(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const email = req.body.email; + const password = req.body.password; + + let user; + try { + user = await User.findOne({ email, isArchived: false }); + console.log("User", user); + } catch (err) { + console.log(`User with email ${email} failed to be found at sign-in.`); + return next(err); + } + + if (!user) { + return res.status(400).json({ general: "Email or password incorrect" }); + } + + if (user.isBlocked) { + return res.status(423).json({ general: "You are blocked" }); + } + + if (!user.hashedPassword) { + return res.status(400).json({ general: "Email or password incorrect" }); + } + + const passwordMatches = user.comparePassword(password); + + if (!passwordMatches) { + return res.status(400).json({ general: "Email or password incorrect" }); + } + + const userId = user.id; + const today = moment.utc(); + const expiresAt = today.add(14, "days").toDate(); + const key = `${userId}${crypto.randomBytes(28).toString("hex")}`; + + let refreshToken; + try { + refreshToken = await RefreshToken.findOneAndUpdate( + { userId }, + { expiresAt, key, userId }, + { new: true, setDefaultsOnInsert: true, upsert: true } + ); + } catch (err) { + console.log( + `Refresh Token for userId ${userId} failed to be created or updated at sign-in.` + ); + return next(err); + } + + const token = jwt.sign({ userId }, process.env.JWT_SECRET, { + expiresIn: 36000, + }); + return res.status(200).json({ refreshToken: refreshToken.key, token }); +}; diff --git a/src/routes/auth/sign-out.js b/src/routes/auth/sign-out.js index 075ef8d..6810f6b 100644 --- a/src/routes/auth/sign-out.js +++ b/src/routes/auth/sign-out.js @@ -1,34 +1,34 @@ -const { RefreshToken } = require('../../models/refresh-token'); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - let refreshToken; - try { - refreshToken = await RefreshToken.findOne({ userId: req.user.id }); - } catch (err) { - console.log( - `Refresh token with userId ${req.user.id} failed to be found at sign-out.` - ); - return next(err); - } - - if (!refreshToken) { - return res.status(204).json({ general: 'Success' }); - } - - try { - await refreshToken.remove(); - } catch (err) { - console.log( - `Refresh token with userId ${ - req.user.id - } failed to be deleted at sign-out.` - ); - return next(err); - } - - return res.status(204).json({ general: 'Success' }); -}; +const { RefreshToken } = require('../../models/refresh-token'); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: 'You are blocked' }); + } + + let refreshToken; + try { + refreshToken = await RefreshToken.findOne({ userId: req.user.id }); + } catch (err) { + console.log( + `Refresh token with userId ${req.user.id} failed to be found at sign-out.` + ); + return next(err); + } + + if (!refreshToken) { + return res.status(204).json({ general: 'Success' }); + } + + try { + await refreshToken.remove(); + } catch (err) { + console.log( + `Refresh token with userId ${ + req.user.id + } failed to be deleted at sign-out.` + ); + return next(err); + } + + return res.status(204).json({ general: 'Success' }); +}; diff --git a/src/routes/auth/sign-up.js b/src/routes/auth/sign-up.js index 8819b94..6bdf8a7 100644 --- a/src/routes/auth/sign-up.js +++ b/src/routes/auth/sign-up.js @@ -1,158 +1,158 @@ -const crypto = require('crypto'); - -const moment = require('moment'); -const { pick } = require('lodash'); -const randomstring = require('randomstring'); -const slugify = require('speakingurl'); - -const { ActivationTicket } = require('../../models/activation-ticket'); -const { cleanSpaces, sendEmail } = require('../../helpers'); -const { User } = require('../../models/user'); - -const { validateSignUp } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateSignUp(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const data = pick(req.body, [ - 'email', - 'firstName', - 'isSubscribed', - 'lastName', - 'password' - ]); - data.firstName = cleanSpaces(data.firstName); - data.lastName = cleanSpaces(data.lastName); - data.username = `${slugify(data.firstName)}-${slugify(data.lastName)}`; - - let activationTicket; - try { - activationTicket = await ActivationTicket.findOne({ email: data.email }); - } catch (err) { - console.log( - `Activation ticket with email ${ - data.email - } failed to be found at sign-up.` - ); - return next(err); - } - - if (activationTicket) { - const expiresAt = moment(activationTicket.expiresAt).utc(); - const today = moment.utc(); - if (expiresAt.isBefore(today)) { - try { - await activationTicket.remove(); - } catch (err) { - console.log( - `Activation ticket with email ${ - activationTicket.email - } failed to be removed at sign-up.` - ); - return next(err); - } - } - } - - let repeatedUsers; - try { - repeatedUsers = await User.find({ - $or: [{ email: data.email }, { username: data.username }], - isArchived: false - }); - } catch (err) { - console.log('Users failed to be found at sign-up.'); - return next(err); - } - - if (repeatedUsers && repeatedUsers.length > 0) { - for (const user of repeatedUsers) { - if (user.email === data.email) { - return res.status(400).json({ email: 'Is already taken' }); - } - - let repeatedUser; - do { - data.username = `${slugify(data.firstName)}-${slugify( - data.lastName - )}-${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}`; - - try { - repeatedUser = await User.findOne({ - username: data.username, - isArchived: false - }); - } catch (err) { - console.log( - `User with username ${data.username} failed to be found at sign-up.` - ); - return next(err); - } - } while (repeatedUser && repeatedUser.username === data.username); - } - } - - const today = moment.utc(); - const expiresAt = today.add(1, 'days').toDate(); - const key = `${crypto - .randomBytes(31) - .toString('hex')}${new Date().getTime().toString()}`; - - const activationTicketData = { - email: data.email, - expiresAt, - key, - userData: { - firstName: data.firstName, - isSubscribed: data.isSubscribed, - lastName: data.lastName, - password: data.password, - username: data.username - } - }; - try { - activationTicket = await ActivationTicket.create(activationTicketData); - } catch (err) { - console.log( - `Activation ticket failed to be created at sign-up.\nData: ${JSON.stringify( - activationTicketData - )}` - ); - return next(err); - } - - const subject = 'Activate Account'; - const htmlContent = ` -To activate your account use the link below:
-Stay awesome.
- `; - const textContent = ` - Welcome to AXS Map! - To activate your account use the link below: - ${process.env.API_URL}/auth/activate-account/${activationTicket.key} - Stay awesome. - `; - const receiversEmails = [activationTicket.email]; - - sendEmail({ - subject, - htmlContent, - textContent, - receiversEmails - }); - - return res.status(201).json({ general: 'Success' }); -}; +const crypto = require('crypto'); + +const moment = require('moment'); +const { pick } = require('lodash'); +const randomstring = require('randomstring'); +const slugify = require('speakingurl'); + +const { ActivationTicket } = require('../../models/activation-ticket'); +const { cleanSpaces, sendEmail } = require('../../helpers'); +const { User } = require('../../models/user'); + +const { validateSignUp } = require('./validations'); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateSignUp(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const data = pick(req.body, [ + 'email', + 'firstName', + 'isSubscribed', + 'lastName', + 'password' + ]); + data.firstName = cleanSpaces(data.firstName); + data.lastName = cleanSpaces(data.lastName); + data.username = `${slugify(data.firstName)}-${slugify(data.lastName)}`; + + let activationTicket; + try { + activationTicket = await ActivationTicket.findOne({ email: data.email }); + } catch (err) { + console.log( + `Activation ticket with email ${ + data.email + } failed to be found at sign-up.` + ); + return next(err); + } + + if (activationTicket) { + const expiresAt = moment(activationTicket.expiresAt).utc(); + const today = moment.utc(); + if (expiresAt.isBefore(today)) { + try { + await activationTicket.remove(); + } catch (err) { + console.log( + `Activation ticket with email ${ + activationTicket.email + } failed to be removed at sign-up.` + ); + return next(err); + } + } + } + + let repeatedUsers; + try { + repeatedUsers = await User.find({ + $or: [{ email: data.email }, { username: data.username }], + isArchived: false + }); + } catch (err) { + console.log('Users failed to be found at sign-up.'); + return next(err); + } + + if (repeatedUsers && repeatedUsers.length > 0) { + for (const user of repeatedUsers) { + if (user.email === data.email) { + return res.status(400).json({ email: 'Is already taken' }); + } + + let repeatedUser; + do { + data.username = `${slugify(data.firstName)}-${slugify( + data.lastName + )}-${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}`; + + try { + repeatedUser = await User.findOne({ + username: data.username, + isArchived: false + }); + } catch (err) { + console.log( + `User with username ${data.username} failed to be found at sign-up.` + ); + return next(err); + } + } while (repeatedUser && repeatedUser.username === data.username); + } + } + + const today = moment.utc(); + const expiresAt = today.add(1, 'days').toDate(); + const key = `${crypto + .randomBytes(31) + .toString('hex')}${new Date().getTime().toString()}`; + + const activationTicketData = { + email: data.email, + expiresAt, + key, + userData: { + firstName: data.firstName, + isSubscribed: data.isSubscribed, + lastName: data.lastName, + password: data.password, + username: data.username + } + }; + try { + activationTicket = await ActivationTicket.create(activationTicketData); + } catch (err) { + console.log( + `Activation ticket failed to be created at sign-up.\nData: ${JSON.stringify( + activationTicketData + )}` + ); + return next(err); + } + + const subject = 'Activate Account'; + const htmlContent = ` +To activate your account use the link below:
+Stay awesome.
+ `; + const textContent = ` + Welcome to AXS Map! + To activate your account use the link below: + ${process.env.API_URL}/auth/activate-account/${activationTicket.key} + Stay awesome. + `; + const receiversEmails = [activationTicket.email]; + + sendEmail({ + subject, + htmlContent, + textContent, + receiversEmails + }); + + return res.status(201).json({ general: 'Success' }); +}; diff --git a/src/routes/auth/validations.js b/src/routes/auth/validations.js index f8bb8f4..7c11055 100644 --- a/src/routes/auth/validations.js +++ b/src/routes/auth/validations.js @@ -1,155 +1,155 @@ -const freemail = require('freemail'); -const { isEmail } = require('validator'); -const { isEmpty } = require('lodash'); - -const { cleanSpaces } = require('../../helpers'); - -module.exports = { - validateFacebookSignIn(data) { - const errors = {}; - - if (!data.code) { - errors.code = 'Is required'; - } else if (typeof data.code !== 'string') { - errors.code = 'Should be a string'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateForgottenPassword(data) { - const errors = {}; - - if (!data.email) { - errors.email = 'Is required'; - } else if (typeof data.email !== 'string') { - errors.email = 'Should be a string'; - } else if (!isEmail(data.email)) { - errors.email = 'Should be a valid email'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateGenerateToken(data) { - const errors = {}; - - if (!data.key) { - errors.key = 'Is required'; - } else if (typeof data.key !== 'string') { - errors.key = 'Should be a string'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateGoogleSignIn(data) { - const errors = {}; - - if (!data.code) { - errors.code = 'Is required'; - } else if (typeof data.code !== 'string') { - errors.code = 'Should be a string'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateResetPassword(data) { - const errors = {}; - - if (!data.key) { - errors.key = 'Is required'; - } else if (typeof data.key !== 'string') { - errors.key = 'Should be a string'; - } - - if (!data.password) { - errors.password = 'Is required'; - } else if (typeof data.password !== 'string') { - errors.password = 'Should be a string'; - } else if (data.password.length < 8) { - errors.password = 'Should have more than 7 characters'; - } else if (data.password.length > 30) { - errors.password = 'Should have less than 31 characters'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateSignIn(data) { - const errors = {}; - - if (!data.email) { - errors.email = 'Is required'; - } else if (typeof data.email !== 'string') { - errors.email = 'Should be a string'; - } - - if (!data.password) { - errors.password = 'Is required'; - } else if (typeof data.password !== 'string') { - errors.password = 'Should be a string'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateSignUp(data) { - const errors = {}; - - if (!data.email) { - errors.email = 'Is required'; - } else if (typeof data.email !== 'string') { - errors.email = 'Should be a string'; - } else if (cleanSpaces(data.email).length > 254) { - errors.email = 'Should have less than 255 characters'; - } else if (!isEmail(data.email) || freemail.isDisposable(data.email)) { - errors.email = 'Should be a valid email'; - } - - if (!data.firstName) { - errors.firstName = 'Is required'; - } else if (typeof data.firstName !== 'string') { - errors.firstName = 'Should be a string'; - } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.firstName)) { - errors.firstName = 'Should only have letters'; - } else if (cleanSpaces(data.firstName).length > 24) { - errors.firstName = 'Should have less than 25 characters'; - } else { - const firstName = cleanSpaces(data.firstName); - - if (firstName.split(' ').length > 1) { - errors.firstName = 'Should only be one name'; - } - } - - if (typeof data.isSubscribed === 'undefined') { - errors.isSubscribed = 'Is required'; - } else if (typeof data.isSubscribed !== 'boolean') { - errors.isSubscribed = 'Should be a boolean'; - } - - if (!data.lastName) { - errors.lastName = 'Is required'; - } else if (typeof data.lastName !== 'string') { - errors.lastName = 'Should be a string'; - } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.lastName)) { - errors.lastName = 'Should only have letters'; - } else if (cleanSpaces(data.lastName).length > 36) { - errors.lastName = 'Should have less than 37 characters'; - } else { - const lastName = cleanSpaces(data.lastName); - - if (lastName.split(' ').length > 1) { - errors.lastName = 'Should only be one surname'; - } - } - - if (!data.password) { - errors.password = 'Is required'; - } else if (typeof data.password !== 'string') { - errors.password = 'Should be a string'; - } else if (data.password.length < 8) { - errors.password = 'Should have more than 7 characters'; - } else if (data.password.length > 30) { - errors.password = 'Should have less than 31 characters'; - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const freemail = require('freemail'); +const { isEmail } = require('validator'); +const { isEmpty } = require('lodash'); + +const { cleanSpaces } = require('../../helpers'); + +module.exports = { + validateFacebookSignIn(data) { + const errors = {}; + + if (!data.code) { + errors.code = 'Is required'; + } else if (typeof data.code !== 'string') { + errors.code = 'Should be a string'; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateForgottenPassword(data) { + const errors = {}; + + if (!data.email) { + errors.email = 'Is required'; + } else if (typeof data.email !== 'string') { + errors.email = 'Should be a string'; + } else if (!isEmail(data.email)) { + errors.email = 'Should be a valid email'; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateGenerateToken(data) { + const errors = {}; + + if (!data.key) { + errors.key = 'Is required'; + } else if (typeof data.key !== 'string') { + errors.key = 'Should be a string'; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateGoogleSignIn(data) { + const errors = {}; + + if (!data.code) { + errors.code = 'Is required'; + } else if (typeof data.code !== 'string') { + errors.code = 'Should be a string'; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateResetPassword(data) { + const errors = {}; + + if (!data.key) { + errors.key = 'Is required'; + } else if (typeof data.key !== 'string') { + errors.key = 'Should be a string'; + } + + if (!data.password) { + errors.password = 'Is required'; + } else if (typeof data.password !== 'string') { + errors.password = 'Should be a string'; + } else if (data.password.length < 8) { + errors.password = 'Should have more than 7 characters'; + } else if (data.password.length > 30) { + errors.password = 'Should have less than 31 characters'; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateSignIn(data) { + const errors = {}; + + if (!data.email) { + errors.email = 'Is required'; + } else if (typeof data.email !== 'string') { + errors.email = 'Should be a string'; + } + + if (!data.password) { + errors.password = 'Is required'; + } else if (typeof data.password !== 'string') { + errors.password = 'Should be a string'; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateSignUp(data) { + const errors = {}; + + if (!data.email) { + errors.email = 'Is required'; + } else if (typeof data.email !== 'string') { + errors.email = 'Should be a string'; + } else if (cleanSpaces(data.email).length > 254) { + errors.email = 'Should have less than 255 characters'; + } else if (!isEmail(data.email) || freemail.isDisposable(data.email)) { + errors.email = 'Should be a valid email'; + } + + if (!data.firstName) { + errors.firstName = 'Is required'; + } else if (typeof data.firstName !== 'string') { + errors.firstName = 'Should be a string'; + } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.firstName)) { + errors.firstName = 'Should only have letters'; + } else if (cleanSpaces(data.firstName).length > 24) { + errors.firstName = 'Should have less than 25 characters'; + } else { + const firstName = cleanSpaces(data.firstName); + + if (firstName.split(' ').length > 1) { + errors.firstName = 'Should only be one name'; + } + } + + if (typeof data.isSubscribed === 'undefined') { + errors.isSubscribed = 'Is required'; + } else if (typeof data.isSubscribed !== 'boolean') { + errors.isSubscribed = 'Should be a boolean'; + } + + if (!data.lastName) { + errors.lastName = 'Is required'; + } else if (typeof data.lastName !== 'string') { + errors.lastName = 'Should be a string'; + } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.lastName)) { + errors.lastName = 'Should only have letters'; + } else if (cleanSpaces(data.lastName).length > 36) { + errors.lastName = 'Should have less than 37 characters'; + } else { + const lastName = cleanSpaces(data.lastName); + + if (lastName.split(' ').length > 1) { + errors.lastName = 'Should only be one surname'; + } + } + + if (!data.password) { + errors.password = 'Is required'; + } else if (typeof data.password !== 'string') { + errors.password = 'Should be a string'; + } else if (data.password.length < 8) { + errors.password = 'Should have more than 7 characters'; + } else if (data.password.length > 30) { + errors.password = 'Should have less than 31 characters'; + } + + return { errors, isValid: isEmpty(errors) }; + } +}; diff --git a/src/routes/events/create-event.js b/src/routes/events/create-event.js index 7b35bda..7787d3f 100644 --- a/src/routes/events/create-event.js +++ b/src/routes/events/create-event.js @@ -1,190 +1,184 @@ -const axios = require('axios'); -const FormData = require('form-data'); -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { cleanSpaces } = require('../../helpers'); -const { Photo } = require('../../models/photo'); -const { Team } = require('../../models/team'); - -const { validateCreateEvent } = require('./validations'); - -module.exports = async (req, res, next) => { - const data = { - address: req.body.address, - description: req.body.description, - donationAmounts: req.body.donationAmounts, - donationEnabled: req.body.donationEnabled, - donationGoal: req.body.donationGoal, - endDate: req.body.endDate, - isOpen: req.body.isOpen, - locationCoordinates: req.body.locationCoordinates, - name: req.body.name, - participantsGoal: req.body.participantsGoal, - poster: req.body.poster, - reviewsGoal: req.body.reviewsGoal, - startDate: req.body.startDate, - teamManager: req.body.teamManager - }; - - const { errors, isValid } = validateCreateEvent(data); - if (!isValid) return res.status(400).json(errors); - - data.address = cleanSpaces(data.address); - - data.endDate = moment(data.endDate) - .endOf('day') - .utc() - .toDate(); - - data.location = { - coordinates: [data.locationCoordinates[1], data.locationCoordinates[0]] - }; - delete data.locationCoordinates; - - data.managers = [req.user.id]; - - data.name = cleanSpaces(data.name); - let repeatedEvent; - try { - repeatedEvent = await Event.findOne({ name: data.name, isArchived: false }); - } catch (err) { - console.log(`Event ${data.name} failed to be found at create-event`); - return next(err); - } - - if (repeatedEvent) { - return res.status(400).json({ name: 'Is already taken' }); - } - - if (data.poster) { - let poster; - try { - poster = await Photo.findOne({ url: data.poster }); - } catch (err) { - console.log(`Poster ${data.poster} failed to be found at create-event`); - return next(err); - } - - if (!poster) { - return res.status(404).json({ poster: 'Not found' }); - } - } - - data.startDate = moment(data.startDate) - .startOf('day') - .utc() - .toDate(); - - if (data.teamManager) { - let team; - try { - team = await Team.findOne({ _id: data.teamManager, isArchived: false }); - } catch (err) { - console.log( - `Team ${data.teamManager} failed to be found at create-event` - ); - return next(err); - } - - if (!team) { - return res.status(404).json({ teamManager: 'Not found' }); - } - - const teamManagers = team.managers.map(m => m.toString()); - if (!teamManagers.includes(req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - } else { - data.teamManager = undefined; - } - - if (data.donationEnabled) { - const campaignData = new FormData(); - campaignData.append('title', data.name); - campaignData.append('goal_in_cents', data.donationGoal * 100); - - let options = { - method: 'POST', - url: `https://${ - process.env.DONATELY_SUBDOMAIN - }.dntly.com/api/v1/admin/campaigns`, - headers: { - 'Content-Type': `multipart/form-data; boundary=${ - campaignData._boundary - }` - }, - auth: { - username: process.env.DONATELY_TOKEN, - password: '' - }, - data: campaignData - }; - - let response; - try { - response = await axios(options); - } catch (err) { - console.log('Donation campaign failed to be created at create-event.'); - return next(err); - } - - data.donationId = response.data.campaign.id; - } - - let event; - try { - event = await Event.create(data); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `Event failed to be created at create-event.\nData: ${JSON.stringify( - data - )}` - ); - return next(err); - } - - req.user.events = [...req.user.events, event.id]; - req.user.updatedAt = moment.utc().toDate(); - - try { - await req.user.save(); - } catch (err) { - console.log(`User ${req.user.id} failed to be updated at create-event`); - return next(err); - } - - let eventLocation; - if (event.location.coordinates) { - eventLocation = { - lat: event.location.coordinates[1], - lng: event.location.coordinates[0] - }; - } - const dataResponse = { - id: event.id, - address: event.address, - description: event.description, - endDate: event.description, - isOpen: event.isOpen, - location: eventLocation, - managers: event.managers, - name: event.name, - participantsGoal: event.participantsGoal, - poster: event.poster, - reviewsGoal: event.reviewsGoal, - teamManager: event.teamManager - }; - - return res.status(201).json(dataResponse); -}; +const axios = require('axios'); +const FormData = require('form-data'); +const moment = require('moment'); + +const { Event } = require('../../models/event'); +const { cleanSpaces } = require('../../helpers'); +const { Photo } = require('../../models/photo'); +const { Team } = require('../../models/team'); + +const { validateCreateEvent } = require('./validations'); + +module.exports = async (req, res, next) => { + const data = { + address: req.body.address, + description: req.body.description, + donationAmounts: req.body.donationAmounts, + donationEnabled: req.body.donationEnabled, + donationGoal: req.body.donationGoal, + endDate: req.body.endDate, + isOpen: req.body.isOpen, + locationCoordinates: req.body.locationCoordinates, + name: req.body.name, + participantsGoal: req.body.participantsGoal, + poster: req.body.poster, + reviewsGoal: req.body.reviewsGoal, + startDate: req.body.startDate, + teamManager: req.body.teamManager + }; + + const { errors, isValid } = validateCreateEvent(data); + if (!isValid) return res.status(400).json(errors); + + data.address = cleanSpaces(data.address); + + data.endDate = moment(data.endDate).endOf('day').utc().toDate(); + + data.location = { + coordinates: [data.locationCoordinates[1], data.locationCoordinates[0]] + }; + delete data.locationCoordinates; + + data.managers = [req.user.id]; + + data.name = cleanSpaces(data.name); + let repeatedEvent; + try { + repeatedEvent = await Event.findOne({ name: data.name, isArchived: false }); + } catch (err) { + console.log(`Event ${data.name} failed to be found at create-event`); + return next(err); + } + + if (repeatedEvent) { + return res.status(400).json({ name: 'Is already taken' }); + } + + if (data.poster) { + let poster; + try { + poster = await Photo.findOne({ url: data.poster }); + } catch (err) { + console.log(`Poster ${data.poster} failed to be found at create-event`); + return next(err); + } + + if (!poster) { + return res.status(404).json({ poster: 'Not found' }); + } + } + + data.startDate = moment(data.startDate).startOf('day').utc().toDate(); + + if (data.teamManager) { + let team; + try { + team = await Team.findOne({ _id: data.teamManager, isArchived: false }); + } catch (err) { + console.log( + `Team ${data.teamManager} failed to be found at create-event` + ); + return next(err); + } + + if (!team) { + return res.status(404).json({ teamManager: 'Not found' }); + } + + const teamManagers = team.managers.map((m) => m.toString()); + if (!teamManagers.includes(req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + } else { + data.teamManager = undefined; + } + + if (data.donationEnabled) { + const campaignData = new FormData(); + campaignData.append('title', data.name); + campaignData.append('goal_in_cents', data.donationGoal * 100); + + let options = { + method: 'POST', + url: `https://${ + process.env.DONATELY_SUBDOMAIN + }.dntly.com/api/v1/admin/campaigns`, + headers: { + 'Content-Type': `multipart/form-data; boundary=${ + campaignData._boundary + }` + }, + auth: { + username: process.env.DONATELY_TOKEN, + password: '' + }, + data: campaignData + }; + + let response; + try { + response = await axios(options); + } catch (err) { + console.log('Donation campaign failed to be created at create-event.'); + return next(err); + } + + data.donationId = response.data.campaign.id; + } + + let event; + try { + event = await Event.create(data); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `Event failed to be created at create-event.\nData: ${JSON.stringify( + data + )}` + ); + return next(err); + } + + req.user.events = [...req.user.events, event.id]; + req.user.updatedAt = moment.utc().toDate(); + + try { + await req.user.save(); + } catch (err) { + console.log(`User ${req.user.id} failed to be updated at create-event`); + return next(err); + } + + let eventLocation; + if (event.location.coordinates) { + eventLocation = { + lat: event.location.coordinates[1], + lng: event.location.coordinates[0] + }; + } + const dataResponse = { + id: event.id, + address: event.address, + description: event.description, + endDate: event.description, + isOpen: event.isOpen, + location: eventLocation, + managers: event.managers, + name: event.name, + participantsGoal: event.participantsGoal, + poster: event.poster, + reviewsGoal: event.reviewsGoal, + teamManager: event.teamManager + }; + + return res.status(201).json(dataResponse); +}; diff --git a/src/routes/events/delete-event.js b/src/routes/events/delete-event.js index 17842f1..ca305ae 100644 --- a/src/routes/events/delete-event.js +++ b/src/routes/events/delete-event.js @@ -1,130 +1,130 @@ -const aws = require('aws-sdk'); -const { last } = require('lodash'); -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { Team } = require('../../models/team'); -const { User } = require('../../models/user'); - -const s3 = new aws.S3(); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - const eventId = req.params.eventId; - - let event; - try { - event = await Event.findOne({ _id: eventId }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Event not found' }); - } - console.log(`Event ${eventId} failed to be found at delete-event`); - return next(err); - } - - if (!event) { - return res.status(404).json({ general: 'Event not found' }); - } - - if ( - !event.managers.find(m => m.toString() === req.user.id) && - !req.user.isAdmin - ) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const endDate = moment(event.endDate).utc(); - const today = moment.utc(); - - if (endDate.isBefore(today) && event.reviews > 0) { - return res.status(423).json({ - general: - 'It cannot be removed because it already ended and has one or more reviews' - }); - } - - const participantsPromises = event.participants.map(p => - User.findOne({ _id: p.toString() }) - ); - - let participants; - try { - participants = await Promise.all(participantsPromises); - } catch (err) { - console.log('A participant failed to be found at delete-event'); - return next(err); - } - - for (const participant of participants) { - participant.events = participant.events.filter( - e => e.toString() !== event.id - ); - participant.updatedAt = moment.utc().toDate(); - - try { - await participant.save(); - } catch (err) { - console.log( - `Participant ${participant.id} failed to be updated at delete-event` - ); - return next(err); - } - } - - if (event.photos && event.photos.length > 0) { - for (const photo of event.photos) { - const photoParams = { - Bucket: process.env.AWS_S3_BUCKET, - Key: `events/photos/${last(photo.url.split('/'))}` - }; - - try { - await s3.deleteObject(photoParams).promise(); - } catch (err) { - console.log( - `Photo ${photoParams.Key} failed to be deleted at delete-event` - ); - return next(err); - } - } - } - - if (event.teams && event.teams.length > 0) { - const teamsPromises = event.teams.map(t => - Team.findOne({ _id: t.toString() }) - ); - - let teams; - try { - teams = await Promise.all(teamsPromises); - } catch (err) { - console.log('A team failed to be found at delete-event'); - return next(err); - } - - for (const team of teams) { - team.events = team.events.filter(e => e.toString() !== event.id); - team.updatedAt = moment.utc().toDate(); - - try { - await team.save(); - } catch (err) { - console.log(`Team ${team.id} failed to be updated at delete-event`); - return next(err); - } - } - } - - try { - await event.remove(); - } catch (err) { - console.log(`Event ${event.id} failed to be removed at delete-event`); - return next(err); - } - - return res.status(204).json({ general: 'Success' }); -}; +const aws = require('aws-sdk'); +const { last } = require('lodash'); +const moment = require('moment'); + +const { Event } = require('../../models/event'); +const { Team } = require('../../models/team'); +const { User } = require('../../models/user'); + +const s3 = new aws.S3(); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: 'You are blocked' }); + } + + const eventId = req.params.eventId; + + let event; + try { + event = await Event.findOne({ _id: eventId }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Event not found' }); + } + console.log(`Event ${eventId} failed to be found at delete-event`); + return next(err); + } + + if (!event) { + return res.status(404).json({ general: 'Event not found' }); + } + + if ( + !event.managers.find((m) => m.toString() === req.user.id) && + !req.user.isAdmin + ) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const endDate = moment(event.endDate).utc(); + const today = moment.utc(); + + if (endDate.isBefore(today) && event.reviews > 0) { + return res.status(423).json({ + general: + 'It cannot be removed because it already ended and has one or more reviews' + }); + } + + const participantsPromises = event.participants.map((p) => + User.findOne({ _id: p.toString() }) + ); + + let participants; + try { + participants = await Promise.all(participantsPromises); + } catch (err) { + console.log('A participant failed to be found at delete-event'); + return next(err); + } + + for (const participant of participants) { + participant.events = participant.events.filter( + (e) => e.toString() !== event.id + ); + participant.updatedAt = moment.utc().toDate(); + + try { + await participant.save(); + } catch (err) { + console.log( + `Participant ${participant.id} failed to be updated at delete-event` + ); + return next(err); + } + } + + if (event.photos && event.photos.length > 0) { + for (const photo of event.photos) { + const photoParams = { + Bucket: process.env.AWS_S3_BUCKET, + Key: `events/photos/${last(photo.url.split('/'))}` + }; + + try { + await s3.deleteObject(photoParams).promise(); + } catch (err) { + console.log( + `Photo ${photoParams.Key} failed to be deleted at delete-event` + ); + return next(err); + } + } + } + + if (event.teams && event.teams.length > 0) { + const teamsPromises = event.teams.map((t) => + Team.findOne({ _id: t.toString() }) + ); + + let teams; + try { + teams = await Promise.all(teamsPromises); + } catch (err) { + console.log('A team failed to be found at delete-event'); + return next(err); + } + + for (const team of teams) { + team.events = team.events.filter((e) => e.toString() !== event.id); + team.updatedAt = moment.utc().toDate(); + + try { + await team.save(); + } catch (err) { + console.log(`Team ${team.id} failed to be updated at delete-event`); + return next(err); + } + } + } + + try { + await event.remove(); + } catch (err) { + console.log(`Event ${event.id} failed to be removed at delete-event`); + return next(err); + } + + return res.status(204).json({ general: 'Success' }); +}; diff --git a/src/routes/events/edit-event.js b/src/routes/events/edit-event.js index 29368ab..96aa7e2 100644 --- a/src/routes/events/edit-event.js +++ b/src/routes/events/edit-event.js @@ -1,387 +1,377 @@ -const { difference, intersection } = require('lodash'); -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { cleanSpaces } = require('../../helpers'); -const { Photo } = require('../../models/photo'); -const { Team } = require('../../models/team'); -const { User } = require('../../models/user'); - -const { validateEditEvent } = require('./validations'); - -module.exports = async (req, res, next) => { - const eventId = req.params.eventId; - - let event; - try { - event = await Event.findOne({ _id: eventId }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Event not found' }); - } - - console.log(`Event ${eventId} failed to be found at edit-event`); - return next(err); - } - - if (!event) { - return res.status(404).json({ general: 'Event not found' }); - } - - if (!event.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const data = { - address: req.body.address, - description: req.body.description, - endDate: req.body.endDate, - isOpen: req.body.isOpen, - locationCoordinates: req.body.locationCoordinates, - managers: req.body.managers, - name: req.body.name, - participants: req.body.participants, - participantsGoal: req.body.participantsGoal, - poster: req.body.poster, - reviewsGoal: req.body.reviewsGoal, - startDate: req.body.startDate, - teamManager: req.body.teamManager, - teams: req.body.teams - }; - - const { errors, isValid } = validateEditEvent(data); - if (!isValid) return res.status(400).json(errors); - - event.address = data.address ? cleanSpaces(data.address) : event.address; - event.description = data.description || event.description; - - if (data.endDate) { - const endDate = moment(data.endDate) - .endOf('day') - .utc(); - const startDate = moment(event.startDate) - .startOf('day') - .utc(); - - if (!data.startDate) { - if (endDate.isBefore(startDate)) { - return res.status(400).json({ - endDate: 'Should be equal to or greater than startDate' - }); - } else if (endDate.diff(startDate, 'days') > 365) { - return res.status(400).json({ - endDate: 'Should last less than 365 days from startDate' - }); - } - } - - event.endDate = endDate.toDate(); - } - - event.isOpen = - typeof data.isOpen !== 'undefined' ? data.isOpen : event.isOpen; - - if (data.locationCoordinates && data.locationCoordinates.length > 0) { - event.location = { - coordinates: [data.locationCoordinates[1], data.locationCoordinates[0]], - type: 'Point' - }; - } - - if (data.managers) { - let managersToAdd = []; - let managersToRemove = []; - - data.managers.forEach(m => { - if (m.startsWith('-')) { - managersToRemove = [...managersToRemove, m.substring(1)]; - } else { - managersToAdd = [...managersToAdd, m]; - } - }); - - const eventManagers = event.managers.map(m => m.toString()); - - managersToAdd = [...new Set(difference(managersToAdd, eventManagers))]; - if (managersToAdd.length > 0) { - const eventParticipants = event.participants.map(p => p.toString()); - const notParticipant = managersToAdd.find( - m => !eventParticipants.includes(m) - ); - - if (notParticipant) { - return res.status(400).json({ - managers: `User ${notParticipant} is not a participant of this event` - }); - } - - event.managers = [...eventManagers, ...managersToAdd]; - event.participants = event.participants.filter( - p => !managersToAdd.includes(p.toString()) - ); - } - - managersToRemove = [ - ...new Set(intersection(managersToRemove, eventManagers)) - ]; - if (managersToRemove.length === event.managers.length) { - return res - .status(400) - .json({ managers: 'Should not remove all managers' }); - } - - event.managers = event.managers.filter( - m => !managersToRemove.includes(m.toString()) - ); - const eventParticipants = event.participants.map(p => p.toString()); - event.participants = [...eventParticipants, ...managersToRemove]; - } - - if (data.name) { - const eventName = cleanSpaces(data.name); - - if (eventName !== event.name) { - let repeatedEvent; - try { - repeatedEvent = await Event.findOne({ - name: eventName, - isArchived: false - }); - } catch (err) { - console.log(`Event ${eventName} failed to be found at edit-event`); - return next(err); - } - - if (repeatedEvent) { - return res.status(400).json({ name: 'Is already taken' }); - } - - event.name = eventName; - } - } - - if (data.participants) { - const eventParticipants = event.participants.map(p => p.toString()); - let participantsToRemove = data.participants.map(p => p.substring(1)); - participantsToRemove = [ - ...new Set(intersection(participantsToRemove, eventParticipants)) - ]; - - const getParticipants = participantsToRemove.map(p => - User.find({ _id: p, isArchived: false }) - ); - let participants; - try { - participants = await Promise.all(getParticipants); - } catch (err) { - console.log('Participants failed to be found at edit-event'); - return next(err); - } - - const updateParticipants = participants.map((p, i) => { - p[i].events = p[i].events.filter(e => e.toString() !== event.id); - return p[i].save(); - }); - - try { - await Promise.all(updateParticipants); - } catch (err) { - console.log('Participants failed to be updated at edit-event'); - return next(err); - } - - event.participants = event.participants.filter( - p => !participantsToRemove.includes(p.toString()) - ); - } - - event.participantsGoal = data.participantsGoal || event.participantsGoal; - - if ( - data.poster && - !data.poster.includes('default') && - data.poster !== event.poster - ) { - let poster; - try { - poster = await Photo.findOne({ url: data.poster }); - } catch (err) { - console.log(`Poster ${data.poster} failed to be found at edit-event`); - return next(err); - } - - if (!poster) { - return res.status(404).json({ poster: 'Not found' }); - } - - event.poster = data.poster; - } else if (data.poster === '') { - event.poster = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/events/posters/default.png`; - } - - event.reviewsGoal = data.reviewsGoal || event.reviewsGoal; - - if (data.startDate) { - const startDate = moment(data.startDate) - .startOf('day') - .utc(); - const endDate = moment(event.endDate) - .endOf('day') - .utc(); - - if (!data.endDate) { - const today = moment() - .startOf('day') - .utc(); - - if (startDate.isBefore(today)) { - return res.status(400).json({ - startDate: 'Should be equal to or greater than the current time' - }); - } else if (startDate.isAfter(endDate)) { - return res.status(400).json({ - startDate: 'Should be equal to or less than endDate' - }); - } else if (endDate.diff(startDate, 'days') > 365) { - return res.status(400).json({ - startDate: 'Should last less than 365 days to endDate' - }); - } - } - - event.startDate = startDate.toDate(); - } - - if (data.teamManager) { - let team; - try { - team = await Team.findOne({ _id: data.teamManager, isArchived: false }); - } catch (err) { - console.log(`Team ${data.teamManager} failed to be found at edit-event`); - return next(err); - } - - if (!team) { - return res.status(404).json({ teamManager: 'Not found' }); - } - - const teamManagers = team.managers.map(m => m.toString()); - if (!teamManagers.includes(req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - event.teamManager = data.teamManager; - - team.events = [...new Set([...team.events, event.id])]; - try { - await team.save(); - } catch (err) { - console.log(`Team ${team.id} failed to be updated at edit-event`); - return next(err); - } - } else if (data.teamManager === '' && event.teamManager) { - let team; - try { - team = await Team.findOne({ _id: event.teamManager, isArchived: false }); - } catch (err) { - console.log(`Team ${event.teamManager} failed to be found at edit-event`); - return next(err); - } - - if (!team) { - return res.status(404).json({ teamManager: 'Not found' }); - } - - const teamManagers = team.managers.map(m => m.toString()); - if (!teamManagers.includes(req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - event.teamManager = null; - - team.events = team.events.filter(e => e.toString() !== event.id); - try { - await team.save(); - } catch (err) { - console.log(`Team ${team.id} failed to be updated at edit-event`); - return next(err); - } - } - - if (data.teams) { - const eventTeams = event.teams.map(t => t.toString()); - let teamsToRemove = data.teams.map(t => t.substring(1)); - teamsToRemove = [...new Set(intersection(teamsToRemove, eventTeams))]; - - const getTeams = teamsToRemove.map(t => - Team.find({ _id: t, isArchived: false }) - ); - let teams; - try { - teams = await Promise.all(getTeams); - } catch (err) { - console.log('Teams failed to be found at edit-event'); - return next(err); - } - - const updateTeams = teams.map((t, i) => { - t[i].events = t[i].events.filter(e => e.toString() !== event.id); - return t[i].save(); - }); - - try { - await Promise.all(updateTeams); - } catch (err) { - console.log('Teams failed to be updated at edit-event'); - return next(err); - } - - event.teams = event.teams.filter( - t => !teamsToRemove.includes(t.toString()) - ); - } - - event.updatedAt = moment.utc().toDate(); - - try { - await event.save(); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log(`Event ${event.id} failed to be updated at edit-event`); - return next(err); - } - - let eventLocation; - if (event.location.coordinates) { - eventLocation = { - lat: event.location.coordinates[1], - lng: event.location.coordinates[0] - }; - } - const dataResponse = { - address: event.address, - description: event.description, - endDate: event.description, - isOpen: event.isOpen, - location: eventLocation, - managers: event.managers, - name: event.name, - participantsGoal: event.participantsGoal, - poster: event.poster, - reviewsGoal: event.reviewsGoal, - teamManager: event.teamManager - }; - - return res.status(200).json(dataResponse); -}; +const { difference, intersection } = require('lodash'); +const moment = require('moment'); + +const { Event } = require('../../models/event'); +const { cleanSpaces } = require('../../helpers'); +const { Photo } = require('../../models/photo'); +const { Team } = require('../../models/team'); +const { User } = require('../../models/user'); + +const { validateEditEvent } = require('./validations'); + +module.exports = async (req, res, next) => { + const eventId = req.params.eventId; + + let event; + try { + event = await Event.findOne({ _id: eventId }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Event not found' }); + } + + console.log(`Event ${eventId} failed to be found at edit-event`); + return next(err); + } + + if (!event) { + return res.status(404).json({ general: 'Event not found' }); + } + + if (!event.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const data = { + address: req.body.address, + description: req.body.description, + endDate: req.body.endDate, + isOpen: req.body.isOpen, + locationCoordinates: req.body.locationCoordinates, + managers: req.body.managers, + name: req.body.name, + participants: req.body.participants, + participantsGoal: req.body.participantsGoal, + poster: req.body.poster, + reviewsGoal: req.body.reviewsGoal, + startDate: req.body.startDate, + teamManager: req.body.teamManager, + teams: req.body.teams + }; + + const { errors, isValid } = validateEditEvent(data); + if (!isValid) return res.status(400).json(errors); + + event.address = data.address ? cleanSpaces(data.address) : event.address; + event.description = data.description || event.description; + + if (data.endDate) { + const endDate = moment(data.endDate).endOf('day').utc(); + const startDate = moment(event.startDate).startOf('day').utc(); + + if (!data.startDate) { + if (endDate.isBefore(startDate)) { + return res.status(400).json({ + endDate: 'Should be equal to or greater than startDate' + }); + } else if (endDate.diff(startDate, 'days') > 365) { + return res.status(400).json({ + endDate: 'Should last less than 365 days from startDate' + }); + } + } + + event.endDate = endDate.toDate(); + } + + event.isOpen = + typeof data.isOpen !== 'undefined' ? data.isOpen : event.isOpen; + + if (data.locationCoordinates && data.locationCoordinates.length > 0) { + event.location = { + coordinates: [data.locationCoordinates[1], data.locationCoordinates[0]], + type: 'Point' + }; + } + + if (data.managers) { + let managersToAdd = []; + let managersToRemove = []; + + data.managers.forEach((m) => { + if (m.startsWith('-')) { + managersToRemove = [...managersToRemove, m.substring(1)]; + } else { + managersToAdd = [...managersToAdd, m]; + } + }); + + const eventManagers = event.managers.map((m) => m.toString()); + + managersToAdd = [...new Set(difference(managersToAdd, eventManagers))]; + if (managersToAdd.length > 0) { + const eventParticipants = event.participants.map((p) => p.toString()); + const notParticipant = managersToAdd.find( + (m) => !eventParticipants.includes(m) + ); + + if (notParticipant) { + return res.status(400).json({ + managers: `User ${notParticipant} is not a participant of this event` + }); + } + + event.managers = [...eventManagers, ...managersToAdd]; + event.participants = event.participants.filter( + (p) => !managersToAdd.includes(p.toString()) + ); + } + + managersToRemove = [ + ...new Set(intersection(managersToRemove, eventManagers)) + ]; + if (managersToRemove.length === event.managers.length) { + return res + .status(400) + .json({ managers: 'Should not remove all managers' }); + } + + event.managers = event.managers.filter( + (m) => !managersToRemove.includes(m.toString()) + ); + const eventParticipants = event.participants.map((p) => p.toString()); + event.participants = [...eventParticipants, ...managersToRemove]; + } + + if (data.name) { + const eventName = cleanSpaces(data.name); + + if (eventName !== event.name) { + let repeatedEvent; + try { + repeatedEvent = await Event.findOne({ + name: eventName, + isArchived: false + }); + } catch (err) { + console.log(`Event ${eventName} failed to be found at edit-event`); + return next(err); + } + + if (repeatedEvent) { + return res.status(400).json({ name: 'Is already taken' }); + } + + event.name = eventName; + } + } + + if (data.participants) { + const eventParticipants = event.participants.map((p) => p.toString()); + let participantsToRemove = data.participants.map((p) => p.substring(1)); + participantsToRemove = [ + ...new Set(intersection(participantsToRemove, eventParticipants)) + ]; + + const getParticipants = participantsToRemove.map((p) => + User.find({ _id: p, isArchived: false }) + ); + let participants; + try { + participants = await Promise.all(getParticipants); + } catch (err) { + console.log('Participants failed to be found at edit-event'); + return next(err); + } + + const updateParticipants = participants.map((p, i) => { + p[i].events = p[i].events.filter((e) => e.toString() !== event.id); + return p[i].save(); + }); + + try { + await Promise.all(updateParticipants); + } catch (err) { + console.log('Participants failed to be updated at edit-event'); + return next(err); + } + + event.participants = event.participants.filter( + (p) => !participantsToRemove.includes(p.toString()) + ); + } + + event.participantsGoal = data.participantsGoal || event.participantsGoal; + + if ( + data.poster && + !data.poster.includes('default') && + data.poster !== event.poster + ) { + let poster; + try { + poster = await Photo.findOne({ url: data.poster }); + } catch (err) { + console.log(`Poster ${data.poster} failed to be found at edit-event`); + return next(err); + } + + if (!poster) { + return res.status(404).json({ poster: 'Not found' }); + } + + event.poster = data.poster; + } else if (data.poster === '') { + event.poster = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/events/posters/default.png`; + } + + event.reviewsGoal = data.reviewsGoal || event.reviewsGoal; + + if (data.startDate) { + const startDate = moment(data.startDate).startOf('day').utc(); + const endDate = moment(event.endDate).endOf('day').utc(); + + if (!data.endDate) { + const today = moment().startOf('day').utc(); + + if (startDate.isBefore(today)) { + return res.status(400).json({ + startDate: 'Should be equal to or greater than the current time' + }); + } else if (startDate.isAfter(endDate)) { + return res.status(400).json({ + startDate: 'Should be equal to or less than endDate' + }); + } else if (endDate.diff(startDate, 'days') > 365) { + return res.status(400).json({ + startDate: 'Should last less than 365 days to endDate' + }); + } + } + + event.startDate = startDate.toDate(); + } + + if (data.teamManager) { + let team; + try { + team = await Team.findOne({ _id: data.teamManager, isArchived: false }); + } catch (err) { + console.log(`Team ${data.teamManager} failed to be found at edit-event`); + return next(err); + } + + if (!team) { + return res.status(404).json({ teamManager: 'Not found' }); + } + + const teamManagers = team.managers.map((m) => m.toString()); + if (!teamManagers.includes(req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + event.teamManager = data.teamManager; + + team.events = [...new Set([...team.events, event.id])]; + try { + await team.save(); + } catch (err) { + console.log(`Team ${team.id} failed to be updated at edit-event`); + return next(err); + } + } else if (data.teamManager === '' && event.teamManager) { + let team; + try { + team = await Team.findOne({ _id: event.teamManager, isArchived: false }); + } catch (err) { + console.log(`Team ${event.teamManager} failed to be found at edit-event`); + return next(err); + } + + if (!team) { + return res.status(404).json({ teamManager: 'Not found' }); + } + + const teamManagers = team.managers.map((m) => m.toString()); + if (!teamManagers.includes(req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + event.teamManager = null; + + team.events = team.events.filter((e) => e.toString() !== event.id); + try { + await team.save(); + } catch (err) { + console.log(`Team ${team.id} failed to be updated at edit-event`); + return next(err); + } + } + + if (data.teams) { + const eventTeams = event.teams.map((t) => t.toString()); + let teamsToRemove = data.teams.map((t) => t.substring(1)); + teamsToRemove = [...new Set(intersection(teamsToRemove, eventTeams))]; + + const getTeams = teamsToRemove.map((t) => + Team.find({ _id: t, isArchived: false }) + ); + let teams; + try { + teams = await Promise.all(getTeams); + } catch (err) { + console.log('Teams failed to be found at edit-event'); + return next(err); + } + + const updateTeams = teams.map((t, i) => { + t[i].events = t[i].events.filter((e) => e.toString() !== event.id); + return t[i].save(); + }); + + try { + await Promise.all(updateTeams); + } catch (err) { + console.log('Teams failed to be updated at edit-event'); + return next(err); + } + + event.teams = event.teams.filter( + (t) => !teamsToRemove.includes(t.toString()) + ); + } + + event.updatedAt = moment.utc().toDate(); + + try { + await event.save(); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log(`Event ${event.id} failed to be updated at edit-event`); + return next(err); + } + + let eventLocation; + if (event.location.coordinates) { + eventLocation = { + lat: event.location.coordinates[1], + lng: event.location.coordinates[0] + }; + } + const dataResponse = { + address: event.address, + description: event.description, + endDate: event.description, + isOpen: event.isOpen, + location: eventLocation, + managers: event.managers, + name: event.name, + participantsGoal: event.participantsGoal, + poster: event.poster, + reviewsGoal: event.reviewsGoal, + teamManager: event.teamManager + }; + + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/events/get-event.js b/src/routes/events/get-event.js index eb8bd3a..c07a89d 100644 --- a/src/routes/events/get-event.js +++ b/src/routes/events/get-event.js @@ -1,207 +1,207 @@ -const axios = require('axios'); -const mongoose = require('mongoose'); -const { isMongoId } = require('validator'); - -const { Event } = require('../../models/event'); - -module.exports = async (req, res, next) => { - let eventId = req.params.eventId; - if (!isMongoId(eventId)) { - return res.status(400).json({ general: 'Event not found' }); - } - eventId = mongoose.Types.ObjectId(eventId); - - let event; - try { - event = await Event.aggregate([ - { - $match: { _id: eventId } - }, - { - $lookup: { - from: 'users', - let: { managers: '$managers' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$managers'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - firstName: 1, - lastName: 1 - } - } - ], - as: 'managers' - } - }, - { - $lookup: { - from: 'users', - let: { participants: '$participants' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$participants'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - firstName: 1, - lastName: 1 - } - } - ], - as: 'participants' - } - }, - { - $lookup: { - from: 'teams', - let: { teams: '$teams' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$teams'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - name: 1 - } - } - ], - as: 'teams' - } - }, - { - $lookup: { - from: 'teams', - let: { teamManager: '$teamManager' }, - pipeline: [ - { - $match: { - $expr: { - $eq: ['$_id', '$$teamManager'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - name: 1 - } - } - ], - as: 'teamManager' - } - }, - { - $unwind: { - path: '$teamManager', - preserveNullAndEmptyArrays: true - } - }, - { - $lookup: { - from: 'events', - let: { reviewsAmount: '$reviewsAmount' }, - pipeline: [ - { - $match: { - $expr: { - $gt: ['$reviewsAmount', '$$reviewsAmount'] - } - } - }, - { - $count: 'ranking' - } - ], - as: 'ranking' - } - }, - { - $project: { - _id: 0, - id: '$_id', - address: 1, - description: 1, - donationAmounts: 1, - donationId: 1, - endDate: 1, - isOpen: 1, - location: 1, - managers: 1, - name: 1, - participants: 1, - participantsGoal: 1, - poster: 1, - ranking: 1, - reviewsAmount: 1, - reviewsGoal: 1, - startDate: 1, - teamManager: 1, - teams: 1 - } - } - ]); - } catch (err) { - console.log(`Event ${eventId} failed to be found at get-event`); - return next(err); - } - - if (!event) { - return res.status(404).json({ general: 'Event not found' }); - } - - const dataResponse = Object.assign({}, event[0], { - ranking: event[0].ranking.length ? event[0].ranking[0].ranking + 1 : 1 - }); - - if (dataResponse.donationId) { - let options = { - method: 'GET', - url: `https://${ - process.env.DONATELY_SUBDOMAIN - }.dntly.com/api/v1/admin/campaigns/${dataResponse.donationId}`, - auth: { - username: process.env.DONATELY_TOKEN, - password: '' - } - }; - - let response; - try { - response = await axios(options); - } catch (err) { - console.log('Donation campaign failed to be found at get-event.'); - return next(err); - } - - dataResponse.donationAmountRaised = response.data.campaign.amount_raised; - dataResponse.donationDonorsCount = response.data.campaign.donors_count; - dataResponse.donationGoal = response.data.campaign.campaign_goal; - } - - return res.status(200).json(dataResponse); -}; +const axios = require('axios'); +const mongoose = require('mongoose'); +const { isMongoId } = require('validator'); + +const { Event } = require('../../models/event'); + +module.exports = async (req, res, next) => { + let eventId = req.params.eventId; + if (!isMongoId(eventId)) { + return res.status(400).json({ general: 'Event not found' }); + } + eventId = new mongoose.Types.ObjectId(eventId); + + let event; + try { + event = await Event.aggregate([ + { + $match: { _id: eventId } + }, + { + $lookup: { + from: 'users', + let: { managers: '$managers' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$managers'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + firstName: 1, + lastName: 1 + } + } + ], + as: 'managers' + } + }, + { + $lookup: { + from: 'users', + let: { participants: '$participants' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$participants'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + firstName: 1, + lastName: 1 + } + } + ], + as: 'participants' + } + }, + { + $lookup: { + from: 'teams', + let: { teams: '$teams' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$teams'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + name: 1 + } + } + ], + as: 'teams' + } + }, + { + $lookup: { + from: 'teams', + let: { teamManager: '$teamManager' }, + pipeline: [ + { + $match: { + $expr: { + $eq: ['$_id', '$$teamManager'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + name: 1 + } + } + ], + as: 'teamManager' + } + }, + { + $unwind: { + path: '$teamManager', + preserveNullAndEmptyArrays: true + } + }, + { + $lookup: { + from: 'events', + let: { reviewsAmount: '$reviewsAmount' }, + pipeline: [ + { + $match: { + $expr: { + $gt: ['$reviewsAmount', '$$reviewsAmount'] + } + } + }, + { + $count: 'ranking' + } + ], + as: 'ranking' + } + }, + { + $project: { + _id: 0, + id: '$_id', + address: 1, + description: 1, + donationAmounts: 1, + donationId: 1, + endDate: 1, + isOpen: 1, + location: 1, + managers: 1, + name: 1, + participants: 1, + participantsGoal: 1, + poster: 1, + ranking: 1, + reviewsAmount: 1, + reviewsGoal: 1, + startDate: 1, + teamManager: 1, + teams: 1 + } + } + ]); + } catch (err) { + console.log(`Event ${eventId} failed to be found at get-event`); + return next(err); + } + + if (!event) { + return res.status(404).json({ general: 'Event not found' }); + } + + const dataResponse = Object.assign({}, event[0], { + ranking: event[0].ranking.length ? event[0].ranking[0].ranking + 1 : 1 + }); + + if (dataResponse.donationId) { + let options = { + method: 'GET', + url: `https://${ + process.env.DONATELY_SUBDOMAIN + }.dntly.com/api/v1/admin/campaigns/${dataResponse.donationId}`, + auth: { + username: process.env.DONATELY_TOKEN, + password: '' + } + }; + + let response; + try { + response = await axios(options); + } catch (err) { + console.log('Donation campaign failed to be found at get-event.'); + return next(err); + } + + dataResponse.donationAmountRaised = response.data.campaign.amount_raised; + dataResponse.donationDonorsCount = response.data.campaign.donors_count; + dataResponse.donationGoal = response.data.campaign.campaign_goal; + } + + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/events/index.js b/src/routes/events/index.js index fbbe43d..901a189 100644 --- a/src/routes/events/index.js +++ b/src/routes/events/index.js @@ -1,31 +1,31 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const createEvent = require('./create-event'); -const deleteEvent = require('./delete-event'); -const editEvent = require('./edit-event'); -const getEvent = require('./get-event'); -const leaveEvent = require('./leave-event'); -const listEvents = require('./list-events'); -const joinEvent = require('./join-event'); - -const router = new express.Router(); - -router.get('', listEvents); -router.post('', isAuthenticated({ isOptional: false }), createEvent); -router.get('/:eventId', getEvent); -router.put('/:eventId', isAuthenticated({ isOptional: false }), editEvent); -router.delete('/:eventId', isAuthenticated({ isOptional: false }), deleteEvent); -router.post( - '/:eventId/join', - isAuthenticated({ isOptional: false }), - joinEvent -); -router.put( - '/:eventId/leave', - isAuthenticated({ isOptional: false }), - leaveEvent -); - -module.exports = router; +const express = require('express'); + +const { isAuthenticated } = require('../../helpers'); + +const createEvent = require('./create-event'); +const deleteEvent = require('./delete-event'); +const editEvent = require('./edit-event'); +const getEvent = require('./get-event'); +const leaveEvent = require('./leave-event'); +const listEvents = require('./list-events'); +const joinEvent = require('./join-event'); + +const router = new express.Router(); + +router.get('', listEvents); +router.post('', isAuthenticated({ isOptional: false }), createEvent); +router.get('/:eventId', getEvent); +router.put('/:eventId', isAuthenticated({ isOptional: false }), editEvent); +router.delete('/:eventId', isAuthenticated({ isOptional: false }), deleteEvent); +router.post( + '/:eventId/join', + isAuthenticated({ isOptional: false }), + joinEvent +); +router.put( + '/:eventId/leave', + isAuthenticated({ isOptional: false }), + leaveEvent +); + +module.exports = router; diff --git a/src/routes/events/join-event.js b/src/routes/events/join-event.js index 91b4f1e..f3b6378 100644 --- a/src/routes/events/join-event.js +++ b/src/routes/events/join-event.js @@ -1,134 +1,134 @@ -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { Petition } = require('../../models/petition'); - -module.exports = async (req, res, next) => { - const eventId = req.params.eventId; - - let event; - try { - event = await Event.findOne({ _id: eventId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Event not found' }); - } - - console.log(`Event ${eventId} failed to be found at join-event`); - return next(err); - } - - if (!event) { - return res.status(404).json({ general: 'Event not found' }); - } - - const eventParticipants = event.participants.map(p => p.toString()); - if (eventParticipants.includes(req.user.id)) { - return res - .status(400) - .json({ general: 'You already are a participant in this event' }); - } - - const eventManagers = event.managers.map(m => m.toString()); - if (eventManagers.includes(req.user.id)) { - return res - .status(400) - .json({ general: 'You already are a participant in this event' }); - } - - if (event.isOpen) { - req.user.events = [...req.user.events, event.id]; - req.user.updatedAt = moment.utc().toDate(); - - try { - await req.user.save(); - } catch (err) { - console.log(`User ${req.user.id} failed to be updated at join-event`); - return next(err); - } - - event.participants = [...event.participants, req.user.id]; - event.updatedAt = moment.utc().toDate(); - - try { - await event.save(); - } catch (err) { - console.log(`Event ${event.id} failed to be updated at join-event`); - return next(err); - } - - return res.status(200).json({ general: 'Joined' }); - } else { - let petition; - try { - petition = await Petition.findOne({ - event: event.id, - sender: req.user.id, - type: 'request-user-event' - }); - } catch (err) { - console.log( - `Petition from user ${req.user.id} to event ${ - event.id - } failed to be found at join-event` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'You already have a pending petition with this event' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at join-event` - ); - return next(err); - } - } - - const endDate = moment(event.endDate).utc(); - const today = moment.utc(); - if (endDate.isBefore(today)) { - return res - .status(423) - .json({ general: 'This event has already finished' }); - } - - const petitionData = { - event: event.id, - sender: req.user.id, - type: 'request-user-event' - }; - try { - await Petition.create(petitionData); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `Petition failed to be created at join-event.\nData: ${JSON.stringify( - petitionData - )}` - ); - return next(err); - } - - return res.status(200).json({ general: 'Requested' }); - } -}; +const moment = require('moment'); + +const { Event } = require('../../models/event'); +const { Petition } = require('../../models/petition'); + +module.exports = async (req, res, next) => { + const eventId = req.params.eventId; + + let event; + try { + event = await Event.findOne({ _id: eventId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Event not found' }); + } + + console.log(`Event ${eventId} failed to be found at join-event`); + return next(err); + } + + if (!event) { + return res.status(404).json({ general: 'Event not found' }); + } + + const eventParticipants = event.participants.map((p) => p.toString()); + if (eventParticipants.includes(req.user.id)) { + return res + .status(400) + .json({ general: 'You already are a participant in this event' }); + } + + const eventManagers = event.managers.map((m) => m.toString()); + if (eventManagers.includes(req.user.id)) { + return res + .status(400) + .json({ general: 'You already are a participant in this event' }); + } + + if (event.isOpen) { + req.user.events = [...req.user.events, event.id]; + req.user.updatedAt = moment.utc().toDate(); + + try { + await req.user.save(); + } catch (err) { + console.log(`User ${req.user.id} failed to be updated at join-event`); + return next(err); + } + + event.participants = [...event.participants, req.user.id]; + event.updatedAt = moment.utc().toDate(); + + try { + await event.save(); + } catch (err) { + console.log(`Event ${event.id} failed to be updated at join-event`); + return next(err); + } + + return res.status(200).json({ general: 'Joined' }); + } else { + let petition; + try { + petition = await Petition.findOne({ + event: event.id, + sender: req.user.id, + type: 'request-user-event' + }); + } catch (err) { + console.log( + `Petition from user ${req.user.id} to event ${ + event.id + } failed to be found at join-event` + ); + return next(err); + } + + if (petition && petition.state === 'pending') { + return res.status(400).json({ + general: 'You already have a pending petition with this event' + }); + } + + if ( + petition && + (petition.state === 'rejected' || petition.state === 'canceled') + ) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at join-event` + ); + return next(err); + } + } + + const endDate = moment(event.endDate).utc(); + const today = moment.utc(); + if (endDate.isBefore(today)) { + return res + .status(423) + .json({ general: 'This event has already finished' }); + } + + const petitionData = { + event: event.id, + sender: req.user.id, + type: 'request-user-event' + }; + try { + await Petition.create(petitionData); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `Petition failed to be created at join-event.\nData: ${JSON.stringify( + petitionData + )}` + ); + return next(err); + } + + return res.status(200).json({ general: 'Requested' }); + } +}; diff --git a/src/routes/events/leave-event.js b/src/routes/events/leave-event.js index 5b4e0fd..17dc445 100644 --- a/src/routes/events/leave-event.js +++ b/src/routes/events/leave-event.js @@ -1,69 +1,69 @@ -const moment = require('moment'); - -const { Event } = require('../../models/event'); - -module.exports = async (req, res, next) => { - const eventId = req.params.eventId; - - let event; - try { - event = await Event.findOne({ _id: eventId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Event not found' }); - } - - console.log(`Event ${eventId} failed to be found at leave-event`); - return next(err); - } - - if (!event) { - return res.status(404).json({ general: 'Event not found' }); - } - - const endDate = moment(event.endDate).utc(); - const today = moment.utc(); - - if (endDate.isBefore(today)) { - return res.status(400).json({ - general: 'You cannot leave because it already ended' - }); - } - - if (event.managers.find(m => m.toString() === req.user.id)) { - event.managers = event.managers.filter(m => m.toString() !== req.user.id); - - if (event.managers.length === 0) { - return res.status(400).json({ - general: 'You cannot leave because you are the only manager' - }); - } - } else if (event.participants.find(p => p.toString() === req.user.id)) { - event.participants = event.participants.filter( - p => p.toString() !== req.user.id - ); - } else { - return res.status(400).json({ general: 'You are not a participant' }); - } - - event.updatedAt = today.toDate(); - - try { - await event.save(); - } catch (err) { - console.log(`Event ${event.id} failed to be updated at leave-event`); - return next(err); - } - - req.user.events = req.user.events.filter(e => e.toString() !== event.id); - req.user.updatedAt = today.toDate(); - - try { - await req.user.save(); - } catch (err) { - console.log(`User ${req.user.id} failed to be updated at leave-event`); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { Event } = require('../../models/event'); + +module.exports = async (req, res, next) => { + const eventId = req.params.eventId; + + let event; + try { + event = await Event.findOne({ _id: eventId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Event not found' }); + } + + console.log(`Event ${eventId} failed to be found at leave-event`); + return next(err); + } + + if (!event) { + return res.status(404).json({ general: 'Event not found' }); + } + + const endDate = moment(event.endDate).utc(); + const today = moment.utc(); + + if (endDate.isBefore(today)) { + return res.status(400).json({ + general: 'You cannot leave because it already ended' + }); + } + + if (event.managers.find((m) => m.toString() === req.user.id)) { + event.managers = event.managers.filter((m) => m.toString() !== req.user.id); + + if (event.managers.length === 0) { + return res.status(400).json({ + general: 'You cannot leave because you are the only manager' + }); + } + } else if (event.participants.find((p) => p.toString() === req.user.id)) { + event.participants = event.participants.filter( + (p) => p.toString() !== req.user.id + ); + } else { + return res.status(400).json({ general: 'You are not a participant' }); + } + + event.updatedAt = today.toDate(); + + try { + await event.save(); + } catch (err) { + console.log(`Event ${event.id} failed to be updated at leave-event`); + return next(err); + } + + req.user.events = req.user.events.filter((e) => e.toString() !== event.id); + req.user.updatedAt = today.toDate(); + + try { + await req.user.save(); + } catch (err) { + console.log(`User ${req.user.id} failed to be updated at leave-event`); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/events/list-events.js b/src/routes/events/list-events.js index 9521d85..7f75d82 100644 --- a/src/routes/events/list-events.js +++ b/src/routes/events/list-events.js @@ -1,95 +1,88 @@ -const moment = require('moment'); - -const { Event } = require('../../models/event'); - -const { validateListEvents } = require('./validations'); - -module.exports = async (req, res, next) => { - const queryParams = req.query; - - const { errors, isValid } = validateListEvents(queryParams); - if (!isValid) return res.status(400).json(errors); - - const eventsQuery = {}; - - if (queryParams.keywords) { - eventsQuery.$text = { $search: queryParams.keywords }; - } - - eventsQuery.isArchived = false; - - let afterDate; - let beforeDate; - if (queryParams.afterDate && queryParams.beforeDate) { - afterDate = moment(queryParams.afterDate) - .utc() - .toDate(); - beforeDate = moment(queryParams.beforeDate) - .utc() - .toDate(); - - eventsQuery.startDate = { $gte: afterDate, $lte: beforeDate }; - } else if (queryParams.afterDate) { - afterDate = moment(queryParams.afterDate) - .utc() - .toDate(); - eventsQuery.startDate = { $gte: afterDate }; - } else if (queryParams.beforeDate) { - beforeDate = moment(queryParams.beforeDate) - .utc() - .toDate(); - eventsQuery.startDate = { $lte: beforeDate }; - } - - let sortBy = queryParams.sortBy || '-startDate'; - let page = queryParams.page ? queryParams.page - 1 : 0; - const pageLimit = queryParams.pageLimit || 12; - - let events; - let total; - try { - [events, total] = await Promise.all([ - Event.aggregate() - .match(eventsQuery) - .project({ - _id: 0, - id: '$_id', - address: 1, - endDate: 1, - name: 1, - poster: 1, - reviewsAmount: 1, - reviewsGoal: 1, - startDate: 1 - }) - .sort(sortBy) - .skip(page * pageLimit) - .limit(pageLimit), - Event.find(eventsQuery).count() - ]); - } catch (err) { - console.log('Events failed to be found or count at list-events'); - return next(err); - } - - let lastPage = Math.ceil(total / pageLimit); - if (lastPage > 0) { - if (page > lastPage) { - return res - .status(400) - .json({ page: `Should be equal to or less than ${lastPage}` }); - } - } else { - page = null; - lastPage = null; - } - - return res.status(200).json({ - page: page + 1, - lastPage, - pageLimit, - total, - sortBy, - results: events - }); -}; +const moment = require("moment"); + +const { Event } = require("../../models/event"); + +const { validateListEvents } = require("./validations"); + +module.exports = async (req, res, next) => { + const queryParams = req.query; + + const { errors, isValid } = validateListEvents(queryParams); + if (!isValid) return res.status(400).json(errors); + + const eventsQuery = {}; + + if (queryParams.keywords) { + eventsQuery.$text = { $search: queryParams.keywords }; + } + + eventsQuery.isArchived = false; + + let afterDate; + let beforeDate; + if (queryParams.afterDate && queryParams.beforeDate) { + afterDate = moment(queryParams.afterDate).utc().toDate(); + beforeDate = moment(queryParams.beforeDate).utc().toDate(); + + eventsQuery.startDate = { $gte: afterDate, $lte: beforeDate }; + } else if (queryParams.afterDate) { + afterDate = moment(queryParams.afterDate).utc().toDate(); + eventsQuery.startDate = { $gte: afterDate }; + } else if (queryParams.beforeDate) { + beforeDate = moment(queryParams.beforeDate).utc().toDate(); + eventsQuery.startDate = { $lte: beforeDate }; + } + + let sortBy = queryParams.sortBy || "-startDate"; + let page = queryParams.page ? queryParams.page - 1 : 0; + const pageLimit = queryParams.pageLimit || 12; + + let events; + let total; + try { + [events, total] = await Promise.all([ + Event.aggregate() + .match(eventsQuery) + .project({ + _id: 0, + id: "$_id", + address: 1, + endDate: 1, + name: 1, + poster: 1, + reviewsAmount: 1, + reviewsGoal: 1, + startDate: 1, + description: 1, + }) + .sort(sortBy) + .skip(page * pageLimit) + .limit(pageLimit), + Event.countDocuments(eventsQuery), + ]); + } catch (err) { + console.log("Events failed to be found or count at list-events"); + return next(err); + } + + let lastPage = Math.ceil(total / pageLimit); + if (lastPage > 0) { + if (page > lastPage) { + return res + .status(400) + .json({ page: `Should be equal to or less than ${lastPage}` }); + } + } else { + page = null; + lastPage = null; + } + + return res.status(200).json({ + page: page + 1, + lastPage, + pageLimit, + total, + sortBy, + results: events, + }); +}; diff --git a/src/routes/events/validations.js b/src/routes/events/validations.js index 2b15620..15b98be 100644 --- a/src/routes/events/validations.js +++ b/src/routes/events/validations.js @@ -1,490 +1,466 @@ -const { isEmpty } = require('lodash'); -const { isInt, isMongoId } = require('validator'); -const moment = require('moment'); - -const { isNumber } = require('../../helpers'); - -module.exports = { - validateCreateEvent(data) { - const errors = {}; - - if (typeof data.address === 'undefined' || data.address === '') { - errors.address = 'Is required'; - } else if (typeof data.address !== 'string') { - errors.address = 'Should be a string'; - } - - if ( - typeof data.description !== 'undefined' && - typeof data.description !== 'string' - ) { - errors.description = 'Should be a string'; - } - - if (data.donationEnabled === true) { - if (typeof data.donationAmounts === 'undefined') { - errors.donationAmounts = 'Is required'; - } - if (typeof data.donationGoal === 'undefined') { - errors.donationGoal = 'Is required'; - } - } - - if (typeof data.donationAmounts !== 'undefined') { - if (!Array.isArray(data.donationAmounts)) { - errors.donationAmounts = 'Should be an array'; - } else { - data.donationAmounts.some(d => { - if (typeof d.value === 'undefined') { - errors.donationAmounts = - 'All elements should have a value property'; - return true; - } else if (typeof d.value !== 'number') { - errors.donationAmounts = 'All value properties should be numbers'; - return true; - } else if (d < 5 || d > 10000) { - errors.donationAmounts = - 'All value properties should be between 5 and 10000'; - return true; - } - }); - } - } - - if ( - typeof data.donationEnabled !== 'undefined' && - typeof data.donationEnabled !== 'boolean' - ) { - errors.donationEnabled = 'Should be a boolean'; - } - - if (typeof data.donationGoal !== 'undefined') { - if (typeof data.donationGoal !== 'number') { - errors.donationGoal = 'Should be a number'; - } else if (!isInt(data.donationGoal.toString())) { - errors.donationGoal = 'Should be a integer'; - } - } - - let endDateIsValid = false; - if (typeof data.endDate === 'undefined' || data.endDate === '') { - errors.endDate = 'Is required'; - } else if (typeof data.endDate !== 'string') { - errors.endDate = 'Should be a string'; - } else if (!moment(data.endDate).isValid()) { - errors.endDate = 'Should have a ISO-8601 format'; - } else { - const endDate = moment(data.endDate) - .endOf('day') - .utc(); - const today = moment() - .startOf('day') - .utc(); - - if (endDate.isBefore(today)) { - errors.endDate = 'Should be greater than or equal to today'; - } else { - endDateIsValid = true; - } - } - - if ( - typeof data.isOpen !== 'undefined' && - typeof data.isOpen !== 'boolean' - ) { - errors.isOpen = 'Should be a boolean'; - } - - if (typeof data.locationCoordinates === 'undefined') { - errors.locationCoordinates = 'Is required'; - } else if (!Array.isArray(data.locationCoordinates)) { - errors.locationCoordinates = 'Should be an array'; - } else if (typeof data.locationCoordinates[0] === 'undefined') { - errors.locationCoordinates = 'Latitude is required'; - } else if (!isNumber(data.locationCoordinates[0])) { - errors.locationCoordinates = 'Latitude should be a number'; - } else if ( - parseFloat(data.locationCoordinates[0]) < -90 || - parseFloat(data.locationCoordinates[0]) > 90 - ) { - errors.locationCoordinates = 'Latitude value is not valid'; - } else if (typeof data.locationCoordinates[1] === 'undefined') { - errors.locationCoordinates = 'Longitude is required'; - } else if (!isNumber(data.locationCoordinates[1])) { - errors.locationCoordinates = 'Longitude should be a number'; - } else if ( - parseFloat(data.locationCoordinates[1]) < -180 || - parseFloat(data.locationCoordinates[1]) > 180 - ) { - errors.locationCoordinates = 'Longitude value is not valid'; - } else if (data.locationCoordinates.length > 2) { - errors.locationCoordinates = 'Should only have latitude and longitude'; - } - - if (typeof data.name === 'undefined' || data.name === '') { - errors.name = 'Is required'; - } else if (typeof data.name !== 'string') { - errors.name = 'Should be a string'; - } - - if (typeof data.participantsGoal === 'undefined') { - errors.participantsGoal = 'Is required'; - } else if (typeof data.participantsGoal !== 'number') { - errors.participantsGoal = 'Should be a number'; - } else if (!isInt(data.participantsGoal.toString())) { - errors.participantsGoal = 'Should be a integer'; - } - - if (typeof data.poster !== 'undefined' && typeof data.poster !== 'string') { - errors.poster = 'Should be a string'; - } - - if (typeof data.reviewsGoal === 'undefined') { - errors.reviewsGoal = 'Is required'; - } else if (typeof data.reviewsGoal !== 'number') { - errors.reviewsGoal = 'Should be a number'; - } else if (!isInt(data.reviewsGoal.toString())) { - errors.reviewsGoal = 'Should be a integer'; - } - - let startDateIsValid = false; - if (typeof data.startDate === 'undefined' || data.startDate === '') { - errors.startDate = 'Is required'; - } else if (typeof data.startDate !== 'string') { - errors.startDate = 'Should be a string'; - } else if (!moment(data.startDate).isValid()) { - errors.startDate = 'Should have a ISO-8601 format'; - } else { - const startDate = moment(data.startDate) - .startOf('day') - .utc(); - const today = moment() - .startOf('day') - .utc(); - - if (startDate.isBefore(today)) { - errors.startDate = 'Should be greater than or equal to today'; - } else { - startDateIsValid = true; - } - } - - if ( - typeof data.teamManager !== 'undefined' && - typeof data.teamManager !== 'string' - ) { - errors.teamManager = 'Should be a string'; - } else if (data.teamManager && !isMongoId(data.teamManager)) { - errors.teamManager = 'Should be a valid id'; - } - - if (endDateIsValid && startDateIsValid) { - const endDate = moment(data.endDate) - .endOf('day') - .utc(); - const startDate = moment(data.startDate) - .startOf('day') - .utc(); - - if (startDate.isAfter(endDate)) { - errors.endDate = 'Should be greater than or equal to startDate'; - errors.startDate = 'Should be less than or equal to endDate'; - } else if (endDate.diff(startDate, 'days') > 365) { - errors.endDate = 'Should last less than 365 days'; - } - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateEditEvent(data) { - const errors = {}; - - if (typeof data.address !== 'undefined') { - if (typeof data.address !== 'string') { - errors.address = 'Should be a string'; - } else if (data.address === '') { - errors.address = 'Is required'; - } - } - - if ( - typeof data.description !== 'undefined' && - typeof data.description !== 'string' - ) { - errors.description = 'Should be a string'; - } - - let endDateIsValid = false; - if (typeof data.endDate !== 'undefined') { - if (typeof data.endDate !== 'string') { - errors.endDate = 'Should be a string'; - } else if (data.endDate === '') { - errors.endDate = 'Is required'; - } else if (!moment(data.endDate).isValid()) { - errors.endDate = 'Should have a ISO-8601 format'; - } else { - const endDate = moment(data.endDate) - .endOf('day') - .utc(); - const today = moment() - .startOf('day') - .utc(); - - if (endDate.isBefore(today)) { - errors.endDate = 'Should be greater than or equal to today'; - } else { - endDateIsValid = true; - } - } - } - - if ( - typeof data.isOpen !== 'undefined' && - typeof data.isOpen !== 'boolean' - ) { - errors.isOpen = 'Should be a boolean'; - } - - if (typeof data.locationCoordinates !== 'undefined') { - if (!Array.isArray(data.locationCoordinates)) { - errors.locationCoordinates = 'Should be an array'; - } else if (typeof data.locationCoordinates[0] === 'undefined') { - errors.locationCoordinates = 'Latitude is required'; - } else if (!isNumber(data.locationCoordinates[0])) { - errors.locationCoordinates = 'Latitude should be a number'; - } else if ( - parseFloat(data.locationCoordinates[0]) < -90 || - parseFloat(data.locationCoordinates[0]) > 90 - ) { - errors.locationCoordinates = 'Latitude value is not valid'; - } else if (typeof data.locationCoordinates[1] === 'undefined') { - errors.locationCoordinates = 'Longitude is required'; - } else if (!isNumber(data.locationCoordinates[1])) { - errors.locationCoordinates = 'Longitude should be a number'; - } else if ( - parseFloat(data.locationCoordinates[1]) < -180 || - parseFloat(data.locationCoordinates[1]) > 180 - ) { - errors.locationCoordinates = 'Longitude value is not valid'; - } else if (data.locationCoordinates.length > 2) { - errors.locationCoordinates = 'Should only have latitude and longitude'; - } - } - - if (typeof data.managers !== 'undefined') { - if (!Array.isArray(data.managers)) { - errors.managers = 'Should be an array'; - } else { - data.managers.some(m => { - if (typeof m !== 'string') { - errors.managers = 'Should only have string values'; - return true; - } else if (!m) { - errors.managers = 'Should not have empty values'; - return true; - } else { - if (m.startsWith('-')) { - m = m.substring(1); - } - - if (!isMongoId(m)) { - errors.managers = `${m} should be an id`; - return true; - } - } - }); - } - } - - if (typeof data.name !== 'undefined') { - if (typeof data.name !== 'string') { - errors.name = 'Should be a string'; - } else if (data.name === '') { - errors.name = 'Is required'; - } - } - - if (typeof data.participants !== 'undefined') { - if (!Array.isArray(data.participants)) { - errors.participants = 'Should be an array'; - } else { - data.participants.some(p => { - if (typeof p !== 'string') { - errors.participants = 'Should only have string values'; - return true; - } else if (!p) { - errors.participants = 'Should not have empty values'; - return true; - } else if (!p.startsWith('-')) { - errors.participants = `${p} should start with -`; - return true; - } else if (!isMongoId(p.substring(1))) { - errors.participants = `${p} should be an id`; - return true; - } - }); - } - } - - if (typeof data.participantsGoal !== 'undefined') { - if (data.participantsGoal === null) { - errors.participantsGoal = 'Is required'; - } else if (typeof data.participantsGoal !== 'number') { - errors.participantsGoal = 'Should be a number'; - } else if (!isInt(data.participantsGoal.toString())) { - errors.participantsGoal = 'Should be a integer'; - } - } - - if (typeof data.poster !== 'undefined' && typeof data.poster !== 'string') { - errors.poster = 'Should be a string'; - } - - if (typeof data.reviewsGoal !== 'undefined') { - if (data.reviewsGoal === null) { - errors.reviewsGoal = 'Is required'; - } else if (typeof data.reviewsGoal !== 'number') { - errors.reviewsGoal = 'Should be a number'; - } else if (!isInt(data.reviewsGoal.toString())) { - errors.reviewsGoal = 'Should be a integer'; - } - } - - let startDateIsValid = false; - if (typeof data.startDate !== 'undefined') { - if (typeof data.startDate !== 'string') { - errors.startDate = 'Should be a string'; - } else if (data.startDate === '') { - errors.startDate = 'Is required'; - } else if (!moment(data.startDate).isValid()) { - errors.startDate = 'Should have a ISO-8601 format'; - } else { - const startDate = moment(data.startDate) - .startOf('day') - .utc(); - const today = moment() - .startOf('day') - .utc(); - - if (startDate.isBefore(today)) { - errors.startDate = 'Should be greater than or equal to today'; - } else { - startDateIsValid = true; - } - } - } - - if ( - typeof data.teamManager !== 'undefined' && - typeof data.teamManager !== 'string' - ) { - errors.teamManager = 'Should be a string'; - } else if (data.teamManager && !isMongoId(data.teamManager)) { - errors.teamManager = 'Should be a valid id'; - } - - if (typeof data.teams !== 'undefined') { - if (!Array.isArray(data.teams)) { - errors.teams = 'Should be an array'; - } else { - data.teams.some(t => { - if (typeof t !== 'string') { - errors.teams = 'Should only have string values'; - return true; - } else if (!t) { - errors.teams = 'Should not have empty values'; - return true; - } else if (!t.startsWith('-')) { - errors.teams = `${t} should start with -`; - return true; - } else if (!isMongoId(t.substring(1))) { - errors.teams = `${t} should be an id`; - return true; - } - }); - } - } - - if (endDateIsValid && startDateIsValid) { - const endDate = moment(data.endDate) - .endOf('day') - .utc(); - const startDate = moment(data.startDate) - .startOf('day') - .utc(); - - if (startDate.isAfter(endDate)) { - errors.endDate = 'Should be greater than or equal to startDate'; - errors.startDate = 'Should be less than or equal to endDate'; - } else if (endDate.diff(startDate, 'days') > 365) { - errors.endDate = 'Should last less than 365 days'; - } - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateListEvents(queryParams) { - const errors = {}; - - let isAfterDateValid = false; - if ( - queryParams.afterDate && - !moment(queryParams.afterDate, 'YYYY-MM-DD', true).isValid() - ) { - errors.afterDate = 'Should have YYYY-MM-DD format'; - } else { - isAfterDateValid = true; - } - - let isBeforeDateValid = false; - if ( - queryParams.beforeDate && - !moment(queryParams.beforeDate, 'YYYY-MM-DD', true).isValid() - ) { - errors.beforeDate = 'Should have YYYY-MM-DD format'; - } else { - isBeforeDateValid = true; - } - - if (isAfterDateValid && isBeforeDateValid) { - const afterDate = moment(queryParams.afterDate, 'YYYY-MM-DD').utc(); - const beforeDate = moment(queryParams.beforeDate, 'YYYY-MM-DD').utc(); - if (afterDate.isAfter(beforeDate)) { - errors.afterDate = 'Should be less than beforeDate'; - errors.beforeDate = 'Should be greater than afterDate'; - } - } - - const sortOptions = [ - 'name', - '-name', - 'reviewsAmount', - '-reviewsAmount', - 'startDate', - '-startDate' - ]; - if (queryParams.sortBy && !sortOptions.includes(queryParams.sortBy)) { - errors.sortBy = 'Should be a valid sort'; - } - - if (queryParams.page) { - if (!isInt(queryParams.page)) { - errors.page = 'Should be a integer'; - } else if (parseInt(queryParams.page, 10) < 1) { - errors.page = 'Should be a positive integer'; - } - } - - if (queryParams.pageLimit) { - if (!isInt(queryParams.pageLimit)) { - errors.pageLimit = 'Should be a integer'; - } else if (parseInt(queryParams.pageLimit, 10) < 1) { - errors.pageLimit = 'Should be a positive integer'; - } else if (parseInt(queryParams.pageLimit, 10) > 12) { - errors.pageLimit = 'Should be less than 13'; - } - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const { isEmpty } = require('lodash'); +const { isInt, isMongoId } = require('validator'); +const moment = require('moment'); + +const { isNumber } = require('../../helpers'); + +module.exports = { + validateCreateEvent(data) { + const errors = {}; + + if (typeof data.address === 'undefined' || data.address === '') { + errors.address = 'Is required'; + } else if (typeof data.address !== 'string') { + errors.address = 'Should be a string'; + } + + if ( + typeof data.description !== 'undefined' && + typeof data.description !== 'string' + ) { + errors.description = 'Should be a string'; + } + + if (data.donationEnabled === true) { + if (typeof data.donationAmounts === 'undefined') { + errors.donationAmounts = 'Is required'; + } + if (typeof data.donationGoal === 'undefined') { + errors.donationGoal = 'Is required'; + } + } + + if (typeof data.donationAmounts !== 'undefined') { + if (!Array.isArray(data.donationAmounts)) { + errors.donationAmounts = 'Should be an array'; + } else { + data.donationAmounts.some((d) => { + if (typeof d.value === 'undefined') { + errors.donationAmounts = + 'All elements should have a value property'; + return true; + } else if (typeof d.value !== 'number') { + errors.donationAmounts = 'All value properties should be numbers'; + return true; + } else if (d < 5 || d > 10000) { + errors.donationAmounts = + 'All value properties should be between 5 and 10000'; + return true; + } + }); + } + } + + if ( + typeof data.donationEnabled !== 'undefined' && + typeof data.donationEnabled !== 'boolean' + ) { + errors.donationEnabled = 'Should be a boolean'; + } + + if (typeof data.donationGoal !== 'undefined') { + if (typeof data.donationGoal !== 'number') { + errors.donationGoal = 'Should be a number'; + } else if (!isInt(data.donationGoal.toString())) { + errors.donationGoal = 'Should be a integer'; + } + } + + let endDateIsValid = false; + if (typeof data.endDate === 'undefined' || data.endDate === '') { + errors.endDate = 'Is required'; + } else if (typeof data.endDate !== 'string') { + errors.endDate = 'Should be a string'; + } else if (!moment(data.endDate).isValid()) { + errors.endDate = 'Should have a ISO-8601 format'; + } else { + const endDate = moment(data.endDate).endOf('day').utc(); + const today = moment().startOf('day').utc(); + + if (endDate.isBefore(today)) { + errors.endDate = 'Should be greater than or equal to today'; + } else { + endDateIsValid = true; + } + } + + if ( + typeof data.isOpen !== 'undefined' && + typeof data.isOpen !== 'boolean' + ) { + errors.isOpen = 'Should be a boolean'; + } + + if (typeof data.locationCoordinates === 'undefined') { + errors.locationCoordinates = 'Is required'; + } else if (!Array.isArray(data.locationCoordinates)) { + errors.locationCoordinates = 'Should be an array'; + } else if (typeof data.locationCoordinates[0] === 'undefined') { + errors.locationCoordinates = 'Latitude is required'; + } else if (!isNumber(data.locationCoordinates[0])) { + errors.locationCoordinates = 'Latitude should be a number'; + } else if ( + parseFloat(data.locationCoordinates[0]) < -90 || + parseFloat(data.locationCoordinates[0]) > 90 + ) { + errors.locationCoordinates = 'Latitude value is not valid'; + } else if (typeof data.locationCoordinates[1] === 'undefined') { + errors.locationCoordinates = 'Longitude is required'; + } else if (!isNumber(data.locationCoordinates[1])) { + errors.locationCoordinates = 'Longitude should be a number'; + } else if ( + parseFloat(data.locationCoordinates[1]) < -180 || + parseFloat(data.locationCoordinates[1]) > 180 + ) { + errors.locationCoordinates = 'Longitude value is not valid'; + } else if (data.locationCoordinates.length > 2) { + errors.locationCoordinates = 'Should only have latitude and longitude'; + } + + if (typeof data.name === 'undefined' || data.name === '') { + errors.name = 'Is required'; + } else if (typeof data.name !== 'string') { + errors.name = 'Should be a string'; + } + + if (typeof data.participantsGoal === 'undefined') { + errors.participantsGoal = 'Is required'; + } else if (typeof data.participantsGoal !== 'number') { + errors.participantsGoal = 'Should be a number'; + } else if (!isInt(data.participantsGoal.toString())) { + errors.participantsGoal = 'Should be a integer'; + } + + if (typeof data.poster !== 'undefined' && typeof data.poster !== 'string') { + errors.poster = 'Should be a string'; + } + + if (typeof data.reviewsGoal === 'undefined') { + errors.reviewsGoal = 'Is required'; + } else if (typeof data.reviewsGoal !== 'number') { + errors.reviewsGoal = 'Should be a number'; + } else if (!isInt(data.reviewsGoal.toString())) { + errors.reviewsGoal = 'Should be a integer'; + } + + let startDateIsValid = false; + if (typeof data.startDate === 'undefined' || data.startDate === '') { + errors.startDate = 'Is required'; + } else if (typeof data.startDate !== 'string') { + errors.startDate = 'Should be a string'; + } else if (!moment(data.startDate).isValid()) { + errors.startDate = 'Should have a ISO-8601 format'; + } else { + const startDate = moment(data.startDate).startOf('day').utc(); + const today = moment().startOf('day').utc(); + + if (startDate.isBefore(today)) { + errors.startDate = 'Should be greater than or equal to today'; + } else { + startDateIsValid = true; + } + } + + if ( + typeof data.teamManager !== 'undefined' && + typeof data.teamManager !== 'string' + ) { + errors.teamManager = 'Should be a string'; + } else if (data.teamManager && !isMongoId(data.teamManager)) { + errors.teamManager = 'Should be a valid id'; + } + + if (endDateIsValid && startDateIsValid) { + const endDate = moment(data.endDate).endOf('day').utc(); + const startDate = moment(data.startDate).startOf('day').utc(); + + if (startDate.isAfter(endDate)) { + errors.endDate = 'Should be greater than or equal to startDate'; + errors.startDate = 'Should be less than or equal to endDate'; + } else if (endDate.diff(startDate, 'days') > 365) { + errors.endDate = 'Should last less than 365 days'; + } + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateEditEvent(data) { + const errors = {}; + + if (typeof data.address !== 'undefined') { + if (typeof data.address !== 'string') { + errors.address = 'Should be a string'; + } else if (data.address === '') { + errors.address = 'Is required'; + } + } + + if ( + typeof data.description !== 'undefined' && + typeof data.description !== 'string' + ) { + errors.description = 'Should be a string'; + } + + let endDateIsValid = false; + if (typeof data.endDate !== 'undefined') { + if (typeof data.endDate !== 'string') { + errors.endDate = 'Should be a string'; + } else if (data.endDate === '') { + errors.endDate = 'Is required'; + } else if (!moment(data.endDate).isValid()) { + errors.endDate = 'Should have a ISO-8601 format'; + } else { + const endDate = moment(data.endDate).endOf('day').utc(); + const today = moment().startOf('day').utc(); + + if (endDate.isBefore(today)) { + errors.endDate = 'Should be greater than or equal to today'; + } else { + endDateIsValid = true; + } + } + } + + if ( + typeof data.isOpen !== 'undefined' && + typeof data.isOpen !== 'boolean' + ) { + errors.isOpen = 'Should be a boolean'; + } + + if (typeof data.locationCoordinates !== 'undefined') { + if (!Array.isArray(data.locationCoordinates)) { + errors.locationCoordinates = 'Should be an array'; + } else if (typeof data.locationCoordinates[0] === 'undefined') { + errors.locationCoordinates = 'Latitude is required'; + } else if (!isNumber(data.locationCoordinates[0])) { + errors.locationCoordinates = 'Latitude should be a number'; + } else if ( + parseFloat(data.locationCoordinates[0]) < -90 || + parseFloat(data.locationCoordinates[0]) > 90 + ) { + errors.locationCoordinates = 'Latitude value is not valid'; + } else if (typeof data.locationCoordinates[1] === 'undefined') { + errors.locationCoordinates = 'Longitude is required'; + } else if (!isNumber(data.locationCoordinates[1])) { + errors.locationCoordinates = 'Longitude should be a number'; + } else if ( + parseFloat(data.locationCoordinates[1]) < -180 || + parseFloat(data.locationCoordinates[1]) > 180 + ) { + errors.locationCoordinates = 'Longitude value is not valid'; + } else if (data.locationCoordinates.length > 2) { + errors.locationCoordinates = 'Should only have latitude and longitude'; + } + } + + if (typeof data.managers !== 'undefined') { + if (!Array.isArray(data.managers)) { + errors.managers = 'Should be an array'; + } else { + data.managers.some((m) => { + if (typeof m !== 'string') { + errors.managers = 'Should only have string values'; + return true; + } else if (!m) { + errors.managers = 'Should not have empty values'; + return true; + } else { + if (m.startsWith('-')) { + m = m.substring(1); + } + + if (!isMongoId(m)) { + errors.managers = `${m} should be an id`; + return true; + } + } + }); + } + } + + if (typeof data.name !== 'undefined') { + if (typeof data.name !== 'string') { + errors.name = 'Should be a string'; + } else if (data.name === '') { + errors.name = 'Is required'; + } + } + + if (typeof data.participants !== 'undefined') { + if (!Array.isArray(data.participants)) { + errors.participants = 'Should be an array'; + } else { + data.participants.some((p) => { + if (typeof p !== 'string') { + errors.participants = 'Should only have string values'; + return true; + } else if (!p) { + errors.participants = 'Should not have empty values'; + return true; + } else if (!p.startsWith('-')) { + errors.participants = `${p} should start with -`; + return true; + } else if (!isMongoId(p.substring(1))) { + errors.participants = `${p} should be an id`; + return true; + } + }); + } + } + + if (typeof data.participantsGoal !== 'undefined') { + if (data.participantsGoal === null) { + errors.participantsGoal = 'Is required'; + } else if (typeof data.participantsGoal !== 'number') { + errors.participantsGoal = 'Should be a number'; + } else if (!isInt(data.participantsGoal.toString())) { + errors.participantsGoal = 'Should be a integer'; + } + } + + if (typeof data.poster !== 'undefined' && typeof data.poster !== 'string') { + errors.poster = 'Should be a string'; + } + + if (typeof data.reviewsGoal !== 'undefined') { + if (data.reviewsGoal === null) { + errors.reviewsGoal = 'Is required'; + } else if (typeof data.reviewsGoal !== 'number') { + errors.reviewsGoal = 'Should be a number'; + } else if (!isInt(data.reviewsGoal.toString())) { + errors.reviewsGoal = 'Should be a integer'; + } + } + + let startDateIsValid = false; + if (typeof data.startDate !== 'undefined') { + if (typeof data.startDate !== 'string') { + errors.startDate = 'Should be a string'; + } else if (data.startDate === '') { + errors.startDate = 'Is required'; + } else if (!moment(data.startDate).isValid()) { + errors.startDate = 'Should have a ISO-8601 format'; + } else { + const startDate = moment(data.startDate).startOf('day').utc(); + const today = moment().startOf('day').utc(); + + if (startDate.isBefore(today)) { + errors.startDate = 'Should be greater than or equal to today'; + } else { + startDateIsValid = true; + } + } + } + + if ( + typeof data.teamManager !== 'undefined' && + typeof data.teamManager !== 'string' + ) { + errors.teamManager = 'Should be a string'; + } else if (data.teamManager && !isMongoId(data.teamManager)) { + errors.teamManager = 'Should be a valid id'; + } + + if (typeof data.teams !== 'undefined') { + if (!Array.isArray(data.teams)) { + errors.teams = 'Should be an array'; + } else { + data.teams.some((t) => { + if (typeof t !== 'string') { + errors.teams = 'Should only have string values'; + return true; + } else if (!t) { + errors.teams = 'Should not have empty values'; + return true; + } else if (!t.startsWith('-')) { + errors.teams = `${t} should start with -`; + return true; + } else if (!isMongoId(t.substring(1))) { + errors.teams = `${t} should be an id`; + return true; + } + }); + } + } + + if (endDateIsValid && startDateIsValid) { + const endDate = moment(data.endDate).endOf('day').utc(); + const startDate = moment(data.startDate).startOf('day').utc(); + + if (startDate.isAfter(endDate)) { + errors.endDate = 'Should be greater than or equal to startDate'; + errors.startDate = 'Should be less than or equal to endDate'; + } else if (endDate.diff(startDate, 'days') > 365) { + errors.endDate = 'Should last less than 365 days'; + } + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateListEvents(queryParams) { + const errors = {}; + + let isAfterDateValid = false; + if ( + queryParams.afterDate && + !moment(queryParams.afterDate, 'YYYY-MM-DD', true).isValid() + ) { + errors.afterDate = 'Should have YYYY-MM-DD format'; + } else { + isAfterDateValid = true; + } + + let isBeforeDateValid = false; + if ( + queryParams.beforeDate && + !moment(queryParams.beforeDate, 'YYYY-MM-DD', true).isValid() + ) { + errors.beforeDate = 'Should have YYYY-MM-DD format'; + } else { + isBeforeDateValid = true; + } + + if (isAfterDateValid && isBeforeDateValid) { + const afterDate = moment(queryParams.afterDate, 'YYYY-MM-DD').utc(); + const beforeDate = moment(queryParams.beforeDate, 'YYYY-MM-DD').utc(); + if (afterDate.isAfter(beforeDate)) { + errors.afterDate = 'Should be less than beforeDate'; + errors.beforeDate = 'Should be greater than afterDate'; + } + } + + const sortOptions = [ + 'name', + '-name', + 'reviewsAmount', + '-reviewsAmount', + 'startDate', + '-startDate' + ]; + if (queryParams.sortBy && !sortOptions.includes(queryParams.sortBy)) { + errors.sortBy = 'Should be a valid sort'; + } + + if (queryParams.page) { + if (!isInt(queryParams.page)) { + errors.page = 'Should be a integer'; + } else if (parseInt(queryParams.page, 10) < 1) { + errors.page = 'Should be a positive integer'; + } + } + + if (queryParams.pageLimit) { + if (!isInt(queryParams.pageLimit)) { + errors.pageLimit = 'Should be a integer'; + } else if (parseInt(queryParams.pageLimit, 10) < 1) { + errors.pageLimit = 'Should be a positive integer'; + } else if (parseInt(queryParams.pageLimit, 10) > 12) { + errors.pageLimit = 'Should be less than 13'; + } + } + + return { errors, isValid: isEmpty(errors) }; + } +}; diff --git a/src/routes/index.js b/src/routes/index.js index 702f72e..b7e0aae 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -1,25 +1,25 @@ -const express = require('express'); - -const auth = require('./auth'); -const events = require('./events'); -const others = require('./others'); -const petitions = require('./petitions'); -const photos = require('./photos'); -const reviews = require('./reviews'); -const teams = require('./teams'); -const users = require('./users'); -const venues = require('./venues'); - -const router = new express.Router(); - -router.use('', others); -router.use('/auth', auth); -router.use('/events', events); -router.use('/petitions', petitions); -router.use('/photos', photos); -router.use('/reviews', reviews); -router.use('/teams', teams); -router.use('/users', users); -router.use('/venues', venues); - -module.exports = router; +const express = require('express'); + +const auth = require('./auth'); +const events = require('./events'); +const others = require('./others'); +const petitions = require('./petitions'); +const photos = require('./photos'); +const reviews = require('./reviews'); +const teams = require('./teams'); +const users = require('./users'); +const venues = require('./venues'); + +const router = new express.Router(); + +router.use('', others); +router.use('/auth', auth); +router.use('/events', events); +router.use('/petitions', petitions); +router.use('/photos', photos); +router.use('/reviews', reviews); +router.use('/teams', teams); +router.use('/users', users); +router.use('/venues', venues); + +module.exports = router; diff --git a/src/routes/others/contact.js b/src/routes/others/contact.js index 73033b7..b0b689e 100644 --- a/src/routes/others/contact.js +++ b/src/routes/others/contact.js @@ -1,37 +1,37 @@ -const { sendEmail } = require('../../helpers'); - -const { validateContact } = require('./validations'); - -module.exports = async (req, res, next) => { - const data = { - email: req.body.email, - message: req.body.message, - name: req.body.name - }; - - const { errors, isValid } = validateContact(data); - if (!isValid) return res.status(400).json(errors); - - const subject = 'Message from Contact Page'; - const htmlContent = ` -${data.message}
-Name: ${data.name}
-Email: ${data.email}
- `; - const textContent = ` - ${data.message}\n\n - Name: ${data.name}\n - Email: ${data.email} - `; - const receiversEmails = [process.env.AXSLAB_EMAIL]; - - sendEmail({ - subject, - htmlContent, - textContent, - receiversEmails - }); - - return res.status(200).json({ message: 'Success' }); -}; +const { sendEmail } = require('../../helpers'); + +const { validateContact } = require('./validations'); + +module.exports = async (req, res) => { + const data = { + email: req.body.email, + message: req.body.message, + name: req.body.name + }; + + const { errors, isValid } = validateContact(data); + if (!isValid) return res.status(400).json(errors); + + const subject = 'Message from Contact Page'; + const htmlContent = ` +${data.message}
+Name: ${data.name}
+Email: ${data.email}
+ `; + const textContent = ` + ${data.message}\n\n + Name: ${data.name}\n + Email: ${data.email} + `; + const receiversEmails = [process.env.AXSLAB_EMAIL]; + + sendEmail({ + subject, + htmlContent, + textContent, + receiversEmails + }); + + return res.status(200).json({ message: 'Success' }); +}; diff --git a/src/routes/others/index.js b/src/routes/others/index.js index 09034dc..7ad24b6 100644 --- a/src/routes/others/index.js +++ b/src/routes/others/index.js @@ -1,11 +1,11 @@ -const express = require('express'); - -const contact = require('./contact'); -const migrateScores = require('./migrate-scores'); - -const router = new express.Router(); - -router.post('/contact', contact); -router.get('/migrate-scores', migrateScores); - -module.exports = router; +const express = require('express'); + +const contact = require('./contact'); +const migrateScores = require('./migrate-scores'); + +const router = new express.Router(); + +router.post('/contact', contact); +router.get('/migrate-scores', migrateScores); + +module.exports = router; diff --git a/src/routes/others/migrate-scores.js b/src/routes/others/migrate-scores.js index 06820bb..f311206 100644 --- a/src/routes/others/migrate-scores.js +++ b/src/routes/others/migrate-scores.js @@ -2,7 +2,7 @@ const { Venue } = require('../../models/venue'); const { Review } = require('../../models/review'); const { User } = require('../../models/user'); -module.exports = async (req, res, next) => { +module.exports = async (req, res) => { const saveChanges = req.query.save && req.query.save === 'true'; console.log('IN MIGRATE SCORES, SAVING CHANGES: ' + saveChanges); @@ -28,7 +28,7 @@ module.exports = async (req, res, next) => { let venuesProcessed = 0; let pages = 0; while (venuesProcessed < venuesTotalCount) { - timeBlockStart = new Date(); + let timeBlockStart = new Date(); let venueChunk; try { venueChunk = await Venue.find({ @@ -52,8 +52,8 @@ module.exports = async (req, res, next) => { console.log('UNEXPECTED AMOUNT OF VENUES UNCONVERTED FOUND'); } - for (venue of venueChunk) { - for (review of venue.reviews) { + for (const venue of venueChunk) { + for (const review of venue.reviews) { //console.log("reviewID: ", review); let dbReview; @@ -88,6 +88,7 @@ module.exports = async (req, res, next) => { case 4: dbReview.hasWideEntrance = true; venue.hasWideEntrance.yes += 1; + break; case 3: dbReview.hasPortableRamp = true; venue.hasPortableRamp.yes += 1; @@ -111,6 +112,7 @@ module.exports = async (req, res, next) => { venue.hasLoweredSinks.yes += 1; dbReview.hasSupportAroundToilet = true; venue.hasSupportAroundToilet.yes += 1; + break; case 3: dbReview.hasSwingOutDoor = true; venue.hasSwingOutDoor.yes += 1; @@ -201,40 +203,47 @@ module.exports = async (req, res, next) => { } //end venues while-loop try { - reviewsTotalCount = await Review.countDocuments({ + // Count the total number of unconverted reviews + const reviewsTotalCount = await Review.countDocuments({ _isScoreConverted: { $ne: true } }); - } catch (err) { - console.log('Reviews unconverted failed to be counted, error: ', err); - return res.status(404).json(err); - } - console.log('THERE ARE ' + reviewsTotalCount + ' UNCONVERTED REVIEWS'); - - if (reviewsTotalCount > 0) { - let unconvertedReviews; + console.log('THERE ARE ' + reviewsTotalCount + ' UNCONVERTED REVIEWS'); - try { - unconvertedReviews = await Review.find({ - _isScoreConverted: { $ne: true } - }); - } catch (err) { - console.log('Reviews unconverted failed to be found, error: ', err); - return res.status(404).json(err); - } + if (reviewsTotalCount > 0) { + let unconvertedReviews; - for (unconvertedReview of unconvertedReviews) { try { - matchingVenue = await Venue.find({ - reviews: unconvertedReview.id + // Find all unconverted reviews + unconvertedReviews = await Review.find({ + _isScoreConverted: { $ne: true } }); } catch (err) { console.log('Reviews unconverted failed to be found, error: ', err); return res.status(404).json(err); } - console.log('Review ID: ' + unconvertedReview.id); - console.log("Review's venue: " + matchingVenue.id); + for (const unconvertedReview of unconvertedReviews) { + let matchingVenue; + + try { + // Find the venue for each unconverted review + matchingVenue = await Venue.findOne({ + reviews: unconvertedReview.id + }); + } catch (err) { + console.log('Venue search failed, error: ', err); + return res.status(404).json(err); + } + + console.log('Review ID: ' + unconvertedReview.id); + console.log( + "Review's venue: " + (matchingVenue ? matchingVenue.id : 'Not found') + ); + } } + } catch (err) { + console.log('Reviews unconverted count failed, error: ', err); + return res.status(404).json(err); } console.log('FINISHED PROCESSING ALL RECORDS'); diff --git a/src/routes/others/validations.js b/src/routes/others/validations.js index b1a8c92..3663493 100644 --- a/src/routes/others/validations.js +++ b/src/routes/others/validations.js @@ -1,37 +1,37 @@ -const freemail = require('freemail'); -const { isEmail } = require('validator'); -const { isEmpty } = require('lodash'); - -module.exports = { - validateContact(data) { - const errors = {}; - - if (typeof data.email === 'undefined' || data.email === '') { - errors.email = 'Is required'; - } else if (typeof data.email !== 'string') { - errors.email = 'Should be a string'; - } else if (data.email.length > 254) { - errors.email = 'Should be less than 255 characters'; - } else if (!isEmail(data.email) || freemail.isDisposable(data.email)) { - errors.email = 'Should be a valid email'; - } - - if (typeof data.message === 'undefined' || data.message === '') { - errors.message = 'Is required'; - } else if (typeof data.message !== 'string') { - errors.message = 'Should be a string'; - } else if (data.message.length > 300) { - errors.message = 'Should be less than 301 characters'; - } - - if (typeof data.name === 'undefined' || data.name === '') { - errors.name = 'Is required'; - } else if (typeof data.name !== 'string') { - errors.name = 'Should be a string'; - } else if (data.name.length > 60) { - errors.name = 'Should be less than 61 characters'; - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const freemail = require('freemail'); +const { isEmail } = require('validator'); +const { isEmpty } = require('lodash'); + +module.exports = { + validateContact(data) { + const errors = {}; + + if (typeof data.email === 'undefined' || data.email === '') { + errors.email = 'Is required'; + } else if (typeof data.email !== 'string') { + errors.email = 'Should be a string'; + } else if (data.email.length > 254) { + errors.email = 'Should be less than 255 characters'; + } else if (!isEmail(data.email) || freemail.isDisposable(data.email)) { + errors.email = 'Should be a valid email'; + } + + if (typeof data.message === 'undefined' || data.message === '') { + errors.message = 'Is required'; + } else if (typeof data.message !== 'string') { + errors.message = 'Should be a string'; + } else if (data.message.length > 300) { + errors.message = 'Should be less than 301 characters'; + } + + if (typeof data.name === 'undefined' || data.name === '') { + errors.name = 'Is required'; + } else if (typeof data.name !== 'string') { + errors.name = 'Should be a string'; + } else if (data.name.length > 60) { + errors.name = 'Should be less than 61 characters'; + } + + return { errors, isValid: isEmpty(errors) }; + } +}; diff --git a/src/routes/petitions/create-petition.js b/src/routes/petitions/create-petition.js index 82ba6b7..3e1b5d8 100644 --- a/src/routes/petitions/create-petition.js +++ b/src/routes/petitions/create-petition.js @@ -1,474 +1,474 @@ -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { Petition } = require('../../models/petition'); -const { Team } = require('../../models/team'); -const { User } = require('../../models/user'); - -const { validateCreatePetition } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateCreatePetition(req.body); - if (!isValid) return res.status(400).json(errors); - - const data = Object.assign( - {}, - { - event: req.body.event, - message: req.body.message, - team: req.body.team, - type: req.body.type, - user: req.body.user - } - ); - data.sender = req.user.id.toString(); - const today = moment.utc(); - - if (data.type === 'invite-team-event') { - delete data.user; - - let petition; - try { - petition = await Petition.findOne({ - event: data.event, - team: data.team, - type: data.type - }); - } catch (err) { - console.log( - `Petition from event ${data.event} to team ${ - data.team - } failed to be found at create-petition` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'Team already has a pending invitation to event' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at create-petition` - ); - return next(err); - } - } - - let event; - try { - event = await Event.findOne({ _id: data.event }); - } catch (err) { - console.log(`Event ${data.event} failed to be found at create-petition`); - return next(err); - } - - if (!event) return res.status(404).json({ event: 'Not found' }); - - if (!event.managers.find(m => m.toString() === data.sender)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (event.teams.find(t => t.toString() === data.team)) { - return res.status(400).json({ - general: 'Team is already participant of event' - }); - } - - const endDate = moment(event.endDate).utc(); - if (endDate.isBefore(today)) { - return res.status(400).json({ general: 'Event has already finished' }); - } - - let team; - try { - team = await Team.findOne({ _id: data.team }); - } catch (err) { - console.log(`Team ${data.team} failed to be found at create-petition`); - return next(err); - } - - if (!team) return res.status(404).json({ general: 'Team not found' }); - } else if (data.type === 'invite-user-event') { - delete data.team; - - let petition; - try { - petition = await Petition.findOne({ - event: data.event, - type: data.type, - user: data.user - }); - } catch (err) { - console.log( - `Petition from event ${data.event} to user ${ - data.user - } failed to be found at create-petition` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'User already has a pending invitation to event' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at create-petition` - ); - return next(err); - } - } - - if (data.sender === data.user) { - return res.status(400).json({ general: 'User should not be you' }); - } - - let event; - try { - event = await Event.findOne({ _id: data.event }); - } catch (err) { - console.log(`Event ${data.event} failed to be found at create-petition`); - return next(err); - } - - if (!event) return res.status(404).json({ general: 'Event not found' }); - - if (!event.managers.find(m => m.toString() === data.sender)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (event.participants.find(p => p.toString() === data.user)) { - return res.status(400).json({ - general: 'User is already participant of event' - }); - } - - const endDate = moment(event.endDate).utc(); - if (endDate.isBefore(today)) { - return res.status(400).json({ general: 'Event has already finished' }); - } - - let user; - try { - user = await User.findOne({ _id: data.user }); - } catch (err) { - console.log(`User ${data.user} failed to be found at create-petition`); - return next(err); - } - - if (!user) return res.status(404).json({ general: 'User not found' }); - } else if (data.type === 'invite-user-team') { - delete data.event; - - let petition; - try { - petition = await Petition.findOne({ - team: data.team, - type: data.type, - user: data.user - }); - } catch (err) { - console.log( - `Petition from team ${data.team} to user ${ - data.user - } failed to be found at create-petition` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'User already has a pending invitation to team' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at create-petition` - ); - return next(err); - } - } - - if (req.sender === data.user) { - return res.status(400).json({ general: 'User should not be you' }); - } - - let team; - try { - team = await Team.findOne({ _id: data.team }); - } catch (err) { - console.log(`Team ${data.team} failed to be found at create-petition`); - return next(err); - } - - if (!team) return res.status(404).json({ general: 'Team not found' }); - - if (!team.managers.find(m => m.toString() === data.sender)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (team.members.find(m => m.toString() === data.user)) { - return res.status(400).json({ - general: 'User is already member of team' - }); - } - - let user; - try { - user = await User.findOne({ _id: data.user }); - } catch (err) { - console.log(`User ${data.user} failed to be found at create-petition`); - return next(err); - } - - if (!user) return res.status(404).json({ general: 'User not found' }); - } else if (data.type === 'request-team-event') { - delete data.user; - - let petition; - try { - petition = await Petition.findOne({ - event: data.event, - team: data.team, - type: data.type - }); - } catch (err) { - console.log( - `Petition from team ${data.team} to event ${ - data.event - } failed to be found at create-petition` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'Team already has a pending request with event' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at create-petition` - ); - return next(err); - } - } - - let event; - try { - event = await Event.findOne({ _id: data.event }); - } catch (err) { - console.log(`Event ${data.event} failed to be found at create-petition`); - return next(err); - } - - if (!event) return res.status(404).json({ general: 'Event not found' }); - - if (event.teams.find(t => t.toString() === data.sender)) { - return res.status(400).json({ - general: 'Team is already participant of event ' - }); - } - - const endDate = moment(event.endDate).utc(); - if (endDate.isBefore(today)) { - return res.status(400).json({ general: 'Event has already finished' }); - } - - let team; - try { - team = await Team.findOne({ _id: data.team }); - } catch (err) { - console.log(`Team ${data.team} failed to be found at create-petition`); - return next(err); - } - - if (!team) return res.status(404).json({ general: 'Team not found' }); - - if (!team.managers.find(m => m.toString() === data.sender)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - } else if (data.type === 'request-user-event') { - delete data.team; - - let petition; - try { - petition = await Petition.findOne({ - event: data.event, - sender: data.sender, - type: data.type - }); - } catch (err) { - console.log( - `Petition from user ${data.sender} to event ${ - data.event - } failed to be found at create-petition` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'User already have a pending request with event' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at create-petition` - ); - return next(err); - } - } - - let event; - try { - event = await Event.findOne({ _id: data.event }); - } catch (err) { - console.log(`Event ${data.event} failed to be found at create-petition`); - return next(err); - } - - if (!event) return res.status(404).json({ general: 'Event not found' }); - - if (event.participants.find(p => p.toString() === data.sender)) { - return res.status(400).json({ - general: 'User already is participant of event' - }); - } - - const endDate = moment(event.endDate).utc(); - if (endDate.isBefore(today)) { - return res.status(400).json({ general: 'Event has already finished' }); - } - } else { - // data.type === request-user-team - delete data.event; - - let petition; - try { - petition = await Petition.findOne({ - team: data.team, - sender: data.sender, - type: data.type - }); - } catch (err) { - console.log( - `Petition from user ${data.sender} to team ${ - data.team - } failed to be found at create-petition` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'User already have a pending request with team' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at create-petition` - ); - return next(err); - } - } - - let team; - try { - team = await Team.findOne({ _id: data.team }); - } catch (err) { - console.log(`Team ${data.team} failed to be found at create-petition`); - return next(err); - } - - if (!team) return res.status(404).json({ general: 'Team not found' }); - - if (team.members.find(m => m.toString() === data.sender)) { - return res.status(400).json({ - general: 'User already is member of team' - }); - } - } - - let petition; - try { - petition = await Petition.create(data); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `Petition failed to be created at create-petition.\nData: ${JSON.stringify( - data - )}` - ); - return next(err); - } - - const dataResponse = Object.assign( - {}, - { - createdAt: petition.createdAt, - event: petition.event, - message: petition.message, - sender: petition.sender, - state: petition.state, - team: petition.team, - type: petition.type, - user: petition.user - } - ); - return res.status(201).json(dataResponse); -}; +const moment = require('moment'); + +const { Event } = require('../../models/event'); +const { Petition } = require('../../models/petition'); +const { Team } = require('../../models/team'); +const { User } = require('../../models/user'); + +const { validateCreatePetition } = require('./validations'); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateCreatePetition(req.body); + if (!isValid) return res.status(400).json(errors); + + const data = Object.assign( + {}, + { + event: req.body.event, + message: req.body.message, + team: req.body.team, + type: req.body.type, + user: req.body.user + } + ); + data.sender = req.user.id.toString(); + const today = moment.utc(); + + if (data.type === 'invite-team-event') { + delete data.user; + + let petition; + try { + petition = await Petition.findOne({ + event: data.event, + team: data.team, + type: data.type + }); + } catch (err) { + console.log( + `Petition from event ${data.event} to team ${ + data.team + } failed to be found at create-petition` + ); + return next(err); + } + + if (petition && petition.state === 'pending') { + return res.status(400).json({ + general: 'Team already has a pending invitation to event' + }); + } + + if ( + petition && + (petition.state === 'rejected' || petition.state === 'canceled') + ) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at create-petition` + ); + return next(err); + } + } + + let event; + try { + event = await Event.findOne({ _id: data.event }); + } catch (err) { + console.log(`Event ${data.event} failed to be found at create-petition`); + return next(err); + } + + if (!event) return res.status(404).json({ event: 'Not found' }); + + if (!event.managers.find((m) => m.toString() === data.sender)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + if (event.teams.find((t) => t.toString() === data.team)) { + return res.status(400).json({ + general: 'Team is already participant of event' + }); + } + + const endDate = moment(event.endDate).utc(); + if (endDate.isBefore(today)) { + return res.status(400).json({ general: 'Event has already finished' }); + } + + let team; + try { + team = await Team.findOne({ _id: data.team }); + } catch (err) { + console.log(`Team ${data.team} failed to be found at create-petition`); + return next(err); + } + + if (!team) return res.status(404).json({ general: 'Team not found' }); + } else if (data.type === 'invite-user-event') { + delete data.team; + + let petition; + try { + petition = await Petition.findOne({ + event: data.event, + type: data.type, + user: data.user + }); + } catch (err) { + console.log( + `Petition from event ${data.event} to user ${ + data.user + } failed to be found at create-petition` + ); + return next(err); + } + + if (petition && petition.state === 'pending') { + return res.status(400).json({ + general: 'User already has a pending invitation to event' + }); + } + + if ( + petition && + (petition.state === 'rejected' || petition.state === 'canceled') + ) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at create-petition` + ); + return next(err); + } + } + + if (data.sender === data.user) { + return res.status(400).json({ general: 'User should not be you' }); + } + + let event; + try { + event = await Event.findOne({ _id: data.event }); + } catch (err) { + console.log(`Event ${data.event} failed to be found at create-petition`); + return next(err); + } + + if (!event) return res.status(404).json({ general: 'Event not found' }); + + if (!event.managers.find((m) => m.toString() === data.sender)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + if (event.participants.find((p) => p.toString() === data.user)) { + return res.status(400).json({ + general: 'User is already participant of event' + }); + } + + const endDate = moment(event.endDate).utc(); + if (endDate.isBefore(today)) { + return res.status(400).json({ general: 'Event has already finished' }); + } + + let user; + try { + user = await User.findOne({ _id: data.user }); + } catch (err) { + console.log(`User ${data.user} failed to be found at create-petition`); + return next(err); + } + + if (!user) return res.status(404).json({ general: 'User not found' }); + } else if (data.type === 'invite-user-team') { + delete data.event; + + let petition; + try { + petition = await Petition.findOne({ + team: data.team, + type: data.type, + user: data.user + }); + } catch (err) { + console.log( + `Petition from team ${data.team} to user ${ + data.user + } failed to be found at create-petition` + ); + return next(err); + } + + if (petition && petition.state === 'pending') { + return res.status(400).json({ + general: 'User already has a pending invitation to team' + }); + } + + if ( + petition && + (petition.state === 'rejected' || petition.state === 'canceled') + ) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at create-petition` + ); + return next(err); + } + } + + if (req.sender === data.user) { + return res.status(400).json({ general: 'User should not be you' }); + } + + let team; + try { + team = await Team.findOne({ _id: data.team }); + } catch (err) { + console.log(`Team ${data.team} failed to be found at create-petition`); + return next(err); + } + + if (!team) return res.status(404).json({ general: 'Team not found' }); + + if (!team.managers.find((m) => m.toString() === data.sender)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + if (team.members.find((m) => m.toString() === data.user)) { + return res.status(400).json({ + general: 'User is already member of team' + }); + } + + let user; + try { + user = await User.findOne({ _id: data.user }); + } catch (err) { + console.log(`User ${data.user} failed to be found at create-petition`); + return next(err); + } + + if (!user) return res.status(404).json({ general: 'User not found' }); + } else if (data.type === 'request-team-event') { + delete data.user; + + let petition; + try { + petition = await Petition.findOne({ + event: data.event, + team: data.team, + type: data.type + }); + } catch (err) { + console.log( + `Petition from team ${data.team} to event ${ + data.event + } failed to be found at create-petition` + ); + return next(err); + } + + if (petition && petition.state === 'pending') { + return res.status(400).json({ + general: 'Team already has a pending request with event' + }); + } + + if ( + petition && + (petition.state === 'rejected' || petition.state === 'canceled') + ) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at create-petition` + ); + return next(err); + } + } + + let event; + try { + event = await Event.findOne({ _id: data.event }); + } catch (err) { + console.log(`Event ${data.event} failed to be found at create-petition`); + return next(err); + } + + if (!event) return res.status(404).json({ general: 'Event not found' }); + + if (event.teams.find((t) => t.toString() === data.sender)) { + return res.status(400).json({ + general: 'Team is already participant of event ' + }); + } + + const endDate = moment(event.endDate).utc(); + if (endDate.isBefore(today)) { + return res.status(400).json({ general: 'Event has already finished' }); + } + + let team; + try { + team = await Team.findOne({ _id: data.team }); + } catch (err) { + console.log(`Team ${data.team} failed to be found at create-petition`); + return next(err); + } + + if (!team) return res.status(404).json({ general: 'Team not found' }); + + if (!team.managers.find((m) => m.toString() === data.sender)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + } else if (data.type === 'request-user-event') { + delete data.team; + + let petition; + try { + petition = await Petition.findOne({ + event: data.event, + sender: data.sender, + type: data.type + }); + } catch (err) { + console.log( + `Petition from user ${data.sender} to event ${ + data.event + } failed to be found at create-petition` + ); + return next(err); + } + + if (petition && petition.state === 'pending') { + return res.status(400).json({ + general: 'User already have a pending request with event' + }); + } + + if ( + petition && + (petition.state === 'rejected' || petition.state === 'canceled') + ) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at create-petition` + ); + return next(err); + } + } + + let event; + try { + event = await Event.findOne({ _id: data.event }); + } catch (err) { + console.log(`Event ${data.event} failed to be found at create-petition`); + return next(err); + } + + if (!event) return res.status(404).json({ general: 'Event not found' }); + + if (event.participants.find((p) => p.toString() === data.sender)) { + return res.status(400).json({ + general: 'User already is participant of event' + }); + } + + const endDate = moment(event.endDate).utc(); + if (endDate.isBefore(today)) { + return res.status(400).json({ general: 'Event has already finished' }); + } + } else { + // data.type === request-user-team + delete data.event; + + let petition; + try { + petition = await Petition.findOne({ + team: data.team, + sender: data.sender, + type: data.type + }); + } catch (err) { + console.log( + `Petition from user ${data.sender} to team ${ + data.team + } failed to be found at create-petition` + ); + return next(err); + } + + if (petition && petition.state === 'pending') { + return res.status(400).json({ + general: 'User already have a pending request with team' + }); + } + + if ( + petition && + (petition.state === 'rejected' || petition.state === 'canceled') + ) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at create-petition` + ); + return next(err); + } + } + + let team; + try { + team = await Team.findOne({ _id: data.team }); + } catch (err) { + console.log(`Team ${data.team} failed to be found at create-petition`); + return next(err); + } + + if (!team) return res.status(404).json({ general: 'Team not found' }); + + if (team.members.find((m) => m.toString() === data.sender)) { + return res.status(400).json({ + general: 'User already is member of team' + }); + } + } + + let petition; + try { + petition = await Petition.create(data); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `Petition failed to be created at create-petition.\nData: ${JSON.stringify( + data + )}` + ); + return next(err); + } + + const dataResponse = Object.assign( + {}, + { + createdAt: petition.createdAt, + event: petition.event, + message: petition.message, + sender: petition.sender, + state: petition.state, + team: petition.team, + type: petition.type, + user: petition.user + } + ); + return res.status(201).json(dataResponse); +}; diff --git a/src/routes/petitions/edit-petition.js b/src/routes/petitions/edit-petition.js index 5537b38..b3adcfa 100644 --- a/src/routes/petitions/edit-petition.js +++ b/src/routes/petitions/edit-petition.js @@ -1,555 +1,557 @@ -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { Petition } = require('../../models/petition'); -const { Team } = require('../../models/team'); -const { User } = require('../../models/user'); - -const { validateEditPetition } = require('./validations'); - -module.exports = async (req, res, next) => { - const petitionId = req.params.petitionId; - - let petition; - try { - petition = await Petition.findOne({ _id: petitionId }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Petition not found' }); - } - - console.log(`Petition ${petitionId} failed to be found at edit-petition`); - return next(err); - } - - if (!petition) { - return res.status(404).json({ general: 'Petition not found' }); - } - - if (petition.state === 'accepted') { - return res.status(400).json({ general: 'Is already accepted' }); - } - - if (petition.state === 'canceled') { - return res.status(400).json({ general: 'Is already canceled' }); - } - - if (petition.state === 'rejected') { - return res.status(400).json({ general: 'Is already rejected' }); - } - - const { errors, isValid } = validateEditPetition(req.body); - if (!isValid) return res.status(400).json(errors); - - let isSender = false; - - if (petition.sender.toString() === req.user.id) { - isSender = true; - if (req.body.state === 'canceled') { - petition.state = 'canceled'; - } else { - return res.status(400).json({ state: 'Should only be canceled' }); - } - } - - if (petition.type.endsWith('event')) { - let event; - try { - event = await Event.findOne({ _id: petition.event }); - } catch (err) { - console.log( - `Event ${petition.event} failed to be found at edit-petition` - ); - return next(err); - } - - if (!event) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'Event is already removed. Petition was removed' - }); - } - - if (petition.type === 'invite-team-event') { - let team; - try { - team = await Team.findOne({ _id: petition.team }); - } catch (err) { - console.log( - `Team ${petition.team} failed to be found at edit-petition` - ); - return next(err); - } - - if (!team) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'Team is already removed. Petition was removed' - }); - } - - if (event.teams.find(t => t.toString() === team.id)) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: - 'Team is already a participant of event. Petition was removed' - }); - } - - if (isSender) { - if (!event.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - } else { - if (!team.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (req.body.state === 'accepted') { - event.teams = [...event.teams, team.id]; - event.updatedAt = moment.utc().toDate(); - - try { - await event.save(); - } catch (err) { - console.log( - `Event ${event.id} failed to be updated at edit-petition` - ); - return next(err); - } - - team.events = [...team.events, event.id]; - team.updatedAt = moment.utc().toDate(); - - try { - await team.save(); - } catch (err) { - console.log( - `Team ${team.id} failed to be updated at edit-petition` - ); - return next(err); - } - - petition.state = 'accepted'; - } else { - petition.state = 'rejected'; - } - } - } else if (petition.type === 'invite-user-event') { - if ( - event.participants.find(p => p.toString() === petition.user.toString()) - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: - 'User is already a participant of event. Petition was removed' - }); - } - - if (isSender) { - if (!event.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - } else { - if (petition.user.toString() !== req.user.id) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (req.body.state === 'accepted') { - event.participants = [...event.participants, req.user.id]; - event.updatedAt = moment.utc().toDate(); - - try { - await event.save(); - } catch (err) { - console.log( - `Event ${event.id} failed to be updated at edit-petition` - ); - return next(err); - } - - req.user.events = [...req.user.events, event.id]; - req.user.updatedAt = moment.utc().toDate(); - - try { - await req.user.save(); - } catch (err) { - console.log( - `User ${req.user.id} failed to be updated at edit-petition` - ); - return next(err); - } - - petition.state = 'accepted'; - } else { - petition.state = 'rejected'; - } - } - } else if (petition.type === 'request-team-event') { - let team; - try { - team = await Team.findOne({ _id: petition.team }); - } catch (err) { - console.log( - `Team ${petition.team} failed to be found at edit-petition` - ); - return next(err); - } - - if (!team) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'Team is already removed. Petition was removed' - }); - } - - if (event.teams.find(t => t.toString() === team.id)) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: - 'Team is already a participant of event. Petition was removed' - }); - } - - if (isSender) { - if (!team.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - } else { - if (!event.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (req.body.state === 'accepted') { - event.teams = [...event.teams, team.id]; - event.updatedAt = moment.utc().toDate(); - - try { - await event.save(); - } catch (err) { - console.log( - `Event ${event.id} failed to be updated at edit-petition` - ); - return next(err); - } - - team.events = [...team.events, event.id]; - team.updatedAt = moment.utc().toDate(); - - try { - await team.save(); - } catch (err) { - console.log( - `Team ${team.id} failed to be updated at edit-petition` - ); - return next(err); - } - - petition.state = 'accepted'; - } else { - petition.state = 'rejected'; - } - } - } else { - // petition.type === 'request-user-event' - let user; - try { - user = await User.findOne({ _id: petition.sender }); - } catch (err) { - console.log( - `User ${petition.user} failed to be found at edit-petition` - ); - return next(err); - } - - if (!user) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'User is already removed. Petition was removed' - }); - } - - if (event.participants.find(p => p.toString() === user.id)) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: - 'User is already a participant of event. Petition was removed' - }); - } - - if (!isSender) { - if (!event.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (req.body.state === 'accepted') { - event.participants = [...event.participants, user.id]; - event.updatedAt = moment.utc().toDate(); - - try { - await event.save(); - } catch (err) { - console.log( - `Event ${event.id} failed to be updated at edit-petition` - ); - return next(err); - } - - user.events = [...user.events, event.id]; - user.updatedAt = moment.utc().toDate(); - - try { - await user.save(); - } catch (err) { - console.log( - `User ${user.id} failed to be updated at edit-petition` - ); - return next(err); - } - - petition.state = 'accepted'; - } else { - petition.state = 'rejected'; - } - } - } - } else { - // petition.type.endsWith('team') - let team; - try { - team = await Team.findOne({ _id: petition.team }); - } catch (err) { - console.log( - `Team ${petition.entityId} failed to be found at edit-petition` - ); - return next(err); - } - - if (!team) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'Team is already removed. Petition was removed' - }); - } - - if (petition.type === 'invite-user-team') { - if (team.members.find(m => m.toString() === petition.user.toString())) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'User is already a member of team. Petition was removed' - }); - } - - if (isSender) { - if (!team.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - } else { - if (petition.user.toString() !== req.user.id) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (req.body.state === 'accepted') { - team.members = [...team.members, req.user.id]; - team.updatedAt = moment.utc().toDate(); - - try { - await team.save(); - } catch (err) { - console.log( - `Team ${team.id} failed to be updated at edit-petition` - ); - return next(err); - } - - req.user.teams = [...req.user.teams, team.id]; - req.user.updatedAt = moment.utc().toDate(); - - try { - await req.user.save(); - } catch (err) { - console.log( - `User ${req.user.id} failed to be updated at edit-petition` - ); - return next(err); - } - - petition.state = 'accepted'; - } else { - petition.state = 'rejected'; - } - } - } else { - // petition.type === 'request-user-team' - - let user; - try { - user = await User.findOne({ _id: petition.sender }); - } catch (err) { - console.log( - `User ${petition.senderId} failed to be found at edit-petition` - ); - return next(err); - } - - if (!user) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'User is already removed. Petition was removed' - }); - } - - if (team.members.find(m => m.toString() === user.id)) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'User is already a member of team. Petition was removed' - }); - } - - if (!isSender) { - if (!team.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (req.body.state === 'accepted') { - team.members = [...team.members, user.id]; - team.updatedAt = moment.utc().toDate(); - - try { - await team.save(); - } catch (err) { - console.log( - `Team ${team.id} failed to be updated at edit-petition` - ); - return next(err); - } - - user.teams = [...user.teams, team.id]; - user.updatedAt = moment.utc().toDate(); - - try { - await user.save(); - } catch (err) { - console.log( - `User ${user.id} failed to be updated at edit-petition` - ); - return next(err); - } - - petition.state = 'accepted'; - } else { - petition.state = 'rejected'; - } - } - } - } - - petition.updatedAt = moment.utc().toDate(); - - try { - await petition.save(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be updated at edit-petition` - ); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { Event } = require('../../models/event'); +const { Petition } = require('../../models/petition'); +const { Team } = require('../../models/team'); +const { User } = require('../../models/user'); + +const { validateEditPetition } = require('./validations'); + +module.exports = async (req, res, next) => { + const petitionId = req.params.petitionId; + + let petition; + try { + petition = await Petition.findOne({ _id: petitionId }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Petition not found' }); + } + + console.log(`Petition ${petitionId} failed to be found at edit-petition`); + return next(err); + } + + if (!petition) { + return res.status(404).json({ general: 'Petition not found' }); + } + + if (petition.state === 'accepted') { + return res.status(400).json({ general: 'Is already accepted' }); + } + + if (petition.state === 'canceled') { + return res.status(400).json({ general: 'Is already canceled' }); + } + + if (petition.state === 'rejected') { + return res.status(400).json({ general: 'Is already rejected' }); + } + + const { errors, isValid } = validateEditPetition(req.body); + if (!isValid) return res.status(400).json(errors); + + let isSender = false; + + if (petition.sender.toString() === req.user.id) { + isSender = true; + if (req.body.state === 'canceled') { + petition.state = 'canceled'; + } else { + return res.status(400).json({ state: 'Should only be canceled' }); + } + } + + if (petition.type.endsWith('event')) { + let event; + try { + event = await Event.findOne({ _id: petition.event }); + } catch (err) { + console.log( + `Event ${petition.event} failed to be found at edit-petition` + ); + return next(err); + } + + if (!event) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: 'Event is already removed. Petition was removed' + }); + } + + if (petition.type === 'invite-team-event') { + let team; + try { + team = await Team.findOne({ _id: petition.team }); + } catch (err) { + console.log( + `Team ${petition.team} failed to be found at edit-petition` + ); + return next(err); + } + + if (!team) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: 'Team is already removed. Petition was removed' + }); + } + + if (event.teams.find((t) => t.toString() === team.id)) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: + 'Team is already a participant of event. Petition was removed' + }); + } + + if (isSender) { + if (!event.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + } else { + if (!team.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + if (req.body.state === 'accepted') { + event.teams = [...event.teams, team.id]; + event.updatedAt = moment.utc().toDate(); + + try { + await event.save(); + } catch (err) { + console.log( + `Event ${event.id} failed to be updated at edit-petition` + ); + return next(err); + } + + team.events = [...team.events, event.id]; + team.updatedAt = moment.utc().toDate(); + + try { + await team.save(); + } catch (err) { + console.log( + `Team ${team.id} failed to be updated at edit-petition` + ); + return next(err); + } + + petition.state = 'accepted'; + } else { + petition.state = 'rejected'; + } + } + } else if (petition.type === 'invite-user-event') { + if ( + event.participants.find( + (p) => p.toString() === petition.user.toString() + ) + ) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: + 'User is already a participant of event. Petition was removed' + }); + } + + if (isSender) { + if (!event.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + } else { + if (petition.user.toString() !== req.user.id) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + if (req.body.state === 'accepted') { + event.participants = [...event.participants, req.user.id]; + event.updatedAt = moment.utc().toDate(); + + try { + await event.save(); + } catch (err) { + console.log( + `Event ${event.id} failed to be updated at edit-petition` + ); + return next(err); + } + + req.user.events = [...req.user.events, event.id]; + req.user.updatedAt = moment.utc().toDate(); + + try { + await req.user.save(); + } catch (err) { + console.log( + `User ${req.user.id} failed to be updated at edit-petition` + ); + return next(err); + } + + petition.state = 'accepted'; + } else { + petition.state = 'rejected'; + } + } + } else if (petition.type === 'request-team-event') { + let team; + try { + team = await Team.findOne({ _id: petition.team }); + } catch (err) { + console.log( + `Team ${petition.team} failed to be found at edit-petition` + ); + return next(err); + } + + if (!team) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: 'Team is already removed. Petition was removed' + }); + } + + if (event.teams.find((t) => t.toString() === team.id)) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: + 'Team is already a participant of event. Petition was removed' + }); + } + + if (isSender) { + if (!team.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + } else { + if (!event.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + if (req.body.state === 'accepted') { + event.teams = [...event.teams, team.id]; + event.updatedAt = moment.utc().toDate(); + + try { + await event.save(); + } catch (err) { + console.log( + `Event ${event.id} failed to be updated at edit-petition` + ); + return next(err); + } + + team.events = [...team.events, event.id]; + team.updatedAt = moment.utc().toDate(); + + try { + await team.save(); + } catch (err) { + console.log( + `Team ${team.id} failed to be updated at edit-petition` + ); + return next(err); + } + + petition.state = 'accepted'; + } else { + petition.state = 'rejected'; + } + } + } else { + // petition.type === 'request-user-event' + let user; + try { + user = await User.findOne({ _id: petition.sender }); + } catch (err) { + console.log( + `User ${petition.user} failed to be found at edit-petition` + ); + return next(err); + } + + if (!user) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: 'User is already removed. Petition was removed' + }); + } + + if (event.participants.find((p) => p.toString() === user.id)) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: + 'User is already a participant of event. Petition was removed' + }); + } + + if (!isSender) { + if (!event.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + if (req.body.state === 'accepted') { + event.participants = [...event.participants, user.id]; + event.updatedAt = moment.utc().toDate(); + + try { + await event.save(); + } catch (err) { + console.log( + `Event ${event.id} failed to be updated at edit-petition` + ); + return next(err); + } + + user.events = [...user.events, event.id]; + user.updatedAt = moment.utc().toDate(); + + try { + await user.save(); + } catch (err) { + console.log( + `User ${user.id} failed to be updated at edit-petition` + ); + return next(err); + } + + petition.state = 'accepted'; + } else { + petition.state = 'rejected'; + } + } + } + } else { + // petition.type.endsWith('team') + let team; + try { + team = await Team.findOne({ _id: petition.team }); + } catch (err) { + console.log( + `Team ${petition.entityId} failed to be found at edit-petition` + ); + return next(err); + } + + if (!team) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: 'Team is already removed. Petition was removed' + }); + } + + if (petition.type === 'invite-user-team') { + if (team.members.find((m) => m.toString() === petition.user.toString())) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: 'User is already a member of team. Petition was removed' + }); + } + + if (isSender) { + if (!team.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + } else { + if (petition.user.toString() !== req.user.id) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + if (req.body.state === 'accepted') { + team.members = [...team.members, req.user.id]; + team.updatedAt = moment.utc().toDate(); + + try { + await team.save(); + } catch (err) { + console.log( + `Team ${team.id} failed to be updated at edit-petition` + ); + return next(err); + } + + req.user.teams = [...req.user.teams, team.id]; + req.user.updatedAt = moment.utc().toDate(); + + try { + await req.user.save(); + } catch (err) { + console.log( + `User ${req.user.id} failed to be updated at edit-petition` + ); + return next(err); + } + + petition.state = 'accepted'; + } else { + petition.state = 'rejected'; + } + } + } else { + // petition.type === 'request-user-team' + + let user; + try { + user = await User.findOne({ _id: petition.sender }); + } catch (err) { + console.log( + `User ${petition.senderId} failed to be found at edit-petition` + ); + return next(err); + } + + if (!user) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: 'User is already removed. Petition was removed' + }); + } + + if (team.members.find((m) => m.toString() === user.id)) { + try { + await petition.remove(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: 'User is already a member of team. Petition was removed' + }); + } + + if (!isSender) { + if (!team.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + if (req.body.state === 'accepted') { + team.members = [...team.members, user.id]; + team.updatedAt = moment.utc().toDate(); + + try { + await team.save(); + } catch (err) { + console.log( + `Team ${team.id} failed to be updated at edit-petition` + ); + return next(err); + } + + user.teams = [...user.teams, team.id]; + user.updatedAt = moment.utc().toDate(); + + try { + await user.save(); + } catch (err) { + console.log( + `User ${user.id} failed to be updated at edit-petition` + ); + return next(err); + } + + petition.state = 'accepted'; + } else { + petition.state = 'rejected'; + } + } + } + } + + petition.updatedAt = moment.utc().toDate(); + + try { + await petition.save(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be updated at edit-petition` + ); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/petitions/index.js b/src/routes/petitions/index.js index c2de682..fb87cfe 100644 --- a/src/routes/petitions/index.js +++ b/src/routes/petitions/index.js @@ -1,19 +1,19 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const createPetition = require('./create-petition'); -const editPetition = require('./edit-petition'); -const listPetitions = require('./list-petitions'); - -const router = new express.Router(); - -router.get('', isAuthenticated({ isOptional: false }), listPetitions); -router.post('', isAuthenticated({ isOptional: false }), createPetition); -router.put( - '/:petitionId', - isAuthenticated({ isOptional: false }), - editPetition -); - -module.exports = router; +const express = require('express'); + +const { isAuthenticated } = require('../../helpers'); + +const createPetition = require('./create-petition'); +const editPetition = require('./edit-petition'); +const listPetitions = require('./list-petitions'); + +const router = new express.Router(); + +router.get('', isAuthenticated({ isOptional: false }), listPetitions); +router.post('', isAuthenticated({ isOptional: false }), createPetition); +router.put( + '/:petitionId', + isAuthenticated({ isOptional: false }), + editPetition +); + +module.exports = router; diff --git a/src/routes/petitions/list-petitions.js b/src/routes/petitions/list-petitions.js index 838d0cb..5188a62 100644 --- a/src/routes/petitions/list-petitions.js +++ b/src/routes/petitions/list-petitions.js @@ -1,277 +1,277 @@ -const mongoose = require('mongoose'); - -const { compact } = require('lodash'); -const { Petition } = require('../../models/petition'); -const { Team } = require('../../models/team'); -const { Event } = require('../../models/event'); - -module.exports = async (req, res, next) => { - const queryParams = req.query; - const userId = mongoose.Types.ObjectId(req.user.id); - - const petitionsQuery = { - state: { $in: ['accepted', 'pending', 'rejected'] } - }; - - if (queryParams.filter === 'sent') { - petitionsQuery.sender = userId; - } else { - // get the user's events - const getUserEvents = req.user.events.map(e => Event.findOne({ _id: e })); - // get the user's teams - const getUserTeams = req.user.teams.map(t => Team.findOne({ _id: t })); - - let userEvents = []; - let userTeams = []; - try { - userEvents = await Promise.all(getUserEvents); - // remove null values from array - userEvents = compact(userEvents); - userTeams = await Promise.all(getUserTeams); - // remove null values from array - userTeams = compact(userTeams); - } catch (err) { - console.log('Events/Teams failed to be found at list-petitions'); - return next(err); - } - - const managedEvents = []; - userEvents.map(e => { - const eventManagers = e.managers.map(m => m.toString()); - if (eventManagers.includes(req.user.id)) { - managedEvents.push(mongoose.Types.ObjectId(e.id)); - } - }); - - const managedTeams = []; - userTeams.map(t => { - const teamManagers = t.managers.map(m => m.toString()); - if (teamManagers.includes(req.user.id)) { - managedTeams.push(mongoose.Types.ObjectId(t.id)); - } - }); - - petitionsQuery.$or = [ - { - $and: [ - { user: userId }, - { type: { $in: ['invite-user-event', 'invite-user-team'] } } - ] - }, - { - $and: [ - { event: { $in: managedEvents } }, - { type: { $in: ['request-team-event', 'request-user-event'] } } - ] - }, - { - $and: [ - { team: { $in: managedTeams } }, - { type: { $in: ['invite-team-event', 'request-user-team'] } } - ] - } - ]; - } - - const sortBy = '-createdAt'; - - let page = queryParams.page || 1; - const pageLimit = 12; - if (page > 0) { - page -= 1; - } else { - return res - .status(400) - .json({ page: 'Should be equal to or greater than 1' }); - } - - // Fetch data - const aggregateQuery = [ - { - $match: petitionsQuery - }, - { - $sort: { createdAt: -1 } - }, - { - $lookup: { - from: 'events', - let: { event: '$event' }, - pipeline: [ - { - $match: { - $expr: { - $eq: ['$_id', '$$event'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - name: 1, - poster: 1 - } - } - ], - as: 'event' - } - }, - { - $unwind: { - path: '$event', - preserveNullAndEmptyArrays: true - } - }, - { - $lookup: { - from: 'users', - let: { sender: '$sender' }, - pipeline: [ - { - $match: { - $expr: { - $eq: ['$_id', '$$sender'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - firstName: 1, - lastName: 1 - } - } - ], - as: 'sender' - } - }, - { - $unwind: { - path: '$sender', - preserveNullAndEmptyArrays: true - } - }, - { - $lookup: { - from: 'teams', - let: { team: '$team' }, - pipeline: [ - { - $match: { - $expr: { - $eq: ['$_id', '$$team'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - name: 1 - } - } - ], - as: 'team' - } - }, - { - $unwind: { - path: '$team', - preserveNullAndEmptyArrays: true - } - }, - { - $lookup: { - from: 'users', - let: { user: '$user' }, - pipeline: [ - { - $match: { - $expr: { - $eq: ['$_id', '$$user'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - firstName: 1, - lastName: 1 - } - } - ], - as: 'user' - } - }, - { - $unwind: { - path: '$user', - preserveNullAndEmptyArrays: true - } - }, - { - $project: { - _id: 0, - id: '$_id', - createdAt: 1, - event: 1, - message: 1, - sender: 1, - state: 1, - team: 1, - type: 1, - user: 1 - } - } - ]; - - // paginate - aggregateQuery.push( - { - $skip: page * pageLimit - }, - { - $limit: pageLimit - } - ); - - let petitions; - let total; - try { - [petitions, total] = await Promise.all([ - Petition.aggregate(aggregateQuery), - Petition.find(petitionsQuery).count() - ]); - } catch (err) { - console.log('Petitions failed to be found or count at list-petitions'); - return next(err); - } - - let lastPage = Math.ceil(total / pageLimit); - if (lastPage > 0) { - page += 1; - if (page > lastPage) { - return res - .status(400) - .json({ page: `Should be equal to or less than ${lastPage}` }); - } - } else { - page = null; - lastPage = null; - } - - return res.status(200).json({ - page, - lastPage, - pageLimit, - total, - sortBy, - results: petitions - }); -}; +const mongoose = require('mongoose'); + +const { compact } = require('lodash'); +const { Petition } = require('../../models/petition'); +const { Team } = require('../../models/team'); +const { Event } = require('../../models/event'); + +module.exports = async (req, res, next) => { + const queryParams = req.query; + const userId = new mongoose.Types.ObjectId(req.user.id); + + const petitionsQuery = { + state: { $in: ['accepted', 'pending', 'rejected'] } + }; + + if (queryParams.filter === 'sent') { + petitionsQuery.sender = userId; + } else { + // get the user's events + const getUserEvents = req.user.events.map((e) => Event.findOne({ _id: e })); + // get the user's teams + const getUserTeams = req.user.teams.map((t) => Team.findOne({ _id: t })); + + let userEvents = []; + let userTeams = []; + try { + userEvents = await Promise.all(getUserEvents); + // remove null values from array + userEvents = compact(userEvents); + userTeams = await Promise.all(getUserTeams); + // remove null values from array + userTeams = compact(userTeams); + } catch (err) { + console.log('Events/Teams failed to be found at list-petitions'); + return next(err); + } + + const managedEvents = []; + userEvents.map((e) => { + const eventManagers = e.managers.map((m) => m.toString()); + if (eventManagers.includes(req.user.id)) { + managedEvents.push(new mongoose.Types.ObjectId(e.id)); + } + }); + + const managedTeams = []; + userTeams.map((t) => { + const teamManagers = t.managers.map((m) => m.toString()); + if (teamManagers.includes(req.user.id)) { + managedTeams.push(new mongoose.Types.ObjectId(t.id)); + } + }); + + petitionsQuery.$or = [ + { + $and: [ + { user: userId }, + { type: { $in: ['invite-user-event', 'invite-user-team'] } } + ] + }, + { + $and: [ + { event: { $in: managedEvents } }, + { type: { $in: ['request-team-event', 'request-user-event'] } } + ] + }, + { + $and: [ + { team: { $in: managedTeams } }, + { type: { $in: ['invite-team-event', 'request-user-team'] } } + ] + } + ]; + } + + const sortBy = '-createdAt'; + + let page = queryParams.page || 1; + const pageLimit = 12; + if (page > 0) { + page -= 1; + } else { + return res + .status(400) + .json({ page: 'Should be equal to or greater than 1' }); + } + + // Fetch data + const aggregateQuery = [ + { + $match: petitionsQuery + }, + { + $sort: { createdAt: -1 } + }, + { + $lookup: { + from: 'events', + let: { event: '$event' }, + pipeline: [ + { + $match: { + $expr: { + $eq: ['$_id', '$$event'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + name: 1, + poster: 1 + } + } + ], + as: 'event' + } + }, + { + $unwind: { + path: '$event', + preserveNullAndEmptyArrays: true + } + }, + { + $lookup: { + from: 'users', + let: { sender: '$sender' }, + pipeline: [ + { + $match: { + $expr: { + $eq: ['$_id', '$$sender'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + firstName: 1, + lastName: 1 + } + } + ], + as: 'sender' + } + }, + { + $unwind: { + path: '$sender', + preserveNullAndEmptyArrays: true + } + }, + { + $lookup: { + from: 'teams', + let: { team: '$team' }, + pipeline: [ + { + $match: { + $expr: { + $eq: ['$_id', '$$team'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + name: 1 + } + } + ], + as: 'team' + } + }, + { + $unwind: { + path: '$team', + preserveNullAndEmptyArrays: true + } + }, + { + $lookup: { + from: 'users', + let: { user: '$user' }, + pipeline: [ + { + $match: { + $expr: { + $eq: ['$_id', '$$user'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + firstName: 1, + lastName: 1 + } + } + ], + as: 'user' + } + }, + { + $unwind: { + path: '$user', + preserveNullAndEmptyArrays: true + } + }, + { + $project: { + _id: 0, + id: '$_id', + createdAt: 1, + event: 1, + message: 1, + sender: 1, + state: 1, + team: 1, + type: 1, + user: 1 + } + } + ]; + + // paginate + aggregateQuery.push( + { + $skip: page * pageLimit + }, + { + $limit: pageLimit + } + ); + + let petitions; + let total; + try { + [petitions, total] = await Promise.all([ + Petition.aggregate(aggregateQuery), + Petition.countDocuments(petitionsQuery) + ]); + } catch (err) { + console.log('Petitions failed to be found or count at list-petitions'); + return next(err); + } + + let lastPage = Math.ceil(total / pageLimit); + if (lastPage > 0) { + page += 1; + if (page > lastPage) { + return res + .status(400) + .json({ page: `Should be equal to or less than ${lastPage}` }); + } + } else { + page = null; + lastPage = null; + } + + return res.status(200).json({ + page, + lastPage, + pageLimit, + total, + sortBy, + results: petitions + }); +}; diff --git a/src/routes/petitions/validations.js b/src/routes/petitions/validations.js index fe683d3..03d0f2b 100644 --- a/src/routes/petitions/validations.js +++ b/src/routes/petitions/validations.js @@ -1,79 +1,79 @@ -const { isEmpty } = require('lodash'); -const { isMongoId } = require('validator'); - -const { Petition } = require('../../models/petition'); - -module.exports = { - validateCreatePetition(data) { - const errors = {}; - - if (data.event) { - if (typeof data.event !== 'string') { - errors.event = 'Should be a string'; - } else if (!isMongoId(data.event)) { - errors.event = 'Should be a valid id'; - } - } - - if (data.message && typeof data.message !== 'string') { - errors.message = 'Should be a string'; - } - - if (data.team) { - if (typeof data.team !== 'string') { - errors.team = 'Should be a string'; - } else if (!isMongoId(data.team)) { - errors.team = 'Should be a valid id'; - } - } - - const petitionTypes = Petition.schema.path('type').enumValues; - if (!data.type) { - errors.type = 'Is required'; - } else if (typeof data.type !== 'string') { - errors.type = 'Should be a string'; - } else if (!petitionTypes.includes(data.type)) { - errors.type = 'Should be a valid type'; - } else if ( - data.type === 'invite-team-event' || - data.type === 'request-team-event' - ) { - if (!data.event) errors.event = 'Is required'; - if (!data.team) errors.team = 'Is required'; - } else if (data.type === 'invite-user-event') { - if (!data.event) errors.event = 'Is required'; - if (!data.user) errors.user = 'Is required'; - } else if (data.type === 'request-user-event' && !data.event) { - errors.event = 'Is required'; - } else if (data.type === 'invite-user-team') { - if (!data.team) errors.team = 'Is required'; - if (!data.user) errors.user = 'Is required'; - } else if (data.type === 'request-user-team' && !data.team) { - errors.team = 'Is required'; - } - - if (data.user) { - if (typeof data.user !== 'string') { - errors.user = 'Should be a string'; - } else if (!isMongoId(data.user)) { - errors.user = 'Should be a valid id'; - } - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateEditPetition(data) { - const errors = {}; - - const petitionStates = Petition.schema.path('state').enumValues; - if (!data.state) { - errors.state = 'Is required'; - } else if (!petitionStates.includes(data.state)) { - errors.state = 'Should be a valid state'; - } else if (data.state === 'pending') { - errors.state = 'Should be a different state'; - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const { isEmpty } = require('lodash'); +const { isMongoId } = require('validator'); + +const { Petition } = require('../../models/petition'); + +module.exports = { + validateCreatePetition(data) { + const errors = {}; + + if (data.event) { + if (typeof data.event !== 'string') { + errors.event = 'Should be a string'; + } else if (!isMongoId(data.event)) { + errors.event = 'Should be a valid id'; + } + } + + if (data.message && typeof data.message !== 'string') { + errors.message = 'Should be a string'; + } + + if (data.team) { + if (typeof data.team !== 'string') { + errors.team = 'Should be a string'; + } else if (!isMongoId(data.team)) { + errors.team = 'Should be a valid id'; + } + } + + const petitionTypes = Petition.schema.path('type').enumValues; + if (!data.type) { + errors.type = 'Is required'; + } else if (typeof data.type !== 'string') { + errors.type = 'Should be a string'; + } else if (!petitionTypes.includes(data.type)) { + errors.type = 'Should be a valid type'; + } else if ( + data.type === 'invite-team-event' || + data.type === 'request-team-event' + ) { + if (!data.event) errors.event = 'Is required'; + if (!data.team) errors.team = 'Is required'; + } else if (data.type === 'invite-user-event') { + if (!data.event) errors.event = 'Is required'; + if (!data.user) errors.user = 'Is required'; + } else if (data.type === 'request-user-event' && !data.event) { + errors.event = 'Is required'; + } else if (data.type === 'invite-user-team') { + if (!data.team) errors.team = 'Is required'; + if (!data.user) errors.user = 'Is required'; + } else if (data.type === 'request-user-team' && !data.team) { + errors.team = 'Is required'; + } + + if (data.user) { + if (typeof data.user !== 'string') { + errors.user = 'Should be a string'; + } else if (!isMongoId(data.user)) { + errors.user = 'Should be a valid id'; + } + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateEditPetition(data) { + const errors = {}; + + const petitionStates = Petition.schema.path('state').enumValues; + if (!data.state) { + errors.state = 'Is required'; + } else if (!petitionStates.includes(data.state)) { + errors.state = 'Should be a valid state'; + } else if (data.state === 'pending') { + errors.state = 'Should be a different state'; + } + + return { errors, isValid: isEmpty(errors) }; + } +}; diff --git a/src/routes/photos/create-photo.js b/src/routes/photos/create-photo.js index 43fd66d..8db09f7 100644 --- a/src/routes/photos/create-photo.js +++ b/src/routes/photos/create-photo.js @@ -1,115 +1,115 @@ -const fs = require('fs'); -const util = require('util'); - -const aws = require('aws-sdk'); -const jimp = require('jimp'); -const multer = require('multer'); -const randomstring = require('randomstring'); - -const { Photo } = require('../../models/photo'); - -jimp.prototype.getBufferAsync = util.promisify(jimp.prototype.getBuffer); - -module.exports = async (req, res, next) => { - const uploadPhoto = util.promisify( - multer({ - dest: '/tmp', - limits: { fileSize: 8388608 }, - fileFilter: (req, file, cb) => { - if (/^image\/(jpe?g|png)$/i.test(file.mimetype)) { - cb(null, true); - } else { - cb(new Error('Should have .jpeg or .png extension')); - } - } - }).single('photo') - ); - try { - await uploadPhoto(req, res); - } catch (err) { - return res.status(400).json({ photo: err.message }); - } - - if (!req.file) { - return res.status(400).json({ photo: 'Is required' }); - } - - let photoFile; - try { - photoFile = await jimp.read(req.file.path); - } catch (err) { - console.log('Photo failed to be read at create-photo'); - return next(err); - } - - if (req.body.isWide === 'true') { - photoFile.cover(640, 480).quality(85); - } else { - photoFile.cover(400, 400).quality(85); - } - - let photoBuffer; - try { - photoBuffer = await photoFile.getBufferAsync(photoFile.getMIME()); - } catch (err) { - return next(err); - } - - const photoExtension = photoFile.getExtension(); - const photoFileName = `${Date.now()}${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}.${photoExtension}`; - - const s3 = new aws.S3(); - try { - await s3 - .putObject({ - ACL: 'public-read', - Body: photoBuffer, - Bucket: process.env.AWS_S3_BUCKET, - ContentType: photoFile.getMIME(), - Key: `photos/${photoFileName}` - }) - .promise(); - } catch (err) { - console.log('Photo failed to be uploaded at create-photo'); - return next(err); - } - - fs.unlink(req.file.path); - - const photoData = { - fileName: photoFileName, - url: `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/photos/${photoFileName}`, - user: req.user.id - }; - - let photo; - try { - photo = await Photo.create(photoData); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log('Photo failed to be created at create-photo'); - return next(err); - } - - const dataResponse = { - id: photo.id, - fileName: photo.fileName, - url: photo.url, - user: photo.user - }; - return res.status(201).json(dataResponse); -}; +const fs = require('fs'); + +const aws = require('aws-sdk'); +const jimp = require('jimp'); +const multer = require('multer'); +const randomstring = require('randomstring'); + +const { Photo } = require('../../models/photo'); + +const upload = multer({ + dest: '/tmp', + limits: { fileSize: 8388608 }, + fileFilter: (req, file, cb) => { + if (/^image\/(jpe?g|png)$/i.test(file.mimetype)) { + cb(null, true); + } else { + cb(new Error('Should have .jpeg or .png extension')); + } + } +}).single('photo'); + +module.exports = async (req, res, next) => { + upload(req, res, async (err) => { + if (err) { + return res.status(400).json({ photo: err.message }); + } + + if (!req.file) { + return res.status(400).json({ photo: 'Is required' }); + } + + let photoFile; + try { + photoFile = await jimp.read(req.file.path); + } catch (err) { + console.log('Photo failed to be read at create-photo'); + return next(err); + } + + if (req.body.isWide === 'true') { + photoFile.cover(640, 480).quality(85); + } else { + photoFile.cover(400, 400).quality(85); + } + + let photoBuffer; + try { + photoBuffer = await photoFile.getBufferAsync(photoFile.getMIME()); + } catch (err) { + return next(err); + } + + const photoExtension = photoFile.getExtension(); + const photoFileName = `${Date.now()}${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}.${photoExtension}`; + + const s3 = new aws.S3(); + try { + await s3 + .putObject({ + ACL: 'public-read', + Body: photoBuffer, + Bucket: process.env.AWS_S3_BUCKET, + ContentType: photoFile.getMIME(), + Key: `photos/${photoFileName}` + }) + .promise(); + } catch (err) { + console.log('Photo failed to be uploaded at create-photo'); + return next(err); + } + + fs.unlink(req.file.path, (err) => { + if (err) { + console.log('Failed to delete temporary file', err); + } + }); + + const photoData = { + fileName: photoFileName, + url: `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/photos/${photoFileName}`, + user: req.user.id + }; + + let photo; + try { + photo = await Photo.create(photoData); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log('Photo failed to be created at create-photo'); + return next(err); + } + + const dataResponse = { + id: photo.id, + fileName: photo.fileName, + url: photo.url, + user: photo.user + }; + return res.status(201).json(dataResponse); + }); +}; diff --git a/src/routes/photos/delete-photo.js b/src/routes/photos/delete-photo.js index fa78064..a859696 100644 --- a/src/routes/photos/delete-photo.js +++ b/src/routes/photos/delete-photo.js @@ -1,47 +1,47 @@ -const aws = require('aws-sdk'); - -const { Photo } = require('../../models/photo'); - -module.exports = async (req, res, next) => { - const photoFileName = req.params.photoFileName; - - let photo; - try { - photo = await Photo.findOne({ fileName: photoFileName }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Photo not found' }); - } - - console.log(`Photo ${photoFileName} failed to be found at delete-photo`); - return next(err); - } - - if (photo) { - try { - await photo.remove(); - } catch (err) { - console.log( - `Photo ${photoFileName} failed to be deleted at delete-photo` - ); - return next(err); - } - } - - if (!photoFileName.includes('default')) { - const s3 = new aws.S3(); - try { - await s3 - .deleteObject({ - Bucket: process.env.AWS_S3_BUCKET, - Key: `photos/${photoFileName}` - }) - .promise(); - } catch (err) { - console.log('Photo failed to be deleted at delete-photo'); - return next(err); - } - } - - return res.status(204).json({ general: 'Success' }); -}; +const aws = require('aws-sdk'); + +const { Photo } = require('../../models/photo'); + +module.exports = async (req, res, next) => { + const photoFileName = req.params.photoFileName; + + let photo; + try { + photo = await Photo.findOne({ fileName: photoFileName }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Photo not found' }); + } + + console.log(`Photo ${photoFileName} failed to be found at delete-photo`); + return next(err); + } + + if (photo) { + try { + await photo.remove(); + } catch (err) { + console.log( + `Photo ${photoFileName} failed to be deleted at delete-photo` + ); + return next(err); + } + } + + if (!photoFileName.includes('default')) { + const s3 = new aws.S3(); + try { + await s3 + .deleteObject({ + Bucket: process.env.AWS_S3_BUCKET, + Key: `photos/${photoFileName}` + }) + .promise(); + } catch (err) { + console.log('Photo failed to be deleted at delete-photo'); + return next(err); + } + } + + return res.status(204).json({ general: 'Success' }); +}; diff --git a/src/routes/photos/index.js b/src/routes/photos/index.js index bd00f27..c1c7280 100644 --- a/src/routes/photos/index.js +++ b/src/routes/photos/index.js @@ -1,17 +1,17 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const createPhoto = require('./create-photo'); -const deletePhoto = require('./delete-photo'); - -const router = new express.Router(); - -router.post('', isAuthenticated({ isOptional: false }), createPhoto); -router.delete( - '/:photoFileName', - isAuthenticated({ isOptional: false }), - deletePhoto -); - -module.exports = router; +const express = require('express'); + +const { isAuthenticated } = require('../../helpers'); + +const createPhoto = require('./create-photo'); +const deletePhoto = require('./delete-photo'); + +const router = new express.Router(); + +router.post('', isAuthenticated({ isOptional: false }), createPhoto); +router.delete( + '/:photoFileName', + isAuthenticated({ isOptional: false }), + deletePhoto +); + +module.exports = router; diff --git a/src/routes/reviews/ban-review.js b/src/routes/reviews/ban-review.js index 6e97ee9..227507e 100644 --- a/src/routes/reviews/ban-review.js +++ b/src/routes/reviews/ban-review.js @@ -1,39 +1,39 @@ -const moment = require('moment'); - -const { Review } = require('../../models/review'); - -module.exports = async (req, res, next) => { - if (!req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const reviewId = req.params.reviewId; - - let review; - try { - review = await Review.findOne({ _id: reviewId }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Review not found' }); - } - - console.log(`Review ${reviewId} failed to be found at ban-review`); - return next(err); - } - - if (!review) { - return res.status(404).json({ general: 'Review not found' }); - } - - review.isBanned = true; - review.updatedAt = moment.utc().toDate(); - - try { - await review.save(); - } catch (err) { - console.log(`Review ${review.id} failed to be updated at ban-review`); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { Review } = require('../../models/review'); + +module.exports = async (req, res, next) => { + if (!req.user.isAdmin) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const reviewId = req.params.reviewId; + + let review; + try { + review = await Review.findOne({ _id: reviewId }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Review not found' }); + } + + console.log(`Review ${reviewId} failed to be found at ban-review`); + return next(err); + } + + if (!review) { + return res.status(404).json({ general: 'Review not found' }); + } + + review.isBanned = true; + review.updatedAt = moment.utc().toDate(); + + try { + await review.save(); + } catch (err) { + console.log(`Review ${review.id} failed to be updated at ban-review`); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/reviews/create-review.js b/src/routes/reviews/create-review.js index ff61b71..7b78f17 100644 --- a/src/routes/reviews/create-review.js +++ b/src/routes/reviews/create-review.js @@ -1,557 +1,555 @@ -const axios = require('axios'); -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { Photo } = require('../../models/photo'); -const { Review } = require('../../models/review'); -const { Team } = require('../../models/team'); -const { Venue } = require('../../models/venue'); - -const { validateCreateEditReview } = require('./validations'); -const venueReviewSummary = require('../../helpers/venue-review-summary.js'); - -module.exports = async (req, res, next) => { - console.log('body: ', req.body); - const { errors, isValid } = validateCreateEditReview(req.body); - if (!isValid) return res.status(400).json(errors); - - const data = { - //new expanded fields - hasPermanentRamp: req.body.hasPermanentRamp, - hasPortableRamp: req.body.hasPortableRamp, - hasWideEntrance: req.body.hasWideEntrance, - hasAccessibleTableHeight: req.body.hasAccessibleTableHeight, - hasAccessibleElevator: req.body.hasAccessibleElevator, - hasInteriorRamp: req.body.hasInteriorRamp, - hasSwingOutDoor: req.body.hasSwingOutDoor, - hasLargeStall: req.body.hasLargeStall, - hasSupportAroundToilet: req.body.hasSupportAroundToilet, - hasLoweredSinks: req.body.hasLoweredSinks, - interiorScore: req.body.interiorScore, - _isScoreConverted: true, - - //original fields - allowsGuideDog: req.body.allowsGuideDog, - //bathroomScore: req.body.bathroomScore, - comments: req.body.comments, - //entryScore: req.body.entryScore, - event: req.body.event, - hasParking: req.body.hasParking, - hasSecondEntry: req.body.hasSecondEntry, - hasWellLit: req.body.hasWellLit, - isQuiet: req.body.isQuiet, - isSpacious: req.body.isSpacious, - steps: req.body.steps, - team: req.body.team, - user: req.user.id - }; - - let event; - if (data.event) { - try { - event = await Event.findOne({ _id: data.event, isArchived: false }); - } catch (err) { - console.log(`Event ${data.event} failed to be found at create-review`); - return next(err); - } - - if (!event) { - return res.status(404).json({ event: 'Event not found' }); - } - - if ( - !event.participants.find(p => p.toString() === data.user) && - !event.managers.find(m => m.toString() === data.user) - ) { - return res - .status(400) - .json({ event: 'You are not a participant of this event' }); - } - - const startDate = moment(event.startDate).utc(); - const endDate = moment(event.endDate).utc(); - const today = moment() - .startOf('day') - .utc(); - if (startDate.isAfter(today)) { - return res.status(400).json({ event: 'Event has not started yet' }); - } else if (endDate.isBefore(today)) { - return res.status(400).json({ event: 'Event has already finished' }); - } - } - - let team; - if (data.team) { - try { - team = await Team.findOne({ _id: data.team, isArchived: false }); - } catch (err) { - console.log(`Team ${data.team} failed to be found at create-review`); - return next(err); - } - - if (!team) { - return res.status(404).json({ team: 'Team not found' }); - } - - if ( - !team.members.find(m => m.toString() === data.user) && - !team.managers.find(m => m.toString() === data.user) - ) { - return res - .status(400) - .json({ team: 'You are not a member of this team' }); - } - } - - const placeId = req.body.place; - let venue; - try { - venue = await Venue.findOne({ placeId }); - } catch (err) { - console.log( - `Venue with placeId ${placeId} failed to be found at create-review` - ); - return next(err); - } - - if (!venue) { - let response; - try { - response = await axios.get( - `https://maps.googleapis.com/maps/api/place/details/json?placeid=${placeId}&key=${ - process.env.PLACES_API_KEY - }` - ); - } catch (err) { - console.log( - `Place ${placeId} failed to be found at create-review, after Google search` - ); - return next(err); - } - - const statusResponse = response.data.status; - if (statusResponse !== 'OK') { - return res.status(404).json({ general: 'Place not found' }); - } - - const placeData = response.data.result; - const venueData = { - address: placeData.formatted_address, - location: { - coordinates: [ - placeData.geometry.location.lng, - placeData.geometry.location.lat - ] - }, - name: placeData.name, - placeId, - types: placeData.types - }; - - try { - venue = await Venue.create(venueData); - } catch (err) { - console.log( - `Venue failed to be created at create-review.\nData: ${JSON.stringify( - venueData - )}` - ); - return next(err); - } - } - data.venue = venue.id; - - let review; - try { - review = await Review.create(data); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `Review failed to be created at create-review.\nData: ${JSON.stringify( - data - )}` - ); - return next(err); - } - - // Sample review Obj - /* - _isScoreConverted: false, - isBanned: false, - voters: [], - _id: 5e853db2587b2740c501f12e, - hasAccessibleElevator: true, - hasInteriorRamp: true, - hasSwingOutDoor: false, - hasLargeStall: false, - user: 5e14e8584701fb22ade354e9, - venue: 5e3da8d56d958200424ffdfe, - complaints: [], - createdAt: 2020-04-02T01:19:46.508Z, - updatedAt: 2020-04-02T01:19:46.508Z, - __v: 0 - */ - - //subtracts out the 10 standard fields to determine - var reviewedFieldsCount = Object.keys(review.toObject()).length - 10; - req.user.reviewFieldsAmount = - req.user.reviewFieldsAmount + reviewedFieldsCount; - req.user.reviewsAmount = req.user.reviewsAmount + 1; - req.user.updatedAt = moment.utc().toDate(); - - try { - await req.user.save(); - } catch (err) { - console.log( - `User ${ - req.user.id - } failed to be updated at create-review, after updated review count` - ); - return next(err); - } - - if (event) { - event.reviewsAmount = event.reviewsAmount + 1; - event.updatedAt = moment.utc().toDate(); - try { - await event.save(); - } catch (err) { - console.log( - `Event ${event.id} failed to be updated at create-review, after event` - ); - return next(err); - } - } - - if (req.body.photo) { - let photo; - try { - photo = await Photo.findOne({ url: req.body.photo }); - } catch (err) { - console.log( - `Photo ${req.body.photo} failed to be found at create-review` - ); - return next(err); - } - - if (!photo) { - return res.status(404).json({ photo: 'Not found' }); - } - - venue.photos = [...venue.photos, photo.id]; - - try { - await venue.save(); - } catch (err) { - console.log( - `Venue ${venue.id} failed to be updated at create-review, after photos` - ); - return next(err); - } - } - - if (team) { - team.reviewsAmount = team.reviewsAmount + 1; - team.updatedAt = moment.utc().toDate(); - try { - await team.save(); - } catch (err) { - console.log( - `Team ${team.id} failed to be updated at create-review, after team` - ); - return next(err); - } - } - - // - //new expanded fields - // - if (typeof review.hasPermanentRamp !== 'undefined') { - venue.hasPermanentRamp = { - yes: review.hasPermanentRamp - ? venue.hasPermanentRamp.yes + 1 - : venue.hasPermanentRamp.yes, - no: review.hasPermanentRamp - ? venue.hasPermanentRamp.no - : venue.hasPermanentRamp.no + 1 - }; - } - - if (typeof review.hasPortableRamp !== 'undefined') { - venue.hasPortableRamp = { - yes: review.hasPortableRamp - ? venue.hasPortableRamp.yes + 1 - : venue.hasPortableRamp.yes, - no: review.hasPortableRamp - ? venue.hasPortableRamp.no - : venue.hasPortableRamp.no + 1 - }; - } - - if (typeof review.hasWideEntrance !== 'undefined') { - venue.hasWideEntrance = { - yes: review.hasWideEntrance - ? venue.hasWideEntrance.yes + 1 - : venue.hasWideEntrance.yes, - no: review.hasWideEntrance - ? venue.hasWideEntrance.no - : venue.hasWideEntrance.no + 1 - }; - } - - if (typeof review.hasAccessibleTableHeight !== 'undefined') { - venue.hasAccessibleTableHeight = { - yes: review.hasAccessibleTableHeight - ? venue.hasAccessibleTableHeight.yes + 1 - : venue.hasAccessibleTableHeight.yes, - no: review.hasAccessibleTableHeight - ? venue.hasAccessibleTableHeight.no - : venue.hasAccessibleTableHeight.no + 1 - }; - } - - if (typeof review.hasAccessibleElevator !== 'undefined') { - venue.hasAccessibleElevator = { - yes: review.hasAccessibleElevator - ? venue.hasAccessibleElevator.yes + 1 - : venue.hasAccessibleElevator.yes, - no: review.hasAccessibleElevator - ? venue.hasAccessibleElevator.no - : venue.hasAccessibleElevator.no + 1 - }; - } - - if (typeof review.hasInteriorRamp !== 'undefined') { - venue.hasInteriorRamp = { - yes: review.hasInteriorRamp - ? venue.hasInteriorRamp.yes + 1 - : venue.hasInteriorRamp.yes, - no: review.hasInteriorRamp - ? venue.hasInteriorRamp.no - : venue.hasInteriorRamp.no + 1 - }; - } - - if (typeof review.hasSwingOutDoor !== 'undefined') { - venue.hasSwingOutDoor = { - yes: review.hasSwingOutDoor - ? venue.hasSwingOutDoor.yes + 1 - : venue.hasSwingOutDoor.yes, - no: review.hasSwingOutDoor - ? venue.hasSwingOutDoor.no - : venue.hasSwingOutDoor.no + 1 - }; - } - - if (typeof review.hasLargeStall !== 'undefined') { - venue.hasLargeStall = { - yes: review.hasLargeStall - ? venue.hasLargeStall.yes + 1 - : venue.hasLargeStall.yes, - no: review.hasLargeStall - ? venue.hasLargeStall.no - : venue.hasLargeStall.no + 1 - }; - } - - if (typeof review.hasSupportAroundToilet !== 'undefined') { - venue.hasSupportAroundToilet = { - yes: review.hasSupportAroundToilet - ? venue.hasSupportAroundToilet.yes + 1 - : venue.hasSupportAroundToilet.yes, - no: review.hasSupportAroundToilet - ? venue.hasSupportAroundToilet.no - : venue.hasSupportAroundToilet.no + 1 - }; - } - - if (typeof review.hasLoweredSinks !== 'undefined') { - venue.hasLoweredSinks = { - yes: review.hasLoweredSinks - ? venue.hasLoweredSinks.yes + 1 - : venue.hasLoweredSinks.yes, - no: review.hasLoweredSinks - ? venue.hasLoweredSinks.no - : venue.hasLoweredSinks.no + 1 - }; - } - - // - //original fields - // - if (typeof review.allowsGuideDog !== 'undefined') { - venue.allowsGuideDog = { - yes: review.allowsGuideDog - ? venue.allowsGuideDog.yes + 1 - : venue.allowsGuideDog.yes, - no: review.allowsGuideDog - ? venue.allowsGuideDog.no - : venue.allowsGuideDog.no + 1 - }; - } - - /* - if (typeof review.bathroomScore !== 'undefined') { - if (venue.bathroomReviews > 0) { - venue.bathroomScore = - (venue.bathroomScore * venue.bathroomReviews + review.bathroomScore) / - (venue.bathroomReviews + 1); - venue.bathroomReviews += 1; - } else { - venue.bathroomScore = review.bathroomScore; - venue.bathroomReviews = 1; - } - } - - if (venue.entryReviews > 0) { - venue.entryScore = - (venue.entryScore * venue.entryReviews + review.entryScore) / - (venue.entryReviews + 1); - venue.entryReviews += 1; - } else { - venue.entryScore = review.entryScore; - venue.entryReviews = 1; - } - */ - - if (typeof review.hasParking !== 'undefined') { - venue.hasParking = { - yes: review.hasParking ? venue.hasParking.yes + 1 : venue.hasParking.yes, - no: review.hasParking ? venue.hasParking.no : venue.hasParking.no + 1 - }; - } - - if (typeof review.hasSecondEntry !== 'undefined') { - venue.hasSecondEntry = { - yes: review.hasSecondEntry - ? venue.hasSecondEntry.yes + 1 - : venue.hasSecondEntry.yes, - no: review.hasSecondEntry - ? venue.hasSecondEntry.no - : venue.hasSecondEntry.no + 1 - }; - } - - if (typeof review.hasWellLit !== 'undefined') { - venue.hasWellLit = { - yes: review.hasWellLit ? venue.hasWellLit.yes + 1 : venue.hasWellLit.yes, - no: review.hasWellLit ? venue.hasWellLit.no : venue.hasWellLit.no + 1 - }; - } - - if (typeof review.isQuiet !== 'undefined') { - venue.isQuiet = { - yes: review.isQuiet ? venue.isQuiet.yes + 1 : venue.isQuiet.yes, - no: review.isQuiet ? venue.isQuiet.no : venue.isQuiet.no + 1 - }; - } - - if (typeof review.isSpacious !== 'undefined') { - venue.isSpacious = { - yes: review.isSpacious ? venue.isSpacious.yes + 1 : venue.isSpacious.yes, - no: review.isSpacious ? venue.isSpacious.no : venue.isSpacious.no + 1 - }; - } - - venue.reviews = [...venue.reviews, review.id]; - - if (typeof review.steps !== 'undefined') { - venue.steps = { - zero: review.steps === 0 ? venue.steps.zero + 1 : venue.steps.zero, - one: review.steps === 1 ? venue.steps.one + 1 : venue.steps.one, - two: review.steps === 2 ? venue.steps.two + 1 : venue.steps.two, - moreThanTwo: - review.steps === 3 - ? venue.steps.moreThanTwo + 1 - : venue.steps.moreThanTwo - }; - } - - let scoring; - //calculate entranceScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('entrance', venue); - //console.log('entrance score: ', scoring); - venue.entranceScore = scoring.ratingLevel; - venue.entranceGlyphs = scoring.ratingGlyphs; - - //calculate interiorScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('interior', venue); - //console.log('interior score: ', scoring); - venue.interiorScore = scoring.ratingLevel; - venue.interiorGlyphs = scoring.ratingGlyphs; - - //calculate restroomScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('restroom', venue); - //console.log('restroom score: ', scoring); - venue.restroomScore = scoring.ratingLevel; - venue.restroomGlyphs = scoring.ratingGlyphs; - - venue.mapMarkerScore = venueReviewSummary.calculateMapMarkerScore( - venue.entranceScore, - venue.interiorScore, - venue.restroomScore - ); - - //console.log('venue: ', venue); - - try { - await venue.save(); - } catch (err) { - console.log( - `Venue ${venue.id} failed to be updated at create-review, at final step` - ); - return next(err); - } - - const dataResponse = { - //new expanded fields - hasPermanentRamp: review.hasPermanentRamp, - hasPortableRamp: req.body.hasPortableRamp, - hasWideEntrance: review.hasWideEntrance, - hasAccessibleTableHeight: review.hasAccessibleTableHeight, - hasAccessibleElevator: review.hasAccessibleElevator, - hasInteriorRamp: review.hasInteriorRamp, - hasSwingOutDoor: review.hasSwingOutDoor, - hasLargeStall: review.hasLargeStall, - hasSupportAroundToilet: review.hasSupportAroundToilet, - hasLoweredSinks: review.hasLoweredSinks, - - /* - entranceScore: review.entranceScore, - entranceGlyph: review.entryGlyph, - interiorScore: review.interiorScore, - interiorGlyph: review.interiorGlyph, - restroomScore: review.restroomScore, - restroomGlyph: review.restroomGlyph, - */ - - //original fields - id: review.id, - allowsGuideDog: review.allowsGuideDog, - //bathroomScore: review.bathroomScore, - comments: review.comments, - //entryScore: review.entryScore, - event: review.event, - hasParking: review.hasParking, - hasSecondEntry: review.hasSecondEntry, - hasWellLit: review.hasWellLit, - isQuiet: review.isQuiet, - isSpacious: review.isSpacious, - steps: review.steps, - team: review.team, - user: review.user, - userReviewFieldsAmount: req.user.reviewFieldsAmount, - userReviewsAmount: req.user.reviewsAmount, - venue: review.venue - }; - return res.status(201).json(dataResponse); -}; +const axios = require('axios'); +const moment = require('moment'); + +const { Event } = require('../../models/event'); +const { Photo } = require('../../models/photo'); +const { Review } = require('../../models/review'); +const { Team } = require('../../models/team'); +const { Venue } = require('../../models/venue'); + +const { validateCreateEditReview } = require('./validations'); +const venueReviewSummary = require('../../helpers/venue-review-summary.js'); + +module.exports = async (req, res, next) => { + console.log('body: ', req.body); + const { errors, isValid } = validateCreateEditReview(req.body); + if (!isValid) return res.status(400).json(errors); + + const data = { + //new expanded fields + hasPermanentRamp: req.body.hasPermanentRamp, + hasPortableRamp: req.body.hasPortableRamp, + hasWideEntrance: req.body.hasWideEntrance, + hasAccessibleTableHeight: req.body.hasAccessibleTableHeight, + hasAccessibleElevator: req.body.hasAccessibleElevator, + hasInteriorRamp: req.body.hasInteriorRamp, + hasSwingOutDoor: req.body.hasSwingOutDoor, + hasLargeStall: req.body.hasLargeStall, + hasSupportAroundToilet: req.body.hasSupportAroundToilet, + hasLoweredSinks: req.body.hasLoweredSinks, + interiorScore: req.body.interiorScore, + _isScoreConverted: true, + + //original fields + allowsGuideDog: req.body.allowsGuideDog, + //bathroomScore: req.body.bathroomScore, + comments: req.body.comments, + //entryScore: req.body.entryScore, + event: req.body.event, + hasParking: req.body.hasParking, + hasSecondEntry: req.body.hasSecondEntry, + hasWellLit: req.body.hasWellLit, + isQuiet: req.body.isQuiet, + isSpacious: req.body.isSpacious, + steps: req.body.steps, + team: req.body.team, + user: req.user.id + }; + + let event; + if (data.event) { + try { + event = await Event.findOne({ _id: data.event, isArchived: false }); + } catch (err) { + console.log(`Event ${data.event} failed to be found at create-review`); + return next(err); + } + + if (!event) { + return res.status(404).json({ event: 'Event not found' }); + } + + if ( + !event.participants.find((p) => p.toString() === data.user) && + !event.managers.find((m) => m.toString() === data.user) + ) { + return res + .status(400) + .json({ event: 'You are not a participant of this event' }); + } + + const startDate = moment(event.startDate).utc(); + const endDate = moment(event.endDate).utc(); + const today = moment().startOf('day').utc(); + if (startDate.isAfter(today)) { + return res.status(400).json({ event: 'Event has not started yet' }); + } else if (endDate.isBefore(today)) { + return res.status(400).json({ event: 'Event has already finished' }); + } + } + + let team; + if (data.team) { + try { + team = await Team.findOne({ _id: data.team, isArchived: false }); + } catch (err) { + console.log(`Team ${data.team} failed to be found at create-review`); + return next(err); + } + + if (!team) { + return res.status(404).json({ team: 'Team not found' }); + } + + if ( + !team.members.find((m) => m.toString() === data.user) && + !team.managers.find((m) => m.toString() === data.user) + ) { + return res + .status(400) + .json({ team: 'You are not a member of this team' }); + } + } + + const placeId = req.body.place; + let venue; + try { + venue = await Venue.findOne({ placeId }); + } catch (err) { + console.log( + `Venue with placeId ${placeId} failed to be found at create-review` + ); + return next(err); + } + + if (!venue) { + let response; + try { + response = await axios.get( + `https://maps.googleapis.com/maps/api/place/details/json?placeid=${placeId}&key=${ + process.env.PLACES_API_KEY + }` + ); + } catch (err) { + console.log( + `Place ${placeId} failed to be found at create-review, after Google search` + ); + return next(err); + } + + const statusResponse = response.data.status; + if (statusResponse !== 'OK') { + return res.status(404).json({ general: 'Place not found' }); + } + + const placeData = response.data.result; + const venueData = { + address: placeData.formatted_address, + location: { + coordinates: [ + placeData.geometry.location.lng, + placeData.geometry.location.lat + ] + }, + name: placeData.name, + placeId, + types: placeData.types + }; + + try { + venue = await Venue.create(venueData); + } catch (err) { + console.log( + `Venue failed to be created at create-review.\nData: ${JSON.stringify( + venueData + )}` + ); + return next(err); + } + } + data.venue = venue.id; + + let review; + try { + review = await Review.create(data); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `Review failed to be created at create-review.\nData: ${JSON.stringify( + data + )}` + ); + return next(err); + } + + // Sample review Obj + /* + _isScoreConverted: false, + isBanned: false, + voters: [], + _id: 5e853db2587b2740c501f12e, + hasAccessibleElevator: true, + hasInteriorRamp: true, + hasSwingOutDoor: false, + hasLargeStall: false, + user: 5e14e8584701fb22ade354e9, + venue: 5e3da8d56d958200424ffdfe, + complaints: [], + createdAt: 2020-04-02T01:19:46.508Z, + updatedAt: 2020-04-02T01:19:46.508Z, + __v: 0 + */ + + //subtracts out the 10 standard fields to determine + var reviewedFieldsCount = Object.keys(review.toObject()).length - 10; + req.user.reviewFieldsAmount = + req.user.reviewFieldsAmount + reviewedFieldsCount; + req.user.reviewsAmount = req.user.reviewsAmount + 1; + req.user.updatedAt = moment.utc().toDate(); + + try { + await req.user.save(); + } catch (err) { + console.log( + `User ${ + req.user.id + } failed to be updated at create-review, after updated review count` + ); + return next(err); + } + + if (event) { + event.reviewsAmount = event.reviewsAmount + 1; + event.updatedAt = moment.utc().toDate(); + try { + await event.save(); + } catch (err) { + console.log( + `Event ${event.id} failed to be updated at create-review, after event` + ); + return next(err); + } + } + + if (req.body.photo) { + let photo; + try { + photo = await Photo.findOne({ url: req.body.photo }); + } catch (err) { + console.log( + `Photo ${req.body.photo} failed to be found at create-review` + ); + return next(err); + } + + if (!photo) { + return res.status(404).json({ photo: 'Not found' }); + } + + venue.photos = [...venue.photos, photo.id]; + + try { + await venue.save(); + } catch (err) { + console.log( + `Venue ${venue.id} failed to be updated at create-review, after photos` + ); + return next(err); + } + } + + if (team) { + team.reviewsAmount = team.reviewsAmount + 1; + team.updatedAt = moment.utc().toDate(); + try { + await team.save(); + } catch (err) { + console.log( + `Team ${team.id} failed to be updated at create-review, after team` + ); + return next(err); + } + } + + // + //new expanded fields + // + if (typeof review.hasPermanentRamp !== 'undefined') { + venue.hasPermanentRamp = { + yes: review.hasPermanentRamp + ? venue.hasPermanentRamp.yes + 1 + : venue.hasPermanentRamp.yes, + no: review.hasPermanentRamp + ? venue.hasPermanentRamp.no + : venue.hasPermanentRamp.no + 1 + }; + } + + if (typeof review.hasPortableRamp !== 'undefined') { + venue.hasPortableRamp = { + yes: review.hasPortableRamp + ? venue.hasPortableRamp.yes + 1 + : venue.hasPortableRamp.yes, + no: review.hasPortableRamp + ? venue.hasPortableRamp.no + : venue.hasPortableRamp.no + 1 + }; + } + + if (typeof review.hasWideEntrance !== 'undefined') { + venue.hasWideEntrance = { + yes: review.hasWideEntrance + ? venue.hasWideEntrance.yes + 1 + : venue.hasWideEntrance.yes, + no: review.hasWideEntrance + ? venue.hasWideEntrance.no + : venue.hasWideEntrance.no + 1 + }; + } + + if (typeof review.hasAccessibleTableHeight !== 'undefined') { + venue.hasAccessibleTableHeight = { + yes: review.hasAccessibleTableHeight + ? venue.hasAccessibleTableHeight.yes + 1 + : venue.hasAccessibleTableHeight.yes, + no: review.hasAccessibleTableHeight + ? venue.hasAccessibleTableHeight.no + : venue.hasAccessibleTableHeight.no + 1 + }; + } + + if (typeof review.hasAccessibleElevator !== 'undefined') { + venue.hasAccessibleElevator = { + yes: review.hasAccessibleElevator + ? venue.hasAccessibleElevator.yes + 1 + : venue.hasAccessibleElevator.yes, + no: review.hasAccessibleElevator + ? venue.hasAccessibleElevator.no + : venue.hasAccessibleElevator.no + 1 + }; + } + + if (typeof review.hasInteriorRamp !== 'undefined') { + venue.hasInteriorRamp = { + yes: review.hasInteriorRamp + ? venue.hasInteriorRamp.yes + 1 + : venue.hasInteriorRamp.yes, + no: review.hasInteriorRamp + ? venue.hasInteriorRamp.no + : venue.hasInteriorRamp.no + 1 + }; + } + + if (typeof review.hasSwingOutDoor !== 'undefined') { + venue.hasSwingOutDoor = { + yes: review.hasSwingOutDoor + ? venue.hasSwingOutDoor.yes + 1 + : venue.hasSwingOutDoor.yes, + no: review.hasSwingOutDoor + ? venue.hasSwingOutDoor.no + : venue.hasSwingOutDoor.no + 1 + }; + } + + if (typeof review.hasLargeStall !== 'undefined') { + venue.hasLargeStall = { + yes: review.hasLargeStall + ? venue.hasLargeStall.yes + 1 + : venue.hasLargeStall.yes, + no: review.hasLargeStall + ? venue.hasLargeStall.no + : venue.hasLargeStall.no + 1 + }; + } + + if (typeof review.hasSupportAroundToilet !== 'undefined') { + venue.hasSupportAroundToilet = { + yes: review.hasSupportAroundToilet + ? venue.hasSupportAroundToilet.yes + 1 + : venue.hasSupportAroundToilet.yes, + no: review.hasSupportAroundToilet + ? venue.hasSupportAroundToilet.no + : venue.hasSupportAroundToilet.no + 1 + }; + } + + if (typeof review.hasLoweredSinks !== 'undefined') { + venue.hasLoweredSinks = { + yes: review.hasLoweredSinks + ? venue.hasLoweredSinks.yes + 1 + : venue.hasLoweredSinks.yes, + no: review.hasLoweredSinks + ? venue.hasLoweredSinks.no + : venue.hasLoweredSinks.no + 1 + }; + } + + // + //original fields + // + if (typeof review.allowsGuideDog !== 'undefined') { + venue.allowsGuideDog = { + yes: review.allowsGuideDog + ? venue.allowsGuideDog.yes + 1 + : venue.allowsGuideDog.yes, + no: review.allowsGuideDog + ? venue.allowsGuideDog.no + : venue.allowsGuideDog.no + 1 + }; + } + + /* + if (typeof review.bathroomScore !== 'undefined') { + if (venue.bathroomReviews > 0) { + venue.bathroomScore = + (venue.bathroomScore * venue.bathroomReviews + review.bathroomScore) / + (venue.bathroomReviews + 1); + venue.bathroomReviews += 1; + } else { + venue.bathroomScore = review.bathroomScore; + venue.bathroomReviews = 1; + } + } + + if (venue.entryReviews > 0) { + venue.entryScore = + (venue.entryScore * venue.entryReviews + review.entryScore) / + (venue.entryReviews + 1); + venue.entryReviews += 1; + } else { + venue.entryScore = review.entryScore; + venue.entryReviews = 1; + } + */ + + if (typeof review.hasParking !== 'undefined') { + venue.hasParking = { + yes: review.hasParking ? venue.hasParking.yes + 1 : venue.hasParking.yes, + no: review.hasParking ? venue.hasParking.no : venue.hasParking.no + 1 + }; + } + + if (typeof review.hasSecondEntry !== 'undefined') { + venue.hasSecondEntry = { + yes: review.hasSecondEntry + ? venue.hasSecondEntry.yes + 1 + : venue.hasSecondEntry.yes, + no: review.hasSecondEntry + ? venue.hasSecondEntry.no + : venue.hasSecondEntry.no + 1 + }; + } + + if (typeof review.hasWellLit !== 'undefined') { + venue.hasWellLit = { + yes: review.hasWellLit ? venue.hasWellLit.yes + 1 : venue.hasWellLit.yes, + no: review.hasWellLit ? venue.hasWellLit.no : venue.hasWellLit.no + 1 + }; + } + + if (typeof review.isQuiet !== 'undefined') { + venue.isQuiet = { + yes: review.isQuiet ? venue.isQuiet.yes + 1 : venue.isQuiet.yes, + no: review.isQuiet ? venue.isQuiet.no : venue.isQuiet.no + 1 + }; + } + + if (typeof review.isSpacious !== 'undefined') { + venue.isSpacious = { + yes: review.isSpacious ? venue.isSpacious.yes + 1 : venue.isSpacious.yes, + no: review.isSpacious ? venue.isSpacious.no : venue.isSpacious.no + 1 + }; + } + + venue.reviews = [...venue.reviews, review.id]; + + if (typeof review.steps !== 'undefined') { + venue.steps = { + zero: review.steps === 0 ? venue.steps.zero + 1 : venue.steps.zero, + one: review.steps === 1 ? venue.steps.one + 1 : venue.steps.one, + two: review.steps === 2 ? venue.steps.two + 1 : venue.steps.two, + moreThanTwo: + review.steps === 3 + ? venue.steps.moreThanTwo + 1 + : venue.steps.moreThanTwo + }; + } + + let scoring; + //calculate entranceScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('entrance', venue); + //console.log('entrance score: ', scoring); + venue.entranceScore = scoring.ratingLevel; + venue.entranceGlyphs = scoring.ratingGlyphs; + + //calculate interiorScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('interior', venue); + //console.log('interior score: ', scoring); + venue.interiorScore = scoring.ratingLevel; + venue.interiorGlyphs = scoring.ratingGlyphs; + + //calculate restroomScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('restroom', venue); + //console.log('restroom score: ', scoring); + venue.restroomScore = scoring.ratingLevel; + venue.restroomGlyphs = scoring.ratingGlyphs; + + venue.mapMarkerScore = venueReviewSummary.calculateMapMarkerScore( + venue.entranceScore, + venue.interiorScore, + venue.restroomScore + ); + + //console.log('venue: ', venue); + + try { + await venue.save(); + } catch (err) { + console.log( + `Venue ${venue.id} failed to be updated at create-review, at final step` + ); + return next(err); + } + + const dataResponse = { + //new expanded fields + hasPermanentRamp: review.hasPermanentRamp, + hasPortableRamp: req.body.hasPortableRamp, + hasWideEntrance: review.hasWideEntrance, + hasAccessibleTableHeight: review.hasAccessibleTableHeight, + hasAccessibleElevator: review.hasAccessibleElevator, + hasInteriorRamp: review.hasInteriorRamp, + hasSwingOutDoor: review.hasSwingOutDoor, + hasLargeStall: review.hasLargeStall, + hasSupportAroundToilet: review.hasSupportAroundToilet, + hasLoweredSinks: review.hasLoweredSinks, + + /* + entranceScore: review.entranceScore, + entranceGlyph: review.entryGlyph, + interiorScore: review.interiorScore, + interiorGlyph: review.interiorGlyph, + restroomScore: review.restroomScore, + restroomGlyph: review.restroomGlyph, + */ + + //original fields + id: review.id, + allowsGuideDog: review.allowsGuideDog, + //bathroomScore: review.bathroomScore, + comments: review.comments, + //entryScore: review.entryScore, + event: review.event, + hasParking: review.hasParking, + hasSecondEntry: review.hasSecondEntry, + hasWellLit: review.hasWellLit, + isQuiet: review.isQuiet, + isSpacious: review.isSpacious, + steps: review.steps, + team: review.team, + user: review.user, + userReviewFieldsAmount: req.user.reviewFieldsAmount, + userReviewsAmount: req.user.reviewsAmount, + venue: review.venue + }; + return res.status(201).json(dataResponse); +}; diff --git a/src/routes/reviews/edit-review.js b/src/routes/reviews/edit-review.js index dd59ebf..251c2d5 100644 --- a/src/routes/reviews/edit-review.js +++ b/src/routes/reviews/edit-review.js @@ -1,217 +1,217 @@ -const moment = require('moment'); -const { pick } = require('lodash'); - -const { Event } = require('../../models/event'); -const { Review } = require('../../models/review'); -const { Team } = require('../../models/team'); -const { Venue } = require('../../models/venue'); - -const { validateCreateEditReview } = require('./validations'); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - const reviewId = req.params.reviewId; - - let review; - try { - review = await Review.findOne({ _id: reviewId }).select( - '-__v -createdAt -updatedAt' - ); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Review not found' }); - } - - console.log(`Review ${reviewId} failed to be found at edit-review`); - return next(err); - } - - if (!review) { - return res.status(404).json({ general: 'Review not found' }); - } - - if (review.user.toString() !== req.user.id) { - return res - .status(423) - .json({ general: 'You cannot edit someone else review' }); - } - - let venue; - try { - venue = await Venue.findOne({ - _id: review.venue.toString(), - isArchived: false - }); - } catch (err) { - console.log( - `Venue ${review.venue.toString()} failed to be found at edit-review` - ); - return next(err); - } - - if (!venue) { - return res.status(404).json({ general: 'Review venue not found' }); - } - - const data = pick(req.body, [ - //new expanded fields - 'hasPermanentRamp', - 'hasPortableRamp', - 'hasWideEntrance', - 'hasAccessibleTableHeight', - 'hasAccessibleElevator', - 'hasInteriorRamp', - 'hasSwingOutDoor', - 'hasLargeStall', - 'hasSupportAroundToilet', - 'hasLoweredSinks', - - //original fields - //'bathroomScore', - 'comments', - //'entryScore', - 'event', - 'guideDog', - 'parking', - 'quiet', - 'ramp', - 'secondEntry', - 'spacious', - 'steps', - 'team', - 'wellLit' - ]); - const { errors, isValid } = validateCreateEditReview(data); - - if (!isValid) { - return res.status(400).json(errors); - } - - //review.bathroomScore = data.bathroomScore || review.bathroomScore; - review.comments = data.comments || review.comments; - //review.entryScore = data.entryScore || review.entryScore; - - if (data.event) { - let event; - try { - event = await Event.findOne({ _id: data.event }); - } catch (err) { - console.log(`Event ${data.event} failed to be found at edit-review`); - return next(err); - } - - if (!event) { - return res.status(404).json({ event: 'Event not found' }); - } - - if (!event.participants.find(p => p.toString() === req.user.id)) { - return res - .status(400) - .json({ event: 'You are not a participant of this event' }); - } - - const startDate = moment(event.startDate).utc(); - const endDate = moment(event.endDate).utc(); - const today = moment.utc(); - if (startDate.isAfter(today)) { - return res.status(400).json({ event: 'Event has not started yet' }); - } else if (endDate.isBefore(today)) { - return res.status(400).json({ event: 'Event has already finished' }); - } - - review.event = data.event; - } - - review.guideDog = data.guideDog || review.guideDog; - review.parking = data.parking || review.parking; - review.quiet = data.quiet || review.quiet; - review.ramp = data.ramp || review.ramp; - review.secondEntry = data.secondEntry || review.secondEntry; - review.spacious = data.spacious || review.spacious; - - //new expanded fields - review.hasPermanentRamp = data.hasPermanentRamp || review.hasPermanentRamp; - review.hasPortableRamp = data.hasPortableRamp || review.hasPortableRamp; - review.hasWideEntrance = data.hasWideEntrance || review.hasWideEntrance; - review.hasAccessibleTableHeight = - data.hasAccessibleTableHeight || review.hasAccessibleTableHeight; - review.hasAccessibleElevator = - data.hasAccessibleElevator || review.hasAccessibleElevator; - review.hasInteriorRamp = data.hasInteriorRamp || review.hasInteriorRamp; - review.hasSwingOutDoor = data.hasSwingOutDoor || review.hasSwingOutDoor; - review.hasLargeStall = data.hasLargeStall || review.hasLargeStall; - review.hasSupportAroundToilet = - data.hasSupportAroundToilet || review.hasSupportAroundToilet; - review.hasLoweredSinks = data.hasLoweredSinks || review.hasLoweredSinks; - - if (data.steps) { - venue.stepsReviews[review.steps] -= 1; - venue.stepsReviews[data.steps] += 1; - review.steps = data.steps; - } - - if (data.team) { - let team; - try { - team = await Team.findOne({ _id: data.team, isArchived: false }); - } catch (err) { - console.log(`Team ${data.team} failed to be found at edit-review`); - return next(err); - } - - if (!team) { - return res.status(404).json({ team: 'Team not found' }); - } - - if (!team.members.find(m => m.toString() === req.user.id)) { - return res - .status(400) - .json({ team: 'You are not a member of this team' }); - } - - review.team = data.team; - } - - review.wellLit = data.wellLit || review.wellLit; - - review.updatedAt = moment.utc().toDate(); - - try { - await review.save(); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log(`Review ${review.id} failed to be updated at edit-review`); - return next(err); - } - - try { - await venue.save(); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log(`Venue ${venue.id} failed to be updated at edit-review`); - return next(err); - } - - return res.status(200).json(review); -}; +const moment = require('moment'); +const { pick } = require('lodash'); + +const { Event } = require('../../models/event'); +const { Review } = require('../../models/review'); +const { Team } = require('../../models/team'); +const { Venue } = require('../../models/venue'); + +const { validateCreateEditReview } = require('./validations'); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: 'You are blocked' }); + } + + const reviewId = req.params.reviewId; + + let review; + try { + review = await Review.findOne({ _id: reviewId }).select( + '-__v -createdAt -updatedAt' + ); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Review not found' }); + } + + console.log(`Review ${reviewId} failed to be found at edit-review`); + return next(err); + } + + if (!review) { + return res.status(404).json({ general: 'Review not found' }); + } + + if (review.user.toString() !== req.user.id) { + return res + .status(423) + .json({ general: 'You cannot edit someone else review' }); + } + + let venue; + try { + venue = await Venue.findOne({ + _id: review.venue.toString(), + isArchived: false + }); + } catch (err) { + console.log( + `Venue ${review.venue.toString()} failed to be found at edit-review` + ); + return next(err); + } + + if (!venue) { + return res.status(404).json({ general: 'Review venue not found' }); + } + + const data = pick(req.body, [ + //new expanded fields + 'hasPermanentRamp', + 'hasPortableRamp', + 'hasWideEntrance', + 'hasAccessibleTableHeight', + 'hasAccessibleElevator', + 'hasInteriorRamp', + 'hasSwingOutDoor', + 'hasLargeStall', + 'hasSupportAroundToilet', + 'hasLoweredSinks', + + //original fields + //'bathroomScore', + 'comments', + //'entryScore', + 'event', + 'guideDog', + 'parking', + 'quiet', + 'ramp', + 'secondEntry', + 'spacious', + 'steps', + 'team', + 'wellLit' + ]); + const { errors, isValid } = validateCreateEditReview(data); + + if (!isValid) { + return res.status(400).json(errors); + } + + //review.bathroomScore = data.bathroomScore || review.bathroomScore; + review.comments = data.comments || review.comments; + //review.entryScore = data.entryScore || review.entryScore; + + if (data.event) { + let event; + try { + event = await Event.findOne({ _id: data.event }); + } catch (err) { + console.log(`Event ${data.event} failed to be found at edit-review`); + return next(err); + } + + if (!event) { + return res.status(404).json({ event: 'Event not found' }); + } + + if (!event.participants.find((p) => p.toString() === req.user.id)) { + return res + .status(400) + .json({ event: 'You are not a participant of this event' }); + } + + const startDate = moment(event.startDate).utc(); + const endDate = moment(event.endDate).utc(); + const today = moment.utc(); + if (startDate.isAfter(today)) { + return res.status(400).json({ event: 'Event has not started yet' }); + } else if (endDate.isBefore(today)) { + return res.status(400).json({ event: 'Event has already finished' }); + } + + review.event = data.event; + } + + review.guideDog = data.guideDog || review.guideDog; + review.parking = data.parking || review.parking; + review.quiet = data.quiet || review.quiet; + review.ramp = data.ramp || review.ramp; + review.secondEntry = data.secondEntry || review.secondEntry; + review.spacious = data.spacious || review.spacious; + + //new expanded fields + review.hasPermanentRamp = data.hasPermanentRamp || review.hasPermanentRamp; + review.hasPortableRamp = data.hasPortableRamp || review.hasPortableRamp; + review.hasWideEntrance = data.hasWideEntrance || review.hasWideEntrance; + review.hasAccessibleTableHeight = + data.hasAccessibleTableHeight || review.hasAccessibleTableHeight; + review.hasAccessibleElevator = + data.hasAccessibleElevator || review.hasAccessibleElevator; + review.hasInteriorRamp = data.hasInteriorRamp || review.hasInteriorRamp; + review.hasSwingOutDoor = data.hasSwingOutDoor || review.hasSwingOutDoor; + review.hasLargeStall = data.hasLargeStall || review.hasLargeStall; + review.hasSupportAroundToilet = + data.hasSupportAroundToilet || review.hasSupportAroundToilet; + review.hasLoweredSinks = data.hasLoweredSinks || review.hasLoweredSinks; + + if (data.steps) { + venue.stepsReviews[review.steps] -= 1; + venue.stepsReviews[data.steps] += 1; + review.steps = data.steps; + } + + if (data.team) { + let team; + try { + team = await Team.findOne({ _id: data.team, isArchived: false }); + } catch (err) { + console.log(`Team ${data.team} failed to be found at edit-review`); + return next(err); + } + + if (!team) { + return res.status(404).json({ team: 'Team not found' }); + } + + if (!team.members.find((m) => m.toString() === req.user.id)) { + return res + .status(400) + .json({ team: 'You are not a member of this team' }); + } + + review.team = data.team; + } + + review.wellLit = data.wellLit || review.wellLit; + + review.updatedAt = moment.utc().toDate(); + + try { + await review.save(); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log(`Review ${review.id} failed to be updated at edit-review`); + return next(err); + } + + try { + await venue.save(); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log(`Venue ${venue.id} failed to be updated at edit-review`); + return next(err); + } + + return res.status(200).json(review); +}; diff --git a/src/routes/reviews/flag-review.js b/src/routes/reviews/flag-review.js index a92319d..9de8ce9 100644 --- a/src/routes/reviews/flag-review.js +++ b/src/routes/reviews/flag-review.js @@ -1,50 +1,50 @@ -const moment = require('moment'); -const { pick } = require('lodash'); - -const { Review } = require('../../models/review'); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - const reviewId = req.params.reviewId; - - let review; - try { - review = await Review.findOne({ _id: reviewId }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Review not found' }); - } - - console.log(`Review ${reviewId} failed to be found at flag-review`); - return next(err); - } - - if (!review) { - return res.status(404).json({ general: 'Review not found' }); - } - - const data = pick(req.body, ['comments', 'type']); - - review.complaints = [ - ...review.complaints, - { - comments: data.comments, - type: data.type, - user: req.user.id - } - ]; - - review.updatedAt = moment.utc().toDate(); - - try { - await review.save(); - } catch (err) { - console.log(`Review ${review.id} failed to be updated at flag-review`); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); +const { pick } = require('lodash'); + +const { Review } = require('../../models/review'); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: 'You are blocked' }); + } + + const reviewId = req.params.reviewId; + + let review; + try { + review = await Review.findOne({ _id: reviewId }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Review not found' }); + } + + console.log(`Review ${reviewId} failed to be found at flag-review`); + return next(err); + } + + if (!review) { + return res.status(404).json({ general: 'Review not found' }); + } + + const data = pick(req.body, ['comments', 'type']); + + review.complaints = [ + ...review.complaints, + { + comments: data.comments, + type: data.type, + user: req.user.id + } + ]; + + review.updatedAt = moment.utc().toDate(); + + try { + await review.save(); + } catch (err) { + console.log(`Review ${review.id} failed to be updated at flag-review`); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/reviews/index.js b/src/routes/reviews/index.js index 8031f89..df1af41 100644 --- a/src/routes/reviews/index.js +++ b/src/routes/reviews/index.js @@ -1,29 +1,29 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const banReview = require('./ban-review'); -const createReview = require('./create-review'); -const editReview = require('./edit-review'); -const flagReview = require('./flag-review'); -const listReviews = require('./list-reviews'); -const voteReview = require('./vote-review'); - -const router = new express.Router(); - -router.get('', isAuthenticated({ isOptional: false }), listReviews); -router.post('', isAuthenticated({ isOptional: false }), createReview); -router.put('/:reviewId', isAuthenticated({ isOptional: false }), editReview); -router.put( - '/:reviewId/vote', - isAuthenticated({ isOptional: false }), - voteReview -); -router.post( - '/:reviewId/flag', - isAuthenticated({ isOptional: false }), - flagReview -); -router.put('/:reviewId/ban', isAuthenticated({ isOptional: false }), banReview); - -module.exports = router; +const express = require('express'); + +const { isAuthenticated } = require('../../helpers'); + +const banReview = require('./ban-review'); +const createReview = require('./create-review'); +const editReview = require('./edit-review'); +const flagReview = require('./flag-review'); +const listReviews = require('./list-reviews'); +const voteReview = require('./vote-review'); + +const router = new express.Router(); + +router.get('', isAuthenticated({ isOptional: false }), listReviews); +router.post('', isAuthenticated({ isOptional: false }), createReview); +router.put('/:reviewId', isAuthenticated({ isOptional: false }), editReview); +router.put( + '/:reviewId/vote', + isAuthenticated({ isOptional: false }), + voteReview +); +router.post( + '/:reviewId/flag', + isAuthenticated({ isOptional: false }), + flagReview +); +router.put('/:reviewId/ban', isAuthenticated({ isOptional: false }), banReview); + +module.exports = router; diff --git a/src/routes/reviews/list-reviews.js b/src/routes/reviews/list-reviews.js index 9050b45..280601c 100644 --- a/src/routes/reviews/list-reviews.js +++ b/src/routes/reviews/list-reviews.js @@ -1,184 +1,184 @@ -const { toBoolean, toInt } = require('validator'); - -const { Review } = require('../../models/review'); - -const { validateListReviews } = require('./validations'); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - const queryParams = req.query; - const { errors, isValid } = validateListReviews(queryParams); - - if (!isValid) { - return res.status(400).json(errors); - } - - const reviewsQuery = {}; - - if (queryParams.restroomScore) { - //const limits = queryParams.bathroomScore.split(','); - reviewsQuery.bathroomScore = { $gte: toInt(queryParams.bathroomScore) }; - } - - if (queryParams.entranceScore) { - //const limits = queryParams.entryScore.split(','); - reviewsQuery.entranceScore = { $gte: toInt(queryParams.entranceScore) }; - } - - if (queryParams.event) { - reviewsQuery.event = queryParams.event; - } - - if (queryParams.guideDog) { - reviewsQuery.guideDog = toBoolean(queryParams.guideDog); - } - - if (queryParams.parking) { - reviewsQuery.parking = toBoolean(queryParams.parking); - } - - if (queryParams.quiet) { - reviewsQuery.quiet = toBoolean(queryParams.quiet); - } - - if (queryParams.ramp) { - reviewsQuery.ramp = toBoolean(queryParams.ramp); - } - - if (queryParams.secondEntry) { - reviewsQuery.secondEntry = toBoolean(queryParams.secondEntry); - } - - if (queryParams.spacious) { - reviewsQuery.spacious = toBoolean(queryParams.spacious); - } - - if (queryParams.steps) { - reviewsQuery.steps = toInt(queryParams.steps); - } - - if (queryParams.team) { - reviewsQuery.team = queryParams.team; - } - - if (queryParams.user) { - reviewsQuery.user = queryParams.user; - } - - if (queryParams.venue) { - reviewsQuery.venue = queryParams.venue; - } - - if (queryParams.wellLit) { - reviewsQuery.wellLit = toBoolean(queryParams.wellLit); - } - - // - // new expanded fields - // - if (queryParams.hasPermanentRamp) { - reviewsQuery.hasPermanentRamp = toBoolean(queryParams.hasPermanentRamp); - } - - if (queryParams.hasPortableRamp) { - reviewsQuery.hasPortableRamp = toBoolean(queryParams.hasPortableRamp); - } - - if (queryParams.hasWideEntrance) { - reviewsQuery.hasWideEntrance = toBoolean(queryParams.hasWideEntrance); - } - - if (queryParams.hasAccessibleTableHeight) { - reviewsQuery.hasAccessibleTableHeight = toBoolean( - queryParams.hasAccessibleTableHeight - ); - } - - if (queryParams.hasAccessibleElevator) { - reviewsQuery.hasAccessibleElevator = toBoolean( - queryParams.hasAccessibleElevator - ); - } - - if (queryParams.hasInteriorRamp) { - reviewsQuery.hasInteriorRamp = toBoolean(queryParams.hasInteriorRamp); - } - - if (queryParams.hasSwingOutDoor) { - reviewsQuery.hasSwingOutDoor = toBoolean(queryParams.hasSwingOutDoor); - } - - if (queryParams.hasLargeStall) { - reviewsQuery.hasLargeStall = toBoolean(queryParams.hasLargeStall); - } - - if (queryParams.hasSupportAroundToilet) { - reviewsQuery.hasSupportAroundToilet = toBoolean( - queryParams.hasSupportAroundToilet - ); - } - - if (queryParams.hasLoweredSinks) { - reviewsQuery.hasLoweredSinks = toBoolean(queryParams.hasLoweredSinks); - } - - if (queryParams.interiorScore) { - reviewsQuery.interiorScore = { $gte: toInt(queryParams.interiorScore) }; - } - - let page = queryParams.page || 1; - const pageLimit = 18; - - if (page > 0) { - page -= 1; - } else { - return res - .status(400) - .json({ page: 'Should be equal to or greater than 1' }); - } - - let reviews; - let total; - try { - [reviews, total] = await Promise.all([ - Review.find(reviewsQuery) - .select('-__v -updatedAt -createdAt') - .sort('createdAt') - .skip(page * pageLimit) - .limit(pageLimit), - Review.find(reviewsQuery).count() - ]); - } catch (err) { - console.log('Reviews failed to be found or count at list-reviews'); - return next(err); - } - - let first = `${process.env.API_URL}/reviews?page=1`; - const lastPage = Math.ceil(total / pageLimit); - let last = `${process.env.API_URL}/reviews?page=${lastPage}`; - - if (lastPage > 0) { - page += 1; - if (page > lastPage) { - return res - .status(400) - .json({ page: `Should be equal to or less than ${lastPage}` }); - } - } else { - first = null; - last = null; - page = null; - } - - return res.status(200).json({ - first, - last, - page, - pageLimit, - results: reviews, - total - }); -}; +const { toBoolean, toInt } = require('validator'); + +const { Review } = require('../../models/review'); + +const { validateListReviews } = require('./validations'); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: 'You are blocked' }); + } + + const queryParams = req.query; + const { errors, isValid } = validateListReviews(queryParams); + + if (!isValid) { + return res.status(400).json(errors); + } + + const reviewsQuery = {}; + + if (queryParams.restroomScore) { + //const limits = queryParams.bathroomScore.split(','); + reviewsQuery.bathroomScore = { $gte: toInt(queryParams.bathroomScore) }; + } + + if (queryParams.entranceScore) { + //const limits = queryParams.entryScore.split(','); + reviewsQuery.entranceScore = { $gte: toInt(queryParams.entranceScore) }; + } + + if (queryParams.event) { + reviewsQuery.event = queryParams.event; + } + + if (queryParams.guideDog) { + reviewsQuery.guideDog = toBoolean(queryParams.guideDog); + } + + if (queryParams.parking) { + reviewsQuery.parking = toBoolean(queryParams.parking); + } + + if (queryParams.quiet) { + reviewsQuery.quiet = toBoolean(queryParams.quiet); + } + + if (queryParams.ramp) { + reviewsQuery.ramp = toBoolean(queryParams.ramp); + } + + if (queryParams.secondEntry) { + reviewsQuery.secondEntry = toBoolean(queryParams.secondEntry); + } + + if (queryParams.spacious) { + reviewsQuery.spacious = toBoolean(queryParams.spacious); + } + + if (queryParams.steps) { + reviewsQuery.steps = toInt(queryParams.steps); + } + + if (queryParams.team) { + reviewsQuery.team = queryParams.team; + } + + if (queryParams.user) { + reviewsQuery.user = queryParams.user; + } + + if (queryParams.venue) { + reviewsQuery.venue = queryParams.venue; + } + + if (queryParams.wellLit) { + reviewsQuery.wellLit = toBoolean(queryParams.wellLit); + } + + // + // new expanded fields + // + if (queryParams.hasPermanentRamp) { + reviewsQuery.hasPermanentRamp = toBoolean(queryParams.hasPermanentRamp); + } + + if (queryParams.hasPortableRamp) { + reviewsQuery.hasPortableRamp = toBoolean(queryParams.hasPortableRamp); + } + + if (queryParams.hasWideEntrance) { + reviewsQuery.hasWideEntrance = toBoolean(queryParams.hasWideEntrance); + } + + if (queryParams.hasAccessibleTableHeight) { + reviewsQuery.hasAccessibleTableHeight = toBoolean( + queryParams.hasAccessibleTableHeight + ); + } + + if (queryParams.hasAccessibleElevator) { + reviewsQuery.hasAccessibleElevator = toBoolean( + queryParams.hasAccessibleElevator + ); + } + + if (queryParams.hasInteriorRamp) { + reviewsQuery.hasInteriorRamp = toBoolean(queryParams.hasInteriorRamp); + } + + if (queryParams.hasSwingOutDoor) { + reviewsQuery.hasSwingOutDoor = toBoolean(queryParams.hasSwingOutDoor); + } + + if (queryParams.hasLargeStall) { + reviewsQuery.hasLargeStall = toBoolean(queryParams.hasLargeStall); + } + + if (queryParams.hasSupportAroundToilet) { + reviewsQuery.hasSupportAroundToilet = toBoolean( + queryParams.hasSupportAroundToilet + ); + } + + if (queryParams.hasLoweredSinks) { + reviewsQuery.hasLoweredSinks = toBoolean(queryParams.hasLoweredSinks); + } + + if (queryParams.interiorScore) { + reviewsQuery.interiorScore = { $gte: toInt(queryParams.interiorScore) }; + } + + let page = queryParams.page || 1; + const pageLimit = 18; + + if (page > 0) { + page -= 1; + } else { + return res + .status(400) + .json({ page: 'Should be equal to or greater than 1' }); + } + + let reviews; + let total; + try { + [reviews, total] = await Promise.all([ + Review.find(reviewsQuery) + .select('-__v -updatedAt -createdAt') + .sort('createdAt') + .skip(page * pageLimit) + .limit(pageLimit), + Review.find(reviewsQuery).count() + ]); + } catch (err) { + console.log('Reviews failed to be found or count at list-reviews'); + return next(err); + } + + let first = `${process.env.API_URL}/reviews?page=1`; + const lastPage = Math.ceil(total / pageLimit); + let last = `${process.env.API_URL}/reviews?page=${lastPage}`; + + if (lastPage > 0) { + page += 1; + if (page > lastPage) { + return res + .status(400) + .json({ page: `Should be equal to or less than ${lastPage}` }); + } + } else { + first = null; + last = null; + page = null; + } + + return res.status(200).json({ + first, + last, + page, + pageLimit, + results: reviews, + total + }); +}; diff --git a/src/routes/reviews/validations.js b/src/routes/reviews/validations.js index 70ea8cb..5a811de 100644 --- a/src/routes/reviews/validations.js +++ b/src/routes/reviews/validations.js @@ -1,376 +1,376 @@ -const { isEmpty } = require('lodash'); -const { isInt, isMongoId } = require('validator'); - -module.exports = { - validateCreateEditReview(data) { - const errors = {}; - - // - // new expanded fields - // - if ( - typeof data.hasPermanentRamp !== 'undefined' && - typeof data.hasPermanentRamp !== 'boolean' - ) { - errors.hasPermanentRamp = 'Should be a boolean'; - } - - if ( - typeof data.hasPortableRamp !== 'undefined' && - typeof data.hasPortableRamp !== 'boolean' - ) { - errors.hasPortableRamp = 'Should be a boolean'; - } - - if ( - typeof data.hasWideEntrance !== 'undefined' && - typeof data.hasWideEntrance !== 'boolean' - ) { - errors.hasWideEntrance = 'Should be a boolean'; - } - - if ( - typeof data.hasAccessibleTableHeight !== 'undefined' && - typeof data.hasAccessibleTableHeight !== 'boolean' - ) { - errors.hasAccessibleTableHeight = 'Should be a boolean'; - } - - if ( - typeof data.hasAccessibleElevator !== 'undefined' && - typeof data.hasAccessibleElevator !== 'boolean' - ) { - errors.hasAccessibleElevator = 'Should be a boolean'; - } - - if ( - typeof data.hasInteriorRamp !== 'undefined' && - typeof data.hasInteriorRamp !== 'boolean' - ) { - errors.hasInteriorRamp = 'Should be a boolean'; - } - - if ( - typeof data.hasSwingOutDoor !== 'undefined' && - typeof data.hasSwingOutDoor !== 'boolean' - ) { - errors.hasSwingOutDoor = 'Should be a boolean'; - } - - if ( - typeof data.hasLargeStall !== 'undefined' && - typeof data.hasLargeStall !== 'boolean' - ) { - errors.hasLargeStall = 'Should be a boolean'; - } - - if ( - typeof data.hasSupportAroundToilet !== 'undefined' && - typeof data.hasSupportAroundToilet !== 'boolean' - ) { - errors.hasSupportAroundToilet = 'Should be a boolean'; - } - - if ( - typeof data.hasLoweredSinks !== 'undefined' && - typeof data.hasLoweredSinks !== 'boolean' - ) { - errors.hasLoweredSinks = 'Should be a boolean'; - } - - /* - *interiorScore - if (typeof data.interiorScore !== 'undefined') { - if (typeof data.interiorScore !== 'number') { - errors.interiorScore = 'Should be a number'; - } else if (data.interiorScore < 1 || data.interiorScore > 7) { - //Remove required interiorScore - //errors.interiorScore = 'Should be between 1 and 7'; - } - } - */ - - // - //original fields - // - if ( - typeof data.allowsGuideDog !== 'undefined' && - typeof data.allowsGuideDog !== 'boolean' - ) { - errors.allowsGuideDog = 'Should be a boolean'; - } - - /* - * bathroomScore - if (typeof data.bathroomScore !== 'undefined') { - if (typeof data.bathroomScore !== 'number') { - errors.bathroomScore = 'Should be a number'; - } else if (data.bathroomScore < 1 || data.bathroomScore > 4) { - //Remove required entryScore - //errors.bathroomScore = 'Should be between 1 and 4'; - } - } - */ - - if (data.comments && typeof data.comments !== 'string') { - errors.comments = 'Should be a string'; - } - - /* - * entryScore - if (typeof data.entryScore === 'undefined') { - //Remove required entryScore - //errors.entryScore = 'Is required'; - } else if (typeof data.entryScore !== 'number') { - errors.entryScore = 'Should be a number'; - } else if (data.entryScore < 1 || data.entryScore > 9) { - //Remove required entryScore - //errors.entryScore = 'Should be between 1 and 9'; - } - */ - - if (data.event) { - if (typeof data.event !== 'string') { - errors.event = 'Should be a string'; - } else if (!isMongoId(data.event)) { - errors.event = 'Should be a valid id'; - } - } - - if ( - typeof data.hasParking !== 'undefined' && - typeof data.hasParking !== 'boolean' - ) { - errors.hasParking = 'Should be a boolean'; - } - - if ( - typeof data.hasSecondEntry !== 'undefined' && - typeof data.hasSecondEntry !== 'boolean' - ) { - errors.hasSecondEntry = 'Should be a boolean'; - } - - if ( - typeof data.hasWellLit !== 'undefined' && - typeof data.hasWellLit !== 'boolean' - ) { - errors.hasWellLit = 'Should be a boolean'; - } - - if ( - typeof data.isQuiet !== 'undefined' && - typeof data.isQuiet !== 'boolean' - ) { - errors.isQuiet = 'Should be a boolean'; - } - - if ( - typeof data.isSpacious !== 'undefined' && - typeof data.isSpacious !== 'boolean' - ) { - errors.isSpacious = 'Should be a boolean'; - } - - if (typeof data.photo !== 'undefined' && typeof data.photo !== 'string') { - errors.photo = 'Should be a string'; - } - - if (!data.place) { - errors.place = 'Is required'; - } else if (typeof data.place !== 'string') { - errors.place = 'Should be a string'; - } - - if (typeof data.steps !== 'undefined') { - if (typeof data.steps !== 'number') { - errors.steps = 'Should be a number'; - } else if (data.steps < 0 || data.steps > 3) { - errors.steps = 'Should be between 0 and 3'; - } - } - - if (data.team) { - if (typeof data.team !== 'string') { - errors.team = 'Should be a string'; - } else if (!isMongoId(data.team)) { - errors.team = 'Should be a valid id'; - } - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateListReviews(queryParams) { - const errors = {}; - - //Remove bathroomScore validation - if (queryParams.bathroomScore) { - /* - const limits = queryParams.bathroomScore.split(','); - - if (limits.length !== 2) { - errors.bathroomScore = 'Should be two integers split by a comma'; - } else if ( - !isInt(limits[0], { min: 1, max: 4 }) || - !isInt(limits[1], { min: 1, max: 4 }) - ) { - errors.bathroomScore = 'Both should be integers between 1 and 4'; - } - */ - } - - //Remove entryScore validation - if (queryParams.entryScore) { - /* - const limits = queryParams.entryScore.split(','); - - if (limits.length !== 2) { - errors.entryScore = 'Should be two integers split by a comma'; - } else if ( - !isInt(limits[0], { min: 1, max: 9 }) || - !isInt(limits[1], { min: 1, max: 9 }) - ) { - errors.entryScore = 'Both should be integers between 1 and 9'; - } - */ - } - - if (queryParams.event && !isMongoId(queryParams.event)) { - errors.event = 'Should be a valid Id'; - } - - if ( - queryParams.guideDog && - !isInt(queryParams.guideDog, { min: 0, max: 1 }) - ) { - errors.guideDog = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.parking && - !isInt(queryParams.parking, { min: 0, max: 1 }) - ) { - errors.parking = 'Should be an integer between 0 and 1'; - } - - if (queryParams.quiet && !isInt(queryParams.quiet, { min: 0, max: 1 })) { - errors.quiet = 'Should be an integer between 0 and 1'; - } - - if (queryParams.ramp && !isInt(queryParams.ramp, { min: 0, max: 1 })) { - errors.ramp = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.secondEntry && - !isInt(queryParams.secondEntry, { min: 0, max: 1 }) - ) { - errors.secondEntry = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.spacious && - !isInt(queryParams.spacious, { min: 0, max: 1 }) - ) { - errors.spacious = 'Should be an integer between 0 and 1'; - } - - if (queryParams.steps && !isInt(queryParams.steps, { min: 0, max: 3 })) { - errors.steps = 'Should be an integer between 0 and 3'; - } - - if (queryParams.team && !isMongoId(queryParams.team)) { - errors.team = 'Should be a valid Id'; - } - - if (queryParams.user && !isMongoId(queryParams.user)) { - errors.user = 'Should be a valid Id'; - } - - if (queryParams.venue && !isMongoId(queryParams.venue)) { - errors.venue = 'Should be a valid Id'; - } - - if ( - queryParams.wellLit && - !isInt(queryParams.wellLit, { min: 0, max: 1 }) - ) { - errors.wellLit = 'Should be an integer between 0 and 1'; - } - - // - // new expanded fields - // - if ( - queryParams.hasPermanentRamp && - !isInt(queryParams.hasPermanentRamp, { min: 0, max: 1 }) - ) { - errors.hasPermanentRamp = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasPortableRamp && - !isInt(queryParams.hasPortableRamp, { min: 0, max: 1 }) - ) { - errors.hasPortableRamp = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasWideEntrance && - !isInt(queryParams.hasWideEntrance, { min: 0, max: 1 }) - ) { - errors.hasWideEntrance = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasAccessibleTableHeight && - !isInt(queryParams.hasAccessibleTableHeight, { min: 0, max: 1 }) - ) { - errors.hasAccessibleTableHeight = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasAccessibleElevator && - !isInt(queryParams.hasAccessibleElevator, { min: 0, max: 1 }) - ) { - errors.hasAccessibleElevator = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasInteriorRamp && - !isInt(queryParams.hasInteriorRamp, { min: 0, max: 1 }) - ) { - errors.hasInteriorRamp = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasSwingOutDoor && - !isInt(queryParams.hasSwingOutDoor, { min: 0, max: 1 }) - ) { - errors.hasSwingOutDoor = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasLargeStall && - !isInt(queryParams.hasLargeStall, { min: 0, max: 1 }) - ) { - errors.hasLargeStall = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasSupportAroundToilet && - !isInt(queryParams.hasSupportAroundToilet, { min: 0, max: 1 }) - ) { - errors.hasSupportAroundToilet = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasLoweredSinks && - !isInt(queryParams.hasLoweredSinks, { min: 0, max: 1 }) - ) { - errors.hasLoweredSinks = 'Should be an integer between 0 and 1'; - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const { isEmpty } = require('lodash'); +const { isInt, isMongoId } = require('validator'); + +module.exports = { + validateCreateEditReview(data) { + const errors = {}; + + // + // new expanded fields + // + if ( + typeof data.hasPermanentRamp !== 'undefined' && + typeof data.hasPermanentRamp !== 'boolean' + ) { + errors.hasPermanentRamp = 'Should be a boolean'; + } + + if ( + typeof data.hasPortableRamp !== 'undefined' && + typeof data.hasPortableRamp !== 'boolean' + ) { + errors.hasPortableRamp = 'Should be a boolean'; + } + + if ( + typeof data.hasWideEntrance !== 'undefined' && + typeof data.hasWideEntrance !== 'boolean' + ) { + errors.hasWideEntrance = 'Should be a boolean'; + } + + if ( + typeof data.hasAccessibleTableHeight !== 'undefined' && + typeof data.hasAccessibleTableHeight !== 'boolean' + ) { + errors.hasAccessibleTableHeight = 'Should be a boolean'; + } + + if ( + typeof data.hasAccessibleElevator !== 'undefined' && + typeof data.hasAccessibleElevator !== 'boolean' + ) { + errors.hasAccessibleElevator = 'Should be a boolean'; + } + + if ( + typeof data.hasInteriorRamp !== 'undefined' && + typeof data.hasInteriorRamp !== 'boolean' + ) { + errors.hasInteriorRamp = 'Should be a boolean'; + } + + if ( + typeof data.hasSwingOutDoor !== 'undefined' && + typeof data.hasSwingOutDoor !== 'boolean' + ) { + errors.hasSwingOutDoor = 'Should be a boolean'; + } + + if ( + typeof data.hasLargeStall !== 'undefined' && + typeof data.hasLargeStall !== 'boolean' + ) { + errors.hasLargeStall = 'Should be a boolean'; + } + + if ( + typeof data.hasSupportAroundToilet !== 'undefined' && + typeof data.hasSupportAroundToilet !== 'boolean' + ) { + errors.hasSupportAroundToilet = 'Should be a boolean'; + } + + if ( + typeof data.hasLoweredSinks !== 'undefined' && + typeof data.hasLoweredSinks !== 'boolean' + ) { + errors.hasLoweredSinks = 'Should be a boolean'; + } + + /* + *interiorScore + if (typeof data.interiorScore !== 'undefined') { + if (typeof data.interiorScore !== 'number') { + errors.interiorScore = 'Should be a number'; + } else if (data.interiorScore < 1 || data.interiorScore > 7) { + //Remove required interiorScore + //errors.interiorScore = 'Should be between 1 and 7'; + } + } + */ + + // + //original fields + // + if ( + typeof data.allowsGuideDog !== 'undefined' && + typeof data.allowsGuideDog !== 'boolean' + ) { + errors.allowsGuideDog = 'Should be a boolean'; + } + + /* + * bathroomScore + if (typeof data.bathroomScore !== 'undefined') { + if (typeof data.bathroomScore !== 'number') { + errors.bathroomScore = 'Should be a number'; + } else if (data.bathroomScore < 1 || data.bathroomScore > 4) { + //Remove required entryScore + //errors.bathroomScore = 'Should be between 1 and 4'; + } + } + */ + + if (data.comments && typeof data.comments !== 'string') { + errors.comments = 'Should be a string'; + } + + /* + * entryScore + if (typeof data.entryScore === 'undefined') { + //Remove required entryScore + //errors.entryScore = 'Is required'; + } else if (typeof data.entryScore !== 'number') { + errors.entryScore = 'Should be a number'; + } else if (data.entryScore < 1 || data.entryScore > 9) { + //Remove required entryScore + //errors.entryScore = 'Should be between 1 and 9'; + } + */ + + if (data.event) { + if (typeof data.event !== 'string') { + errors.event = 'Should be a string'; + } else if (!isMongoId(data.event)) { + errors.event = 'Should be a valid id'; + } + } + + if ( + typeof data.hasParking !== 'undefined' && + typeof data.hasParking !== 'boolean' + ) { + errors.hasParking = 'Should be a boolean'; + } + + if ( + typeof data.hasSecondEntry !== 'undefined' && + typeof data.hasSecondEntry !== 'boolean' + ) { + errors.hasSecondEntry = 'Should be a boolean'; + } + + if ( + typeof data.hasWellLit !== 'undefined' && + typeof data.hasWellLit !== 'boolean' + ) { + errors.hasWellLit = 'Should be a boolean'; + } + + if ( + typeof data.isQuiet !== 'undefined' && + typeof data.isQuiet !== 'boolean' + ) { + errors.isQuiet = 'Should be a boolean'; + } + + if ( + typeof data.isSpacious !== 'undefined' && + typeof data.isSpacious !== 'boolean' + ) { + errors.isSpacious = 'Should be a boolean'; + } + + if (typeof data.photo !== 'undefined' && typeof data.photo !== 'string') { + errors.photo = 'Should be a string'; + } + + if (!data.place) { + errors.place = 'Is required'; + } else if (typeof data.place !== 'string') { + errors.place = 'Should be a string'; + } + + if (typeof data.steps !== 'undefined') { + if (typeof data.steps !== 'number') { + errors.steps = 'Should be a number'; + } else if (data.steps < 0 || data.steps > 3) { + errors.steps = 'Should be between 0 and 3'; + } + } + + if (data.team) { + if (typeof data.team !== 'string') { + errors.team = 'Should be a string'; + } else if (!isMongoId(data.team)) { + errors.team = 'Should be a valid id'; + } + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateListReviews(queryParams) { + const errors = {}; + + //Remove bathroomScore validation + if (queryParams.bathroomScore) { + /* + const limits = queryParams.bathroomScore.split(','); + + if (limits.length !== 2) { + errors.bathroomScore = 'Should be two integers split by a comma'; + } else if ( + !isInt(limits[0], { min: 1, max: 4 }) || + !isInt(limits[1], { min: 1, max: 4 }) + ) { + errors.bathroomScore = 'Both should be integers between 1 and 4'; + } + */ + } + + //Remove entryScore validation + if (queryParams.entryScore) { + /* + const limits = queryParams.entryScore.split(','); + + if (limits.length !== 2) { + errors.entryScore = 'Should be two integers split by a comma'; + } else if ( + !isInt(limits[0], { min: 1, max: 9 }) || + !isInt(limits[1], { min: 1, max: 9 }) + ) { + errors.entryScore = 'Both should be integers between 1 and 9'; + } + */ + } + + if (queryParams.event && !isMongoId(queryParams.event)) { + errors.event = 'Should be a valid Id'; + } + + if ( + queryParams.guideDog && + !isInt(queryParams.guideDog, { min: 0, max: 1 }) + ) { + errors.guideDog = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.parking && + !isInt(queryParams.parking, { min: 0, max: 1 }) + ) { + errors.parking = 'Should be an integer between 0 and 1'; + } + + if (queryParams.quiet && !isInt(queryParams.quiet, { min: 0, max: 1 })) { + errors.quiet = 'Should be an integer between 0 and 1'; + } + + if (queryParams.ramp && !isInt(queryParams.ramp, { min: 0, max: 1 })) { + errors.ramp = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.secondEntry && + !isInt(queryParams.secondEntry, { min: 0, max: 1 }) + ) { + errors.secondEntry = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.spacious && + !isInt(queryParams.spacious, { min: 0, max: 1 }) + ) { + errors.spacious = 'Should be an integer between 0 and 1'; + } + + if (queryParams.steps && !isInt(queryParams.steps, { min: 0, max: 3 })) { + errors.steps = 'Should be an integer between 0 and 3'; + } + + if (queryParams.team && !isMongoId(queryParams.team)) { + errors.team = 'Should be a valid Id'; + } + + if (queryParams.user && !isMongoId(queryParams.user)) { + errors.user = 'Should be a valid Id'; + } + + if (queryParams.venue && !isMongoId(queryParams.venue)) { + errors.venue = 'Should be a valid Id'; + } + + if ( + queryParams.wellLit && + !isInt(queryParams.wellLit, { min: 0, max: 1 }) + ) { + errors.wellLit = 'Should be an integer between 0 and 1'; + } + + // + // new expanded fields + // + if ( + queryParams.hasPermanentRamp && + !isInt(queryParams.hasPermanentRamp, { min: 0, max: 1 }) + ) { + errors.hasPermanentRamp = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasPortableRamp && + !isInt(queryParams.hasPortableRamp, { min: 0, max: 1 }) + ) { + errors.hasPortableRamp = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasWideEntrance && + !isInt(queryParams.hasWideEntrance, { min: 0, max: 1 }) + ) { + errors.hasWideEntrance = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasAccessibleTableHeight && + !isInt(queryParams.hasAccessibleTableHeight, { min: 0, max: 1 }) + ) { + errors.hasAccessibleTableHeight = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasAccessibleElevator && + !isInt(queryParams.hasAccessibleElevator, { min: 0, max: 1 }) + ) { + errors.hasAccessibleElevator = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasInteriorRamp && + !isInt(queryParams.hasInteriorRamp, { min: 0, max: 1 }) + ) { + errors.hasInteriorRamp = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasSwingOutDoor && + !isInt(queryParams.hasSwingOutDoor, { min: 0, max: 1 }) + ) { + errors.hasSwingOutDoor = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasLargeStall && + !isInt(queryParams.hasLargeStall, { min: 0, max: 1 }) + ) { + errors.hasLargeStall = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasSupportAroundToilet && + !isInt(queryParams.hasSupportAroundToilet, { min: 0, max: 1 }) + ) { + errors.hasSupportAroundToilet = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasLoweredSinks && + !isInt(queryParams.hasLoweredSinks, { min: 0, max: 1 }) + ) { + errors.hasLoweredSinks = 'Should be an integer between 0 and 1'; + } + + return { errors, isValid: isEmpty(errors) }; + } +}; diff --git a/src/routes/reviews/vote-review.js b/src/routes/reviews/vote-review.js index dbd8b6c..e3e9472 100644 --- a/src/routes/reviews/vote-review.js +++ b/src/routes/reviews/vote-review.js @@ -1,49 +1,49 @@ -const moment = require('moment'); - -const { Review } = require('../../models/review'); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - const reviewId = req.params.reviewId; - - let review; - try { - review = await Review.findOne({ _id: reviewId }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Review not found' }); - } - - console.log(`Review ${reviewId} failed to be found at vote-review`); - return next(err); - } - - if (!review) { - return res.status(404).json({ general: 'Review not found' }); - } - - let addVote = true; - - if (review.voters.find(v => v.toString() === req.user.id)) { - review.voters = review.voters.filter(v => v.toString() !== req.user.id); - addVote = false; - } else { - review.voters = [...review.voters, req.user.id]; - } - - review.updatedAt = moment.utc().toDate(); - - try { - await review.save(); - } catch (err) { - console.log(`Review ${review.id} failed to be updated at vote-review`); - return next(err); - } - - return res - .status(200) - .json({ general: addVote ? 'One more vote' : 'One less vote' }); -}; +const moment = require('moment'); + +const { Review } = require('../../models/review'); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: 'You are blocked' }); + } + + const reviewId = req.params.reviewId; + + let review; + try { + review = await Review.findOne({ _id: reviewId }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Review not found' }); + } + + console.log(`Review ${reviewId} failed to be found at vote-review`); + return next(err); + } + + if (!review) { + return res.status(404).json({ general: 'Review not found' }); + } + + let addVote = true; + + if (review.voters.find((v) => v.toString() === req.user.id)) { + review.voters = review.voters.filter((v) => v.toString() !== req.user.id); + addVote = false; + } else { + review.voters = [...review.voters, req.user.id]; + } + + review.updatedAt = moment.utc().toDate(); + + try { + await review.save(); + } catch (err) { + console.log(`Review ${review.id} failed to be updated at vote-review`); + return next(err); + } + + return res + .status(200) + .json({ general: addVote ? 'One more vote' : 'One less vote' }); +}; diff --git a/src/routes/teams/create-team.js b/src/routes/teams/create-team.js index a40dc19..799bdfe 100644 --- a/src/routes/teams/create-team.js +++ b/src/routes/teams/create-team.js @@ -1,93 +1,93 @@ -const { cleanSpaces } = require('../../helpers'); -const { Photo } = require('../../models/photo'); -const { Team } = require('../../models/team'); - -const { validateCreateTeam } = require('./validations'); - -module.exports = async (req, res, next) => { - const data = { - avatar: req.body.avatar, - description: req.body.description, - name: req.body.name - }; - - const { errors, isValid } = validateCreateTeam(data); - if (!isValid) return res.status(400).json(errors); - - if (data.avatar) { - let avatar; - try { - avatar = await Photo.findOne({ url: data.avatar }); - } catch (err) { - console.log(`Avatar ${data.avatar} failed to be found at create-team`); - return next(err); - } - - if (!avatar) { - return res.status(404).json({ avatar: 'Not found' }); - } - } - - data.managers = [req.user.id]; - - data.name = cleanSpaces(data.name); - - let repeatedTeam; - try { - repeatedTeam = await Team.findOne({ name: data.name, isArchived: false }); - } catch (err) { - console.log(`Team ${data.name} failed to be found at create-team`); - return next(err); - } - - if (repeatedTeam) { - return res.status(400).json({ name: 'Is already taken' }); - } - - let team; - try { - team = await Team.create(data); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `Team ${ - data.name - } failed to be created at create-team.\nData: ${JSON.stringify(data)}` - ); - return next(err); - } - - req.user.teams = [...req.user.teams, team.id]; - - try { - await req.user.save(); - } catch (err) { - console.log(`User ${req.user.id} failed to be updated at create-team`); - return next(err); - } - - const dataResponse = { - id: team.id, - avatar: team.avatar, - description: team.description, - managers: [ - { - id: req.user.id, - avatar: req.user.avatar, - name: `${req.user.firstName} ${req.user.lastName}` - } - ], - name: team.name - }; - - return res.status(201).json(dataResponse); -}; +const { cleanSpaces } = require('../../helpers'); +const { Photo } = require('../../models/photo'); +const { Team } = require('../../models/team'); + +const { validateCreateTeam } = require('./validations'); + +module.exports = async (req, res, next) => { + const data = { + avatar: req.body.avatar, + description: req.body.description, + name: req.body.name + }; + + const { errors, isValid } = validateCreateTeam(data); + if (!isValid) return res.status(400).json(errors); + + if (data.avatar) { + let avatar; + try { + avatar = await Photo.findOne({ url: data.avatar }); + } catch (err) { + console.log(`Avatar ${data.avatar} failed to be found at create-team`); + return next(err); + } + + if (!avatar) { + return res.status(404).json({ avatar: 'Not found' }); + } + } + + data.managers = [req.user.id]; + + data.name = cleanSpaces(data.name); + + let repeatedTeam; + try { + repeatedTeam = await Team.findOne({ name: data.name, isArchived: false }); + } catch (err) { + console.log(`Team ${data.name} failed to be found at create-team`); + return next(err); + } + + if (repeatedTeam) { + return res.status(400).json({ name: 'Is already taken' }); + } + + let team; + try { + team = await Team.create(data); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `Team ${ + data.name + } failed to be created at create-team.\nData: ${JSON.stringify(data)}` + ); + return next(err); + } + + req.user.teams = [...req.user.teams, team.id]; + + try { + await req.user.save(); + } catch (err) { + console.log(`User ${req.user.id} failed to be updated at create-team`); + return next(err); + } + + const dataResponse = { + id: team.id, + avatar: team.avatar, + description: team.description, + managers: [ + { + id: req.user.id, + avatar: req.user.avatar, + name: `${req.user.firstName} ${req.user.lastName}` + } + ], + name: team.name + }; + + return res.status(201).json(dataResponse); +}; diff --git a/src/routes/teams/delete-team.js b/src/routes/teams/delete-team.js index 0bf3431..912b7a1 100644 --- a/src/routes/teams/delete-team.js +++ b/src/routes/teams/delete-team.js @@ -1,115 +1,115 @@ -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { Team } = require('../../models/team'); -const { User } = require('../../models/user'); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - const teamId = req.params.teamId; - - let team; - try { - team = await Team.findOne({ _id: teamId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Team not found' }); - } - - console.log(`Team ${teamId} failed to be found at delete-team`); - return next(err); - } - - if (!team) { - return res.status(404).json({ general: 'Team not found' }); - } - - if ( - !team.managers.find(m => m.toString() === req.user.id) && - !req.user.isAdmin - ) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - let archiveTeam = false; - - if (team.events && team.events.length > 0) { - const teamEventsPromises = team.events.map(e => - Event.findOne({ _id: e.toString() }) - ); - - let teamEvents; - try { - teamEvents = await Promise.all(teamEventsPromises); - } catch (err) { - console.log('A team event failed to be found at delete-team'); - return next(err); - } - - for (const event of teamEvents) { - const endDate = moment(event.endDate).utc(); - const endOfToday = moment.utc().endOf('day'); - if (endDate.isBefore(endOfToday)) { - event.teams = event.teams.filter(t => t.toString() !== team.id); - event.updatedAt = moment.utc().toDate(); - - try { - await event.save(); - } catch (err) { - console.log(`Event ${event.id} failed to be updated at delete-team`); - return next(err); - } - } else { - archiveTeam = true; - } - } - } - - const teamMembersPromises = team.members.map(m => - User.findOne({ _id: m.toString() }) - ); - - let teamMembers; - try { - teamMembers = await Promise.all(teamMembersPromises); - } catch (err) { - console.log('A team member failed to be found at delete-team'); - return next(err); - } - - for (const member of teamMembers) { - member.teams = member.teams.filter(t => t.toString() !== team.id); - member.updatedAt = moment.utc().toDate(); - - try { - await member.save(); - } catch (err) { - console.log(`Member ${member.id} failed to be updated at delete-team`); - return next(err); - } - } - - if (archiveTeam) { - team.isArchived = true; - team.updatedAt = moment.utc().toDate(); - - try { - await team.save(); - } catch (err) { - console.log(`Team ${team.id} failed to be updated at delete-team`); - return next(err); - } - } else { - try { - await team.remove(); - } catch (err) { - console.log(`Team ${team.id} failed to be removed at delete-team`); - return next(err); - } - } - - return res.status(204).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { Event } = require('../../models/event'); +const { Team } = require('../../models/team'); +const { User } = require('../../models/user'); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: 'You are blocked' }); + } + + const teamId = req.params.teamId; + + let team; + try { + team = await Team.findOne({ _id: teamId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Team not found' }); + } + + console.log(`Team ${teamId} failed to be found at delete-team`); + return next(err); + } + + if (!team) { + return res.status(404).json({ general: 'Team not found' }); + } + + if ( + !team.managers.find((m) => m.toString() === req.user.id) && + !req.user.isAdmin + ) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + let archiveTeam = false; + + if (team.events && team.events.length > 0) { + const teamEventsPromises = team.events.map((e) => + Event.findOne({ _id: e.toString() }) + ); + + let teamEvents; + try { + teamEvents = await Promise.all(teamEventsPromises); + } catch (err) { + console.log('A team event failed to be found at delete-team'); + return next(err); + } + + for (const event of teamEvents) { + const endDate = moment(event.endDate).utc(); + const endOfToday = moment.utc().endOf('day'); + if (endDate.isBefore(endOfToday)) { + event.teams = event.teams.filter((t) => t.toString() !== team.id); + event.updatedAt = moment.utc().toDate(); + + try { + await event.save(); + } catch (err) { + console.log(`Event ${event.id} failed to be updated at delete-team`); + return next(err); + } + } else { + archiveTeam = true; + } + } + } + + const teamMembersPromises = team.members.map((m) => + User.findOne({ _id: m.toString() }) + ); + + let teamMembers; + try { + teamMembers = await Promise.all(teamMembersPromises); + } catch (err) { + console.log('A team member failed to be found at delete-team'); + return next(err); + } + + for (const member of teamMembers) { + member.teams = member.teams.filter((t) => t.toString() !== team.id); + member.updatedAt = moment.utc().toDate(); + + try { + await member.save(); + } catch (err) { + console.log(`Member ${member.id} failed to be updated at delete-team`); + return next(err); + } + } + + if (archiveTeam) { + team.isArchived = true; + team.updatedAt = moment.utc().toDate(); + + try { + await team.save(); + } catch (err) { + console.log(`Team ${team.id} failed to be updated at delete-team`); + return next(err); + } + } else { + try { + await team.remove(); + } catch (err) { + console.log(`Team ${team.id} failed to be removed at delete-team`); + return next(err); + } + } + + return res.status(204).json({ general: 'Success' }); +}; diff --git a/src/routes/teams/edit-team.js b/src/routes/teams/edit-team.js index 0afd345..dbbedb4 100644 --- a/src/routes/teams/edit-team.js +++ b/src/routes/teams/edit-team.js @@ -1,205 +1,205 @@ -const { difference, intersection } = require('lodash'); -const moment = require('moment'); - -const { cleanSpaces } = require('../../helpers'); -const { Photo } = require('../../models/photo'); -const { Team } = require('../../models/team'); -const { User } = require('../../models/user'); - -const { validateEditTeam } = require('./validations'); - -module.exports = async (req, res, next) => { - const teamId = req.params.teamId; - - let team; - try { - team = await Team.findOne({ _id: teamId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Team not found' }); - } - - console.log(`Team ${teamId} failed to be found at edit-team`); - return next(err); - } - - if (!team) { - return res.status(404).json({ general: 'Team not found' }); - } - - if ( - !team.managers.find(m => m.toString() === req.user.id) && - !req.user.isAdmin - ) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const data = { - avatar: req.body.avatar, - description: req.body.description, - managers: req.body.managers, - members: req.body.members, - name: req.body.name - }; - const { errors, isValid } = validateEditTeam(data); - if (!isValid) return res.status(400).json(errors); - - if ( - data.avatar && - !data.avatar.includes('default') && - data.avatar !== team.avatar - ) { - let avatar; - try { - avatar = await Photo.findOne({ url: data.avatar }); - } catch (err) { - console.log(`Avatar ${data.avatar} failed to be found at edit-team`); - return next(err); - } - - if (!avatar) { - return res.status(404).json({ avatar: 'Not found' }); - } - - team.avatar = data.avatar; - } else if (data.avatar === '') { - team.avatar = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/teams/avatars/default.png`; - } - - team.description = data.description || team.description; - - if (data.managers) { - let managersToAdd = []; - let managersToRemove = []; - - data.managers.forEach(m => { - if (m.startsWith('-')) { - managersToRemove = [...managersToRemove, m.substring(1)]; - } else { - managersToAdd = [...managersToAdd, m]; - } - }); - - const teamManagers = team.managers.map(m => m.toString()); - - managersToAdd = [...new Set(difference(managersToAdd, teamManagers))]; - if (managersToAdd.length > 0) { - const teamMembers = team.members.map(m => m.toString()); - const notMember = managersToAdd.find(m => !teamMembers.includes(m)); - - if (notMember) { - return res - .status(400) - .json({ managers: `User ${notMember} is not a member of this team` }); - } - - team.managers = [...teamManagers, ...managersToAdd]; - team.members = team.members.filter( - m => !managersToAdd.includes(m.toString()) - ); - } - - managersToRemove = [ - ...new Set(intersection(managersToRemove, teamManagers)) - ]; - if (managersToRemove.length === team.managers.length) { - return res - .status(400) - .json({ managers: 'Should not remove all managers' }); - } - - team.managers = team.managers.filter( - m => !managersToRemove.includes(m.toString()) - ); - const teamMembers = team.members.map(m => m.toString()); - team.members = [...teamMembers, ...managersToRemove]; - } - - if (data.members) { - const teamMembers = team.members.map(m => m.toString()); - let membersToRemove = data.members.map(m => m.substring(1)); - membersToRemove = [...new Set(intersection(membersToRemove, teamMembers))]; - - const getMembers = membersToRemove.map(m => - User.find({ _id: m, isArchived: false }) - ); - let members; - try { - members = await Promise.all(getMembers); - } catch (err) { - console.log(`Members failed to be found at edit-team`); - return next(err); - } - - const updateMembers = members.map((m, i) => { - m[i].teams = m[i].teams.filter(t => t.toString() !== team.id); - return m[i].save(); - }); - - try { - await Promise.all(updateMembers); - } catch (err) { - console.log(`Members failed to be updated at edit-team`); - return next(err); - } - - team.members = team.members.filter( - m => !membersToRemove.includes(m.toString()) - ); - } - - if (data.name) { - const teamName = cleanSpaces(data.name); - - if (teamName !== team.name) { - let repeatedTeam; - try { - repeatedTeam = await Team.findOne({ - name: teamName, - isArchived: false - }); - } catch (err) { - console.log(`Team ${teamName} failed to be found at edit-team`); - return next(err); - } - - if (repeatedTeam) { - return res.status(400).json({ name: 'Is already taken' }); - } - - team.name = teamName; - } - } - - team.updatedAt = moment.utc().toDate(); - - try { - await team.save(); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log(`Team ${team.id} failed to be updated at edit-team`); - return next(err); - } - - const dataResponse = { - id: team.id, - avatar: team.avatar, - description: team.description, - managers: team.managers, - members: team.members, - name: team.name - }; - - return res.status(200).json(dataResponse); -}; +const { difference, intersection } = require('lodash'); +const moment = require('moment'); + +const { cleanSpaces } = require('../../helpers'); +const { Photo } = require('../../models/photo'); +const { Team } = require('../../models/team'); +const { User } = require('../../models/user'); + +const { validateEditTeam } = require('./validations'); + +module.exports = async (req, res, next) => { + const teamId = req.params.teamId; + + let team; + try { + team = await Team.findOne({ _id: teamId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Team not found' }); + } + + console.log(`Team ${teamId} failed to be found at edit-team`); + return next(err); + } + + if (!team) { + return res.status(404).json({ general: 'Team not found' }); + } + + if ( + !team.managers.find((m) => m.toString() === req.user.id) && + !req.user.isAdmin + ) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const data = { + avatar: req.body.avatar, + description: req.body.description, + managers: req.body.managers, + members: req.body.members, + name: req.body.name + }; + const { errors, isValid } = validateEditTeam(data); + if (!isValid) return res.status(400).json(errors); + + if ( + data.avatar && + !data.avatar.includes('default') && + data.avatar !== team.avatar + ) { + let avatar; + try { + avatar = await Photo.findOne({ url: data.avatar }); + } catch (err) { + console.log(`Avatar ${data.avatar} failed to be found at edit-team`); + return next(err); + } + + if (!avatar) { + return res.status(404).json({ avatar: 'Not found' }); + } + + team.avatar = data.avatar; + } else if (data.avatar === '') { + team.avatar = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/teams/avatars/default.png`; + } + + team.description = data.description || team.description; + + if (data.managers) { + let managersToAdd = []; + let managersToRemove = []; + + data.managers.forEach((m) => { + if (m.startsWith('-')) { + managersToRemove = [...managersToRemove, m.substring(1)]; + } else { + managersToAdd = [...managersToAdd, m]; + } + }); + + const teamManagers = team.managers.map((m) => m.toString()); + + managersToAdd = [...new Set(difference(managersToAdd, teamManagers))]; + if (managersToAdd.length > 0) { + const teamMembers = team.members.map((m) => m.toString()); + const notMember = managersToAdd.find((m) => !teamMembers.includes(m)); + + if (notMember) { + return res + .status(400) + .json({ managers: `User ${notMember} is not a member of this team` }); + } + + team.managers = [...teamManagers, ...managersToAdd]; + team.members = team.members.filter( + (m) => !managersToAdd.includes(m.toString()) + ); + } + + managersToRemove = [ + ...new Set(intersection(managersToRemove, teamManagers)) + ]; + if (managersToRemove.length === team.managers.length) { + return res + .status(400) + .json({ managers: 'Should not remove all managers' }); + } + + team.managers = team.managers.filter( + (m) => !managersToRemove.includes(m.toString()) + ); + const teamMembers = team.members.map((m) => m.toString()); + team.members = [...teamMembers, ...managersToRemove]; + } + + if (data.members) { + const teamMembers = team.members.map((m) => m.toString()); + let membersToRemove = data.members.map((m) => m.substring(1)); + membersToRemove = [...new Set(intersection(membersToRemove, teamMembers))]; + + const getMembers = membersToRemove.map((m) => + User.find({ _id: m, isArchived: false }) + ); + let members; + try { + members = await Promise.all(getMembers); + } catch (err) { + console.log(`Members failed to be found at edit-team`); + return next(err); + } + + const updateMembers = members.map((m, i) => { + m[i].teams = m[i].teams.filter((t) => t.toString() !== team.id); + return m[i].save(); + }); + + try { + await Promise.all(updateMembers); + } catch (err) { + console.log(`Members failed to be updated at edit-team`); + return next(err); + } + + team.members = team.members.filter( + (m) => !membersToRemove.includes(m.toString()) + ); + } + + if (data.name) { + const teamName = cleanSpaces(data.name); + + if (teamName !== team.name) { + let repeatedTeam; + try { + repeatedTeam = await Team.findOne({ + name: teamName, + isArchived: false + }); + } catch (err) { + console.log(`Team ${teamName} failed to be found at edit-team`); + return next(err); + } + + if (repeatedTeam) { + return res.status(400).json({ name: 'Is already taken' }); + } + + team.name = teamName; + } + } + + team.updatedAt = moment.utc().toDate(); + + try { + await team.save(); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log(`Team ${team.id} failed to be updated at edit-team`); + return next(err); + } + + const dataResponse = { + id: team.id, + avatar: team.avatar, + description: team.description, + managers: team.managers, + members: team.members, + name: team.name + }; + + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/teams/get-team.js b/src/routes/teams/get-team.js index ea86094..9f3f0ca 100644 --- a/src/routes/teams/get-team.js +++ b/src/routes/teams/get-team.js @@ -1,144 +1,144 @@ -const mongoose = require('mongoose'); - -const { Team } = require('../../models/team'); - -module.exports = async (req, res, next) => { - const teamId = req.params.teamId; - - const teamIdObj = mongoose.Types.ObjectId(teamId); - let team; - try { - team = await Team.aggregate([ - { - $match: { _id: teamIdObj } - }, - { - $lookup: { - from: 'users', - let: { members: '$members' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$members'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - firstName: 1, - lastName: 1, - username: 1 - } - } - ], - as: 'members' - } - }, - { - $lookup: { - from: 'users', - let: { managers: '$managers' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$managers'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - firstName: 1, - lastName: 1, - username: 1 - } - } - ], - as: 'managers' - } - }, - { - $lookup: { - from: 'events', - let: { events: '$events' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$events'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - endDate: 1, - name: 1, - poster: 1, - startDate: 1 - } - } - ], - as: 'events' - } - }, - { - $lookup: { - from: 'teams', - let: { reviewsAmount: '$reviewsAmount' }, - pipeline: [ - { - $match: { - $expr: { - $gt: ['$reviewsAmount', '$$reviewsAmount'] - } - } - }, - { - $count: 'ranking' - } - ], - as: 'ranking' - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - description: 1, - reviewsAmount: 1, - name: 1, - members: 1, - events: 1, - managers: 1, - ranking: 1 - } - } - ]); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Team not found' }); - } - - console.log(`Team ${teamId} failed to be found at get-team`); - return next(err); - } - - if (!team) { - return res.status(404).json({ general: 'Team not found' }); - } - - const dataResponse = Object.assign({}, team[0], { - ranking: team[0].ranking.length ? team[0].ranking[0].ranking + 1 : 1 - }); - return res.status(200).json(dataResponse); -}; +const mongoose = require('mongoose'); + +const { Team } = require('../../models/team'); + +module.exports = async (req, res, next) => { + const teamId = req.params.teamId; + + const teamIdObj = new mongoose.Types.ObjectId(teamId); + let team; + try { + team = await Team.aggregate([ + { + $match: { _id: teamIdObj } + }, + { + $lookup: { + from: 'users', + let: { members: '$members' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$members'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + firstName: 1, + lastName: 1, + username: 1 + } + } + ], + as: 'members' + } + }, + { + $lookup: { + from: 'users', + let: { managers: '$managers' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$managers'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + firstName: 1, + lastName: 1, + username: 1 + } + } + ], + as: 'managers' + } + }, + { + $lookup: { + from: 'events', + let: { events: '$events' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$events'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + endDate: 1, + name: 1, + poster: 1, + startDate: 1 + } + } + ], + as: 'events' + } + }, + { + $lookup: { + from: 'teams', + let: { reviewsAmount: '$reviewsAmount' }, + pipeline: [ + { + $match: { + $expr: { + $gt: ['$reviewsAmount', '$$reviewsAmount'] + } + } + }, + { + $count: 'ranking' + } + ], + as: 'ranking' + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + description: 1, + reviewsAmount: 1, + name: 1, + members: 1, + events: 1, + managers: 1, + ranking: 1 + } + } + ]); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Team not found' }); + } + + console.log(`Team ${teamId} failed to be found at get-team`); + return next(err); + } + + if (!team) { + return res.status(404).json({ general: 'Team not found' }); + } + + const dataResponse = Object.assign({}, team[0], { + ranking: team[0].ranking.length ? team[0].ranking[0].ranking + 1 : 1 + }); + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/teams/index.js b/src/routes/teams/index.js index 8ffc659..83b4f3e 100644 --- a/src/routes/teams/index.js +++ b/src/routes/teams/index.js @@ -1,23 +1,23 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const createTeam = require('./create-team'); -const deleteTeam = require('./delete-team'); -const editTeam = require('./edit-team'); -const getTeam = require('./get-team'); -const joinTeam = require('./join-team'); -const leaveTeam = require('./leave-team'); -const listTeams = require('./list-teams'); - -const router = new express.Router(); - -router.get('', isAuthenticated({ isOptional: true }), listTeams); -router.post('', isAuthenticated({ isOptional: false }), createTeam); -router.get('/:teamId', getTeam); -router.put('/:teamId', isAuthenticated({ isOptional: false }), editTeam); -router.delete('/:teamId', isAuthenticated({ isOptional: false }), deleteTeam); -router.post('/:teamId/join', isAuthenticated({ isOptional: false }), joinTeam); -router.put('/:teamId/leave', isAuthenticated({ isOptional: false }), leaveTeam); - -module.exports = router; +const express = require('express'); + +const { isAuthenticated } = require('../../helpers'); + +const createTeam = require('./create-team'); +const deleteTeam = require('./delete-team'); +const editTeam = require('./edit-team'); +const getTeam = require('./get-team'); +const joinTeam = require('./join-team'); +const leaveTeam = require('./leave-team'); +const listTeams = require('./list-teams'); + +const router = new express.Router(); + +router.get('', isAuthenticated({ isOptional: true }), listTeams); +router.post('', isAuthenticated({ isOptional: false }), createTeam); +router.get('/:teamId', getTeam); +router.put('/:teamId', isAuthenticated({ isOptional: false }), editTeam); +router.delete('/:teamId', isAuthenticated({ isOptional: false }), deleteTeam); +router.post('/:teamId/join', isAuthenticated({ isOptional: false }), joinTeam); +router.put('/:teamId/leave', isAuthenticated({ isOptional: false }), leaveTeam); + +module.exports = router; diff --git a/src/routes/teams/join-team.js b/src/routes/teams/join-team.js index caf65ea..c2de2e4 100644 --- a/src/routes/teams/join-team.js +++ b/src/routes/teams/join-team.js @@ -1,98 +1,98 @@ -const { Petition } = require('../../models/petition'); -const { Team } = require('../../models/team'); - -module.exports = async (req, res, next) => { - const teamId = req.params.teamId; - - let team; - try { - team = await Team.findOne({ _id: teamId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Team not found' }); - } - - console.log(`Team ${teamId} failed to be found at join-team`); - return next(err); - } - - if (!team) { - return res.status(404).json({ general: 'Team not found' }); - } - - const eventMembers = team.members.map(m => m.toString()); - if (eventMembers.includes(req.user.id)) { - return res - .status(400) - .json({ general: 'You already are a member in this team' }); - } - - const eventManagers = team.managers.map(m => m.toString()); - if (eventManagers.includes(req.user.id)) { - return res - .status(400) - .json({ general: 'You already are a member in this team' }); - } - - let petition; - try { - petition = await Petition.findOne({ - team: team.id, - sender: req.user.id, - type: 'request-user-team' - }); - } catch (err) { - console.log( - `Petition from user ${req.user.id} to team ${ - team.id - } failed to be found at join-team` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'You already have a pending petition with this team' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log(`Petition ${petition.id} failed to be removed at join-team`); - return next(err); - } - } - - const petitionData = { - team: team.id, - sender: req.user.id, - type: 'request-user-team' - }; - try { - await Petition.create(petitionData); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `Petition failed to be created at join-team.\nData: ${JSON.stringify( - petitionData - )}` - ); - return next(err); - } - - return res.status(200).json({ general: 'Requested' }); -}; +const { Petition } = require('../../models/petition'); +const { Team } = require('../../models/team'); + +module.exports = async (req, res, next) => { + const teamId = req.params.teamId; + + let team; + try { + team = await Team.findOne({ _id: teamId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Team not found' }); + } + + console.log(`Team ${teamId} failed to be found at join-team`); + return next(err); + } + + if (!team) { + return res.status(404).json({ general: 'Team not found' }); + } + + const eventMembers = team.members.map((m) => m.toString()); + if (eventMembers.includes(req.user.id)) { + return res + .status(400) + .json({ general: 'You already are a member in this team' }); + } + + const eventManagers = team.managers.map((m) => m.toString()); + if (eventManagers.includes(req.user.id)) { + return res + .status(400) + .json({ general: 'You already are a member in this team' }); + } + + let petition; + try { + petition = await Petition.findOne({ + team: team.id, + sender: req.user.id, + type: 'request-user-team' + }); + } catch (err) { + console.log( + `Petition from user ${req.user.id} to team ${ + team.id + } failed to be found at join-team` + ); + return next(err); + } + + if (petition && petition.state === 'pending') { + return res.status(400).json({ + general: 'You already have a pending petition with this team' + }); + } + + if ( + petition && + (petition.state === 'rejected' || petition.state === 'canceled') + ) { + try { + await petition.remove(); + } catch (err) { + console.log(`Petition ${petition.id} failed to be removed at join-team`); + return next(err); + } + } + + const petitionData = { + team: team.id, + sender: req.user.id, + type: 'request-user-team' + }; + try { + await Petition.create(petitionData); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `Petition failed to be created at join-team.\nData: ${JSON.stringify( + petitionData + )}` + ); + return next(err); + } + + return res.status(200).json({ general: 'Requested' }); +}; diff --git a/src/routes/teams/leave-team.js b/src/routes/teams/leave-team.js index 8a9a954..1311c88 100644 --- a/src/routes/teams/leave-team.js +++ b/src/routes/teams/leave-team.js @@ -1,59 +1,59 @@ -const moment = require('moment'); - -const { Team } = require('../../models/team'); - -module.exports = async (req, res, next) => { - const teamId = req.params.teamId; - - let team; - try { - team = await Team.findOne({ _id: teamId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Team not found' }); - } - - console.log(`Team ${teamId} failed to be found at leave-team`); - return next(err); - } - - if (!team) { - return res.status(404).json({ general: 'Team not found' }); - } - - if (team.managers.find(m => m.toString() === req.user.id)) { - team.managers = team.managers.filter(m => m.toString() !== req.user.id); - - if (team.managers.length === 0) { - return res.status(400).json({ - general: 'You cannot leave because you are the only manager' - }); - } - } else if (team.members.find(m => m.toString() === req.user.id)) { - team.members = team.members.filter(m => m.toString() !== req.user.id); - } else { - return res.status(400).json({ general: 'You are not a member' }); - } - - const today = moment.utc(); - team.updatedAt = today.toDate(); - - try { - await team.save(); - } catch (err) { - console.log(`Team ${team.id} failed to be updated at leave-team`); - return next(err); - } - - req.user.teams = req.user.teams.filter(t => t.toString() !== team.id); - req.user.updatedAt = today.toDate(); - - try { - await req.user.save(); - } catch (err) { - console.log(`User ${req.user.id} failed to be updated at leave-team`); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { Team } = require('../../models/team'); + +module.exports = async (req, res, next) => { + const teamId = req.params.teamId; + + let team; + try { + team = await Team.findOne({ _id: teamId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Team not found' }); + } + + console.log(`Team ${teamId} failed to be found at leave-team`); + return next(err); + } + + if (!team) { + return res.status(404).json({ general: 'Team not found' }); + } + + if (team.managers.find((m) => m.toString() === req.user.id)) { + team.managers = team.managers.filter((m) => m.toString() !== req.user.id); + + if (team.managers.length === 0) { + return res.status(400).json({ + general: 'You cannot leave because you are the only manager' + }); + } + } else if (team.members.find((m) => m.toString() === req.user.id)) { + team.members = team.members.filter((m) => m.toString() !== req.user.id); + } else { + return res.status(400).json({ general: 'You are not a member' }); + } + + const today = moment.utc(); + team.updatedAt = today.toDate(); + + try { + await team.save(); + } catch (err) { + console.log(`Team ${team.id} failed to be updated at leave-team`); + return next(err); + } + + req.user.teams = req.user.teams.filter((t) => t.toString() !== team.id); + req.user.updatedAt = today.toDate(); + + try { + await req.user.save(); + } catch (err) { + console.log(`User ${req.user.id} failed to be updated at leave-team`); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/teams/list-teams.js b/src/routes/teams/list-teams.js index a667d81..605bcf6 100644 --- a/src/routes/teams/list-teams.js +++ b/src/routes/teams/list-teams.js @@ -1,104 +1,104 @@ -const mongoose = require('mongoose'); -const { toBoolean } = require('validator'); - -const { Team } = require('../../models/team'); - -const { validateListTeams } = require('./validations'); - -module.exports = async (req, res, next) => { - const queryParams = req.query; - - const { errors, isValid } = validateListTeams(queryParams); - if (!isValid) return res.status(400).json(errors); - - const teamsQuery = { isArchived: false }; - - if (queryParams.keywords) { - teamsQuery.$text = { $search: queryParams.keywords }; - } - - if (queryParams.managed) { - if (!req.user) { - return res - .status(400) - .json({ general: 'You cannot use managed filter as anonymous' }); - } - - const managed = toBoolean(queryParams.managed); - if (managed) { - teamsQuery.managers = { $in: [mongoose.Types.ObjectId(req.user.id)] }; - } else { - teamsQuery.managers = { $nin: [mongoose.Types.ObjectId(req.user.id)] }; - } - } - - let sortBy = queryParams.sortBy || '-reviewsAmount'; - let page = queryParams.page ? Number(queryParams.page) - 1 : 0; - const pageLimit = Number(queryParams.pageLimit) || 12; - - let teams; - let total; - try { - [teams, total] = await Promise.all([ - Team.aggregate() - .match(teamsQuery) - .project({ - _id: 0, - id: '$_id', - avatar: 1, - description: 1, - name: 1, - reviewsAmount: 1 - }) - .sort(sortBy) - .skip(page * pageLimit) - .limit(pageLimit), - Team.find(teamsQuery).count() - ]); - } catch (err) { - console.log('Teams failed to be found or count at list-teams'); - return next(err); - } - - const getTeamsRankings = teams.map(t => - Team.find({ reviewsAmount: { $gt: t.reviewsAmount } }).count() - ); - - let teamsRankings; - try { - teamsRankings = await Promise.all(getTeamsRankings); - } catch (err) { - console.log('Teams rankings failed to be count at list-teams'); - return next(err); - } - - teams = teams.map((t, i) => ({ - id: t.id, - avatar: t.avatar, - description: t.description, - name: t.name, - ranking: teamsRankings[i] + 1, - reviewsAmount: t.reviewsAmount - })); - - let lastPage = Math.ceil(total / pageLimit); - if (lastPage > 0) { - if (page > lastPage) { - return res - .status(400) - .json({ page: `Should be equal to or less than ${lastPage}` }); - } - } else { - page = null; - lastPage = null; - } - - return res.status(200).json({ - page: page + 1, - lastPage, - pageLimit, - total, - sortBy, - results: teams - }); -}; +const mongoose = require('mongoose'); +const { toBoolean } = require('validator'); + +const { Team } = require('../../models/team'); + +const { validateListTeams } = require('./validations'); + +module.exports = async (req, res, next) => { + const queryParams = req.query; + + const { errors, isValid } = validateListTeams(queryParams); + if (!isValid) return res.status(400).json(errors); + + const teamsQuery = { isArchived: false }; + + if (queryParams.keywords) { + teamsQuery.$text = { $search: queryParams.keywords }; + } + + if (queryParams.managed) { + if (!req.user) { + return res + .status(400) + .json({ general: 'You cannot use managed filter as anonymous' }); + } + + const managed = toBoolean(queryParams.managed); + if (managed) { + teamsQuery.managers = { $in: [new mongoose.Types.ObjectId(req.user.id)] }; + } else { + teamsQuery.managers = { $nin: [new mongoose.Types.ObjectId(req.user.id)] }; + } + } + + let sortBy = queryParams.sortBy || '-reviewsAmount'; + let page = queryParams.page ? Number(queryParams.page) - 1 : 0; + const pageLimit = Number(queryParams.pageLimit) || 12; + + let teams; + let total; + try { + [teams, total] = await Promise.all([ + Team.aggregate() + .match(teamsQuery) + .project({ + _id: 0, + id: '$_id', + avatar: 1, + description: 1, + name: 1, + reviewsAmount: 1 + }) + .sort(sortBy) + .skip(page * pageLimit) + .limit(pageLimit), + Team.find(teamsQuery).count() + ]); + } catch (err) { + console.log('Teams failed to be found or count at list-teams'); + return next(err); + } + + const getTeamsRankings = teams.map((t) => + Team.find({ reviewsAmount: { $gt: t.reviewsAmount } }).count() + ); + + let teamsRankings; + try { + teamsRankings = await Promise.all(getTeamsRankings); + } catch (err) { + console.log('Teams rankings failed to be count at list-teams'); + return next(err); + } + + teams = teams.map((t, i) => ({ + id: t.id, + avatar: t.avatar, + description: t.description, + name: t.name, + ranking: teamsRankings[i] + 1, + reviewsAmount: t.reviewsAmount + })); + + let lastPage = Math.ceil(total / pageLimit); + if (lastPage > 0) { + if (page > lastPage) { + return res + .status(400) + .json({ page: `Should be equal to or less than ${lastPage}` }); + } + } else { + page = null; + lastPage = null; + } + + return res.status(200).json({ + page: page + 1, + lastPage, + pageLimit, + total, + sortBy, + results: teams + }); +}; diff --git a/src/routes/teams/validations.js b/src/routes/teams/validations.js index 045359a..ce1f9b2 100644 --- a/src/routes/teams/validations.js +++ b/src/routes/teams/validations.js @@ -1,134 +1,134 @@ -const { isEmpty } = require('lodash'); -const { isInt, isMongoId } = require('validator'); - -module.exports = { - validateCreateTeam(data) { - const errors = {}; - - if (typeof data.avatar !== 'undefined' && typeof data.avatar !== 'string') { - errors.avatar = 'Should be a string'; - } - - if ( - typeof data.description !== 'undefined' && - typeof data.description !== 'string' - ) { - errors.description = 'Should be a string'; - } - - if (typeof data.name === 'undefined' || data.name === '') { - errors.name = 'Is required'; - } else if (typeof data.name !== 'string') { - errors.name = 'Should be a string'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateEditTeam(data) { - const errors = {}; - - if (typeof data.avatar !== 'undefined' && typeof data.avatar !== 'string') { - errors.avatar = 'Should be a string'; - } - - if ( - typeof data.description !== 'undefined' && - typeof data.description !== 'string' - ) { - errors.description = 'Should be a string'; - } - - if (typeof data.name !== 'undefined') { - if (typeof data.name !== 'string') { - errors.name = 'Should be a string'; - } else if (data.name === '') { - errors.name = 'Is required'; - } - } - - if (data.managers) { - if (!Array.isArray(data.managers)) { - errors.managers = 'Should be an array'; - } else { - data.managers.some(m => { - if (typeof m !== 'string') { - errors.managers = 'Should only have string values'; - return true; - } else if (!m) { - errors.managers = 'Should not have empty values'; - return true; - } else { - if (m.startsWith('-')) { - m = m.substring(1); - } - - if (!isMongoId(m)) { - errors.managers = `${m} should be an id`; - return true; - } - } - }); - } - } - - if (data.members) { - if (!Array.isArray(data.members)) { - errors.members = 'Should be an array'; - } else { - data.members.some(m => { - if (typeof m !== 'string') { - errors.members = 'Should only have string values'; - return true; - } else if (!m) { - errors.managers = 'Should not have empty values'; - return true; - } else if (!m.startsWith('-')) { - errors.members = `${m} should start with -`; - return true; - } else if (!isMongoId(m.substring(1))) { - errors.members = `${m} should be an id`; - return true; - } - }); - } - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateListTeams(queryParams) { - const errors = {}; - - if ( - queryParams.managed && - queryParams.managed !== '0' && - queryParams.managed !== '1' - ) { - errors.managed = 'Should be 0 or 1'; - } - - const sortOptions = ['name', '-name', 'reviewsAmount', '-reviewsAmount']; - if (queryParams.sortBy && !sortOptions.includes(queryParams.sortBy)) { - errors.sortBy = 'Should be a valid sort'; - } - - if (queryParams.page) { - if (!isInt(queryParams.page)) { - errors.page = 'Should be a integer'; - } else if (parseInt(queryParams.page, 10) < 1) { - errors.page = 'Should be a positive integer'; - } - } - - if (queryParams.pageLimit) { - if (!isInt(queryParams.pageLimit)) { - errors.pageLimit = 'Should be a integer'; - } else if (parseInt(queryParams.pageLimit, 10) < 1) { - errors.pageLimit = 'Should be a positive integer'; - } else if (parseInt(queryParams.pageLimit, 10) > 12) { - errors.pageLimit = 'Should be less than 13'; - } - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const { isEmpty } = require('lodash'); +const { isInt, isMongoId } = require('validator'); + +module.exports = { + validateCreateTeam(data) { + const errors = {}; + + if (typeof data.avatar !== 'undefined' && typeof data.avatar !== 'string') { + errors.avatar = 'Should be a string'; + } + + if ( + typeof data.description !== 'undefined' && + typeof data.description !== 'string' + ) { + errors.description = 'Should be a string'; + } + + if (typeof data.name === 'undefined' || data.name === '') { + errors.name = 'Is required'; + } else if (typeof data.name !== 'string') { + errors.name = 'Should be a string'; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateEditTeam(data) { + const errors = {}; + + if (typeof data.avatar !== 'undefined' && typeof data.avatar !== 'string') { + errors.avatar = 'Should be a string'; + } + + if ( + typeof data.description !== 'undefined' && + typeof data.description !== 'string' + ) { + errors.description = 'Should be a string'; + } + + if (typeof data.name !== 'undefined') { + if (typeof data.name !== 'string') { + errors.name = 'Should be a string'; + } else if (data.name === '') { + errors.name = 'Is required'; + } + } + + if (data.managers) { + if (!Array.isArray(data.managers)) { + errors.managers = 'Should be an array'; + } else { + data.managers.some((m) => { + if (typeof m !== 'string') { + errors.managers = 'Should only have string values'; + return true; + } else if (!m) { + errors.managers = 'Should not have empty values'; + return true; + } else { + if (m.startsWith('-')) { + m = m.substring(1); + } + + if (!isMongoId(m)) { + errors.managers = `${m} should be an id`; + return true; + } + } + }); + } + } + + if (data.members) { + if (!Array.isArray(data.members)) { + errors.members = 'Should be an array'; + } else { + data.members.some((m) => { + if (typeof m !== 'string') { + errors.members = 'Should only have string values'; + return true; + } else if (!m) { + errors.managers = 'Should not have empty values'; + return true; + } else if (!m.startsWith('-')) { + errors.members = `${m} should start with -`; + return true; + } else if (!isMongoId(m.substring(1))) { + errors.members = `${m} should be an id`; + return true; + } + }); + } + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateListTeams(queryParams) { + const errors = {}; + + if ( + queryParams.managed && + queryParams.managed !== '0' && + queryParams.managed !== '1' + ) { + errors.managed = 'Should be 0 or 1'; + } + + const sortOptions = ['name', '-name', 'reviewsAmount', '-reviewsAmount']; + if (queryParams.sortBy && !sortOptions.includes(queryParams.sortBy)) { + errors.sortBy = 'Should be a valid sort'; + } + + if (queryParams.page) { + if (!isInt(queryParams.page)) { + errors.page = 'Should be a integer'; + } else if (parseInt(queryParams.page, 10) < 1) { + errors.page = 'Should be a positive integer'; + } + } + + if (queryParams.pageLimit) { + if (!isInt(queryParams.pageLimit)) { + errors.pageLimit = 'Should be a integer'; + } else if (parseInt(queryParams.pageLimit, 10) < 1) { + errors.pageLimit = 'Should be a positive integer'; + } else if (parseInt(queryParams.pageLimit, 10) > 12) { + errors.pageLimit = 'Should be less than 13'; + } + } + + return { errors, isValid: isEmpty(errors) }; + } +}; diff --git a/src/routes/users/archive-user.js b/src/routes/users/archive-user.js index 46e3f3c..4d19eba 100644 --- a/src/routes/users/archive-user.js +++ b/src/routes/users/archive-user.js @@ -1,101 +1,101 @@ -const moment = require('moment'); - -const { ActivationTicket } = require('../../models/activation-ticket'); -const { PasswordTicket } = require('../../models/password-ticket'); -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); - -module.exports = async (req, res, next) => { - const userId = req.params.userId; - - let user; - try { - user = await User.findOne({ _id: userId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'User not found' }); - } - - console.log(`User with Id ${userId} failed to be found at archive-user.`); - return next(err); - } - - if (!user) { - return res.status(404).json({ general: 'User not found' }); - } - - if (user.id !== req.user.id && !req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - let activateAccountTicket; - let passwordTicket; - let refreshToken; - try { - [activateAccountTicket, passwordTicket, refreshToken] = await Promise.all([ - ActivationTicket.findOne({ email: user.email }), - PasswordTicket.findOne({ email: user.email }), - RefreshToken.findOne({ userId: user.id }) - ]); - } catch (err) { - console.log( - `Activate account ticket, password ticket or refresh token with email ${ - user.email - } failed to be found at archive-user.` - ); - return next(err); - } - - if (activateAccountTicket) { - try { - await activateAccountTicket.remove(); - } catch (err) { - console.log( - `Activate user ticket with key ${ - activateAccountTicket.key - } failed to be removed at archive-user.` - ); - return next(err); - } - } - - if (passwordTicket) { - try { - await passwordTicket.remove(); - } catch (err) { - console.log( - `Password ticket with key ${ - passwordTicket.key - } failed to be removed at archive-user.` - ); - return next(err); - } - } - - if (refreshToken) { - try { - await refreshToken.remove(); - } catch (err) { - console.log( - `Refresh token with key ${ - refreshToken.key - } failed to be removed at archive-user.` - ); - return next(err); - } - } - - user.isArchived = true; - user.updatedAt = moment.utc().toDate(); - - try { - await user.save(); - } catch (err) { - console.log( - `User with email ${user.email} failed to be updated at archive-user.` - ); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { ActivationTicket } = require('../../models/activation-ticket'); +const { PasswordTicket } = require('../../models/password-ticket'); +const { RefreshToken } = require('../../models/refresh-token'); +const { User } = require('../../models/user'); + +module.exports = async (req, res, next) => { + const userId = req.params.userId; + + let user; + try { + user = await User.findOne({ _id: userId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'User not found' }); + } + + console.log(`User with Id ${userId} failed to be found at archive-user.`); + return next(err); + } + + if (!user) { + return res.status(404).json({ general: 'User not found' }); + } + + if (user.id !== req.user.id && !req.user.isAdmin) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + let activateAccountTicket; + let passwordTicket; + let refreshToken; + try { + [activateAccountTicket, passwordTicket, refreshToken] = await Promise.all([ + ActivationTicket.findOne({ email: user.email }), + PasswordTicket.findOne({ email: user.email }), + RefreshToken.findOne({ userId: user.id }) + ]); + } catch (err) { + console.log( + `Activate account ticket, password ticket or refresh token with email ${ + user.email + } failed to be found at archive-user.` + ); + return next(err); + } + + if (activateAccountTicket) { + try { + await activateAccountTicket.remove(); + } catch (err) { + console.log( + `Activate user ticket with key ${ + activateAccountTicket.key + } failed to be removed at archive-user.` + ); + return next(err); + } + } + + if (passwordTicket) { + try { + await passwordTicket.remove(); + } catch (err) { + console.log( + `Password ticket with key ${ + passwordTicket.key + } failed to be removed at archive-user.` + ); + return next(err); + } + } + + if (refreshToken) { + try { + await refreshToken.remove(); + } catch (err) { + console.log( + `Refresh token with key ${ + refreshToken.key + } failed to be removed at archive-user.` + ); + return next(err); + } + } + + user.isArchived = true; + user.updatedAt = moment.utc().toDate(); + + try { + await user.save(); + } catch (err) { + console.log( + `User with email ${user.email} failed to be updated at archive-user.` + ); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/users/block-user.js b/src/routes/users/block-user.js index 6e93c8a..44c88ec 100644 --- a/src/routes/users/block-user.js +++ b/src/routes/users/block-user.js @@ -1,39 +1,39 @@ -const moment = require('moment'); - -const { User } = require('../../models/user'); - -module.exports = async (req, res, next) => { - if (!req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const userId = req.params.userId; - - let user; - try { - user = await User.findOne({ _id: userId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'User not found' }); - } - - console.log(`User with Id ${userId} failed to be found at block-user.`); - return next(err); - } - - if (!user) { - return res.status(404).json({ general: 'User not found' }); - } - - user.isBlocked = true; - user.updatedAt = moment.utc().toDate(); - - try { - await user.save(); - } catch (err) { - console.log(`User with Id ${user.id} failed to be updated at block-user.`); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { User } = require('../../models/user'); + +module.exports = async (req, res, next) => { + if (!req.user.isAdmin) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const userId = req.params.userId; + + let user; + try { + user = await User.findOne({ _id: userId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'User not found' }); + } + + console.log(`User with Id ${userId} failed to be found at block-user.`); + return next(err); + } + + if (!user) { + return res.status(404).json({ general: 'User not found' }); + } + + user.isBlocked = true; + user.updatedAt = moment.utc().toDate(); + + try { + await user.save(); + } catch (err) { + console.log(`User with Id ${user.id} failed to be updated at block-user.`); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/users/change-password.js b/src/routes/users/change-password.js index 13b2391..2c88231 100644 --- a/src/routes/users/change-password.js +++ b/src/routes/users/change-password.js @@ -1,64 +1,64 @@ -const moment = require('moment'); - -const { RefreshToken } = require('../../models/refresh-token'); - -const { validateChangePassword } = require('./validations'); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - const { errors, isValid } = validateChangePassword(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const oldPassword = req.body.oldPassword; - const password = req.body.password; - - const passwordMatches = req.user.comparePassword(oldPassword); - - if (!passwordMatches) { - return res.status(400).json({ oldPassword: 'Wrong password' }); - } - - let refreshToken; - try { - refreshToken = await RefreshToken.findOne({ userId: req.user.id }); - } catch (err) { - console.log( - `Refresh Token with userId ${ - req.user.id - } failed to be found at change-password.` - ); - return next(err); - } - - if (refreshToken) { - try { - await refreshToken.remove(); - } catch (err) { - console.log( - `Refresh Token with key ${ - refreshToken.key - } failed to be removed at change-password.` - ); - return next(err); - } - } - - req.user.password = password; - req.user.updatedAt = moment.utc().toDate(); - - try { - req.user.save(); - } catch (err) { - console.log( - `User with Id ${req.user.id} failed to be updated at change-password.` - ); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { RefreshToken } = require('../../models/refresh-token'); + +const { validateChangePassword } = require('./validations'); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: 'You are blocked' }); + } + + const { errors, isValid } = validateChangePassword(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const oldPassword = req.body.oldPassword; + const password = req.body.password; + + const passwordMatches = req.user.comparePassword(oldPassword); + + if (!passwordMatches) { + return res.status(400).json({ oldPassword: 'Wrong password' }); + } + + let refreshToken; + try { + refreshToken = await RefreshToken.findOne({ userId: req.user.id }); + } catch (err) { + console.log( + `Refresh Token with userId ${ + req.user.id + } failed to be found at change-password.` + ); + return next(err); + } + + if (refreshToken) { + try { + await refreshToken.remove(); + } catch (err) { + console.log( + `Refresh Token with key ${ + refreshToken.key + } failed to be removed at change-password.` + ); + return next(err); + } + } + + req.user.password = password; + req.user.updatedAt = moment.utc().toDate(); + + try { + req.user.save(); + } catch (err) { + console.log( + `User with Id ${req.user.id} failed to be updated at change-password.` + ); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/users/create-user.js b/src/routes/users/create-user.js index 937fb97..3fb3d2e 100644 --- a/src/routes/users/create-user.js +++ b/src/routes/users/create-user.js @@ -1,153 +1,150 @@ -const crypto = require('crypto'); - -const moment = require('moment'); -const { pick } = require('lodash'); -const randomstring = require('randomstring'); -const slugify = require('speakingurl'); - -const { cleanSpaces } = require('../../helpers'); -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); - -const { validateCreateUser } = require('./validations'); - -module.exports = async (req, res, next) => { - if (!req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const { errors, isValid } = validateCreateUser(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const userData = pick(req.body, [ - 'description', - 'disabilities', - 'email', - 'firstName', - 'gender', - 'isSubscribed', - 'lastName', - 'password', - 'phone', - 'showDisabilities', - 'showEmail', - 'showPhone', - 'username', - 'zip' - ]); - userData.firstName = cleanSpaces(userData.firstName); - userData.lastName = cleanSpaces(userData.lastName); - - let usernameSent = true; - - if (!userData.username) { - userData.username = `${slugify(userData.firstName)}-${slugify( - userData.lastName - )}`; - usernameSent = false; - } - - let repeatedUsers; - try { - repeatedUsers = await User.find({ - $or: [{ email: userData.email }, { username: userData.username }], - isArchived: false - }); - } catch (err) { - console.log('Users failed to be found at create-user.'); - return next(err); - } - - if (repeatedUsers && repeatedUsers.length > 0) { - for (const user of repeatedUsers) { - if (user.email === userData.email) { - return res.status(400).json({ email: 'Is already taken' }); - } else if (usernameSent && user.username === userData.username) { - return res.status(400).json({ username: 'Is already taken' }); - } - - let repeatedUser; - do { - userData.username = `${slugify(userData.firstName)}-${slugify( - userData.lastName - )}-${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}`; - - try { - repeatedUser = await User.findOne({ - username: userData.username, - isArchived: false - }); - } catch (err) { - console.log( - `User with username ${ - userData.username - } failed to be found at create-user.` - ); - return next(err); - } - } while (repeatedUser && repeatedUser.username === userData.username); - } - } - - let user; - try { - user = await User.create(userData); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `User with email ${userData.email} failed to be created at create-user.` - ); - return next(err); - } - - const refreshTokenData = { - expiresAt: moment - .utc() - .add(14, 'days') - .toDate(), - key: `${user.id}${crypto.randomBytes(40).toString('hex')}`, - userId: user.id - }; - try { - await RefreshToken.create(refreshTokenData); - } catch (err) { - console.log( - `Refresh token with userId ${ - refreshTokenData.userId - } failed to be created at create-user.` - ); - return next(err); - } - - const dataResponse = pick(user, [ - '_id', - 'description', - 'disabilities', - 'email', - 'firstName', - 'gender', - 'isSubscribed', - 'lastName', - 'phone', - 'showDisabilities', - 'showEmail', - 'showPhone', - 'username', - 'zip' - ]); - return res.status(201).json(dataResponse); -}; +const crypto = require('crypto'); + +const moment = require('moment'); +const { pick } = require('lodash'); +const randomstring = require('randomstring'); +const slugify = require('speakingurl'); + +const { cleanSpaces } = require('../../helpers'); +const { RefreshToken } = require('../../models/refresh-token'); +const { User } = require('../../models/user'); + +const { validateCreateUser } = require('./validations'); + +module.exports = async (req, res, next) => { + if (!req.user.isAdmin) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const { errors, isValid } = validateCreateUser(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const userData = pick(req.body, [ + 'description', + 'disabilities', + 'email', + 'firstName', + 'gender', + 'isSubscribed', + 'lastName', + 'password', + 'phone', + 'showDisabilities', + 'showEmail', + 'showPhone', + 'username', + 'zip' + ]); + userData.firstName = cleanSpaces(userData.firstName); + userData.lastName = cleanSpaces(userData.lastName); + + let usernameSent = true; + + if (!userData.username) { + userData.username = `${slugify(userData.firstName)}-${slugify( + userData.lastName + )}`; + usernameSent = false; + } + + let repeatedUsers; + try { + repeatedUsers = await User.find({ + $or: [{ email: userData.email }, { username: userData.username }], + isArchived: false + }); + } catch (err) { + console.log('Users failed to be found at create-user.'); + return next(err); + } + + if (repeatedUsers && repeatedUsers.length > 0) { + for (const user of repeatedUsers) { + if (user.email === userData.email) { + return res.status(400).json({ email: 'Is already taken' }); + } else if (usernameSent && user.username === userData.username) { + return res.status(400).json({ username: 'Is already taken' }); + } + + let repeatedUser; + do { + userData.username = `${slugify(userData.firstName)}-${slugify( + userData.lastName + )}-${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}`; + + try { + repeatedUser = await User.findOne({ + username: userData.username, + isArchived: false + }); + } catch (err) { + console.log( + `User with username ${ + userData.username + } failed to be found at create-user.` + ); + return next(err); + } + } while (repeatedUser && repeatedUser.username === userData.username); + } + } + + let user; + try { + user = await User.create(userData); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `User with email ${userData.email} failed to be created at create-user.` + ); + return next(err); + } + + const refreshTokenData = { + expiresAt: moment.utc().add(14, 'days').toDate(), + key: `${user.id}${crypto.randomBytes(40).toString('hex')}`, + userId: user.id + }; + try { + await RefreshToken.create(refreshTokenData); + } catch (err) { + console.log( + `Refresh token with userId ${ + refreshTokenData.userId + } failed to be created at create-user.` + ); + return next(err); + } + + const dataResponse = pick(user, [ + '_id', + 'description', + 'disabilities', + 'email', + 'firstName', + 'gender', + 'isSubscribed', + 'lastName', + 'phone', + 'showDisabilities', + 'showEmail', + 'showPhone', + 'username', + 'zip' + ]); + return res.status(201).json(dataResponse); +}; diff --git a/src/routes/users/delete-user.js b/src/routes/users/delete-user.js index 39464d2..401e7e4 100644 --- a/src/routes/users/delete-user.js +++ b/src/routes/users/delete-user.js @@ -1,36 +1,36 @@ -const { User } = require('../../models/user'); - -module.exports = async (req, res, next) => { - if (!req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const userId = req.params.userId; - - let user; - try { - user = await User.findOne({ _id: userId, isArchived: true }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Archived user not found' }); - } - - console.log(`User with Id ${userId} failed to be found at delete-user.`); - return next(err); - } - - if (!user) { - return res.status(404).json({ general: 'Archived user not found' }); - } - - try { - await user.remove(); - } catch (err) { - console.log( - `User with email ${user.email} failed to be deleted at delete-user.` - ); - return next(err); - } - - return res.status(204).json({ general: 'Success' }); -}; +const { User } = require('../../models/user'); + +module.exports = async (req, res, next) => { + if (!req.user.isAdmin) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const userId = req.params.userId; + + let user; + try { + user = await User.findOne({ _id: userId, isArchived: true }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Archived user not found' }); + } + + console.log(`User with Id ${userId} failed to be found at delete-user.`); + return next(err); + } + + if (!user) { + return res.status(404).json({ general: 'Archived user not found' }); + } + + try { + await user.remove(); + } catch (err) { + console.log( + `User with email ${user.email} failed to be deleted at delete-user.` + ); + return next(err); + } + + return res.status(204).json({ general: 'Success' }); +}; diff --git a/src/routes/users/edit-user.js b/src/routes/users/edit-user.js index ae6cb80..f0be2a1 100644 --- a/src/routes/users/edit-user.js +++ b/src/routes/users/edit-user.js @@ -1,160 +1,160 @@ -const moment = require('moment'); - -const { cleanSpaces } = require('../../helpers'); -const { Photo } = require('../../models/photo'); -const { User } = require('../../models/user'); - -const { validateEditUser } = require('./validations'); - -module.exports = async (req, res, next) => { - const userId = req.params.userId; - - let user; - try { - user = await User.findOne({ _id: userId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'User not found' }); - } - - console.log(`User with Id ${userId} failed to be found at edit-user.`); - return next(err); - } - - if (!user) { - return res.status(404).json({ general: 'User not found' }); - } - - if (user.id !== req.user.id && !req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const data = req.body; - - const { errors, isValid } = validateEditUser(data); - if (!isValid) return res.status(400).json(errors); - - if ( - data.avatar && - !data.avatar.includes('default') && - data.avatar !== user.avatar - ) { - let avatar; - try { - avatar = await Photo.findOne({ url: data.avatar }); - } catch (err) { - console.log(`Avatar ${data.avatar} failed to be found at edit-user`); - return next(err); - } - - if (!avatar) { - return res.status(404).json({ avatar: 'Not found' }); - } - - user.avatar = data.avatar; - } else if (data.avatar === '') { - user.avatar = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/users/avatars/default.png`; - } - - user.description = data.description || user.description; - - user.disabilities = data.disabilities || user.disabilities; - - user.firstName = data.firstName - ? cleanSpaces(data.firstName) - : user.firstName; - - user.gender = data.gender || user.gender; - - user.isSubscribed = - typeof data.isSubscribed !== 'undefined' - ? data.isSubscribed - : user.isSubscribed; - - user.language = data.language || user.language; - - user.lastName = data.lastName ? cleanSpaces(data.lastName) : user.lastName; - - user.phone = data.phone || user.phone; - - user.showDisabilities = - typeof data.showDisabilities !== 'undefined' - ? data.showDisabilities - : user.showDisabilities; - - user.showEmail = - typeof data.showEmail !== 'undefined' ? data.showEmail : user.showEmail; - - user.showPhone = - typeof data.showPhone !== 'undefined' ? data.showPhone : user.showPhone; - - if (data.username && data.username !== user.username) { - let repeatedUser; - try { - repeatedUser = await User.findOne({ - username: data.username, - isArchived: false - }); - } catch (err) { - console.log( - `User with username ${data.username} failed to be found at edit-user.` - ); - return next(err); - } - - if (repeatedUser) { - return res.status(400).json({ username: 'Is already taken' }); - } - - user.username = data.username; - } - - user.zip = data.zip ? cleanSpaces(data.zip) : user.zip; - - user.updatedAt = moment.utc().toDate(); - - try { - await user.save(); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `User ${ - user.id - } failed to be updated at edit-user.\nData: ${JSON.stringify( - data, - null, - 2 - )}` - ); - return next(err); - } - - const dataResponse = { - id: user.id, - avatar: user.avatar, - description: user.description, - disabilities: user.disabilities, - firstName: user.firstName, - gender: user.gender, - isSubscribed: user.isSubscribed, - lastName: user.lastName, - phone: user.phone, - showDisabilities: user.showDisabilities, - showEmail: user.showEmail, - showPhone: user.showPhone, - username: user.username, - zip: user.zip - }; - return res.status(200).json(dataResponse); -}; +const moment = require('moment'); + +const { cleanSpaces } = require('../../helpers'); +const { Photo } = require('../../models/photo'); +const { User } = require('../../models/user'); + +const { validateEditUser } = require('./validations'); + +module.exports = async (req, res, next) => { + const userId = req.params.userId; + + let user; + try { + user = await User.findOne({ _id: userId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'User not found' }); + } + + console.log(`User with Id ${userId} failed to be found at edit-user.`); + return next(err); + } + + if (!user) { + return res.status(404).json({ general: 'User not found' }); + } + + if (user.id !== req.user.id && !req.user.isAdmin) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const data = req.body; + + const { errors, isValid } = validateEditUser(data); + if (!isValid) return res.status(400).json(errors); + + if ( + data.avatar && + !data.avatar.includes('default') && + data.avatar !== user.avatar + ) { + let avatar; + try { + avatar = await Photo.findOne({ url: data.avatar }); + } catch (err) { + console.log(`Avatar ${data.avatar} failed to be found at edit-user`); + return next(err); + } + + if (!avatar) { + return res.status(404).json({ avatar: 'Not found' }); + } + + user.avatar = data.avatar; + } else if (data.avatar === '') { + user.avatar = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/users/avatars/default.png`; + } + + user.description = data.description || user.description; + + user.disabilities = data.disabilities || user.disabilities; + + user.firstName = data.firstName + ? cleanSpaces(data.firstName) + : user.firstName; + + user.gender = data.gender || user.gender; + + user.isSubscribed = + typeof data.isSubscribed !== 'undefined' + ? data.isSubscribed + : user.isSubscribed; + + user.language = data.language || user.language; + + user.lastName = data.lastName ? cleanSpaces(data.lastName) : user.lastName; + + user.phone = data.phone || user.phone; + + user.showDisabilities = + typeof data.showDisabilities !== 'undefined' + ? data.showDisabilities + : user.showDisabilities; + + user.showEmail = + typeof data.showEmail !== 'undefined' ? data.showEmail : user.showEmail; + + user.showPhone = + typeof data.showPhone !== 'undefined' ? data.showPhone : user.showPhone; + + if (data.username && data.username !== user.username) { + let repeatedUser; + try { + repeatedUser = await User.findOne({ + username: data.username, + isArchived: false + }); + } catch (err) { + console.log( + `User with username ${data.username} failed to be found at edit-user.` + ); + return next(err); + } + + if (repeatedUser) { + return res.status(400).json({ username: 'Is already taken' }); + } + + user.username = data.username; + } + + user.zip = data.zip ? cleanSpaces(data.zip) : user.zip; + + user.updatedAt = moment.utc().toDate(); + + try { + await user.save(); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `User ${ + user.id + } failed to be updated at edit-user.\nData: ${JSON.stringify( + data, + null, + 2 + )}` + ); + return next(err); + } + + const dataResponse = { + id: user.id, + avatar: user.avatar, + description: user.description, + disabilities: user.disabilities, + firstName: user.firstName, + gender: user.gender, + isSubscribed: user.isSubscribed, + lastName: user.lastName, + phone: user.phone, + showDisabilities: user.showDisabilities, + showEmail: user.showEmail, + showPhone: user.showPhone, + username: user.username, + zip: user.zip + }; + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/users/get-profile.js b/src/routes/users/get-profile.js index 0d83096..f9685c0 100644 --- a/src/routes/users/get-profile.js +++ b/src/routes/users/get-profile.js @@ -1,93 +1,93 @@ -const { Event } = require('../../models/event'); -const { Team } = require('../../models/team'); - -module.exports = async (req, res, next) => { - const getUserTeams = req.user.teams.map(t => Team.findOne({ _id: t })); - let userTeams; - try { - userTeams = await Promise.all(getUserTeams); - } catch (err) { - console.log('Teams failed to be found at get-profile'); - return next(err); - } - - const teams = []; - const managedTeams = []; - userTeams.map(t => { - if (t) { - const teamManagers = t.managers.map(m => m.toString()); - if (teamManagers.includes(req.user.id)) { - managedTeams.push({ - id: t.id.toString(), - avatar: t.avatar, - name: t.name - }); - } else { - teams.push({ - id: t.id.toString(), - avatar: t.avatar, - name: t.name - }); - } - } - }); - - const getUserEvents = req.user.events.map(e => Event.findOne({ _id: e })); - let userEvents; - try { - userEvents = await Promise.all(getUserEvents); - } catch (err) { - console.log('Events failed to be found at get-profile'); - return next(err); - } - - const events = []; - const managedEvents = []; - userEvents.map(e => { - if (e) { - const eventManagers = e.managers.map(m => m.toString()); - if (eventManagers.includes(req.user.id)) { - managedEvents.push({ - id: e.id.toString(), - endDate: e.endDate, - name: e.name, - poster: e.poster, - startDate: e.startDate - }); - } else { - events.push({ - id: e.id.toString(), - endDate: e.endDate, - name: e.name, - poster: e.poster, - startDate: e.startDate - }); - } - } - }); - - const userData = { - id: req.user.id, - avatar: req.user.avatar, - description: req.user.description, - disabilities: req.user.disabilities, - email: req.user.email, - events, - firstName: req.user.firstName, - gender: req.user.gender, - isSubscribed: req.user.isSubscribed, - lastName: req.user.lastName, - managedEvents, - managedTeams, - phone: req.user.phone, - reviewFieldsAmount: req.user.reviewFieldsAmount, - reviewsAmount: req.user.reviewsAmount, - showDisabilities: req.user.showDisabilities, - showEmail: req.user.showEmail, - showPhone: req.user.showPhone, - teams, - username: req.user.username, - zip: req.user.zip - }; - return res.status(200).json(userData); -}; +const { Event } = require('../../models/event'); +const { Team } = require('../../models/team'); + +module.exports = async (req, res, next) => { + const getUserTeams = req.user.teams.map((t) => Team.findOne({ _id: t })); + let userTeams; + try { + userTeams = await Promise.all(getUserTeams); + } catch (err) { + console.log('Teams failed to be found at get-profile'); + return next(err); + } + + const teams = []; + const managedTeams = []; + userTeams.map((t) => { + if (t) { + const teamManagers = t.managers.map((m) => m.toString()); + if (teamManagers.includes(req.user.id)) { + managedTeams.push({ + id: t.id.toString(), + avatar: t.avatar, + name: t.name + }); + } else { + teams.push({ + id: t.id.toString(), + avatar: t.avatar, + name: t.name + }); + } + } + }); + + const getUserEvents = req.user.events.map((e) => Event.findOne({ _id: e })); + let userEvents; + try { + userEvents = await Promise.all(getUserEvents); + } catch (err) { + console.log('Events failed to be found at get-profile'); + return next(err); + } + + const events = []; + const managedEvents = []; + userEvents.map((e) => { + if (e) { + const eventManagers = e.managers.map((m) => m.toString()); + if (eventManagers.includes(req.user.id)) { + managedEvents.push({ + id: e.id.toString(), + endDate: e.endDate, + name: e.name, + poster: e.poster, + startDate: e.startDate + }); + } else { + events.push({ + id: e.id.toString(), + endDate: e.endDate, + name: e.name, + poster: e.poster, + startDate: e.startDate + }); + } + } + }); + + const userData = { + id: req.user.id, + avatar: req.user.avatar, + description: req.user.description, + disabilities: req.user.disabilities, + email: req.user.email, + events, + firstName: req.user.firstName, + gender: req.user.gender, + isSubscribed: req.user.isSubscribed, + lastName: req.user.lastName, + managedEvents, + managedTeams, + phone: req.user.phone, + reviewFieldsAmount: req.user.reviewFieldsAmount, + reviewsAmount: req.user.reviewsAmount, + showDisabilities: req.user.showDisabilities, + showEmail: req.user.showEmail, + showPhone: req.user.showPhone, + teams, + username: req.user.username, + zip: req.user.zip + }; + return res.status(200).json(userData); +}; diff --git a/src/routes/users/get-user.js b/src/routes/users/get-user.js index a24972f..f6d7a08 100644 --- a/src/routes/users/get-user.js +++ b/src/routes/users/get-user.js @@ -1,127 +1,127 @@ -const mongoose = require('mongoose'); - -const { User } = require('../../models/user'); - -module.exports = async (req, res, next) => { - const userId = req.params.userId; - - const userIdObj = mongoose.Types.ObjectId(userId); - let user; - try { - user = await User.aggregate([ - { - $match: { _id: userIdObj } - }, - { - $lookup: { - from: 'events', - let: { events: '$events' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$events'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - endDate: 1, - name: 1, - poster: 1, - startDate: 1 - } - } - ], - as: 'events' - } - }, - { - $lookup: { - from: 'teams', - let: { teams: '$teams' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$teams'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - name: 1 - } - } - ], - as: 'teams' - } - }, - { - $lookup: { - from: 'users', - let: { reviewsAmount: '$reviewsAmount' }, - pipeline: [ - { - $match: { - $expr: { - $gt: ['$reviewsAmount', '$$reviewsAmount'] - } - } - }, - { - $count: 'ranking' - } - ], - as: 'ranking' - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - description: 1, - disabilities: 1, - email: 1, - events: 1, - firstName: 1, - gender: 1, - isSubscribed: 1, - language: 1, - lastName: 1, - phone: 1, - ranking: 1, - reviewsAmount: 1, - showDisabilities: 1, - showEmail: 1, - showPhone: 1, - teams: 1, - username: 1, - zip: 1 - } - } - ]); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'User not found' }); - } - - console.log(`User ${userId} failed to be found at get-user`); - return next(err); - } - - if (!user) { - return res.status(404).json({ general: 'User not found' }); - } - - const dataResponse = Object.assign({}, user[0], { - ranking: user[0].ranking.length ? user[0].ranking[0].ranking + 1 : 1 - }); - return res.status(200).json(dataResponse); -}; +const mongoose = require('mongoose'); + +const { User } = require('../../models/user'); + +module.exports = async (req, res, next) => { + const userId = req.params.userId; + + const userIdObj = new mongoose.Types.ObjectId(userId); + let user; + try { + user = await User.aggregate([ + { + $match: { _id: userIdObj } + }, + { + $lookup: { + from: 'events', + let: { events: '$events' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$events'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + endDate: 1, + name: 1, + poster: 1, + startDate: 1 + } + } + ], + as: 'events' + } + }, + { + $lookup: { + from: 'teams', + let: { teams: '$teams' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$teams'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + name: 1 + } + } + ], + as: 'teams' + } + }, + { + $lookup: { + from: 'users', + let: { reviewsAmount: '$reviewsAmount' }, + pipeline: [ + { + $match: { + $expr: { + $gt: ['$reviewsAmount', '$$reviewsAmount'] + } + } + }, + { + $count: 'ranking' + } + ], + as: 'ranking' + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + description: 1, + disabilities: 1, + email: 1, + events: 1, + firstName: 1, + gender: 1, + isSubscribed: 1, + language: 1, + lastName: 1, + phone: 1, + ranking: 1, + reviewsAmount: 1, + showDisabilities: 1, + showEmail: 1, + showPhone: 1, + teams: 1, + username: 1, + zip: 1 + } + } + ]); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'User not found' }); + } + + console.log(`User ${userId} failed to be found at get-user`); + return next(err); + } + + if (!user) { + return res.status(404).json({ general: 'User not found' }); + } + + const dataResponse = Object.assign({}, user[0], { + ranking: user[0].ranking.length ? user[0].ranking[0].ranking + 1 : 1 + }); + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/users/index.js b/src/routes/users/index.js index ec792de..eb38e7a 100644 --- a/src/routes/users/index.js +++ b/src/routes/users/index.js @@ -1,43 +1,43 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const archiveUser = require('./archive-user'); -const blockUser = require('./block-user'); -const changePassword = require('./change-password'); -const createUser = require('./create-user'); -const deleteUser = require('./delete-user'); -const editUser = require('./edit-user'); -const getUser = require('./get-user'); -const getProfile = require('./get-profile'); -const listUsers = require('./list-users'); -const unblockUser = require('./unblock-user'); -const deactivateUser = require('./deactivate-user'); - -const router = new express.Router(); - -router.get('/profile', isAuthenticated({ isOptional: false }), getProfile); -router.put('/password', isAuthenticated({ isOptional: false }), changePassword); -router.get('', isAuthenticated({ isOptional: false }), listUsers); -router.post('', isAuthenticated({ isOptional: false }), createUser); -router.get('/:userId', getUser); -router.put('/:userId', isAuthenticated({ isOptional: false }), editUser); -router.delete( - '/deactivate', - isAuthenticated({ isOptional: false }), - deactivateUser -); -router.delete('/:userId', isAuthenticated({ isOptional: false }), deleteUser); -router.put( - '/:userId/archive', - isAuthenticated({ isOptional: false }), - archiveUser -); -router.put('/:userId/block', isAuthenticated({ isOptional: false }), blockUser); -router.put( - '/:userId/unblock', - isAuthenticated({ isOptional: false }), - unblockUser -); - -module.exports = router; +const express = require('express'); + +const { isAuthenticated } = require('../../helpers'); + +const archiveUser = require('./archive-user'); +const blockUser = require('./block-user'); +const changePassword = require('./change-password'); +const createUser = require('./create-user'); +const deleteUser = require('./delete-user'); +const editUser = require('./edit-user'); +const getUser = require('./get-user'); +const getProfile = require('./get-profile'); +const listUsers = require('./list-users'); +const unblockUser = require('./unblock-user'); +const deactivateUser = require('./deactivate-user'); + +const router = new express.Router(); + +router.get('/profile', isAuthenticated({ isOptional: false }), getProfile); +router.put('/password', isAuthenticated({ isOptional: false }), changePassword); +router.get('', isAuthenticated({ isOptional: false }), listUsers); +router.post('', isAuthenticated({ isOptional: false }), createUser); +router.get('/:userId', getUser); +router.put('/:userId', isAuthenticated({ isOptional: false }), editUser); +router.delete( + '/deactivate', + isAuthenticated({ isOptional: false }), + deactivateUser +); +router.delete('/:userId', isAuthenticated({ isOptional: false }), deleteUser); +router.put( + '/:userId/archive', + isAuthenticated({ isOptional: false }), + archiveUser +); +router.put('/:userId/block', isAuthenticated({ isOptional: false }), blockUser); +router.put( + '/:userId/unblock', + isAuthenticated({ isOptional: false }), + unblockUser +); + +module.exports = router; diff --git a/src/routes/users/list-users.js b/src/routes/users/list-users.js index 543cd98..a3d7e7b 100644 --- a/src/routes/users/list-users.js +++ b/src/routes/users/list-users.js @@ -1,75 +1,75 @@ -const { User } = require('../../models/user'); - -const { validateListUsers } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateListUsers(req.query); - if (!isValid) return res.status(400).json(errors); - - const queryParams = req.query; - - const usersQuery = { isArchived: false }; - usersQuery.$text = { $search: queryParams.keywords || '' }; - - const sort = queryParams.sortBy || { - score: { $meta: 'textScore' } - }; - let page = queryParams.page ? parseInt(queryParams.page, 10) - 1 : 1; - const pageLimit = queryParams.pageLimit - ? parseInt(queryParams.pageLimit, 10) - : 12; - - let total; - let users; - try { - [users, total] = await Promise.all([ - User.aggregate() - .match(usersQuery) - .project({ - _id: 0, - id: '$_id', - avatar: 1, - email: 1, - firstName: 1, - lastName: 1, - score: { $meta: 'textScore' }, - username: 1 - }) - .match({ score: { $gt: 1 } }) - .sort(sort) - .skip(page * pageLimit) - .limit(pageLimit), - User.find(usersQuery).count() - ]); - } catch (err) { - console.log( - `Users failed to be found or count at list-users.\nusersQuery: ${JSON.stringify( - usersQuery - )}` - ); - return next(err); - } - - let lastPage = Math.ceil(total / pageLimit); - if (lastPage > 0) { - page += 1; - if (page > lastPage) { - return res - .status(400) - .json({ page: `Should be less than or equal to ${lastPage}` }); - } - } else { - page = null; - lastPage = null; - } - - const dataResponse = { - page, - lastPage, - pageLimit, - total, - sortBy: queryParams.sortBy, - results: users - }; - return res.status(200).json(dataResponse); -}; +const { User } = require('../../models/user'); + +const { validateListUsers } = require('./validations'); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateListUsers(req.query); + if (!isValid) return res.status(400).json(errors); + + const queryParams = req.query; + + const usersQuery = { isArchived: false }; + usersQuery.$text = { $search: queryParams.keywords || '' }; + + const sort = queryParams.sortBy || { + score: { $meta: 'textScore' } + }; + let page = queryParams.page ? parseInt(queryParams.page, 10) - 1 : 1; + const pageLimit = queryParams.pageLimit + ? parseInt(queryParams.pageLimit, 10) + : 12; + + let total; + let users; + try { + [users, total] = await Promise.all([ + User.aggregate() + .match(usersQuery) + .project({ + _id: 0, + id: '$_id', + avatar: 1, + email: 1, + firstName: 1, + lastName: 1, + score: { $meta: 'textScore' }, + username: 1 + }) + .match({ score: { $gt: 1 } }) + .sort(sort) + .skip(page * pageLimit) + .limit(pageLimit), + User.find(usersQuery).count() + ]); + } catch (err) { + console.log( + `Users failed to be found or count at list-users.\nusersQuery: ${JSON.stringify( + usersQuery + )}` + ); + return next(err); + } + + let lastPage = Math.ceil(total / pageLimit); + if (lastPage > 0) { + page += 1; + if (page > lastPage) { + return res + .status(400) + .json({ page: `Should be less than or equal to ${lastPage}` }); + } + } else { + page = null; + lastPage = null; + } + + const dataResponse = { + page, + lastPage, + pageLimit, + total, + sortBy: queryParams.sortBy, + results: users + }; + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/users/unblock-user.js b/src/routes/users/unblock-user.js index 88a9c17..3340936 100644 --- a/src/routes/users/unblock-user.js +++ b/src/routes/users/unblock-user.js @@ -1,41 +1,41 @@ -const moment = require('moment'); - -const { User } = require('../../models/user'); - -module.exports = async (req, res, next) => { - if (!req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const userId = req.params.userId; - - let user; - try { - user = await User.findOne({ _id: userId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'User not found' }); - } - - console.log(`User with Id ${userId} failed to be found at unblock-user.`); - return next(err); - } - - if (!user) { - return res.status(404).json({ general: 'User not found' }); - } - - user.isBlocked = false; - user.updatedAt = moment.utc().toDate(); - - try { - await user.save(); - } catch (err) { - console.log( - `User with Id ${user.id} failed to be updated at unblock-user.` - ); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { User } = require('../../models/user'); + +module.exports = async (req, res, next) => { + if (!req.user.isAdmin) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const userId = req.params.userId; + + let user; + try { + user = await User.findOne({ _id: userId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'User not found' }); + } + + console.log(`User with Id ${userId} failed to be found at unblock-user.`); + return next(err); + } + + if (!user) { + return res.status(404).json({ general: 'User not found' }); + } + + user.isBlocked = false; + user.updatedAt = moment.utc().toDate(); + + try { + await user.save(); + } catch (err) { + console.log( + `User with Id ${user.id} failed to be updated at unblock-user.` + ); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/users/validations.js b/src/routes/users/validations.js index 66236ae..d59b5f9 100644 --- a/src/routes/users/validations.js +++ b/src/routes/users/validations.js @@ -1,299 +1,299 @@ -const freemail = require('freemail'); -const { isEmail, isInt } = require('validator'); -const { isEmpty } = require('lodash'); -const slugify = require('speakingurl'); - -const { cleanSpaces } = require('../../helpers'); -const { User } = require('../../models/user'); - -module.exports = { - validateChangePassword(data) { - const errors = {}; - - if (!data.oldPassword) { - errors.oldPassword = 'Is required'; - } else if (typeof data.oldPassword !== 'string') { - errors.oldPassword = 'Should be a string'; - } - - if (!data.password) { - errors.password = 'Is required'; - } else if (typeof data.password !== 'string') { - errors.password = 'Should be a string'; - } else if (data.password.length < 8) { - errors.password = 'Should have more than 7 characters'; - } else if (data.password.length > 30) { - errors.password = 'Should have less than 31 characters'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateCreateUser(data) { - const errors = {}; - - if (data.description) { - if (typeof data.description !== 'string') { - errors.description = 'Should be a string'; - } else if (cleanSpaces(data.description).length > 2000) { - errors.description = 'Should have less than 2001 characters'; - } - } - - if (!data.email) { - errors.email = 'Is required'; - } else if (typeof data.email !== 'string') { - errors.email = 'Should be a string'; - } else if (cleanSpaces(data.email).length > 254) { - errors.email = 'Should have less than 255 characters'; - } else if (!isEmail(data.email) || freemail.isDisposable(data.email)) { - errors.email = 'Is not a valid email'; - } - - if (!data.firstName) { - errors.firstName = 'Is required'; - } else if (typeof data.firstName !== 'string') { - errors.firstName = 'Should be a string'; - } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.firstName)) { - errors.firstName = 'Should only have letters'; - } else if (cleanSpaces(data.firstName).length > 24) { - errors.firstName = 'Should have less than 25 characters'; - } else { - const firstName = cleanSpaces(data.firstName); - - if (firstName.split(' ').length > 1) { - errors.firstName = 'Should only be one name'; - } - } - - if (!data.lastName) { - errors.lastName = 'Is required'; - } else if (typeof data.lastName !== 'string') { - errors.lastName = 'Should be a string'; - } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.lastName)) { - errors.lastName = 'Should only have letters'; - } else if (cleanSpaces(data.lastName).length > 36) { - errors.lastName = 'Should have less than 37 characters'; - } else { - const lastName = cleanSpaces(data.lastName); - - if (lastName.split(' ').length > 1) { - errors.lastName = 'Should only be one last name'; - } - } - - if (!data.password) { - errors.password = 'Is required'; - } else if (typeof data.password !== 'string') { - errors.password = 'Should be a string'; - } else if (data.password.length < 8) { - errors.password = 'Should be more than 7 characters'; - } else if (data.password.length > 30) { - errors.password = 'Should be less than 31 characters'; - } - - if (data.phone) { - if (typeof data.phone !== 'string') { - errors.phone = 'Should be a string'; - } else if (cleanSpaces(data.phone).length > 50) { - errors.phone = 'Should have less than 51 characters'; - } - } - - if (data.username) { - if (typeof data.username !== 'string') { - errors.username = 'Should be a string'; - } else if (cleanSpaces(data.username).length > 67) { - errors.username = 'Should have less than 68 characters'; - } else { - const username = slugify(data.username); - - if (username !== data.username) { - errors.username = 'Should only have lowercase letters and hyphens'; - } - } - } - - if (data.zip) { - if (typeof data.zip !== 'string') { - errors.zip = 'Should be a string'; - } else if (cleanSpaces(data.zip).length > 32) { - errors.zip = 'Should have less than 33 characters'; - } - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateEditUser(data) { - const errors = {}; - - if (typeof data.avatar !== 'undefined' && typeof data.avatar !== 'string') { - errors.avatar = 'Should be a string'; - } - - if ( - typeof data.description !== 'undefined' && - typeof data.description !== 'string' - ) { - errors.description = 'Should be a string'; - } - - if (typeof data.disabilities !== 'undefined') { - if (!Array.isArray(data.disabilities)) { - errors.disabilities = 'Should be an array'; - } else { - const disabilitiesTypes = [ - 'brain', - 'cognitive', - 'hearing', - 'invisible', - 'none', - 'other', - 'physical', - 'private', - 'psychological', - 'spinal-cord', - 'vision' - ]; - data.disabilities.some(d => { - if (typeof d !== 'string') { - errors.disabilities = 'All values should be strings'; - return true; - } else if (!disabilitiesTypes.includes(d)) { - errors.disabilities = 'All values should be valid disabilities'; - return true; - } - }); - } - } - - if (typeof data.firstName !== 'undefined') { - if (typeof data.firstName !== 'string') { - errors.firstName = 'Should be a string'; - } else if (data.firstName === '') { - errors.firstName = 'Is required'; - } else if ( - /[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.firstName) - ) { - errors.firstName = 'Should only have letters'; - } else { - const firstName = cleanSpaces(data.firstName); - - if (firstName.split(' ').length > 1) { - errors.firstName = 'Should only be one first name'; - } - } - } - - if (typeof data.gender !== 'undefined') { - const gendersTypes = User.schema.path('gender').enumValues; - if (typeof data.gender !== 'string') { - errors.gender = 'Should be a string'; - } else if (data.gender === '') { - errors.gender = 'Is required'; - } else if (!gendersTypes.includes(data.gender)) { - errors.gender = 'Should be a valid gender'; - } - } - - if ( - typeof data.isSubscribed !== 'undefined' && - typeof data.isSubscribed !== 'boolean' - ) { - errors.isSubscribed = 'Should be a boolean'; - } - - if (typeof data.lastName !== 'undefined') { - if (typeof data.lastName !== 'string') { - errors.lastName = 'Should be a string'; - } else if (data.lastName === '') { - errors.lastName = 'Is required'; - } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.lastName)) { - errors.lastName = 'Should only have letters'; - } else { - const lastName = cleanSpaces(data.lastName); - - if (lastName.split(' ').length > 1) { - errors.lastName = 'Should only be one last name'; - } - } - } - - if (typeof data.phone !== 'undefined' && typeof data.phone !== 'string') { - errors.phone = 'Should be a string'; - } - - if ( - typeof data.showDisabilities !== 'undefined' && - typeof data.showDisabilities !== 'boolean' - ) { - errors.showDisabilities = 'Should be a boolean'; - } - - if ( - typeof data.showEmail !== 'undefined' && - typeof data.showEmail !== 'boolean' - ) { - errors.showEmail = 'Should be a boolean'; - } - - if ( - typeof data.showPhone !== 'undefined' && - typeof data.showPhone !== 'boolean' - ) { - errors.showPhone = 'Should be a boolean'; - } - - if (typeof data.username !== 'undefined') { - if (typeof data.username !== 'string') { - errors.username = 'Should be a string'; - } else if (data.username === '') { - errors.username = 'Is required'; - } else { - const username = slugify(data.username); - - if (username !== data.username) { - errors.username = 'Should only have lowercase letters and hyphens'; - } - } - } - - if (typeof data.zip !== 'undefined' && typeof data.zip !== 'string') { - errors.zip = 'Should be a string'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateListUsers(queryParams) { - const errors = {}; - - if (queryParams.page && !isInt(queryParams.page)) { - errors.page = 'Should be a integer'; - } else if (parseInt(queryParams.page, 10) < 1) { - errors.page = 'Should be greater than or equal to 1'; - } - - if (queryParams.pageLimit && !isInt(queryParams.pageLimit)) { - errors.pageLimit = 'Should be a integer'; - } else if (parseInt(queryParams.pageLimit, 10) < 1) { - errors.pageLimit = 'Should be greater than or equal to 1'; - } else if (parseInt(queryParams.pageLimit, 10) > 12) { - errors.pageLimit = 'Should be less than or equal to 12'; - } - - const sortOptions = [ - 'email', - '-email', - 'firstName', - '-firstName', - 'lastName', - '-lastName', - 'username', - '-username' - ]; - if (queryParams.sortBy && !sortOptions.includes(queryParams.sortBy)) { - errors.sortBy = 'Should be a valid sort'; - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const freemail = require('freemail'); +const { isEmail, isInt } = require('validator'); +const { isEmpty } = require('lodash'); +const slugify = require('speakingurl'); + +const { cleanSpaces } = require('../../helpers'); +const { User } = require('../../models/user'); + +module.exports = { + validateChangePassword(data) { + const errors = {}; + + if (!data.oldPassword) { + errors.oldPassword = 'Is required'; + } else if (typeof data.oldPassword !== 'string') { + errors.oldPassword = 'Should be a string'; + } + + if (!data.password) { + errors.password = 'Is required'; + } else if (typeof data.password !== 'string') { + errors.password = 'Should be a string'; + } else if (data.password.length < 8) { + errors.password = 'Should have more than 7 characters'; + } else if (data.password.length > 30) { + errors.password = 'Should have less than 31 characters'; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateCreateUser(data) { + const errors = {}; + + if (data.description) { + if (typeof data.description !== 'string') { + errors.description = 'Should be a string'; + } else if (cleanSpaces(data.description).length > 2000) { + errors.description = 'Should have less than 2001 characters'; + } + } + + if (!data.email) { + errors.email = 'Is required'; + } else if (typeof data.email !== 'string') { + errors.email = 'Should be a string'; + } else if (cleanSpaces(data.email).length > 254) { + errors.email = 'Should have less than 255 characters'; + } else if (!isEmail(data.email) || freemail.isDisposable(data.email)) { + errors.email = 'Is not a valid email'; + } + + if (!data.firstName) { + errors.firstName = 'Is required'; + } else if (typeof data.firstName !== 'string') { + errors.firstName = 'Should be a string'; + } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.firstName)) { + errors.firstName = 'Should only have letters'; + } else if (cleanSpaces(data.firstName).length > 24) { + errors.firstName = 'Should have less than 25 characters'; + } else { + const firstName = cleanSpaces(data.firstName); + + if (firstName.split(' ').length > 1) { + errors.firstName = 'Should only be one name'; + } + } + + if (!data.lastName) { + errors.lastName = 'Is required'; + } else if (typeof data.lastName !== 'string') { + errors.lastName = 'Should be a string'; + } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.lastName)) { + errors.lastName = 'Should only have letters'; + } else if (cleanSpaces(data.lastName).length > 36) { + errors.lastName = 'Should have less than 37 characters'; + } else { + const lastName = cleanSpaces(data.lastName); + + if (lastName.split(' ').length > 1) { + errors.lastName = 'Should only be one last name'; + } + } + + if (!data.password) { + errors.password = 'Is required'; + } else if (typeof data.password !== 'string') { + errors.password = 'Should be a string'; + } else if (data.password.length < 8) { + errors.password = 'Should be more than 7 characters'; + } else if (data.password.length > 30) { + errors.password = 'Should be less than 31 characters'; + } + + if (data.phone) { + if (typeof data.phone !== 'string') { + errors.phone = 'Should be a string'; + } else if (cleanSpaces(data.phone).length > 50) { + errors.phone = 'Should have less than 51 characters'; + } + } + + if (data.username) { + if (typeof data.username !== 'string') { + errors.username = 'Should be a string'; + } else if (cleanSpaces(data.username).length > 67) { + errors.username = 'Should have less than 68 characters'; + } else { + const username = slugify(data.username); + + if (username !== data.username) { + errors.username = 'Should only have lowercase letters and hyphens'; + } + } + } + + if (data.zip) { + if (typeof data.zip !== 'string') { + errors.zip = 'Should be a string'; + } else if (cleanSpaces(data.zip).length > 32) { + errors.zip = 'Should have less than 33 characters'; + } + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateEditUser(data) { + const errors = {}; + + if (typeof data.avatar !== 'undefined' && typeof data.avatar !== 'string') { + errors.avatar = 'Should be a string'; + } + + if ( + typeof data.description !== 'undefined' && + typeof data.description !== 'string' + ) { + errors.description = 'Should be a string'; + } + + if (typeof data.disabilities !== 'undefined') { + if (!Array.isArray(data.disabilities)) { + errors.disabilities = 'Should be an array'; + } else { + const disabilitiesTypes = [ + 'brain', + 'cognitive', + 'hearing', + 'invisible', + 'none', + 'other', + 'physical', + 'private', + 'psychological', + 'spinal-cord', + 'vision' + ]; + data.disabilities.some((d) => { + if (typeof d !== 'string') { + errors.disabilities = 'All values should be strings'; + return true; + } else if (!disabilitiesTypes.includes(d)) { + errors.disabilities = 'All values should be valid disabilities'; + return true; + } + }); + } + } + + if (typeof data.firstName !== 'undefined') { + if (typeof data.firstName !== 'string') { + errors.firstName = 'Should be a string'; + } else if (data.firstName === '') { + errors.firstName = 'Is required'; + } else if ( + /[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.firstName) + ) { + errors.firstName = 'Should only have letters'; + } else { + const firstName = cleanSpaces(data.firstName); + + if (firstName.split(' ').length > 1) { + errors.firstName = 'Should only be one first name'; + } + } + } + + if (typeof data.gender !== 'undefined') { + const gendersTypes = User.schema.path('gender').enumValues; + if (typeof data.gender !== 'string') { + errors.gender = 'Should be a string'; + } else if (data.gender === '') { + errors.gender = 'Is required'; + } else if (!gendersTypes.includes(data.gender)) { + errors.gender = 'Should be a valid gender'; + } + } + + if ( + typeof data.isSubscribed !== 'undefined' && + typeof data.isSubscribed !== 'boolean' + ) { + errors.isSubscribed = 'Should be a boolean'; + } + + if (typeof data.lastName !== 'undefined') { + if (typeof data.lastName !== 'string') { + errors.lastName = 'Should be a string'; + } else if (data.lastName === '') { + errors.lastName = 'Is required'; + } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.lastName)) { + errors.lastName = 'Should only have letters'; + } else { + const lastName = cleanSpaces(data.lastName); + + if (lastName.split(' ').length > 1) { + errors.lastName = 'Should only be one last name'; + } + } + } + + if (typeof data.phone !== 'undefined' && typeof data.phone !== 'string') { + errors.phone = 'Should be a string'; + } + + if ( + typeof data.showDisabilities !== 'undefined' && + typeof data.showDisabilities !== 'boolean' + ) { + errors.showDisabilities = 'Should be a boolean'; + } + + if ( + typeof data.showEmail !== 'undefined' && + typeof data.showEmail !== 'boolean' + ) { + errors.showEmail = 'Should be a boolean'; + } + + if ( + typeof data.showPhone !== 'undefined' && + typeof data.showPhone !== 'boolean' + ) { + errors.showPhone = 'Should be a boolean'; + } + + if (typeof data.username !== 'undefined') { + if (typeof data.username !== 'string') { + errors.username = 'Should be a string'; + } else if (data.username === '') { + errors.username = 'Is required'; + } else { + const username = slugify(data.username); + + if (username !== data.username) { + errors.username = 'Should only have lowercase letters and hyphens'; + } + } + } + + if (typeof data.zip !== 'undefined' && typeof data.zip !== 'string') { + errors.zip = 'Should be a string'; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateListUsers(queryParams) { + const errors = {}; + + if (queryParams.page && !isInt(queryParams.page)) { + errors.page = 'Should be a integer'; + } else if (parseInt(queryParams.page, 10) < 1) { + errors.page = 'Should be greater than or equal to 1'; + } + + if (queryParams.pageLimit && !isInt(queryParams.pageLimit)) { + errors.pageLimit = 'Should be a integer'; + } else if (parseInt(queryParams.pageLimit, 10) < 1) { + errors.pageLimit = 'Should be greater than or equal to 1'; + } else if (parseInt(queryParams.pageLimit, 10) > 12) { + errors.pageLimit = 'Should be less than or equal to 12'; + } + + const sortOptions = [ + 'email', + '-email', + 'firstName', + '-firstName', + 'lastName', + '-lastName', + 'username', + '-username' + ]; + if (queryParams.sortBy && !sortOptions.includes(queryParams.sortBy)) { + errors.sortBy = 'Should be a valid sort'; + } + + return { errors, isValid: isEmpty(errors) }; + } +}; diff --git a/src/routes/venues/archive-venue.js b/src/routes/venues/archive-venue.js index af8a0c6..bfaf8b9 100644 --- a/src/routes/venues/archive-venue.js +++ b/src/routes/venues/archive-venue.js @@ -1,39 +1,39 @@ -const moment = require('moment'); - -const { Venue } = require('../../models/venue'); - -module.exports = async (req, res, next) => { - if (!req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const venueId = req.params.venueId; - - let venue; - try { - venue = await Venue.findOne({ _id: venueId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Venue not found' }); - } - - console.log(`Venue ${venueId} failed to be found at delete-venue`); - return next(err); - } - - if (!venue) { - return res.status(404).json({ general: 'Venue not found' }); - } - - venue.isArchived = true; - venue.updatedAt = moment.utc().toDate(); - - try { - await venue.save(); - } catch (err) { - console.log(`Venue ${venue.id} failed to be updated at delete-venue`); - return next(err); - } - - return res.status(204).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { Venue } = require('../../models/venue'); + +module.exports = async (req, res, next) => { + if (!req.user.isAdmin) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const venueId = req.params.venueId; + + let venue; + try { + venue = await Venue.findOne({ _id: venueId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Venue not found' }); + } + + console.log(`Venue ${venueId} failed to be found at delete-venue`); + return next(err); + } + + if (!venue) { + return res.status(404).json({ general: 'Venue not found' }); + } + + venue.isArchived = true; + venue.updatedAt = moment.utc().toDate(); + + try { + await venue.save(); + } catch (err) { + console.log(`Venue ${venue.id} failed to be updated at delete-venue`); + return next(err); + } + + return res.status(204).json({ general: 'Success' }); +}; diff --git a/src/routes/venues/get-venue.js b/src/routes/venues/get-venue.js index d1b3fe8..bc30464 100644 --- a/src/routes/venues/get-venue.js +++ b/src/routes/venues/get-venue.js @@ -1,347 +1,348 @@ -const axios = require('axios'); -const { isEqual } = require('lodash'); -const slugify = require('speakingurl'); - -const { Venue } = require('../../models/venue'); -const venueReviewSummary = require('../../helpers/venue-review-summary.js'); - -module.exports = async (req, res, next) => { - const placeId = req.params.placeId; - - let response; - try { - response = await axios.get( - `https://maps.googleapis.com/maps/api/place/details/json?placeid=${placeId}&key=${ - process.env.PLACES_API_KEY - }` - ); - } catch (err) { - console.log(`Place ${placeId} failed to be found at get-venue.`); - return next(err); - } - - const statusResponse = response.data.status; - if (statusResponse !== 'OK') { - return res.status(404).json({ general: 'Place not found' }); - } - - const placeData = response.data.result; - const dataResponse = {}; - dataResponse.address = placeData.formatted_address; - - let useStreetviewCover = false; - let streetViewError = false; - let streetViewResponse; - try { - streetViewResponse = await axios.get( - `https://maps.googleapis.com/maps/api/streetview/metadata?location=${slugify( - dataResponse.address - )}&key=${process.env.PLACES_API_KEY}` - ); - } catch (err) { - console.log(`Streetview for ${placeId} failed to be found at get-venue.`); - streetViewError = true; - } - - let streetViewPanoId; - if (!streetViewError) { - const streetViewMetadataStatus = streetViewResponse.data.status; - if (streetViewMetadataStatus == 'OK') { - useStreetviewCover = true; - streetViewPanoId = streetViewResponse.data.pano_id; - } - } - - if (useStreetviewCover) { - dataResponse.coverPhoto = `https://maps.googleapis.com/maps/api/streetview?key=${ - process.env.PLACES_API_KEY - }&size=800x400&fov=110&location=${slugify(dataResponse.address)}`; - //}&size=800x400&fov=110&heading=0&pano=${streetViewPanoId}`; - //seems like heading needs to be set when using pano id but not for the address - } else if (placeData.photos && placeData.photos.length > 0) { - dataResponse.coverPhoto = `https://maps.googleapis.com/maps/api/place/photo?key=${ - process.env.PLACES_API_KEY - }&maxwidth=500&photoreference=${placeData.photos[0].photo_reference}`; - } - - let coverPhotoLink = - //(useStreetviewCover) ? - `https://www.google.com/maps/@?api=1&map_action=pano&pano=${streetViewPanoId}&viewpoint=${ - placeData.geometry.location.lat - },${placeData.geometry.location.lng}`; - console.log('Cover photo link: ', coverPhotoLink); - - dataResponse.formattedPhone = placeData.formatted_phone_number; - dataResponse.googleRating = placeData.rating; - dataResponse.googleUrl = placeData.url; - dataResponse.internationalPhone = placeData.international_phone_number; - dataResponse.location = { - lat: placeData.geometry.location.lat, - lng: placeData.geometry.location.lng - }; - dataResponse.name = placeData.name; - dataResponse.placeId = placeId; - dataResponse.types = placeData.types; - dataResponse.website = placeData.website; - - dataResponse.allowsGuideDog = { yes: 0, no: 0 }; - //dataResponse.bathroomReviews = 0; - //dataResponse.bathroomScore = null; - //dataResponse.entryReviews = 0; - //dataResponse.entryScore = null; - dataResponse.hasParking = { yes: 0, no: 0 }; - dataResponse.hasSecondEntry = { yes: 0, no: 0 }; - dataResponse.hasWellLit = { yes: 0, no: 0 }; - dataResponse.isQuiet = { yes: 0, no: 0 }; - dataResponse.isSpacious = { yes: 0, no: 0 }; - dataResponse.steps = { - zero: 0, - one: 0, - two: 0, - moreThanTwo: 0 - }; - - //new expanded fields - dataResponse.hasPermanentRamp = { yes: 0, no: 0 }; - dataResponse.hasPortableRamp = { yes: 0, no: 0 }; - dataResponse.hasWideEntrance = { yes: 0, no: 0 }; - dataResponse.hasAccessibleTableHeight = { yes: 0, no: 0 }; - dataResponse.hasAccessibleElevator = { yes: 0, no: 0 }; - dataResponse.hasInteriorRamp = { yes: 0, no: 0 }; - dataResponse.hasSwingOutDoor = { yes: 0, no: 0 }; - dataResponse.hasLargeStall = { yes: 0, no: 0 }; - dataResponse.hasSupportAroundToilet = { yes: 0, no: 0 }; - dataResponse.hasLoweredSinks = { yes: 0, no: 0 }; - - dataResponse.entranceScore = 0; - dataResponse.entranceGlyphs = ''; - dataResponse.interiorScore = 0; - dataResponse.interiorGlyphs = ''; - dataResponse.restroomScore = 0; - dataResponse.restroomGlyphs = ''; - dataResponse.mapMarkerScore = 0; - - let venue; - let venueToSave; - try { - [venue, venueToSave] = await Promise.all([ - Venue.aggregate([ - { - $match: { placeId, isArchived: false } - }, - { - $lookup: { - from: 'reviews', - let: { reviews: '$reviews' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$reviews'] - } - } - }, - { - $lookup: { - from: 'users', - let: { user: '$user' }, - pipeline: [ - { - $match: { - $expr: { - $eq: ['$_id', '$$user'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - firstName: 1, - lastName: 1 - } - } - ], - as: 'user' - } - }, - { - $project: { - _id: 0, - id: '$_id', - //bathroomScore: 1, - comments: 1, - createdAt: 1, - //entryScore: 1, - user: 1, - voters: 1 - } - } - ], - as: 'reviews' - } - }, - { - $lookup: { - from: 'photos', - let: { photos: { $ifNull: ['$photos', []] } }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$photos'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - url: 1 - } - } - ], - as: 'photos' - } - }, - { - $project: { - _id: 0, - id: '$_id', - address: 1, - description: 1, - allowsGuideDog: 1, - //bathroomReviews: 1, - //bathroomScore: 1, - //entryReviews: 1, - //entryScore: 1, - hasParking: 1, - hasSecondEntry: 1, - hasWellLit: 1, - isQuiet: 1, - isSpacious: 1, - location: 1, - name: 1, - photos: 1, - placeId: 1, - steps: 1, - types: 1, - reviews: 1, - hasPermanentRamp: 1, - hasPortableRamp: 1, - hasWideEntrance: 1, - hasAccessibleTableHeight: 1, - hasAccessibleElevator: 1, - hasInteriorRamp: 1, - hasSwingOutDoor: 1, - hasLargeStall: 1, - hasSupportAroundToilet: 1, - hasLoweredSinks: 1 - } - } - ]), - Venue.findOne({ placeId, isArchived: false }) - ]); - } catch (err) { - console.log( - `Venue with placeId ${placeId} failed to be found at get-venue` - ); - return next(err); - } - - if (venue && venue[0]) { - let venueHasUpdates = false; - if (venueToSave.address !== dataResponse.address) { - venueToSave.address = dataResponse.address; - venueHasUpdates = true; - } - if ( - venueToSave.location.coordinates[0] !== dataResponse.location.lng || - venueToSave.location.coordinates[1] !== dataResponse.location.lat - ) { - venueToSave.location.coordinates = [ - dataResponse.location.lng, - dataResponse.location.lat - ]; - venueHasUpdates = true; - } - if (venueToSave.name !== dataResponse.name) { - venueToSave.name = dataResponse.name; - venueHasUpdates = true; - } - if (!isEqual(venueToSave.types, dataResponse.types)) { - venueToSave.types = dataResponse.types; - venueHasUpdates = true; - } - - if (venueHasUpdates) { - try { - await venueToSave.save(); - } catch (err) { - console.log( - `Venue with id ${venueToSave.id} failed to be updated at get-venue.` - ); - return next(err); - } - } - - //TEMP: - let scoring; - //console.log('venue0: ', venue[0]); - - //calculate entranceScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('entrance', venue[0]); - console.log('entrance score: ', scoring); - dataResponse.entranceScore = scoring.ratingLevel; - dataResponse.entranceGlyphs = scoring.ratingGlyphs; - - //calculate interiorScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('interior', venue[0]); - console.log('interior score: ', scoring); - dataResponse.interiorScore = scoring.ratingLevel; - dataResponse.interiorGlyphs = scoring.ratingGlyphs; - - //calculate restroomScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('restroom', venue[0]); - console.log('restroom score: ', scoring); - dataResponse.restroomScore = scoring.ratingLevel; - dataResponse.restroomGlyphs = scoring.ratingGlyphs; - - dataResponse.mapMarkerScore = venueReviewSummary.calculateMapMarkerScore( - dataResponse.entranceScore, - dataResponse.interiorScore, - dataResponse.restroomScore - ); - - dataResponse.id = venue[0]._id; - - dataResponse.allowsGuideDog = venue[0].allowsGuideDog; - //dataResponse.bathroomReviews = venue[0].bathroomReviews; - //dataResponse.bathroomScore = venue[0].bathroomScore; - //dataResponse.entryReviews = venue[0].entryReviews; - //dataResponse.entryScore = venue[0].entryScore; - dataResponse.hasParking = venue[0].hasParking; - dataResponse.hasSecondEntry = venue[0].hasSecondEntry; - dataResponse.hasWellLit = venue[0].hasWellLit; - dataResponse.isQuiet = venue[0].isQuiet; - dataResponse.isSpacious = venue[0].isSpacious; - dataResponse.photos = venue[0].photos; - dataResponse.steps = venue[0].steps; - //new expanded fields - dataResponse.hasPermanentRamp = venue[0].hasPermanentRamp; - dataResponse.hasPortableRamp = venue[0].hasPortableRamp; - dataResponse.hasWideEntrance = venue[0].hasWideEntrance; - dataResponse.hasAccessibleTableHeight = venue[0].hasAccessibleTableHeight; - dataResponse.hasAccessibleElevator = venue[0].hasAccessibleElevator; - dataResponse.hasInteriorRamp = venue[0].hasInteriorRamp; - dataResponse.hasSwingOutDoor = venue[0].hasSwingOutDoor; - dataResponse.hasLargeStall = venue[0].hasLargeStall; - dataResponse.hasSupportAroundToilet = venue[0].hasSupportAroundToilet; - dataResponse.hasLoweredSinks = venue[0].hasLoweredSinks; - - dataResponse.reviews = venue[0].reviews; - } - - return res.status(200).json(dataResponse); -}; +const axios = require('axios'); +const { isEqual } = require('lodash'); +const slugify = require('speakingurl'); + +const { Venue } = require('../../models/venue'); +const venueReviewSummary = require('../../helpers/venue-review-summary.js'); + +module.exports = async (req, res, next) => { + const placeId = req.params.placeId; + + let response; + try { + response = await axios.get( + `https://maps.googleapis.com/maps/api/place/details/json?placeid=${placeId}&key=${ + process.env.PLACES_API_KEY + }` + ); + } catch (err) { + console.log(`Place ${placeId} failed to be found at get-venue.`); + return next(err); + } + + const statusResponse = response.data.status; + if (statusResponse !== 'OK') { + return res.status(404).json({ general: 'Place not found' }); + } + + const placeData = response.data.result; + const dataResponse = {}; + dataResponse.address = placeData.formatted_address; + + let useStreetviewCover = false; + let streetViewError = false; + let streetViewResponse; + try { + streetViewResponse = await axios.get( + `https://maps.googleapis.com/maps/api/streetview/metadata?location=${slugify( + dataResponse.address + )}&key=${process.env.PLACES_API_KEY}` + ); + } catch (err) { + console.error(err); + console.log(`Streetview for ${placeId} failed to be found at get-venue.`); + streetViewError = true; + } + + let streetViewPanoId; + if (!streetViewError) { + const streetViewMetadataStatus = streetViewResponse.data.status; + if (streetViewMetadataStatus == 'OK') { + useStreetviewCover = true; + streetViewPanoId = streetViewResponse.data.pano_id; + } + } + + if (useStreetviewCover) { + dataResponse.coverPhoto = `https://maps.googleapis.com/maps/api/streetview?key=${ + process.env.PLACES_API_KEY + }&size=800x400&fov=110&location=${slugify(dataResponse.address)}`; + //}&size=800x400&fov=110&heading=0&pano=${streetViewPanoId}`; + //seems like heading needs to be set when using pano id but not for the address + } else if (placeData.photos && placeData.photos.length > 0) { + dataResponse.coverPhoto = `https://maps.googleapis.com/maps/api/place/photo?key=${ + process.env.PLACES_API_KEY + }&maxwidth=500&photoreference=${placeData.photos[0].photo_reference}`; + } + + let coverPhotoLink = + //(useStreetviewCover) ? + `https://www.google.com/maps/@?api=1&map_action=pano&pano=${streetViewPanoId}&viewpoint=${ + placeData.geometry.location.lat + },${placeData.geometry.location.lng}`; + console.log('Cover photo link: ', coverPhotoLink); + + dataResponse.formattedPhone = placeData.formatted_phone_number; + dataResponse.googleRating = placeData.rating; + dataResponse.googleUrl = placeData.url; + dataResponse.internationalPhone = placeData.international_phone_number; + dataResponse.location = { + lat: placeData.geometry.location.lat, + lng: placeData.geometry.location.lng + }; + dataResponse.name = placeData.name; + dataResponse.placeId = placeId; + dataResponse.types = placeData.types; + dataResponse.website = placeData.website; + + dataResponse.allowsGuideDog = { yes: 0, no: 0 }; + //dataResponse.bathroomReviews = 0; + //dataResponse.bathroomScore = null; + //dataResponse.entryReviews = 0; + //dataResponse.entryScore = null; + dataResponse.hasParking = { yes: 0, no: 0 }; + dataResponse.hasSecondEntry = { yes: 0, no: 0 }; + dataResponse.hasWellLit = { yes: 0, no: 0 }; + dataResponse.isQuiet = { yes: 0, no: 0 }; + dataResponse.isSpacious = { yes: 0, no: 0 }; + dataResponse.steps = { + zero: 0, + one: 0, + two: 0, + moreThanTwo: 0 + }; + + //new expanded fields + dataResponse.hasPermanentRamp = { yes: 0, no: 0 }; + dataResponse.hasPortableRamp = { yes: 0, no: 0 }; + dataResponse.hasWideEntrance = { yes: 0, no: 0 }; + dataResponse.hasAccessibleTableHeight = { yes: 0, no: 0 }; + dataResponse.hasAccessibleElevator = { yes: 0, no: 0 }; + dataResponse.hasInteriorRamp = { yes: 0, no: 0 }; + dataResponse.hasSwingOutDoor = { yes: 0, no: 0 }; + dataResponse.hasLargeStall = { yes: 0, no: 0 }; + dataResponse.hasSupportAroundToilet = { yes: 0, no: 0 }; + dataResponse.hasLoweredSinks = { yes: 0, no: 0 }; + + dataResponse.entranceScore = 0; + dataResponse.entranceGlyphs = ''; + dataResponse.interiorScore = 0; + dataResponse.interiorGlyphs = ''; + dataResponse.restroomScore = 0; + dataResponse.restroomGlyphs = ''; + dataResponse.mapMarkerScore = 0; + + let venue; + let venueToSave; + try { + [venue, venueToSave] = await Promise.all([ + Venue.aggregate([ + { + $match: { placeId, isArchived: false } + }, + { + $lookup: { + from: 'reviews', + let: { reviews: '$reviews' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$reviews'] + } + } + }, + { + $lookup: { + from: 'users', + let: { user: '$user' }, + pipeline: [ + { + $match: { + $expr: { + $eq: ['$_id', '$$user'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + firstName: 1, + lastName: 1 + } + } + ], + as: 'user' + } + }, + { + $project: { + _id: 0, + id: '$_id', + //bathroomScore: 1, + comments: 1, + createdAt: 1, + //entryScore: 1, + user: 1, + voters: 1 + } + } + ], + as: 'reviews' + } + }, + { + $lookup: { + from: 'photos', + let: { photos: { $ifNull: ['$photos', []] } }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$photos'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + url: 1 + } + } + ], + as: 'photos' + } + }, + { + $project: { + _id: 0, + id: '$_id', + address: 1, + description: 1, + allowsGuideDog: 1, + //bathroomReviews: 1, + //bathroomScore: 1, + //entryReviews: 1, + //entryScore: 1, + hasParking: 1, + hasSecondEntry: 1, + hasWellLit: 1, + isQuiet: 1, + isSpacious: 1, + location: 1, + name: 1, + photos: 1, + placeId: 1, + steps: 1, + types: 1, + reviews: 1, + hasPermanentRamp: 1, + hasPortableRamp: 1, + hasWideEntrance: 1, + hasAccessibleTableHeight: 1, + hasAccessibleElevator: 1, + hasInteriorRamp: 1, + hasSwingOutDoor: 1, + hasLargeStall: 1, + hasSupportAroundToilet: 1, + hasLoweredSinks: 1 + } + } + ]), + Venue.findOne({ placeId, isArchived: false }) + ]); + } catch (err) { + console.log( + `Venue with placeId ${placeId} failed to be found at get-venue` + ); + return next(err); + } + + if (venue && venue[0]) { + let venueHasUpdates = false; + if (venueToSave.address !== dataResponse.address) { + venueToSave.address = dataResponse.address; + venueHasUpdates = true; + } + if ( + venueToSave.location.coordinates[0] !== dataResponse.location.lng || + venueToSave.location.coordinates[1] !== dataResponse.location.lat + ) { + venueToSave.location.coordinates = [ + dataResponse.location.lng, + dataResponse.location.lat + ]; + venueHasUpdates = true; + } + if (venueToSave.name !== dataResponse.name) { + venueToSave.name = dataResponse.name; + venueHasUpdates = true; + } + if (!isEqual(venueToSave.types, dataResponse.types)) { + venueToSave.types = dataResponse.types; + venueHasUpdates = true; + } + + if (venueHasUpdates) { + try { + await venueToSave.save(); + } catch (err) { + console.log( + `Venue with id ${venueToSave.id} failed to be updated at get-venue.` + ); + return next(err); + } + } + + //TEMP: + let scoring; + //console.log('venue0: ', venue[0]); + + //calculate entranceScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('entrance', venue[0]); + console.log('entrance score: ', scoring); + dataResponse.entranceScore = scoring.ratingLevel; + dataResponse.entranceGlyphs = scoring.ratingGlyphs; + + //calculate interiorScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('interior', venue[0]); + console.log('interior score: ', scoring); + dataResponse.interiorScore = scoring.ratingLevel; + dataResponse.interiorGlyphs = scoring.ratingGlyphs; + + //calculate restroomScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('restroom', venue[0]); + console.log('restroom score: ', scoring); + dataResponse.restroomScore = scoring.ratingLevel; + dataResponse.restroomGlyphs = scoring.ratingGlyphs; + + dataResponse.mapMarkerScore = venueReviewSummary.calculateMapMarkerScore( + dataResponse.entranceScore, + dataResponse.interiorScore, + dataResponse.restroomScore + ); + + dataResponse.id = venue[0]._id; + + dataResponse.allowsGuideDog = venue[0].allowsGuideDog; + //dataResponse.bathroomReviews = venue[0].bathroomReviews; + //dataResponse.bathroomScore = venue[0].bathroomScore; + //dataResponse.entryReviews = venue[0].entryReviews; + //dataResponse.entryScore = venue[0].entryScore; + dataResponse.hasParking = venue[0].hasParking; + dataResponse.hasSecondEntry = venue[0].hasSecondEntry; + dataResponse.hasWellLit = venue[0].hasWellLit; + dataResponse.isQuiet = venue[0].isQuiet; + dataResponse.isSpacious = venue[0].isSpacious; + dataResponse.photos = venue[0].photos; + dataResponse.steps = venue[0].steps; + //new expanded fields + dataResponse.hasPermanentRamp = venue[0].hasPermanentRamp; + dataResponse.hasPortableRamp = venue[0].hasPortableRamp; + dataResponse.hasWideEntrance = venue[0].hasWideEntrance; + dataResponse.hasAccessibleTableHeight = venue[0].hasAccessibleTableHeight; + dataResponse.hasAccessibleElevator = venue[0].hasAccessibleElevator; + dataResponse.hasInteriorRamp = venue[0].hasInteriorRamp; + dataResponse.hasSwingOutDoor = venue[0].hasSwingOutDoor; + dataResponse.hasLargeStall = venue[0].hasLargeStall; + dataResponse.hasSupportAroundToilet = venue[0].hasSupportAroundToilet; + dataResponse.hasLoweredSinks = venue[0].hasLoweredSinks; + + dataResponse.reviews = venue[0].reviews; + } + + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/venues/index.js b/src/routes/venues/index.js index 2f35371..94fec3d 100644 --- a/src/routes/venues/index.js +++ b/src/routes/venues/index.js @@ -1,19 +1,19 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const archiveVenue = require('./archive-venue'); -const getVenue = require('./get-venue'); -const listVenues = require('./list-venues'); - -const router = new express.Router(); - -router.get('', listVenues); -router.get('/:placeId', getVenue); -router.put( - '/:venueId/archive', - isAuthenticated({ isOptional: false }), - archiveVenue -); - -module.exports = router; +const express = require('express'); + +const { isAuthenticated } = require('../../helpers'); + +const archiveVenue = require('./archive-venue'); +const getVenue = require('./get-venue'); +const listVenues = require('./list-venues'); + +const router = new express.Router(); + +router.get('', listVenues); +router.get('/:placeId', getVenue); +router.put( + '/:venueId/archive', + isAuthenticated({ isOptional: false }), + archiveVenue +); + +module.exports = router; diff --git a/src/routes/venues/list-venues.js b/src/routes/venues/list-venues.js index 306ddd9..81b6821 100644 --- a/src/routes/venues/list-venues.js +++ b/src/routes/venues/list-venues.js @@ -1,642 +1,630 @@ -const axios = require('axios'); -const { find, isEmpty } = require('lodash'); -const slugify = require('speakingurl'); - -const { isNumber } = require('../../helpers'); -const { Venue } = require('../../models/venue'); - -const { validateListVenues } = require('./validations'); -const venueReviewSummary = require('../../helpers/venue-review-summary.js'); - -module.exports = async (req, res, next) => { - const queryParams = req.query; - - const { errors, isValid } = validateListVenues(queryParams); - if (!isValid) return res.status(400).json(errors); - - let coordinates = queryParams.location.split(','); - - //Legacy function from two-bar search, geocodes from string address - if (queryParams.address && !queryParams.page) { - console.log('in address conditional, ', queryParams); - queryParams.name = queryParams.address; - const geocodeParams = `?key=${process.env.PLACES_API_KEY}&address=${slugify( - queryParams.address - )}`; - - let geocodeResponse; - try { - geocodeResponse = await axios.get( - `https://maps.googleapis.com/maps/api/geocode/json${geocodeParams}` - ); - } catch (err) { - console.log( - `Geocode failed to be found at list-venues.\nQuery Params: ${JSON.stringify( - queryParams - )}` - ); - return next(err); - } - - const statusCode = geocodeResponse.data.status; - if (statusCode === 'ZERO_RESULTS') { - return res.status(404).json({ keywords: 'Address not found' }); - } else if (statusCode === 'OVER_QUERY_LIMIT') { - return next(new Error('Over query limit with Google Places API')); - } else if (statusCode === 'REQUEST_DENIED') { - return next(new Error('Request denied with Google Places API')); - } else if (statusCode === 'INVALID_REQUEST') { - return next(new Error('Invalid request with Google Places API')); - } else if (statusCode === 'UNKNOWN_ERROR') { - return next(new Error('Unknown error with Google Places API')); - } - - coordinates = [ - geocodeResponse.data.results[0].geometry.location.lat, - geocodeResponse.data.results[0].geometry.location.lng - ]; - } //end address geocode - - let venuesFilters = {}; - let dbVenuesFilters = {}; - - /* - * Legacy filter string building function, - * has a critical defect condition where if - * no > yes but yes is at least 1, then there - * would be a false match. - */ - if (queryParams.entranceScore) { - venuesFilters.entranceScore = parseFloat(queryParams.entranceScore); - //{ $gte: parseFloat(queryParams.entranceScore) }; - } - - if (queryParams.interiorScore) { - venuesFilters.interiorScore = parseFloat(queryParams.interiorScore); - //{ $gte: parseFloat(queryParams.interiorScore) }; - } - - if (queryParams.restroomScore) { - venuesFilters.restroomScore = parseFloat(queryParams.restroomScore); - //{ $gte: parseFloat(queryParams.restroomScore) }; - } - - if (queryParams.allowsGuideDog) { - venuesFilters.allowsGuideDog = parseFloat(queryParams.allowsGuideDog); - - const allowsGuideDog = parseFloat(queryParams.allowsGuideDog) === 1; - if (allowsGuideDog) { - dbVenuesFilters['allowsGuideDog.yes'] = { $gte: 1 }; - } else { - dbVenuesFilters['allowsGuideDog.no'] = { $gte: 1 }; - } - } - - if (queryParams.hasParking) { - venuesFilters.hasParking = queryParams.hasParking; - - const hasParking = parseFloat(queryParams.hasParking) === 1; - if (hasParking) { - dbVenuesFilters['hasParking.yes'] = { $gte: 1 }; - } else { - dbVenuesFilters['hasParking.no'] = { $gte: 1 }; - } - } - - /* - * Not used - * - if (queryParams.hasRamp) { - const hasRamp = parseFloat(queryParams.hasRamp) === 1; - if (hasRamp) { - venuesFilters['hasRamp.yes'] = { $gte: 1 }; - } else { - venuesFilters['hasRamp.no'] = { $gte: 1 }; - } - } - - if (queryParams.hasSecondEntry) { - const hasSecondEntry = parseFloat(queryParams.hasSecondEntry) === 1; - if (hasSecondEntry) { - venuesFilters['hasSecondEntry.yes'] = { $gte: 1 }; - } else { - venuesFilters['hasSecondEntry.no'] = { $gte: 1 }; - } - } - - if (queryParams.hasWellLit) { - const hasWellLit = parseFloat(queryParams.hasWellLit) === 1; - if (hasWellLit) { - venuesFilters['hasWellLit.yes'] = { $gte: 1 }; - } else { - venuesFilters['hasWellLit.no'] = { $gte: 1 }; - } - } - - if (queryParams.isQuiet) { - const isQuiet = parseFloat(queryParams.isQuiet) === 1; - if (isQuiet) { - venuesFilters['isQuiet.yes'] = { $gte: 1 }; - } else { - venuesFilters['isQuiet.no'] = { $gte: 1 }; - } - } - - if (queryParams.isSpacious) { - const isSpacious = parseFloat(queryParams.isSpacious) === 1; - if (isSpacious) { - venuesFilters['isSpacious.yes'] = { $gte: 1 }; - } else { - venuesFilters['isSpacious.no'] = { $gte: 1 }; - } - } - - if (queryParams.steps) { - if (parseFloat(queryParams.steps) === 0) { - venuesFilters['steps.zero'] = { $gte: 1 }; - } else if (parseFloat(queryParams.steps) === 1) { - venuesFilters['steps.one'] = { $gte: 1 }; - } else if (parseFloat(queryParams.steps) === 2) { - venuesFilters['steps.two'] = { $gte: 1 }; - } else if (parseFloat(queryParams.steps) === 3) { - venuesFilters['steps.moreThanTwo'] = { $gte: 1 }; - } - } - * - */ - - let dataResponse; - - /* - * Legacy filtering function that searches solely on - * AXS Venue data and provides it's own pagination of 20 - * UPDATED 05/2020 TO SUPPORT FILTER ONLY SELF SEARCH - */ - if (!isEmpty(venuesFilters) && isEmpty(queryParams.name)) { - console.log('>> Performing DB search'); - /* - if (queryParams.name) { - //performs literal name match against AXS Venue name - venuesFilters.name = { $regex: queryParams.name, $options: 'i' }; - } - */ - - dbVenuesFilters.location = { - $near: { - $geometry: { - type: 'Point', - coordinates: [coordinates[1], coordinates[0]] - }, - $maxDistance: 50000 - } - }; - - if (queryParams.type) { - dbVenuesFilters.types = queryParams.type; - } - - dbVenuesFilters.isArchived = false; - - let page = 1; - if (isNumber(queryParams.page)) { - page = queryParams.page; - } - - const pageLimit = - venuesFilters.hasOwnProperty('entranceScore') || - venuesFilters.hasOwnProperty('interiorScore') || - venuesFilters.hasOwnProperty('restroomScore') - ? 80 - : 20; - - if (page > 0) { - page -= 1; - } else { - return res - .status(400) - .json({ page: 'Should be equal to or greater than 1' }); - } - - let total; - let venues; - try { - [venues, total] = await Promise.all([ - Venue.find( - dbVenuesFilters - /*,'address allowsGuideDog hasParking hasSecondEntry hasWellLit isQuiet isSpacious location name photos placeId steps types'*/ - ) - .skip(page * pageLimit) - .limit(pageLimit), - Venue.find(dbVenuesFilters).count() - /*TODO: count is deprecated in favor of countDocuments, but that does not support $near - would need to move to GeoWithin but that does not return sorted results - */ - ]); - } catch (err) { - console.log( - `Venues failed to be found or count at list-venues.\nvenuesQuery: ${JSON.stringify( - dbVenuesFilters - )}` - ); - console.log(err); - return next(err); - } - - venues = venues.map(venue => - Object.assign({}, venue.toObject(), { - id: venue._id, - _id: undefined, - location: venue.coordinates - }) - ); - - //+ADDED - //Perform ratings logic on all returned venues - console.log('Raw venues count: ' + venues.length); - venues = venues.filter(venue => { - //console.log('In scoring assignment'); - let scoring; - //calculate entranceScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('entrance', venue); - venue.entranceScore = scoring.ratingLevel; - venue.entranceGlyphs = scoring.ratingGlyphs; - - //calculate interiorScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('interior', venue); - venue.interiorScore = scoring.ratingLevel; - venue.interiorGlyphs = scoring.ratingGlyphs; - - //calculate restroomScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('restroom', venue); - venue.restroomScore = scoring.ratingLevel; - venue.restroomGlyphs = scoring.ratingGlyphs; - - venue.mapMarkerScore = venueReviewSummary.calculateMapMarkerScore( - venue.entranceScore, - venue.interiorScore, - venue.restroomScore - ); - - let passesValidation = true; - if (venuesFilters.hasOwnProperty('entranceScore')) { - if ( - !venue.entranceScore || - venue.entranceScore < venuesFilters.entranceScore - ) { - passesValidation = false; - } - } - - if (passesValidation && venuesFilters.hasOwnProperty('interiorScore')) { - if ( - !venue.interiorScore || - venue.interiorScore < venuesFilters.interiorScore - ) { - passesValidation = false; - } - } - - if (passesValidation && venuesFilters.hasOwnProperty('restroomScore')) { - if ( - !venue.restroomScore || - venue.restroomScore < venuesFilters.restroomScore - ) { - passesValidation = false; - } - } - - if (passesValidation) { - return venue; - } - }); - - const lastPage = Math.ceil(total / pageLimit); - let nextPage; - if (lastPage > 0) { - page += 1; - if (page > lastPage || page > 3) { - return res.status(400).json({ - page: `Should be equal to or less than ${lastPage > 3 ? 3 : lastPage}` - }); - } - } - - dataResponse = { - nextPage, - results: venues - }; - /* - * End legacy filter - */ - } else { - console.log('>> Performing Google search'); - - /* - * Perform Google search when there text entered or no filters selected - */ - let nearbyParams = `?key=${process.env.PLACES_API_KEY}`; - let searchType = queryParams.name ? 'textsearch' : 'nearbysearch'; - - if (!queryParams.page) { - nearbyParams = `${nearbyParams}&location=${coordinates[0]},${ - coordinates[1] - //}&rankby=distance`; - }`; - - if (queryParams.name) { - //nearbyParams = `${nearbyParams}&keyword=${queryParams.name}`; - nearbyParams = `${nearbyParams}&query=${queryParams.name}&radius=5000`; - } else { - //empty search, such as on load - nearbyParams = `${nearbyParams}&rankby=distance`; - } - - if (queryParams.type) { - nearbyParams = `${nearbyParams}&type=${queryParams.type}`; - } else { - nearbyParams = `${nearbyParams}&type=establishment`; - } - } else { - nearbyParams = `${nearbyParams}&pagetoken=${queryParams.page}`; - } - - if (queryParams.rankby) { - nearbyParams = `${nearbyParams}&rankby=${queryParams.rankby}`; - } - if (queryParams.opennow) { - nearbyParams = `${nearbyParams}&opennow=${queryParams.opennow}`; - } - if (queryParams.minprice) { - nearbyParams = `${nearbyParams}&minprice=${queryParams.minprice}`; - } - if (queryParams.maxprice) { - nearbyParams = `${nearbyParams}&maxprice=${queryParams.maxprice}`; - } - - let placesResponse; - try { - console.log( - 'performing google search: ' + - `https://maps.googleapis.com/maps/api/place/${searchType}/json${nearbyParams}` - ); - placesResponse = await axios.get( - `https://maps.googleapis.com/maps/api/place/${searchType}/json${nearbyParams}` - ); - } catch (err) { - console.log( - `Places failed to be found at list-venues.\nQuery Params: ${JSON.stringify( - queryParams - )}` - ); - return next(err); - } - - const statusCode = placesResponse.data.status; - if (statusCode === 'OVER_QUERY_LIMIT') { - return next(new Error('Over query limit with Google Places API')); - } else if (statusCode === 'REQUEST_DENIED') { - return next(new Error('Request denied with Google Places API')); - } else if (statusCode === 'INVALID_REQUEST') { - return next(new Error('Invalid request with Google Places API')); - } else if (statusCode === 'UNKNOWN_ERROR') { - return next(new Error('Unknown error with Google Places API')); - } - //do we need to check for 0? - - if (placesResponse.data.results.length == 1) { - if (placesResponse.data.results[0].types[0] == 'locality') { - console.log( - 'Found a city only: ', - placesResponse.data.results[0].geometry.location - ); - //TODO: redo search with new coordinates and no query/name or change/add "places in " to the first part of the string - } - } - - //Format Google Places results and get array of IDs - let places = []; - const placesIds = []; - placesResponse.data.results.forEach(place => { - let photo = ''; - if (place.photos) { - photo = `https://maps.googleapis.com/maps/api/place/photo?key=${ - process.env.PLACES_API_KEY - }&maxwidth=300&photoreference=${place.photos[0].photo_reference}`; - } - - places.push({ - //address: place.vicinity, - address: place.formatted_address, - location: { - lat: place.geometry.location.lat, - lng: place.geometry.location.lng - }, - name: place.name, - photo, - placeId: place.place_id, - types: place.types - }); - placesIds.push(place.place_id); - }); - - //Use array of Google Place IDs to find AXS Venues - let venues; - try { - venues = await Venue.find({ placeId: { $in: placesIds } }); - } catch (err) { - console.log( - `Venues failed to be found at list-venues.\nPlaces ids: [${placesIds}]` - ); - return next(err); - } - - //Perform ratings logic on all returned venues - venues.forEach(venue => { - //console.log('In scoring assignment'); - let scoring; - //calculate entranceScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('entrance', venue); - venue.entranceScore = scoring.ratingLevel; - venue.entranceGlyphs = scoring.ratingGlyphs; - - //calculate interiorScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('interior', venue); - venue.interiorScore = scoring.ratingLevel; - venue.interiorGlyphs = scoring.ratingGlyphs; - - //calculate restroomScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('restroom', venue); - venue.restroomScore = scoring.ratingLevel; - venue.restroomGlyphs = scoring.ratingGlyphs; - - venue.mapMarkerScore = venueReviewSummary.calculateMapMarkerScore( - venue.entranceScore, - venue.interiorScore, - venue.restroomScore - ); - }); - - //Filter out, remove, Google Places that are not AXS Venues - // Can't use hasOwnProperty() on mongoose model objects // - if (!isEmpty(venuesFilters)) { - console.log('>> Performing secondary DB filtering'); - places = places.filter(place => { - const venue = find(venues, venue => venue.placeId === place.placeId); - if (venue) { - //console.log('In verification of filters'); - let passesValidation = true; - if ( - passesValidation && - venuesFilters.hasOwnProperty('allowsGuideDog') - ) { - if ( - !venue.allowsGuideDog || - venue.allowsGuideDog.yes < venue.allowsGuideDog.no || - venue.allowsGuideDog.yes == 0 - ) { - passesValidation = false; - } - } - - if (passesValidation && venuesFilters.hasOwnProperty('hasParking')) { - if ( - !venue.hasParking || - venue.hasParking.yes < venue.hasParking.no || - venue.hasParking.yes == 0 - ) { - passesValidation = false; - } - } - - if ( - passesValidation && - venuesFilters.hasOwnProperty('entranceScore') - ) { - if ( - !venue.entranceScore || - venue.entranceScore < venuesFilters.entranceScore - ) { - passesValidation = false; - } - } - - if ( - passesValidation && - venuesFilters.hasOwnProperty('interiorScore') - ) { - if ( - !venue.interiorScore || - venue.interiorScore < venuesFilters.interiorScore - ) { - passesValidation = false; - } - } - - if ( - passesValidation && - venuesFilters.hasOwnProperty('restroomScore') - ) { - if ( - !venue.restroomScore || - venue.restroomScore < venuesFilters.restroomScore - ) { - passesValidation = false; - } - } - - if (passesValidation) { - return venue; - } - } - }); - } //end filtering Google results - - // - places = places.map(place => { - const venue = find(venues, venue => venue.placeId === place.placeId); - if (venue) { - return Object.assign({}, place, { - //new expanded fields - hasPermanentRamp: venue.hasPermanentRamp, - hasPortableRamp: venue.hasPortableRamp, - hasWideEntrance: venue.hasWideEntrance, - hasAccessibleTableHeight: venue.hasAccessibleTableHeight, - hasAccessibleElevator: venue.hasAccessibleElevator, - hasInteriorRamp: venue.hasInteriorRamp, - hasSwingInDoor: venue.hasSwingInDoor, - hasSwingOutDoor: venue.hasSwingOutDoor, - hasLargeStall: venue.hasLargeStall, - hasSupportAroundToilet: venue.hasSupportAroundToilet, - hasLoweredSinks: venue.hasLoweredSinks, - - entranceScore: venue.entranceScore, - entranceGlyphs: venue.entranceGlyphs, - interiorScore: venue.interiorScore, - interiorGlyphs: venue.interiorGlyphs, - restroomScore: venue.restroomScore, - restroomGlyphs: venue.restroomGlyphs, - mapMarkerScore: venue.mapMarkerScore, - - //original fields - allowsGuideDog: venue.allowsGuideDog, - //_bathroomScore: venue.bathroomScore, - //_entryScore: venue.entryScore, - hasParking: venue.hasParking, - hasSecondEntry: venue.hasSecondEntry, - hasWellLit: venue.hasWellLit, - isQuiet: venue.isQuiet, - isSpacious: venue.isSpacious, - steps: venue.steps - }); - } - - //venue not found - return Object.assign({}, place, { - //new expanded fields - hasPermanentRamp: { yes: 0, no: 0 }, - hasPortableRamp: { yes: 0, no: 0 }, - hasWideEntrance: { yes: 0, no: 0 }, - hasAccessibleTableHeight: { yes: 0, no: 0 }, - hasAccessibleElevator: { yes: 0, no: 0 }, - hasInteriorRamp: { yes: 0, no: 0 }, - hasSwingInDoor: { yes: 0, no: 0 }, - hasSwingOutDoor: { yes: 0, no: 0 }, - hasLargeStall: { yes: 0, no: 0 }, - hasSupportAroundToilet: { yes: 0, no: 0 }, - hasLoweredSinks: { yes: 0, no: 0 }, - interiorScore: 0, - interiorGlyphs: 'interior', - restroomScore: 0, - restroomGlyphs: 'restroom', - entranceScore: 0, - entranceGlyphs: 'entrylg', - mapMarkerScore: 0, - - //original fields - allowsGuideDog: { yes: 0, no: 0 }, - //_bathroomReviews: 0, - //_bathroomScore: null, - //_entryReviews: 0, - //_entryScore: null, - hasParking: { yes: 0, no: 0 }, - hasSecondEntry: { yes: 0, no: 0 }, - hasWellLit: { yes: 0, no: 0 }, - isQuiet: { yes: 0, no: 0 }, - isSpacious: { yes: 0, no: 0 }, - steps: { - zero: 0, - one: 0, - two: 0, - moreThanTwo: 0 - } - }); - }); - - dataResponse = { - nextPage: placesResponse.data.next_page_token, - results: places - }; - } //ends legacy filter logic, false conditional - - return res.status(200).json(dataResponse); -}; +const axios = require('axios'); +const { find, isEmpty } = require('lodash'); +const slugify = require('speakingurl'); + +const { isNumber } = require('../../helpers'); +const { Venue } = require('../../models/venue'); + +const { validateListVenues } = require('./validations'); +const venueReviewSummary = require('../../helpers/venue-review-summary.js'); + +module.exports = async (req, res, next) => { + const queryParams = req.query; + + const { errors, isValid } = validateListVenues(queryParams); + if (!isValid) return res.status(400).json(errors); + + let coordinates = queryParams.location.split(','); + + //Legacy function from two-bar search, geocodes from string address + if (queryParams.address && !queryParams.page) { + console.log('in address conditional, ', queryParams); + queryParams.name = queryParams.address; + const geocodeParams = `?key=${process.env.PLACES_API_KEY}&address=${slugify( + queryParams.address + )}`; + + let geocodeResponse; + try { + geocodeResponse = await axios.get( + `https://maps.googleapis.com/maps/api/geocode/json${geocodeParams}` + ); + } catch (err) { + console.log( + `Geocode failed to be found at list-venues.\nQuery Params: ${JSON.stringify( + queryParams + )}` + ); + return next(err); + } + + const statusCode = geocodeResponse.data.status; + if (statusCode === 'ZERO_RESULTS') { + return res.status(404).json({ keywords: 'Address not found' }); + } else if (statusCode === 'OVER_QUERY_LIMIT') { + return next(new Error('Over query limit with Google Places API')); + } else if (statusCode === 'REQUEST_DENIED') { + return next(new Error('Request denied with Google Places API')); + } else if (statusCode === 'INVALID_REQUEST') { + return next(new Error('Invalid request with Google Places API')); + } else if (statusCode === 'UNKNOWN_ERROR') { + return next(new Error('Unknown error with Google Places API')); + } + + coordinates = [ + geocodeResponse.data.results[0].geometry.location.lat, + geocodeResponse.data.results[0].geometry.location.lng + ]; + } //end address geocode + + let venuesFilters = {}; + let dbVenuesFilters = {}; + + /* + * Legacy filter string building function, + * has a critical defect condition where if + * no > yes but yes is at least 1, then there + * would be a false match. + */ + if (queryParams.entranceScore) { + venuesFilters.entranceScore = parseFloat(queryParams.entranceScore); + //{ $gte: parseFloat(queryParams.entranceScore) }; + } + + if (queryParams.interiorScore) { + venuesFilters.interiorScore = parseFloat(queryParams.interiorScore); + //{ $gte: parseFloat(queryParams.interiorScore) }; + } + + if (queryParams.restroomScore) { + venuesFilters.restroomScore = parseFloat(queryParams.restroomScore); + //{ $gte: parseFloat(queryParams.restroomScore) }; + } + + if (queryParams.allowsGuideDog) { + venuesFilters.allowsGuideDog = parseFloat(queryParams.allowsGuideDog); + + const allowsGuideDog = parseFloat(queryParams.allowsGuideDog) === 1; + if (allowsGuideDog) { + dbVenuesFilters['allowsGuideDog.yes'] = { $gte: 1 }; + } else { + dbVenuesFilters['allowsGuideDog.no'] = { $gte: 1 }; + } + } + + if (queryParams.hasParking) { + venuesFilters.hasParking = queryParams.hasParking; + + const hasParking = parseFloat(queryParams.hasParking) === 1; + if (hasParking) { + dbVenuesFilters['hasParking.yes'] = { $gte: 1 }; + } else { + dbVenuesFilters['hasParking.no'] = { $gte: 1 }; + } + } + + /* + * Not used + * + if (queryParams.hasRamp) { + const hasRamp = parseFloat(queryParams.hasRamp) === 1; + if (hasRamp) { + venuesFilters['hasRamp.yes'] = { $gte: 1 }; + } else { + venuesFilters['hasRamp.no'] = { $gte: 1 }; + } + } + + if (queryParams.hasSecondEntry) { + const hasSecondEntry = parseFloat(queryParams.hasSecondEntry) === 1; + if (hasSecondEntry) { + venuesFilters['hasSecondEntry.yes'] = { $gte: 1 }; + } else { + venuesFilters['hasSecondEntry.no'] = { $gte: 1 }; + } + } + + if (queryParams.hasWellLit) { + const hasWellLit = parseFloat(queryParams.hasWellLit) === 1; + if (hasWellLit) { + venuesFilters['hasWellLit.yes'] = { $gte: 1 }; + } else { + venuesFilters['hasWellLit.no'] = { $gte: 1 }; + } + } + + if (queryParams.isQuiet) { + const isQuiet = parseFloat(queryParams.isQuiet) === 1; + if (isQuiet) { + venuesFilters['isQuiet.yes'] = { $gte: 1 }; + } else { + venuesFilters['isQuiet.no'] = { $gte: 1 }; + } + } + + if (queryParams.isSpacious) { + const isSpacious = parseFloat(queryParams.isSpacious) === 1; + if (isSpacious) { + venuesFilters['isSpacious.yes'] = { $gte: 1 }; + } else { + venuesFilters['isSpacious.no'] = { $gte: 1 }; + } + } + + if (queryParams.steps) { + if (parseFloat(queryParams.steps) === 0) { + venuesFilters['steps.zero'] = { $gte: 1 }; + } else if (parseFloat(queryParams.steps) === 1) { + venuesFilters['steps.one'] = { $gte: 1 }; + } else if (parseFloat(queryParams.steps) === 2) { + venuesFilters['steps.two'] = { $gte: 1 }; + } else if (parseFloat(queryParams.steps) === 3) { + venuesFilters['steps.moreThanTwo'] = { $gte: 1 }; + } + } + * + */ + + let dataResponse; + + /* + * Legacy filtering function that searches solely on + * AXS Venue data and provides it's own pagination of 20 + * UPDATED 05/2020 TO SUPPORT FILTER ONLY SELF SEARCH + */ + if (!isEmpty(venuesFilters) && isEmpty(queryParams.name)) { + console.log('>> Performing DB search'); + /* + if (queryParams.name) { + //performs literal name match against AXS Venue name + venuesFilters.name = { $regex: queryParams.name, $options: 'i' }; + } + */ + + dbVenuesFilters.location = { + $near: { + $geometry: { + type: 'Point', + coordinates: [coordinates[1], coordinates[0]] + }, + $maxDistance: 50000 + } + }; + + if (queryParams.type) { + dbVenuesFilters.types = queryParams.type; + } + + dbVenuesFilters.isArchived = false; + + let page = 1; + if (isNumber(queryParams.page)) { + page = queryParams.page; + } + + const pageLimit = + 'entranceScore' in venuesFilters || + 'interiorScore' in venuesFilters || + 'restroomScore' in venuesFilters + ? 80 + : 20; + + if (page > 0) { + page -= 1; + } else { + return res + .status(400) + .json({ page: 'Should be equal to or greater than 1' }); + } + + let total; + let venues; + try { + [venues, total] = await Promise.all([ + Venue.find( + dbVenuesFilters + /*,'address allowsGuideDog hasParking hasSecondEntry hasWellLit isQuiet isSpacious location name photos placeId steps types'*/ + ) + .skip(page * pageLimit) + .limit(pageLimit), + Venue.find(dbVenuesFilters).count() + /*TODO: count is deprecated in favor of countDocuments, but that does not support $near + would need to move to GeoWithin but that does not return sorted results + */ + ]); + } catch (err) { + console.log( + `Venues failed to be found or count at list-venues.\nvenuesQuery: ${JSON.stringify( + dbVenuesFilters + )}` + ); + console.log(err); + return next(err); + } + + venues = venues.map((venue) => + Object.assign({}, venue.toObject(), { + id: venue._id, + _id: undefined, + location: venue.coordinates + }) + ); + + //+ADDED + //Perform ratings logic on all returned venues + console.log('Raw venues count: ' + venues.length); + venues = venues.filter((venue) => { + //console.log('In scoring assignment'); + let scoring; + //calculate entranceScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('entrance', venue); + venue.entranceScore = scoring.ratingLevel; + venue.entranceGlyphs = scoring.ratingGlyphs; + + //calculate interiorScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('interior', venue); + venue.interiorScore = scoring.ratingLevel; + venue.interiorGlyphs = scoring.ratingGlyphs; + + //calculate restroomScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('restroom', venue); + venue.restroomScore = scoring.ratingLevel; + venue.restroomGlyphs = scoring.ratingGlyphs; + + venue.mapMarkerScore = venueReviewSummary.calculateMapMarkerScore( + venue.entranceScore, + venue.interiorScore, + venue.restroomScore + ); + + let passesValidation = true; + if ('entranceScore' in venuesFilters) { + if ( + !venue.entranceScore || + venue.entranceScore < venuesFilters.entranceScore + ) { + passesValidation = false; + } + } + + if (passesValidation && 'interiorScore' in venuesFilters) { + if ( + !venue.interiorScore || + venue.interiorScore < venuesFilters.interiorScore + ) { + passesValidation = false; + } + } + + if (passesValidation && 'restroomScore' in venuesFilters) { + if ( + !venue.restroomScore || + venue.restroomScore < venuesFilters.restroomScore + ) { + passesValidation = false; + } + } + + if (passesValidation) { + return venue; + } + }); + + const lastPage = Math.ceil(total / pageLimit); + let nextPage; + if (lastPage > 0) { + page += 1; + if (page > lastPage || page > 3) { + return res.status(400).json({ + page: `Should be equal to or less than ${lastPage > 3 ? 3 : lastPage}` + }); + } + } + + dataResponse = { + nextPage, + results: venues + }; + /* + * End legacy filter + */ + } else { + console.log('>> Performing Google search'); + + /* + * Perform Google search when there text entered or no filters selected + */ + let nearbyParams = `?key=${process.env.PLACES_API_KEY}`; + let searchType = queryParams.name ? 'textsearch' : 'nearbysearch'; + + if (!queryParams.page) { + nearbyParams = `${nearbyParams}&location=${coordinates[0]},${ + coordinates[1] + //}&rankby=distance`; + }`; + + if (queryParams.name) { + //nearbyParams = `${nearbyParams}&keyword=${queryParams.name}`; + nearbyParams = `${nearbyParams}&query=${queryParams.name}&radius=5000`; + } else { + //empty search, such as on load + nearbyParams = `${nearbyParams}&rankby=distance`; + } + + if (queryParams.type) { + nearbyParams = `${nearbyParams}&type=${queryParams.type}`; + } else { + nearbyParams = `${nearbyParams}&type=establishment`; + } + } else { + nearbyParams = `${nearbyParams}&pagetoken=${queryParams.page}`; + } + + if (queryParams.rankby) { + nearbyParams = `${nearbyParams}&rankby=${queryParams.rankby}`; + } + if (queryParams.opennow) { + nearbyParams = `${nearbyParams}&opennow=${queryParams.opennow}`; + } + if (queryParams.minprice) { + nearbyParams = `${nearbyParams}&minprice=${queryParams.minprice}`; + } + if (queryParams.maxprice) { + nearbyParams = `${nearbyParams}&maxprice=${queryParams.maxprice}`; + } + + let placesResponse; + try { + console.log( + 'performing google search: ' + + `https://maps.googleapis.com/maps/api/place/${searchType}/json${nearbyParams}` + ); + placesResponse = await axios.get( + `https://maps.googleapis.com/maps/api/place/${searchType}/json${nearbyParams}` + ); + } catch (err) { + console.log( + `Places failed to be found at list-venues.\nQuery Params: ${JSON.stringify( + queryParams + )}` + ); + return next(err); + } + + const statusCode = placesResponse.data.status; + if (statusCode === 'OVER_QUERY_LIMIT') { + return next(new Error('Over query limit with Google Places API')); + } else if (statusCode === 'REQUEST_DENIED') { + return next(new Error('Request denied with Google Places API')); + } else if (statusCode === 'INVALID_REQUEST') { + return next(new Error('Invalid request with Google Places API')); + } else if (statusCode === 'UNKNOWN_ERROR') { + return next(new Error('Unknown error with Google Places API')); + } + //do we need to check for 0? + + if (placesResponse.data.results.length == 1) { + if (placesResponse.data.results[0].types[0] == 'locality') { + console.log( + 'Found a city only: ', + placesResponse.data.results[0].geometry.location + ); + //TODO: redo search with new coordinates and no query/name or change/add "places in " to the first part of the string + } + } + + //Format Google Places results and get array of IDs + let places = []; + const placesIds = []; + placesResponse.data.results.forEach((place) => { + let photo = ''; + if (place.photos) { + photo = `https://maps.googleapis.com/maps/api/place/photo?key=${ + process.env.PLACES_API_KEY + }&maxwidth=300&photoreference=${place.photos[0].photo_reference}`; + } + + places.push({ + //address: place.vicinity, + address: place.formatted_address, + location: { + lat: place.geometry.location.lat, + lng: place.geometry.location.lng + }, + name: place.name, + photo, + placeId: place.place_id, + types: place.types + }); + placesIds.push(place.place_id); + }); + + //Use array of Google Place IDs to find AXS Venues + let venues; + try { + venues = await Venue.find({ placeId: { $in: placesIds } }); + } catch (err) { + console.log( + `Venues failed to be found at list-venues.\nPlaces ids: [${placesIds}]` + ); + return next(err); + } + + //Perform ratings logic on all returned venues + venues.forEach((venue) => { + //console.log('In scoring assignment'); + let scoring; + //calculate entranceScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('entrance', venue); + venue.entranceScore = scoring.ratingLevel; + venue.entranceGlyphs = scoring.ratingGlyphs; + + //calculate interiorScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('interior', venue); + venue.interiorScore = scoring.ratingLevel; + venue.interiorGlyphs = scoring.ratingGlyphs; + + //calculate restroomScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('restroom', venue); + venue.restroomScore = scoring.ratingLevel; + venue.restroomGlyphs = scoring.ratingGlyphs; + + venue.mapMarkerScore = venueReviewSummary.calculateMapMarkerScore( + venue.entranceScore, + venue.interiorScore, + venue.restroomScore + ); + }); + + //Filter out, remove, Google Places that are not AXS Venues + // Can't use hasOwnProperty() on mongoose model objects // + if (!isEmpty(venuesFilters)) { + console.log('>> Performing secondary DB filtering'); + places = places.filter((place) => { + const venue = find(venues, (venue) => venue.placeId === place.placeId); + if (venue) { + //console.log('In verification of filters'); + let passesValidation = true; + if (passesValidation && 'allowsGuideDog' in venuesFilters) { + if ( + !venue.allowsGuideDog || + venue.allowsGuideDog.yes < venue.allowsGuideDog.no || + venue.allowsGuideDog.yes == 0 + ) { + passesValidation = false; + } + } + + if (passesValidation && 'hasParking' in venuesFilters) { + if ( + !venue.hasParking || + venue.hasParking.yes < venue.hasParking.no || + venue.hasParking.yes == 0 + ) { + passesValidation = false; + } + } + + if (passesValidation && 'entranceScore' in venuesFilters) { + if ( + !venue.entranceScore || + venue.entranceScore < venuesFilters.entranceScore + ) { + passesValidation = false; + } + } + + if (passesValidation && 'interiorScore' in venuesFilters) { + if ( + !venue.interiorScore || + venue.interiorScore < venuesFilters.interiorScore + ) { + passesValidation = false; + } + } + + if (passesValidation && 'restroomScore' in venuesFilters) { + if ( + !venue.restroomScore || + venue.restroomScore < venuesFilters.restroomScore + ) { + passesValidation = false; + } + } + + if (passesValidation) { + return venue; + } + } + }); + } //end filtering Google results + + // + places = places.map((place) => { + const venue = find(venues, (venue) => venue.placeId === place.placeId); + if (venue) { + return Object.assign({}, place, { + //new expanded fields + hasPermanentRamp: venue.hasPermanentRamp, + hasPortableRamp: venue.hasPortableRamp, + hasWideEntrance: venue.hasWideEntrance, + hasAccessibleTableHeight: venue.hasAccessibleTableHeight, + hasAccessibleElevator: venue.hasAccessibleElevator, + hasInteriorRamp: venue.hasInteriorRamp, + hasSwingInDoor: venue.hasSwingInDoor, + hasSwingOutDoor: venue.hasSwingOutDoor, + hasLargeStall: venue.hasLargeStall, + hasSupportAroundToilet: venue.hasSupportAroundToilet, + hasLoweredSinks: venue.hasLoweredSinks, + + entranceScore: venue.entranceScore, + entranceGlyphs: venue.entranceGlyphs, + interiorScore: venue.interiorScore, + interiorGlyphs: venue.interiorGlyphs, + restroomScore: venue.restroomScore, + restroomGlyphs: venue.restroomGlyphs, + mapMarkerScore: venue.mapMarkerScore, + + //original fields + allowsGuideDog: venue.allowsGuideDog, + //_bathroomScore: venue.bathroomScore, + //_entryScore: venue.entryScore, + hasParking: venue.hasParking, + hasSecondEntry: venue.hasSecondEntry, + hasWellLit: venue.hasWellLit, + isQuiet: venue.isQuiet, + isSpacious: venue.isSpacious, + steps: venue.steps + }); + } + + //venue not found + return Object.assign({}, place, { + //new expanded fields + hasPermanentRamp: { yes: 0, no: 0 }, + hasPortableRamp: { yes: 0, no: 0 }, + hasWideEntrance: { yes: 0, no: 0 }, + hasAccessibleTableHeight: { yes: 0, no: 0 }, + hasAccessibleElevator: { yes: 0, no: 0 }, + hasInteriorRamp: { yes: 0, no: 0 }, + hasSwingInDoor: { yes: 0, no: 0 }, + hasSwingOutDoor: { yes: 0, no: 0 }, + hasLargeStall: { yes: 0, no: 0 }, + hasSupportAroundToilet: { yes: 0, no: 0 }, + hasLoweredSinks: { yes: 0, no: 0 }, + interiorScore: 0, + interiorGlyphs: 'interior', + restroomScore: 0, + restroomGlyphs: 'restroom', + entranceScore: 0, + entranceGlyphs: 'entrylg', + mapMarkerScore: 0, + + //original fields + allowsGuideDog: { yes: 0, no: 0 }, + //_bathroomReviews: 0, + //_bathroomScore: null, + //_entryReviews: 0, + //_entryScore: null, + hasParking: { yes: 0, no: 0 }, + hasSecondEntry: { yes: 0, no: 0 }, + hasWellLit: { yes: 0, no: 0 }, + isQuiet: { yes: 0, no: 0 }, + isSpacious: { yes: 0, no: 0 }, + steps: { + zero: 0, + one: 0, + two: 0, + moreThanTwo: 0 + } + }); + }); + + dataResponse = { + nextPage: placesResponse.data.next_page_token, + results: places + }; + } //ends legacy filter logic, false conditional + + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/venues/validations.js b/src/routes/venues/validations.js index 6d393cc..a234600 100644 --- a/src/routes/venues/validations.js +++ b/src/routes/venues/validations.js @@ -1,154 +1,154 @@ -const { isEmpty } = require('lodash'); - -const { isNumber } = require('../../helpers'); -const { placesTypes } = require('../../helpers/constants'); - -module.exports = { - validateListVenues(queryParams) { - const errors = {}; - - if (!queryParams.location) { - errors.location = 'Is required'; - } else { - const location = queryParams.location.split(','); - - if (location.length !== 2) { - errors.location = 'Should have two coordinates'; - } else if (!location[0]) { - errors.location = 'Latitude is required'; - } else if (!isNumber(location[0])) { - errors.location = 'Latitude should be a number'; - } else if ( - parseFloat(location[0]) < -90 || - parseFloat(location[0]) > 90 - ) { - errors.location = 'Latitude value out of bounds'; - } else if (!location[1]) { - errors.location = 'Longitude is required'; - } else if (!isNumber(location[1])) { - errors.location = 'Longitude should be a number'; - } else if ( - parseFloat(location[1]) < -180 || - parseFloat(location[1]) > 180 - ) { - errors.location = 'Longitude value out of bounds'; - } - } - - if (queryParams.bathroomScore) { - if (!isNumber(queryParams.bathroomScore)) { - errors.bathroomScore = 'Should be a number'; - } else if ( - parseFloat(queryParams.bathroomScore) < 1 || - parseFloat(queryParams.bathroomScore) > 5 - ) { - errors.bathroomScore = 'Should be between 1 and 5'; - } - } - - if (queryParams.entryScore) { - if (!isNumber(queryParams.entryScore)) { - errors.entryScore = 'Should be a number'; - } else if ( - parseFloat(queryParams.entryScore) < 1 || - parseFloat(queryParams.entryScore) > 5 - ) { - errors.entryScore = 'Should be between 1 and 5'; - } - } - - if (queryParams.allowsGuideDog) { - if (!isNumber(queryParams.allowsGuideDog)) { - errors.allowsGuideDog = 'Should be a number'; - } else if ( - parseFloat(queryParams.allowsGuideDog) !== 0 && - parseFloat(queryParams.allowsGuideDog) !== 1 - ) { - errors.allowsGuideDog = 'Should be 0 or 1'; - } - } - - if (queryParams.hasParking) { - if (!isNumber(queryParams.hasParking)) { - errors.hasParking = 'Should be a number'; - } else if ( - parseFloat(queryParams.hasParking) !== 0 && - parseFloat(queryParams.hasParking) !== 1 - ) { - errors.hasParking = 'Should be 0 or 1'; - } - } - - if (queryParams.hasRamp) { - if (!isNumber(queryParams.hasRamp)) { - errors.hasRamp = 'Should be a number'; - } else if ( - parseFloat(queryParams.hasRamp) !== 0 && - parseFloat(queryParams.hasRamp) !== 1 - ) { - errors.hasRamp = 'Should be 0 or 1'; - } - } - - if (queryParams.hasSecondEntry) { - if (!isNumber(queryParams.hasSecondEntry)) { - errors.hasSecondEntry = 'Should be a number'; - } else if ( - parseFloat(queryParams.hasSecondEntry) !== 0 && - parseFloat(queryParams.hasSecondEntry) !== 1 - ) { - errors.hasSecondEntry = 'Should be 0 or 1'; - } - } - - if (queryParams.hasWellLit) { - if (!isNumber(queryParams.hasWellLit)) { - errors.hasWellLit = 'Should be a number'; - } else if ( - parseFloat(queryParams.hasWellLit) !== 0 && - parseFloat(queryParams.hasWellLit) !== 1 - ) { - errors.hasWellLit = 'Should be 0 or 1'; - } - } - - if (queryParams.isQuiet) { - if (!isNumber(queryParams.isQuiet)) { - errors.isQuiet = 'Should be a number'; - } else if ( - parseFloat(queryParams.isQuiet) !== 0 && - parseFloat(queryParams.isQuiet) !== 1 - ) { - errors.isQuiet = 'Should be 0 or 1'; - } - } - - if (queryParams.isSpacious) { - if (!isNumber(queryParams.isSpacious)) { - errors.isSpacious = 'Should be a number'; - } else if ( - parseFloat(queryParams.isSpacious) !== 0 && - parseFloat(queryParams.isSpacious) !== 1 - ) { - errors.isSpacious = 'Should be 0 or 1'; - } - } - - if (queryParams.steps) { - if (!isNumber(queryParams.steps)) { - errors.steps = 'Should be a number'; - } else if ( - parseFloat(queryParams.steps) < 0 || - parseFloat(queryParams.steps) > 3 - ) { - errors.steps = 'Should be between 0 and 3'; - } - } - - if (queryParams.type && !placesTypes.includes(queryParams.type)) { - errors.type = 'Should be a valid type'; - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const { isEmpty } = require('lodash'); + +const { isNumber } = require('../../helpers'); +const { placesTypes } = require('../../helpers/constants'); + +module.exports = { + validateListVenues(queryParams) { + const errors = {}; + + if (!queryParams.location) { + errors.location = 'Is required'; + } else { + const location = queryParams.location.split(','); + + if (location.length !== 2) { + errors.location = 'Should have two coordinates'; + } else if (!location[0]) { + errors.location = 'Latitude is required'; + } else if (!isNumber(location[0])) { + errors.location = 'Latitude should be a number'; + } else if ( + parseFloat(location[0]) < -90 || + parseFloat(location[0]) > 90 + ) { + errors.location = 'Latitude value out of bounds'; + } else if (!location[1]) { + errors.location = 'Longitude is required'; + } else if (!isNumber(location[1])) { + errors.location = 'Longitude should be a number'; + } else if ( + parseFloat(location[1]) < -180 || + parseFloat(location[1]) > 180 + ) { + errors.location = 'Longitude value out of bounds'; + } + } + + if (queryParams.bathroomScore) { + if (!isNumber(queryParams.bathroomScore)) { + errors.bathroomScore = 'Should be a number'; + } else if ( + parseFloat(queryParams.bathroomScore) < 1 || + parseFloat(queryParams.bathroomScore) > 5 + ) { + errors.bathroomScore = 'Should be between 1 and 5'; + } + } + + if (queryParams.entryScore) { + if (!isNumber(queryParams.entryScore)) { + errors.entryScore = 'Should be a number'; + } else if ( + parseFloat(queryParams.entryScore) < 1 || + parseFloat(queryParams.entryScore) > 5 + ) { + errors.entryScore = 'Should be between 1 and 5'; + } + } + + if (queryParams.allowsGuideDog) { + if (!isNumber(queryParams.allowsGuideDog)) { + errors.allowsGuideDog = 'Should be a number'; + } else if ( + parseFloat(queryParams.allowsGuideDog) !== 0 && + parseFloat(queryParams.allowsGuideDog) !== 1 + ) { + errors.allowsGuideDog = 'Should be 0 or 1'; + } + } + + if (queryParams.hasParking) { + if (!isNumber(queryParams.hasParking)) { + errors.hasParking = 'Should be a number'; + } else if ( + parseFloat(queryParams.hasParking) !== 0 && + parseFloat(queryParams.hasParking) !== 1 + ) { + errors.hasParking = 'Should be 0 or 1'; + } + } + + if (queryParams.hasRamp) { + if (!isNumber(queryParams.hasRamp)) { + errors.hasRamp = 'Should be a number'; + } else if ( + parseFloat(queryParams.hasRamp) !== 0 && + parseFloat(queryParams.hasRamp) !== 1 + ) { + errors.hasRamp = 'Should be 0 or 1'; + } + } + + if (queryParams.hasSecondEntry) { + if (!isNumber(queryParams.hasSecondEntry)) { + errors.hasSecondEntry = 'Should be a number'; + } else if ( + parseFloat(queryParams.hasSecondEntry) !== 0 && + parseFloat(queryParams.hasSecondEntry) !== 1 + ) { + errors.hasSecondEntry = 'Should be 0 or 1'; + } + } + + if (queryParams.hasWellLit) { + if (!isNumber(queryParams.hasWellLit)) { + errors.hasWellLit = 'Should be a number'; + } else if ( + parseFloat(queryParams.hasWellLit) !== 0 && + parseFloat(queryParams.hasWellLit) !== 1 + ) { + errors.hasWellLit = 'Should be 0 or 1'; + } + } + + if (queryParams.isQuiet) { + if (!isNumber(queryParams.isQuiet)) { + errors.isQuiet = 'Should be a number'; + } else if ( + parseFloat(queryParams.isQuiet) !== 0 && + parseFloat(queryParams.isQuiet) !== 1 + ) { + errors.isQuiet = 'Should be 0 or 1'; + } + } + + if (queryParams.isSpacious) { + if (!isNumber(queryParams.isSpacious)) { + errors.isSpacious = 'Should be a number'; + } else if ( + parseFloat(queryParams.isSpacious) !== 0 && + parseFloat(queryParams.isSpacious) !== 1 + ) { + errors.isSpacious = 'Should be 0 or 1'; + } + } + + if (queryParams.steps) { + if (!isNumber(queryParams.steps)) { + errors.steps = 'Should be a number'; + } else if ( + parseFloat(queryParams.steps) < 0 || + parseFloat(queryParams.steps) > 3 + ) { + errors.steps = 'Should be between 0 and 3'; + } + } + + if (queryParams.type && !placesTypes.includes(queryParams.type)) { + errors.type = 'Should be a valid type'; + } + + return { errors, isValid: isEmpty(errors) }; + } +}; diff --git a/src/scripts/db/import-events.js b/src/scripts/db/import-events.js index 6ad0a17..65fa480 100644 --- a/src/scripts/db/import-events.js +++ b/src/scripts/db/import-events.js @@ -1,154 +1,154 @@ -const mongoose = require('mongoose'); - -require('dotenv').config(); - -const { eventSchema } = require('../../models/event'); - -const oldEventsSchema = require('./old-schemas/event'); - -mongoose.Promise = global.Promise; - -async function closeConnections(db, oldDb) { - try { - await oldDb.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const oldUri = process.env.OLD_DB_URI; - const oldDb = mongoose.createConnection(oldUri, options); - - oldDb.on('connected', async () => { - console.log('Connection to old DB established successfully'); - - const oldEvent = oldDb.model('events', oldEventsSchema); - - let totalOldEvents; - try { - totalOldEvents = await oldEvent.count({ name: { $ne: '' } }); - } catch (error) { - console.log('Old events failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total old events: ${totalOldEvents}`); - - console.time('createEvents'); - - let page = 0; - const pageLimit = 100; - let i = 0; - do { - let oldEvents; - try { - oldEvents = await oldEvent - .find({ name: { $ne: '' } }) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Old events failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const Event = db.model('Event', eventSchema); - - const createEvents = []; - for (let oldEventItem of oldEvents) { - let participants = oldEventItem.members.map(member => member.user); - participants = participants.filter( - p => p.toString() !== oldEventItem.creator.toString() - ); - - const eventData = { - _id: oldEventItem.id, - createdAt: oldEventItem.created_at, - description: oldEventItem.description.substring(0, 300), - endDate: oldEventItem.event_end, - managers: [oldEventItem.creator], - name: oldEventItem.name, - participants, - participantsGoal: oldEventItem.participant_goal - ? oldEventItem.participant_goal > 1000 - ? 1000 - : oldEventItem.participant_goal - : 1, - poster: oldEventItem.image, - reviewsGoal: oldEventItem.mapping_goal - ? oldEventItem.mapping_goal > 10000 - ? 10000 - : oldEventItem.mapping_goal - : 1, - startDate: oldEventItem.event_start, - teams: oldEventItem.teams, - updatedAt: oldEventItem.updated_at, - venue: oldEventItem.location - }; - - createEvents.push(Event.create(eventData)); - } - - try { - await Promise.all(createEvents); - } catch (error) { - console.log( - `Events failed to be created.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(error); - await closeConnections(db, oldDb); - } - - page = page + 1; - i = i + oldEvents.length; - console.log(i); - } while (i < totalOldEvents); - - console.timeEnd('createEvents'); - - await closeConnections(db, oldDb); - }); - - oldDb.on('error', err => { - console.log('Connection to old DB failed ' + err); - process.exit(0); - }); - - oldDb.on('disconnected', () => { - console.log('Connection from old DB closed'); - }); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const mongoose = require('mongoose'); + +require('dotenv').config(); + +const { eventSchema } = require('../../models/event'); + +const oldEventsSchema = require('./old-schemas/event'); + +mongoose.Promise = global.Promise; + +async function closeConnections(db, oldDb) { + try { + await oldDb.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const oldUri = process.env.OLD_DB_URI; + const oldDb = mongoose.createConnection(oldUri, options); + + oldDb.on('connected', async () => { + console.log('Connection to old DB established successfully'); + + const oldEvent = oldDb.model('events', oldEventsSchema); + + let totalOldEvents; + try { + totalOldEvents = await oldEvent.count({ name: { $ne: '' } }); + } catch (error) { + console.log('Old events failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total old events: ${totalOldEvents}`); + + console.time('createEvents'); + + let page = 0; + const pageLimit = 100; + let i = 0; + do { + let oldEvents; + try { + oldEvents = await oldEvent + .find({ name: { $ne: '' } }) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Old events failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const Event = db.model('Event', eventSchema); + + const createEvents = []; + for (let oldEventItem of oldEvents) { + let participants = oldEventItem.members.map((member) => member.user); + participants = participants.filter( + (p) => p.toString() !== oldEventItem.creator.toString() + ); + + const eventData = { + _id: oldEventItem.id, + createdAt: oldEventItem.created_at, + description: oldEventItem.description.substring(0, 300), + endDate: oldEventItem.event_end, + managers: [oldEventItem.creator], + name: oldEventItem.name, + participants, + participantsGoal: oldEventItem.participant_goal + ? oldEventItem.participant_goal > 1000 + ? 1000 + : oldEventItem.participant_goal + : 1, + poster: oldEventItem.image, + reviewsGoal: oldEventItem.mapping_goal + ? oldEventItem.mapping_goal > 10000 + ? 10000 + : oldEventItem.mapping_goal + : 1, + startDate: oldEventItem.event_start, + teams: oldEventItem.teams, + updatedAt: oldEventItem.updated_at, + venue: oldEventItem.location + }; + + createEvents.push(Event.create(eventData)); + } + + try { + await Promise.all(createEvents); + } catch (error) { + console.log( + `Events failed to be created.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(error); + await closeConnections(db, oldDb); + } + + page = page + 1; + i = i + oldEvents.length; + console.log(i); + } while (i < totalOldEvents); + + console.timeEnd('createEvents'); + + await closeConnections(db, oldDb); + }); + + oldDb.on('error', (err) => { + console.log('Connection to old DB failed ' + err); + process.exit(0); + }); + + oldDb.on('disconnected', () => { + console.log('Connection from old DB closed'); + }); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); diff --git a/src/scripts/db/import-reviews.js b/src/scripts/db/import-reviews.js index 4f36291..1e125c3 100644 --- a/src/scripts/db/import-reviews.js +++ b/src/scripts/db/import-reviews.js @@ -1,149 +1,149 @@ -const mongoose = require('mongoose'); - -require('dotenv').config(); - -const { reviewSchema } = require('../../models/review'); - -const oldReviewSchema = require('./old-schemas/review'); - -mongoose.Promise = global.Promise; - -async function closeConnections(db, oldDb) { - try { - await oldDb.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const oldUri = process.env.OLD_DB_URI; - const oldDb = mongoose.createConnection(oldUri, options); - - oldDb.on('connected', async () => { - console.log('Connection to old DB established successfully'); - - const OldReview = oldDb.model('reviews', oldReviewSchema); - - let totalOldReviews; - try { - totalOldReviews = await OldReview.count(); - } catch (error) { - console.log('Old reviews failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total old reviews: ${totalOldReviews}`); - - console.time('createReviews'); - - let page = 0; - const pageLimit = 100; - let i = 0; - do { - let oldReviews; - try { - oldReviews = await OldReview.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Old reviews failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const Review = db.model('Review', reviewSchema); - - const createReviews = []; - for (let oldReview of oldReviews) { - if (oldReview.venue_id && oldReview.user_id) { - const reviewData = { - _id: oldReview.id, - allowsGuideDog: oldReview.guidedog, - createdAt: oldReview.created_at, - bathroomScore: oldReview.bathroom, - entryScore: oldReview.entry, - event: oldReview.event, - hasParking: oldReview.parking, - hasRamp: oldReview.ramp, - hasSecondEntry: oldReview.secondentrance, - hasWellLit: oldReview.welllit, - isQuiet: oldReview.quiet, - isSpacious: oldReview.spacious, - steps: oldReview.steps, - team: oldReview.team, - updatedAt: oldReview.updated_at, - user: oldReview.user_id, - venue: oldReview.venue_id - }; - - if (oldReview.comment && oldReview.comment.length <= 300) { - reviewData.comments = oldReview.comment; - } - - createReviews.push(Review.create(reviewData)); - } - } - - try { - await Promise.all(createReviews); - } catch (error) { - console.log( - `Reviews failed to be created.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(error); - await closeConnections(db, oldDb); - } - - page = page + 1; - i = i + oldReviews.length; - console.log(i); - } while (i < totalOldReviews); - - console.timeEnd('createReviews'); - - await closeConnections(db, oldDb); - }); - - oldDb.on('error', err => { - console.log('Connection to old DB failed ' + err); - process.exit(0); - }); - - oldDb.on('disconnected', () => { - console.log('Connection from old DB closed'); - }); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const mongoose = require('mongoose'); + +require('dotenv').config(); + +const { reviewSchema } = require('../../models/review'); + +const oldReviewSchema = require('./old-schemas/review'); + +mongoose.Promise = global.Promise; + +async function closeConnections(db, oldDb) { + try { + await oldDb.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const oldUri = process.env.OLD_DB_URI; + const oldDb = mongoose.createConnection(oldUri, options); + + oldDb.on('connected', async () => { + console.log('Connection to old DB established successfully'); + + const OldReview = oldDb.model('reviews', oldReviewSchema); + + let totalOldReviews; + try { + totalOldReviews = await OldReview.count(); + } catch (error) { + console.log('Old reviews failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total old reviews: ${totalOldReviews}`); + + console.time('createReviews'); + + let page = 0; + const pageLimit = 100; + let i = 0; + do { + let oldReviews; + try { + oldReviews = await OldReview.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Old reviews failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const Review = db.model('Review', reviewSchema); + + const createReviews = []; + for (let oldReview of oldReviews) { + if (oldReview.venue_id && oldReview.user_id) { + const reviewData = { + _id: oldReview.id, + allowsGuideDog: oldReview.guidedog, + createdAt: oldReview.created_at, + bathroomScore: oldReview.bathroom, + entryScore: oldReview.entry, + event: oldReview.event, + hasParking: oldReview.parking, + hasRamp: oldReview.ramp, + hasSecondEntry: oldReview.secondentrance, + hasWellLit: oldReview.welllit, + isQuiet: oldReview.quiet, + isSpacious: oldReview.spacious, + steps: oldReview.steps, + team: oldReview.team, + updatedAt: oldReview.updated_at, + user: oldReview.user_id, + venue: oldReview.venue_id + }; + + if (oldReview.comment && oldReview.comment.length <= 300) { + reviewData.comments = oldReview.comment; + } + + createReviews.push(Review.create(reviewData)); + } + } + + try { + await Promise.all(createReviews); + } catch (error) { + console.log( + `Reviews failed to be created.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(error); + await closeConnections(db, oldDb); + } + + page = page + 1; + i = i + oldReviews.length; + console.log(i); + } while (i < totalOldReviews); + + console.timeEnd('createReviews'); + + await closeConnections(db, oldDb); + }); + + oldDb.on('error', (err) => { + console.log('Connection to old DB failed ' + err); + process.exit(0); + }); + + oldDb.on('disconnected', () => { + console.log('Connection from old DB closed'); + }); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); diff --git a/src/scripts/db/import-teams.js b/src/scripts/db/import-teams.js index 4334d0b..b9393ce 100644 --- a/src/scripts/db/import-teams.js +++ b/src/scripts/db/import-teams.js @@ -1,270 +1,270 @@ -const aws = require('aws-sdk'); -const jimp = require('jimp'); -const mongoose = require('mongoose'); -const randomstring = require('randomstring'); - -require('dotenv').config(); - -const { reviewSchema } = require('../../models/review'); -const { teamSchema } = require('../../models/team'); - -const oldTeamSchema = require('./old-schemas/team'); - -mongoose.Promise = global.Promise; - -const s3 = new aws.S3(); - -async function closeConnections(db, oldDb) { - try { - await oldDb.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const oldUri = process.env.OLD_DB_URI; - const oldDb = mongoose.createConnection(oldUri, options); - - oldDb.on('connected', async () => { - console.log('Connection to old DB established successfully'); - - const OldTeam = oldDb.model('teams', oldTeamSchema); - - let totalOldTeams; - try { - totalOldTeams = await OldTeam.count(); - } catch (error) { - console.log('Old teams failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total old teams: ${totalOldTeams}`); - - const Team = db.model('Team', teamSchema); - - console.time('createTeams'); - - let i = 0; - let page = 0; - const pageLimit = 100; - do { - let oldTeams; - try { - oldTeams = await OldTeam.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Old teams failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const createTeams = []; - const uploadTeamsAvatars = []; - for (let oldTeam of oldTeams) { - if (oldTeam.name) { - const members = oldTeam.members.filter( - m => m.toString() !== oldTeam.creator.toString() - ); - const teamData = { - _id: oldTeam.id, - createdAt: oldTeam.created_at, - events: oldTeam.events, - managers: [oldTeam.creator], - members: members, - name: - oldTeam.name.length > 35 - ? oldTeam.name.substring(0, 35) - : oldTeam.name, - updatedAt: oldTeam.updated_at - }; - - if (oldTeam.description) { - teamData.description = - oldTeam.description.length <= 300 - ? oldTeam.description - : oldTeam.description.substring(0, 300); - } - - if (oldTeam.image && !oldTeam.image.includes('icon_team.png')) { - let avatarImage; - try { - avatarImage = await jimp.read(encodeURI(oldTeam.image)); - } catch (err) { - console.log('Old team avatar image failed to be read'); - console.log(err); - await closeConnections(db, oldDb); - } - - if (avatarImage) { - const avatarExtension = avatarImage.getExtension(); - const avatarFileName = `${Date.now()}${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}.${avatarExtension}`; - - if ( - avatarExtension === 'png' || - avatarExtension === 'jpeg' || - avatarExtension === 'jpg' || - avatarExtension === 'bmp' - ) { - teamData.avatar = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/teams/avatars/${avatarFileName}`; - avatarImage - .cover(400, 400) - .quality(85) - .getBuffer( - avatarImage.getMIME(), - async (err, avatarBuffer) => { - if (err) { - console.log('Old team avatar buffer failed to be read'); - console.log(err); - await closeConnections(db, oldDb); - } - - uploadTeamsAvatars.push( - s3 - .putObject({ - ACL: 'public-read', - Body: avatarBuffer, - Bucket: process.env.AWS_S3_BUCKET, - ContentType: avatarImage.getMIME(), - Key: `teams/avatars/${avatarFileName}` - }) - .promise() - ); - } - ); - } - } - } - - createTeams.push(Team.create(teamData)); - } - } - - try { - await Promise.all([...createTeams, ...uploadTeamsAvatars]); - } catch (error) { - console.log( - `Teams failed to be created.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(error); - await closeConnections(db, oldDb); - } - - page = page + 1; - i = i + oldTeams.length; - console.log(i); - } while (i < totalOldTeams); - - console.timeEnd('createTeams'); - - const Review = db.model('Review', reviewSchema); - - let totalTeams; - try { - totalTeams = await Team.count(); - } catch (error) { - console.log('Teams failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total teams: ${totalTeams}`); - - i = 0; - page = 0; - do { - let teams; - try { - teams = await Team.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Teams failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const updateTeams = []; - for (let team of teams) { - let teamReviews; - try { - teamReviews = await Review.find({ team: team.id }).count(); - } catch (err) { - console.log('Team reviews failed to be count'); - console.log(err); - await closeConnections(db, oldDb); - } - - team.reviewsAmount = teamReviews; - updateTeams.push(team.save()); - } - - try { - await Promise.all(updateTeams); - } catch (err) { - console.log( - `Teams failed to be updated.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(err); - await closeConnections(db, oldDb); - } - - page = page + 1; - i = i + teams.length; - console.log(i); - } while (i < totalTeams); - - await closeConnections(db, oldDb); - }); - - oldDb.on('error', err => { - console.log('Connection to old DB failed ' + err); - process.exit(0); - }); - - oldDb.on('disconnected', () => { - console.log('Connection from old DB closed'); - }); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const aws = require('aws-sdk'); +const jimp = require('jimp'); +const mongoose = require('mongoose'); +const randomstring = require('randomstring'); + +require('dotenv').config(); + +const { reviewSchema } = require('../../models/review'); +const { teamSchema } = require('../../models/team'); + +const oldTeamSchema = require('./old-schemas/team'); + +mongoose.Promise = global.Promise; + +const s3 = new aws.S3(); + +async function closeConnections(db, oldDb) { + try { + await oldDb.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const oldUri = process.env.OLD_DB_URI; + const oldDb = mongoose.createConnection(oldUri, options); + + oldDb.on('connected', async () => { + console.log('Connection to old DB established successfully'); + + const OldTeam = oldDb.model('teams', oldTeamSchema); + + let totalOldTeams; + try { + totalOldTeams = await OldTeam.count(); + } catch (error) { + console.log('Old teams failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total old teams: ${totalOldTeams}`); + + const Team = db.model('Team', teamSchema); + + console.time('createTeams'); + + let i = 0; + let page = 0; + const pageLimit = 100; + do { + let oldTeams; + try { + oldTeams = await OldTeam.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Old teams failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const createTeams = []; + const uploadTeamsAvatars = []; + for (let oldTeam of oldTeams) { + if (oldTeam.name) { + const members = oldTeam.members.filter( + (m) => m.toString() !== oldTeam.creator.toString() + ); + const teamData = { + _id: oldTeam.id, + createdAt: oldTeam.created_at, + events: oldTeam.events, + managers: [oldTeam.creator], + members: members, + name: + oldTeam.name.length > 35 + ? oldTeam.name.substring(0, 35) + : oldTeam.name, + updatedAt: oldTeam.updated_at + }; + + if (oldTeam.description) { + teamData.description = + oldTeam.description.length <= 300 + ? oldTeam.description + : oldTeam.description.substring(0, 300); + } + + if (oldTeam.image && !oldTeam.image.includes('icon_team.png')) { + let avatarImage; + try { + avatarImage = await jimp.read(encodeURI(oldTeam.image)); + } catch (err) { + console.log('Old team avatar image failed to be read'); + console.log(err); + await closeConnections(db, oldDb); + } + + if (avatarImage) { + const avatarExtension = avatarImage.getExtension(); + const avatarFileName = `${Date.now()}${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}.${avatarExtension}`; + + if ( + avatarExtension === 'png' || + avatarExtension === 'jpeg' || + avatarExtension === 'jpg' || + avatarExtension === 'bmp' + ) { + teamData.avatar = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/teams/avatars/${avatarFileName}`; + avatarImage + .cover(400, 400) + .quality(85) + .getBuffer( + avatarImage.getMIME(), + async (err, avatarBuffer) => { + if (err) { + console.log('Old team avatar buffer failed to be read'); + console.log(err); + await closeConnections(db, oldDb); + } + + uploadTeamsAvatars.push( + s3 + .putObject({ + ACL: 'public-read', + Body: avatarBuffer, + Bucket: process.env.AWS_S3_BUCKET, + ContentType: avatarImage.getMIME(), + Key: `teams/avatars/${avatarFileName}` + }) + .promise() + ); + } + ); + } + } + } + + createTeams.push(Team.create(teamData)); + } + } + + try { + await Promise.all([...createTeams, ...uploadTeamsAvatars]); + } catch (error) { + console.log( + `Teams failed to be created.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(error); + await closeConnections(db, oldDb); + } + + page = page + 1; + i = i + oldTeams.length; + console.log(i); + } while (i < totalOldTeams); + + console.timeEnd('createTeams'); + + const Review = db.model('Review', reviewSchema); + + let totalTeams; + try { + totalTeams = await Team.count(); + } catch (error) { + console.log('Teams failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total teams: ${totalTeams}`); + + i = 0; + page = 0; + do { + let teams; + try { + teams = await Team.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Teams failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const updateTeams = []; + for (let team of teams) { + let teamReviews; + try { + teamReviews = await Review.find({ team: team.id }).count(); + } catch (err) { + console.log('Team reviews failed to be count'); + console.log(err); + await closeConnections(db, oldDb); + } + + team.reviewsAmount = teamReviews; + updateTeams.push(team.save()); + } + + try { + await Promise.all(updateTeams); + } catch (err) { + console.log( + `Teams failed to be updated.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(err); + await closeConnections(db, oldDb); + } + + page = page + 1; + i = i + teams.length; + console.log(i); + } while (i < totalTeams); + + await closeConnections(db, oldDb); + }); + + oldDb.on('error', (err) => { + console.log('Connection to old DB failed ' + err); + process.exit(0); + }); + + oldDb.on('disconnected', () => { + console.log('Connection from old DB closed'); + }); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); diff --git a/src/scripts/db/import-users.js b/src/scripts/db/import-users.js index ed75da7..55fdd69 100644 --- a/src/scripts/db/import-users.js +++ b/src/scripts/db/import-users.js @@ -1,275 +1,275 @@ -const mongoose = require('mongoose'); -const randomstring = require('randomstring'); -const slugify = require('speakingurl'); - -require('dotenv').config(); - -const { cleanSpaces } = require('../../helpers'); -const { reviewSchema } = require('../../models/review'); -const { userSchema } = require('../../models/user'); - -const oldUserSchema = require('./old-schemas/user'); - -mongoose.Promise = global.Promise; - -async function closeConnections(db, oldDb) { - try { - await oldDb.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const oldUri = process.env.OLD_DB_URI; - const oldDb = mongoose.createConnection(oldUri, options); - - oldDb.on('connected', async () => { - console.log('Connection to old DB established successfully'); - - const OldUser = oldDb.model('users', oldUserSchema); - - let totalOldUsers; - try { - totalOldUsers = await OldUser.count(); - } catch (error) { - console.log('Old users failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total old users: ${totalOldUsers}`); - - const User = db.model('User', userSchema); - - console.time('createUsers'); - - let page = 0; - const pageLimit = 100; - let i = 0; - do { - let oldUsers; - try { - oldUsers = await OldUser.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Old users failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const createUsers = []; - for (let oldUser of oldUsers) { - if (oldUser.isactive) { - const userData = { - _id: oldUser.id, - createdAt: oldUser.createdAt, - description: oldUser.description - ? cleanSpaces(oldUser.description) - : '', - email: oldUser.email, - events: oldUser.events, - facebookId: oldUser.facebookAuth, - firstName: - oldUser.name.first && cleanSpaces(oldUser.name.first) - ? cleanSpaces(oldUser.name.first) - : 'first', - hashedPassword: oldUser.hash, - isSubscribed: oldUser.newsletter, - lastName: - oldUser.name.last && cleanSpaces(oldUser.name.last) - ? cleanSpaces(oldUser.name.last) - : 'last', - phone: oldUser.phone ? cleanSpaces(oldUser.phone) : '', - showEmail: oldUser.showEmail, - showPhone: oldUser.showPhone, - teams: oldUser.teams, - updatedAt: oldUser.updatedAt, - username: `${slugify(oldUser.name.first)}-${slugify( - oldUser.name.last - )}-${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}` - }; - - switch (oldUser.disabilitytype.toLowerCase()) { - case 'audio': - userData.disabilities = ['audio']; - break; - - case 'other': - userData.disabilities = ['other']; - break; - - case 'private': - userData.disabilities = ['private']; - break; - - case 'visual': - userData.disabilities = ['vision']; - break; - - case 'wheelchair': - userData.disabilities = ['physical']; - break; - - default: - userData.disabilities = ['none']; - } - - switch (oldUser.gender.toLowerCase()) { - case 'female': - userData.gender = 'female'; - break; - - case 'male': - userData.gender = 'male'; - break; - - case 'other': - userData.gender = 'other'; - break; - - case 'transgender': - userData.gender = 'transgender'; - break; - - default: - userData.gender = 'private'; - } - - if (oldUser.zip && oldUser.zip.length <= 32) { - userData.zip = oldUser.zip; - } - - createUsers.push(User.create(userData)); - } - } - - try { - await Promise.all(createUsers); - } catch (error) { - console.log( - `Users failed to be created.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(error); - await closeConnections(db, oldDb); - } - - page = page + 1; - i = i + oldUsers.length; - console.log(i); - } while (i < totalOldUsers); - - console.timeEnd('createUsers'); - - const Review = db.model('Review', reviewSchema); - - let totalUsers; - try { - totalUsers = await User.count(); - } catch (error) { - console.log('Users failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total users: ${totalUsers}`); - - console.time('updateReviewsAmount'); - - i = 0; - page = 0; - do { - let users; - try { - users = await User.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Users failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const updateUsers = []; - for (let user of users) { - let userReviews; - try { - userReviews = await Review.find({ user: user.id }).count(); - } catch (err) { - console.log('User reviews failed to be count'); - console.log(err); - await closeConnections(db, oldDb); - } - - user.reviewsAmount = userReviews; - updateUsers.push(user.save()); - } - - try { - await Promise.all(updateUsers); - } catch (err) { - console.log( - `Users failed to be updated.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(err); - await closeConnections(db, oldDb); - } - - page = page + 1; - i = i + users.length; - console.log(i); - } while (i < totalUsers); - - console.timeEnd('updateReviewsAmount'); - - await closeConnections(db, oldDb); - }); - - oldDb.on('error', err => { - console.log('Connection to old DB failed ' + err); - process.exit(0); - }); - - oldDb.on('disconnected', () => { - console.log('Connection from old DB closed'); - }); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const mongoose = require('mongoose'); +const randomstring = require('randomstring'); +const slugify = require('speakingurl'); + +require('dotenv').config(); + +const { cleanSpaces } = require('../../helpers'); +const { reviewSchema } = require('../../models/review'); +const { userSchema } = require('../../models/user'); + +const oldUserSchema = require('./old-schemas/user'); + +mongoose.Promise = global.Promise; + +async function closeConnections(db, oldDb) { + try { + await oldDb.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const oldUri = process.env.OLD_DB_URI; + const oldDb = mongoose.createConnection(oldUri, options); + + oldDb.on('connected', async () => { + console.log('Connection to old DB established successfully'); + + const OldUser = oldDb.model('users', oldUserSchema); + + let totalOldUsers; + try { + totalOldUsers = await OldUser.count(); + } catch (error) { + console.log('Old users failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total old users: ${totalOldUsers}`); + + const User = db.model('User', userSchema); + + console.time('createUsers'); + + let page = 0; + const pageLimit = 100; + let i = 0; + do { + let oldUsers; + try { + oldUsers = await OldUser.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Old users failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const createUsers = []; + for (let oldUser of oldUsers) { + if (oldUser.isactive) { + const userData = { + _id: oldUser.id, + createdAt: oldUser.createdAt, + description: oldUser.description + ? cleanSpaces(oldUser.description) + : '', + email: oldUser.email, + events: oldUser.events, + facebookId: oldUser.facebookAuth, + firstName: + oldUser.name.first && cleanSpaces(oldUser.name.first) + ? cleanSpaces(oldUser.name.first) + : 'first', + hashedPassword: oldUser.hash, + isSubscribed: oldUser.newsletter, + lastName: + oldUser.name.last && cleanSpaces(oldUser.name.last) + ? cleanSpaces(oldUser.name.last) + : 'last', + phone: oldUser.phone ? cleanSpaces(oldUser.phone) : '', + showEmail: oldUser.showEmail, + showPhone: oldUser.showPhone, + teams: oldUser.teams, + updatedAt: oldUser.updatedAt, + username: `${slugify(oldUser.name.first)}-${slugify( + oldUser.name.last + )}-${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}` + }; + + switch (oldUser.disabilitytype.toLowerCase()) { + case 'audio': + userData.disabilities = ['audio']; + break; + + case 'other': + userData.disabilities = ['other']; + break; + + case 'private': + userData.disabilities = ['private']; + break; + + case 'visual': + userData.disabilities = ['vision']; + break; + + case 'wheelchair': + userData.disabilities = ['physical']; + break; + + default: + userData.disabilities = ['none']; + } + + switch (oldUser.gender.toLowerCase()) { + case 'female': + userData.gender = 'female'; + break; + + case 'male': + userData.gender = 'male'; + break; + + case 'other': + userData.gender = 'other'; + break; + + case 'transgender': + userData.gender = 'transgender'; + break; + + default: + userData.gender = 'private'; + } + + if (oldUser.zip && oldUser.zip.length <= 32) { + userData.zip = oldUser.zip; + } + + createUsers.push(User.create(userData)); + } + } + + try { + await Promise.all(createUsers); + } catch (error) { + console.log( + `Users failed to be created.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(error); + await closeConnections(db, oldDb); + } + + page = page + 1; + i = i + oldUsers.length; + console.log(i); + } while (i < totalOldUsers); + + console.timeEnd('createUsers'); + + const Review = db.model('Review', reviewSchema); + + let totalUsers; + try { + totalUsers = await User.count(); + } catch (error) { + console.log('Users failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total users: ${totalUsers}`); + + console.time('updateReviewsAmount'); + + i = 0; + page = 0; + do { + let users; + try { + users = await User.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Users failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const updateUsers = []; + for (let user of users) { + let userReviews; + try { + userReviews = await Review.find({ user: user.id }).count(); + } catch (err) { + console.log('User reviews failed to be count'); + console.log(err); + await closeConnections(db, oldDb); + } + + user.reviewsAmount = userReviews; + updateUsers.push(user.save()); + } + + try { + await Promise.all(updateUsers); + } catch (err) { + console.log( + `Users failed to be updated.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(err); + await closeConnections(db, oldDb); + } + + page = page + 1; + i = i + users.length; + console.log(i); + } while (i < totalUsers); + + console.timeEnd('updateReviewsAmount'); + + await closeConnections(db, oldDb); + }); + + oldDb.on('error', (err) => { + console.log('Connection to old DB failed ' + err); + process.exit(0); + }); + + oldDb.on('disconnected', () => { + console.log('Connection from old DB closed'); + }); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); diff --git a/src/scripts/db/import-venues.js b/src/scripts/db/import-venues.js index 331c7b3..bf03081 100644 --- a/src/scripts/db/import-venues.js +++ b/src/scripts/db/import-venues.js @@ -1,182 +1,182 @@ -const mongoose = require('mongoose'); - -require('dotenv').config(); - -const { venueSchema } = require('../../models/venue'); - -const oldVenueSchema = require('./old-schemas/venue'); - -mongoose.Promise = global.Promise; - -async function closeConnections(db, oldDb) { - try { - await oldDb.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const oldUri = process.env.OLD_DB_URI; - const oldDb = mongoose.createConnection(oldUri, options); - - oldDb.on('connected', async () => { - console.log('Connection to old DB established successfully'); - - const OldVenue = oldDb.model('venues', oldVenueSchema); - - let totalOldVenues; - try { - totalOldVenues = await OldVenue.find({ - lngLat: { $exists: true }, - place_id: { $exists: true, $ne: '' }, - types: { $ne: [] } - }).count(); - } catch (error) { - console.log('Old venues failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total old venues: ${totalOldVenues}`); - - console.time('createVenues'); - - let page = 0; - const pageLimit = 100; - let i = 0; - do { - let oldVenues; - try { - oldVenues = await OldVenue.find({ - lngLat: { $exists: true }, - place_id: { $exists: true, $ne: '' }, - types: { $ne: [] } - }) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Old venues failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const Venue = db.model('Venue', venueSchema); - - const createVenues = []; - for (let oldVenue of oldVenues) { - const addressOne = oldVenue.addr1; - const addressTwo = oldVenue.addr2 ? ` ${oldVenue.addr2}` : ''; - const city = oldVenue.city ? `, ${oldVenue.city}` : ''; - const state = oldVenue.state ? `, ${oldVenue.state}` : ''; - const address = `${addressOne}${addressTwo}${city}${state}`; - - const bathroomScore = - oldVenue.bathroom >= 1 ? oldVenue.bathroom : undefined; - const entryScore = oldVenue.entry >= 1 ? oldVenue.entry : undefined; - - let longitude; - if (oldVenue.lngLat[1] >= -180 && oldVenue.lngLat[1] <= 180) { - longitude = oldVenue.lngLat[1]; - } - let latitude; - if (oldVenue.lngLat[0] >= -90 && oldVenue.lngLat[0] <= 90) { - latitude = oldVenue.lngLat[0]; - } else { - longitude = oldVenue.lngLat[0]; - latitude = oldVenue.lngLat[1]; - } - - const venueData = { - _id: oldVenue.id, - address: oldVenue.addr1 ? address : '', - allowsGuideDog: { yes: oldVenue.guidedog }, - bathroomReviews: oldVenue.b_reviews, - bathroomScore, - createdAt: oldVenue.created_at, - entryReviews: oldVenue.e_reviews, - entryScore, - hasParking: { yes: oldVenue.parking }, - hasRamp: { yes: oldVenue.ramp }, - hasSecondEntry: { yes: oldVenue.secondentrance }, - hasWellLit: { yes: oldVenue.welllit }, - isQuiet: { yes: oldVenue.quiet }, - isSpacious: { yes: oldVenue.spacious }, - location: { coordinates: [longitude, latitude] }, - name: oldVenue.name, - placeId: oldVenue.place_id, - reviews: oldVenue.reviewdata, - steps: { - zero: oldVenue.steps_0, - one: oldVenue.steps_1, - two: oldVenue.steps_2, - moreThanTwo: oldVenue.steps_3 - }, - types: oldVenue.types, - updatedAt: oldVenue.updated_at - }; - - createVenues.push(Venue.create(venueData)); - } - - try { - await Promise.all(createVenues); - } catch (error) { - console.log( - `Venues failed to be created.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(error); - await closeConnections(db, oldDb); - } - - page = page + 1; - i = i + oldVenues.length; - console.log(i); - } while (i < totalOldVenues); - - console.timeEnd('createVenues'); - - await closeConnections(db, oldDb); - }); - - oldDb.on('error', err => { - console.log('Connection to old DB failed ' + err); - process.exit(0); - }); - - oldDb.on('disconnected', () => { - console.log('Connection from old DB closed'); - }); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const mongoose = require('mongoose'); + +require('dotenv').config(); + +const { venueSchema } = require('../../models/venue'); + +const oldVenueSchema = require('./old-schemas/venue'); + +mongoose.Promise = global.Promise; + +async function closeConnections(db, oldDb) { + try { + await oldDb.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const oldUri = process.env.OLD_DB_URI; + const oldDb = mongoose.createConnection(oldUri, options); + + oldDb.on('connected', async () => { + console.log('Connection to old DB established successfully'); + + const OldVenue = oldDb.model('venues', oldVenueSchema); + + let totalOldVenues; + try { + totalOldVenues = await OldVenue.find({ + lngLat: { $exists: true }, + place_id: { $exists: true, $ne: '' }, + types: { $ne: [] } + }).count(); + } catch (error) { + console.log('Old venues failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total old venues: ${totalOldVenues}`); + + console.time('createVenues'); + + let page = 0; + const pageLimit = 100; + let i = 0; + do { + let oldVenues; + try { + oldVenues = await OldVenue.find({ + lngLat: { $exists: true }, + place_id: { $exists: true, $ne: '' }, + types: { $ne: [] } + }) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Old venues failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const Venue = db.model('Venue', venueSchema); + + const createVenues = []; + for (let oldVenue of oldVenues) { + const addressOne = oldVenue.addr1; + const addressTwo = oldVenue.addr2 ? ` ${oldVenue.addr2}` : ''; + const city = oldVenue.city ? `, ${oldVenue.city}` : ''; + const state = oldVenue.state ? `, ${oldVenue.state}` : ''; + const address = `${addressOne}${addressTwo}${city}${state}`; + + const bathroomScore = + oldVenue.bathroom >= 1 ? oldVenue.bathroom : undefined; + const entryScore = oldVenue.entry >= 1 ? oldVenue.entry : undefined; + + let longitude; + if (oldVenue.lngLat[1] >= -180 && oldVenue.lngLat[1] <= 180) { + longitude = oldVenue.lngLat[1]; + } + let latitude; + if (oldVenue.lngLat[0] >= -90 && oldVenue.lngLat[0] <= 90) { + latitude = oldVenue.lngLat[0]; + } else { + longitude = oldVenue.lngLat[0]; + latitude = oldVenue.lngLat[1]; + } + + const venueData = { + _id: oldVenue.id, + address: oldVenue.addr1 ? address : '', + allowsGuideDog: { yes: oldVenue.guidedog }, + bathroomReviews: oldVenue.b_reviews, + bathroomScore, + createdAt: oldVenue.created_at, + entryReviews: oldVenue.e_reviews, + entryScore, + hasParking: { yes: oldVenue.parking }, + hasRamp: { yes: oldVenue.ramp }, + hasSecondEntry: { yes: oldVenue.secondentrance }, + hasWellLit: { yes: oldVenue.welllit }, + isQuiet: { yes: oldVenue.quiet }, + isSpacious: { yes: oldVenue.spacious }, + location: { coordinates: [longitude, latitude] }, + name: oldVenue.name, + placeId: oldVenue.place_id, + reviews: oldVenue.reviewdata, + steps: { + zero: oldVenue.steps_0, + one: oldVenue.steps_1, + two: oldVenue.steps_2, + moreThanTwo: oldVenue.steps_3 + }, + types: oldVenue.types, + updatedAt: oldVenue.updated_at + }; + + createVenues.push(Venue.create(venueData)); + } + + try { + await Promise.all(createVenues); + } catch (error) { + console.log( + `Venues failed to be created.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(error); + await closeConnections(db, oldDb); + } + + page = page + 1; + i = i + oldVenues.length; + console.log(i); + } while (i < totalOldVenues); + + console.timeEnd('createVenues'); + + await closeConnections(db, oldDb); + }); + + oldDb.on('error', (err) => { + console.log('Connection to old DB failed ' + err); + process.exit(0); + }); + + oldDb.on('disconnected', () => { + console.log('Connection from old DB closed'); + }); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); diff --git a/src/scripts/db/old-schemas/event.js b/src/scripts/db/old-schemas/event.js index cd99ce5..370e451 100644 --- a/src/scripts/db/old-schemas/event.js +++ b/src/scripts/db/old-schemas/event.js @@ -1,83 +1,83 @@ -const mongoose = require('mongoose'); - -const Schema = mongoose.Schema; -const ObjectId = Schema.ObjectId; - -const schema = new Schema({ - name: { - type: String, - required: true - }, - description: { - type: String, - required: true - }, - creator: { - type: ObjectId, - ref: 'users', - required: true - }, - approved: { - type: Boolean, - default: true - }, - event_start: { - type: Date, - required: true - }, - event_end: { - type: Date, - required: true - }, - created_at: { - type: Date, - default: Date.now - }, - updated_at: { - type: Date, - default: Date.now - }, - location: { - type: ObjectId, - ref: 'venues' - }, - goal: Number, - mapping_goal: Number, - participant_goal: Number, - participant_limit: Number, - type: String, - image: { - type: String, - default: '/images/icon_pin_mapathon_water.png' - }, - company: { - name: String, - address: String - }, - charity: { - name: String, - email: String, - website: String - }, - teams: [ - { - type: ObjectId, - ref: 'teams' - } - ], - members: [ - { - _id: false, - user: { - type: ObjectId, - ref: 'users' - }, - team: { - type: ObjectId, - ref: 'teams' - } - } - ] -}); - -module.exports = schema; +const mongoose = require('mongoose'); + +const Schema = mongoose.Schema; +const ObjectId = Schema.ObjectId; + +const schema = new Schema({ + name: { + type: String, + required: true + }, + description: { + type: String, + required: true + }, + creator: { + type: ObjectId, + ref: 'users', + required: true + }, + approved: { + type: Boolean, + default: true + }, + event_start: { + type: Date, + required: true + }, + event_end: { + type: Date, + required: true + }, + created_at: { + type: Date, + default: Date.now + }, + updated_at: { + type: Date, + default: Date.now + }, + location: { + type: ObjectId, + ref: 'venues' + }, + goal: Number, + mapping_goal: Number, + participant_goal: Number, + participant_limit: Number, + type: String, + image: { + type: String, + default: '/images/icon_pin_mapathon_water.png' + }, + company: { + name: String, + address: String + }, + charity: { + name: String, + email: String, + website: String + }, + teams: [ + { + type: ObjectId, + ref: 'teams' + } + ], + members: [ + { + _id: false, + user: { + type: ObjectId, + ref: 'users' + }, + team: { + type: ObjectId, + ref: 'teams' + } + } + ] +}); + +module.exports = schema; diff --git a/src/scripts/db/old-schemas/photo.js b/src/scripts/db/old-schemas/photo.js index d6cf920..e416234 100644 --- a/src/scripts/db/old-schemas/photo.js +++ b/src/scripts/db/old-schemas/photo.js @@ -1,37 +1,37 @@ -const mongoose = require('mongoose'); - -const reviewSchema = new mongoose.Schema({ - review_id: { - type: mongoose.Schema.ObjectId, - index: true, - ref: 'reviews' - }, - venue_id: { - type: mongoose.Schema.ObjectId, - index: true, - ref: 'venues' - }, - user_id: { - type: mongoose.Schema.ObjectId, - index: true - }, - flag: Number, - flaggers: [ - { - type: mongoose.Schema.ObjectId, - index: true - } - ], - s3_id: String, - url: String, - created_at: { - type: Date, - default: Date.now - }, - updated_at: { - type: Date, - default: Date.now - } -}); - -module.exports = reviewSchema; +const mongoose = require('mongoose'); + +const reviewSchema = new mongoose.Schema({ + review_id: { + type: mongoose.Schema.ObjectId, + index: true, + ref: 'reviews' + }, + venue_id: { + type: mongoose.Schema.ObjectId, + index: true, + ref: 'venues' + }, + user_id: { + type: mongoose.Schema.ObjectId, + index: true + }, + flag: Number, + flaggers: [ + { + type: mongoose.Schema.ObjectId, + index: true + } + ], + s3_id: String, + url: String, + created_at: { + type: Date, + default: Date.now + }, + updated_at: { + type: Date, + default: Date.now + } +}); + +module.exports = reviewSchema; diff --git a/src/scripts/db/old-schemas/review.js b/src/scripts/db/old-schemas/review.js index 23ba9a9..2e9e45a 100644 --- a/src/scripts/db/old-schemas/review.js +++ b/src/scripts/db/old-schemas/review.js @@ -1,81 +1,81 @@ -const mongoose = require('mongoose'); - -const reviewSchema = new mongoose.Schema({ - venue_id: { - type: mongoose.Schema.ObjectId, - index: true, - ref: 'venues' - }, - user_id: { - type: mongoose.Schema.ObjectId, - index: true - }, - team: { - type: mongoose.Schema.ObjectId, - ref: 'teams' - }, - event: { - type: mongoose.Schema.ObjectId, - ref: 'events' - }, - entry: Number, - bathroom: Number, - spacious: { - type: Boolean, - default: false - }, - quiet: { - type: Boolean, - default: false - }, - parking: { - type: Boolean, - default: false - }, - ramp: { - type: Boolean, - default: false - }, - secondentrance: { - type: Boolean, - default: false - }, - guidedog: { - type: Boolean, - default: false - }, - welllit: { - type: Boolean, - default: false - }, - comment: String, - username: String, - abuse: Number, - flag: Number, - flaggers: [ - { - type: mongoose.Schema.ObjectId, - index: true - } - ], - deleted: Boolean, - steps: Number, - votes: Number, - images: [ - { - type: mongoose.Schema.ObjectId, - index: true, - ref: 'photos' - } - ], - created_at: { - type: Date, - default: Date.now - }, - updated_at: { - type: Date, - default: Date.now - } -}); - -module.exports = reviewSchema; +const mongoose = require('mongoose'); + +const reviewSchema = new mongoose.Schema({ + venue_id: { + type: mongoose.Schema.ObjectId, + index: true, + ref: 'venues' + }, + user_id: { + type: mongoose.Schema.ObjectId, + index: true + }, + team: { + type: mongoose.Schema.ObjectId, + ref: 'teams' + }, + event: { + type: mongoose.Schema.ObjectId, + ref: 'events' + }, + entry: Number, + bathroom: Number, + spacious: { + type: Boolean, + default: false + }, + quiet: { + type: Boolean, + default: false + }, + parking: { + type: Boolean, + default: false + }, + ramp: { + type: Boolean, + default: false + }, + secondentrance: { + type: Boolean, + default: false + }, + guidedog: { + type: Boolean, + default: false + }, + welllit: { + type: Boolean, + default: false + }, + comment: String, + username: String, + abuse: Number, + flag: Number, + flaggers: [ + { + type: mongoose.Schema.ObjectId, + index: true + } + ], + deleted: Boolean, + steps: Number, + votes: Number, + images: [ + { + type: mongoose.Schema.ObjectId, + index: true, + ref: 'photos' + } + ], + created_at: { + type: Date, + default: Date.now + }, + updated_at: { + type: Date, + default: Date.now + } +}); + +module.exports = reviewSchema; diff --git a/src/scripts/db/old-schemas/team.js b/src/scripts/db/old-schemas/team.js index be70c88..85581c3 100644 --- a/src/scripts/db/old-schemas/team.js +++ b/src/scripts/db/old-schemas/team.js @@ -1,49 +1,49 @@ -const mongoose = require('mongoose'); - -const venueSchema = new mongoose.Schema({ - name: String, - goal: Number, - corporation: String, - description: String, - password: String, - image: { - type: String, - default: '/images/icon_team.png' - }, - creator: { - type: mongoose.Schema.ObjectId, - ref: 'users' - }, - events: [ - { - type: mongoose.Schema.ObjectId, - ref: 'events' - } - ], - updated_at: { - type: Date, - default: Date.now - }, - created_at: { - type: Date, - default: Date.now - }, - members: [ - { - type: mongoose.Schema.ObjectId, - ref: 'users' - } - ], - invites: [ - { - type: mongoose.Schema.ObjectId, - ref: 'invites' - } - ], - approved: { - type: Boolean, - default: true - } -}); - -module.exports = venueSchema; +const mongoose = require('mongoose'); + +const venueSchema = new mongoose.Schema({ + name: String, + goal: Number, + corporation: String, + description: String, + password: String, + image: { + type: String, + default: '/images/icon_team.png' + }, + creator: { + type: mongoose.Schema.ObjectId, + ref: 'users' + }, + events: [ + { + type: mongoose.Schema.ObjectId, + ref: 'events' + } + ], + updated_at: { + type: Date, + default: Date.now + }, + created_at: { + type: Date, + default: Date.now + }, + members: [ + { + type: mongoose.Schema.ObjectId, + ref: 'users' + } + ], + invites: [ + { + type: mongoose.Schema.ObjectId, + ref: 'invites' + } + ], + approved: { + type: Boolean, + default: true + } +}); + +module.exports = venueSchema; diff --git a/src/scripts/db/old-schemas/user.js b/src/scripts/db/old-schemas/user.js index 311e828..46664c3 100644 --- a/src/scripts/db/old-schemas/user.js +++ b/src/scripts/db/old-schemas/user.js @@ -1,125 +1,125 @@ -const mongoose = require('mongoose'); - -const userSchema = new mongoose.Schema({ - schema_version: Number, - name: { - first: { - type: String, - required: true - }, - last: { - type: String, - required: true - } - }, - fullName: String, - type: String, - description: String, - showEmail: { - type: Boolean, - default: true - }, - showPhone: { - type: Boolean, - default: true - }, - image: { - type: String, - default: '/images/icon_guy.png' - }, - company: { - name: String, - address: String - }, - email: { - type: String, - unique: true, - required: true - }, - phone: { - type: String - }, - location: { - type: String - }, - zip: { - type: String - }, - gender: { - type: String, - default: '' - }, - disabilitytype: { - type: String, - default: '' - }, - newsletter: { - type: Boolean, - default: true - }, - isactive: { - type: Boolean, - default: false - }, - isadmin: { - type: Boolean, - default: false - }, - salt: { - type: String - }, - hash: { - type: String - }, - token: { - type: String, - default: false - }, - activatedAt: { - type: Date - }, - createdAt: { - type: Date, - default: Date.now - }, - updatedAt: { - type: Date, - default: Date.now - }, - events: [ - { - type: mongoose.Schema.ObjectId, - ref: 'events' - } - ], - images: [ - { - type: mongoose.Schema.ObjectId, - index: true, - ref: 'photos' - } - ], - teams: [ - { - type: mongoose.Schema.ObjectId, - ref: 'teams' - } - ], - reset: { - createdAt: Date, - link: mongoose.Schema.ObjectId - }, - foursquareId: String, - facebookAuth: String, - foursquareVerified: { - type: Boolean, - default: false - }, - facebookVerified: { - type: Boolean, - default: false - }, - username: String -}); - -module.exports = userSchema; +const mongoose = require('mongoose'); + +const userSchema = new mongoose.Schema({ + schema_version: Number, + name: { + first: { + type: String, + required: true + }, + last: { + type: String, + required: true + } + }, + fullName: String, + type: String, + description: String, + showEmail: { + type: Boolean, + default: true + }, + showPhone: { + type: Boolean, + default: true + }, + image: { + type: String, + default: '/images/icon_guy.png' + }, + company: { + name: String, + address: String + }, + email: { + type: String, + unique: true, + required: true + }, + phone: { + type: String + }, + location: { + type: String + }, + zip: { + type: String + }, + gender: { + type: String, + default: '' + }, + disabilitytype: { + type: String, + default: '' + }, + newsletter: { + type: Boolean, + default: true + }, + isactive: { + type: Boolean, + default: false + }, + isadmin: { + type: Boolean, + default: false + }, + salt: { + type: String + }, + hash: { + type: String + }, + token: { + type: String, + default: false + }, + activatedAt: { + type: Date + }, + createdAt: { + type: Date, + default: Date.now + }, + updatedAt: { + type: Date, + default: Date.now + }, + events: [ + { + type: mongoose.Schema.ObjectId, + ref: 'events' + } + ], + images: [ + { + type: mongoose.Schema.ObjectId, + index: true, + ref: 'photos' + } + ], + teams: [ + { + type: mongoose.Schema.ObjectId, + ref: 'teams' + } + ], + reset: { + createdAt: Date, + link: mongoose.Schema.ObjectId + }, + foursquareId: String, + facebookAuth: String, + foursquareVerified: { + type: Boolean, + default: false + }, + facebookVerified: { + type: Boolean, + default: false + }, + username: String +}); + +module.exports = userSchema; diff --git a/src/scripts/db/old-schemas/venue.js b/src/scripts/db/old-schemas/venue.js index 490278f..fe44826 100644 --- a/src/scripts/db/old-schemas/venue.js +++ b/src/scripts/db/old-schemas/venue.js @@ -1,119 +1,119 @@ -const mongoose = require('mongoose'); - -const venueSchema = new mongoose.Schema({ - schema_version: Number, - google_id: { - type: String, - index: true - }, - google_ref: String, - place_id: { - type: String, - index: true - }, - name: String, - addr1: String, - addr2: String, - city: String, - state: String, - ph: String, - url: String, - types: Array, - ll: Array, - lngLat: { - type: Array, - index: '2d' - }, - google_rating: { - type: Number, - default: 0 - }, - google_url: String, - entry: { - type: Number, - default: 0 - }, - e_reviews: { - type: Number, - default: 0 - }, - bathroom: { - type: Number, - default: 0 - }, - b_reviews: { - type: Number, - default: 0 - }, - welllit: { - type: Number, - default: 0 - }, - spacious: { - type: Number, - default: 0 - }, - quiet: { - type: Number, - default: 0 - }, - parking: { - type: Number, - default: 0 - }, - ramp: { - type: Number, - default: 0 - }, - secondentrance: { - type: Number, - default: 0 - }, - guidedog: { - type: Number, - default: 0 - }, - steps: { - type: Number, - default: -1 - }, - steps_0: { - type: Number, - default: 0 - }, - steps_1: { - type: Number, - default: 0 - }, - steps_2: { - type: Number, - default: 0 - }, - steps_3: { - type: Number, - default: 0 - }, - created_at: { - type: Date, - default: Date.now - }, - updated_at: { - type: Date, - default: Date.now - }, - reviewdata: [ - { - type: mongoose.Schema.ObjectId, - ref: 'reviews' - } - ], - images: [ - { - type: mongoose.Schema.ObjectId, - index: true, - ref: 'photos' - } - ] -}); - -module.exports = venueSchema; +const mongoose = require('mongoose'); + +const venueSchema = new mongoose.Schema({ + schema_version: Number, + google_id: { + type: String, + index: true + }, + google_ref: String, + place_id: { + type: String, + index: true + }, + name: String, + addr1: String, + addr2: String, + city: String, + state: String, + ph: String, + url: String, + types: Array, + ll: Array, + lngLat: { + type: Array, + index: '2d' + }, + google_rating: { + type: Number, + default: 0 + }, + google_url: String, + entry: { + type: Number, + default: 0 + }, + e_reviews: { + type: Number, + default: 0 + }, + bathroom: { + type: Number, + default: 0 + }, + b_reviews: { + type: Number, + default: 0 + }, + welllit: { + type: Number, + default: 0 + }, + spacious: { + type: Number, + default: 0 + }, + quiet: { + type: Number, + default: 0 + }, + parking: { + type: Number, + default: 0 + }, + ramp: { + type: Number, + default: 0 + }, + secondentrance: { + type: Number, + default: 0 + }, + guidedog: { + type: Number, + default: 0 + }, + steps: { + type: Number, + default: -1 + }, + steps_0: { + type: Number, + default: 0 + }, + steps_1: { + type: Number, + default: 0 + }, + steps_2: { + type: Number, + default: 0 + }, + steps_3: { + type: Number, + default: 0 + }, + created_at: { + type: Date, + default: Date.now + }, + updated_at: { + type: Date, + default: Date.now + }, + reviewdata: [ + { + type: mongoose.Schema.ObjectId, + ref: 'reviews' + } + ], + images: [ + { + type: mongoose.Schema.ObjectId, + index: true, + ref: 'photos' + } + ] +}); + +module.exports = venueSchema; diff --git a/src/scripts/db/update-events-locations.js b/src/scripts/db/update-events-locations.js index 57ff40b..ead1a7f 100644 --- a/src/scripts/db/update-events-locations.js +++ b/src/scripts/db/update-events-locations.js @@ -1,150 +1,150 @@ -const axios = require('axios'); -const mongoose = require('mongoose'); - -require('dotenv').config(); - -const { eventSchema } = require('../../models/event'); -const { venueSchema } = require('../../models/venue'); - -mongoose.Promise = global.Promise; - -async function closeConnections(db) { - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const Event = db.model('Event', eventSchema); - const Venue = db.model('Venue', venueSchema); - - let totalEvents; - try { - totalEvents = await Event.count(); - } catch (error) { - console.log('Events failed to be count'); - console.log(error); - await closeConnections(db); - } - - console.log(`Total events: ${totalEvents}`); - - let i = 0; - let page = 0; - const pageLimit = 100; - do { - let events; - try { - events = await Event.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Events failed to be found'); - console.log(error); - await closeConnections(db); - } - - console.log(`${events.length} events found`); - - const getVenues = events.map(e => Venue.findOne({ _id: e.venue })); - let venues; - try { - venues = await Promise.all(getVenues); - } catch (err) { - console.log('Venues failed to be found'); - console.log(err); - await closeConnections(db); - } - - console.log(`${venues.length} venues found`); - - const getPlaces = venues.map(v => { - if (v) { - return axios.get( - `https://maps.googleapis.com/maps/api/place/details/json?placeid=${ - v.placeId - }&key=${process.env.PLACES_API_KEY}` - ); - } - }); - let places; - try { - places = await Promise.all(getPlaces); - } catch (err) { - console.log('Places failed to be found'); - console.log(err); - await closeConnections(db); - } - - console.log(`${places.length} places found`); - - const updateEvents = []; - const removeEvents = []; - places.map((p, i) => { - if ((p && p.data && p.data.result) || venues[i]) { - const place = p && p.data && p.data.result ? p.data.result : undefined; - const event = events[i]; - event.address = place ? place.formatted_address : venues[i].address; - event.location.coordinates = place - ? [place.geometry.location.lng, place.geometry.location.lat] - : venues[i].location.coordinates; - updateEvents.push(event.save()); - } else { - const event = events[i]; - removeEvents.push(event.remove()); - } - }); - try { - await Promise.all([...updateEvents, ...removeEvents]); - } catch (err) { - console.log( - `Events failed to be updated.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(err); - await closeConnections(db); - } - - console.log('Events updated'); - - page = page + 1; - i = i + events.length; - console.log(i); - - try { - totalEvents = await Event.count(); - } catch (error) { - console.log('Events failed to be count'); - console.log(error); - await closeConnections(db); - } - } while (i < totalEvents); - - await closeConnections(db); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const axios = require('axios'); +const mongoose = require('mongoose'); + +require('dotenv').config(); + +const { eventSchema } = require('../../models/event'); +const { venueSchema } = require('../../models/venue'); + +mongoose.Promise = global.Promise; + +async function closeConnections(db) { + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const Event = db.model('Event', eventSchema); + const Venue = db.model('Venue', venueSchema); + + let totalEvents; + try { + totalEvents = await Event.count(); + } catch (error) { + console.log('Events failed to be count'); + console.log(error); + await closeConnections(db); + } + + console.log(`Total events: ${totalEvents}`); + + let i = 0; + let page = 0; + const pageLimit = 100; + do { + let events; + try { + events = await Event.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Events failed to be found'); + console.log(error); + await closeConnections(db); + } + + console.log(`${events.length} events found`); + + const getVenues = events.map((e) => Venue.findOne({ _id: e.venue })); + let venues; + try { + venues = await Promise.all(getVenues); + } catch (err) { + console.log('Venues failed to be found'); + console.log(err); + await closeConnections(db); + } + + console.log(`${venues.length} venues found`); + + const getPlaces = venues.map((v) => { + if (v) { + return axios.get( + `https://maps.googleapis.com/maps/api/place/details/json?placeid=${ + v.placeId + }&key=${process.env.PLACES_API_KEY}` + ); + } + }); + let places; + try { + places = await Promise.all(getPlaces); + } catch (err) { + console.log('Places failed to be found'); + console.log(err); + await closeConnections(db); + } + + console.log(`${places.length} places found`); + + const updateEvents = []; + const removeEvents = []; + places.map((p, i) => { + if ((p && p.data && p.data.result) || venues[i]) { + const place = p && p.data && p.data.result ? p.data.result : undefined; + const event = events[i]; + event.address = place ? place.formatted_address : venues[i].address; + event.location.coordinates = place + ? [place.geometry.location.lng, place.geometry.location.lat] + : venues[i].location.coordinates; + updateEvents.push(event.save()); + } else { + const event = events[i]; + removeEvents.push(event.remove()); + } + }); + try { + await Promise.all([...updateEvents, ...removeEvents]); + } catch (err) { + console.log( + `Events failed to be updated.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(err); + await closeConnections(db); + } + + console.log('Events updated'); + + page = page + 1; + i = i + events.length; + console.log(i); + + try { + totalEvents = await Event.count(); + } catch (error) { + console.log('Events failed to be count'); + console.log(error); + await closeConnections(db); + } + } while (i < totalEvents); + + await closeConnections(db); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); diff --git a/src/scripts/db/update-events-posters.js b/src/scripts/db/update-events-posters.js index 8159465..03c2df0 100644 --- a/src/scripts/db/update-events-posters.js +++ b/src/scripts/db/update-events-posters.js @@ -1,160 +1,160 @@ -const aws = require('aws-sdk'); -const jimp = require('jimp'); -const mongoose = require('mongoose'); -const randomstring = require('randomstring'); - -require('dotenv').config(); - -const { eventSchema } = require('../../models/event'); - -mongoose.Promise = global.Promise; - -const s3 = new aws.S3(); - -async function closeConnections(db) { - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const Event = db.model('Event', eventSchema); - - let totalEvents; - try { - totalEvents = await Event.count(); - } catch (error) { - console.log('Events failed to be count'); - console.log(error); - await closeConnections(db); - } - - console.log(`Total events: ${totalEvents}`); - - let i = 0; - let page = 0; - const pageLimit = 100; - do { - let events; - try { - events = await Event.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Teams failed to be found'); - console.log(error); - await closeConnections(db); - } - - const updateEvents = []; - const uploadEventsPosters = []; - for (let event of events) { - if (event.poster && !event.poster.includes('icon_guy')) { - let posterImage; - try { - posterImage = await jimp.read(encodeURI(event.poster)); - } catch (err) { - console.log('Event poster image failed to be read'); - console.log(err); - await closeConnections(db); - } - - if (posterImage) { - const posterExtension = posterImage.getExtension(); - const posterFileName = `${Date.now()}${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}.${posterExtension}`; - - if ( - posterExtension === 'png' || - posterExtension === 'jpeg' || - posterExtension === 'jpg' || - posterExtension === 'bmp' - ) { - const posterMIME = posterImage.getMIME(); - if (posterMIME) { - event.poster = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/events/posters/${posterFileName}`; - posterImage - .cover(400, 400) - .quality(85) - .getBuffer(posterMIME, async (err, posterBuffer) => { - if (err) { - console.log('Event poster buffer failed to be read'); - console.log(err); - await closeConnections(db); - } - - uploadEventsPosters.push( - s3 - .putObject({ - ACL: 'public-read', - Body: posterBuffer, - Bucket: process.env.AWS_S3_BUCKET, - ContentType: posterImage.getMIME(), - Key: `events/posters/${posterFileName}` - }) - .promise() - ); - }); - } else { - event.poster = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/events/posters/default.png`; - } - } - } - } else { - event.poster = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/events/posters/default.png`; - } - updateEvents.push(event.save()); - } - - try { - await Promise.all([...updateEvents, ...uploadEventsPosters]); - } catch (err) { - console.log( - `Events failed to be updated.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(err); - await closeConnections(db); - } - - page = page + 1; - i = i + events.length; - console.log(i); - } while (i < totalEvents); - - await closeConnections(db); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const aws = require('aws-sdk'); +const jimp = require('jimp'); +const mongoose = require('mongoose'); +const randomstring = require('randomstring'); + +require('dotenv').config(); + +const { eventSchema } = require('../../models/event'); + +mongoose.Promise = global.Promise; + +const s3 = new aws.S3(); + +async function closeConnections(db) { + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const Event = db.model('Event', eventSchema); + + let totalEvents; + try { + totalEvents = await Event.count(); + } catch (error) { + console.log('Events failed to be count'); + console.log(error); + await closeConnections(db); + } + + console.log(`Total events: ${totalEvents}`); + + let i = 0; + let page = 0; + const pageLimit = 100; + do { + let events; + try { + events = await Event.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Teams failed to be found'); + console.log(error); + await closeConnections(db); + } + + const updateEvents = []; + const uploadEventsPosters = []; + for (let event of events) { + if (event.poster && !event.poster.includes('icon_guy')) { + let posterImage; + try { + posterImage = await jimp.read(encodeURI(event.poster)); + } catch (err) { + console.log('Event poster image failed to be read'); + console.log(err); + await closeConnections(db); + } + + if (posterImage) { + const posterExtension = posterImage.getExtension(); + const posterFileName = `${Date.now()}${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}.${posterExtension}`; + + if ( + posterExtension === 'png' || + posterExtension === 'jpeg' || + posterExtension === 'jpg' || + posterExtension === 'bmp' + ) { + const posterMIME = posterImage.getMIME(); + if (posterMIME) { + event.poster = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/events/posters/${posterFileName}`; + posterImage + .cover(400, 400) + .quality(85) + .getBuffer(posterMIME, async (err, posterBuffer) => { + if (err) { + console.log('Event poster buffer failed to be read'); + console.log(err); + await closeConnections(db); + } + + uploadEventsPosters.push( + s3 + .putObject({ + ACL: 'public-read', + Body: posterBuffer, + Bucket: process.env.AWS_S3_BUCKET, + ContentType: posterImage.getMIME(), + Key: `events/posters/${posterFileName}` + }) + .promise() + ); + }); + } else { + event.poster = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/events/posters/default.png`; + } + } + } + } else { + event.poster = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/events/posters/default.png`; + } + updateEvents.push(event.save()); + } + + try { + await Promise.all([...updateEvents, ...uploadEventsPosters]); + } catch (err) { + console.log( + `Events failed to be updated.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(err); + await closeConnections(db); + } + + page = page + 1; + i = i + events.length; + console.log(i); + } while (i < totalEvents); + + await closeConnections(db); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); diff --git a/src/scripts/db/update-events-reviews.js b/src/scripts/db/update-events-reviews.js index b2e2afe..bf9950e 100644 --- a/src/scripts/db/update-events-reviews.js +++ b/src/scripts/db/update-events-reviews.js @@ -1,104 +1,104 @@ -const mongoose = require('mongoose'); - -require('dotenv').config(); - -const { eventSchema } = require('../../models/event'); -const { reviewSchema } = require('../../models/review'); - -mongoose.Promise = global.Promise; - -async function closeConnections(db) { - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const Event = db.model('Event', eventSchema); - const Review = db.model('Review', reviewSchema); - - let totalEvents; - try { - totalEvents = await Event.count(); - } catch (error) { - console.log('Events failed to be count'); - console.log(error); - await closeConnections(db); - } - - console.log(`Total events: ${totalEvents}`); - - let i = 0; - let page = 0; - const pageLimit = 100; - do { - let events; - try { - events = await Event.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Teams failed to be found'); - console.log(error); - await closeConnections(db); - } - - const updateEvents = []; - for (let event of events) { - let eventReviews; - try { - eventReviews = await Review.find({ event: event.id }).count(); - } catch (err) { - console.log('Event reviews failed to be count'); - console.log(err); - await closeConnections(db); - } - - event.reviewsAmount = eventReviews; - updateEvents.push(event.save()); - } - - try { - await Promise.all(updateEvents); - } catch (err) { - console.log( - `Events failed to be updated.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(err); - await closeConnections(db); - } - - page = page + 1; - i = i + events.length; - console.log(i); - } while (i < totalEvents); - - await closeConnections(db); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const mongoose = require('mongoose'); + +require('dotenv').config(); + +const { eventSchema } = require('../../models/event'); +const { reviewSchema } = require('../../models/review'); + +mongoose.Promise = global.Promise; + +async function closeConnections(db) { + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const Event = db.model('Event', eventSchema); + const Review = db.model('Review', reviewSchema); + + let totalEvents; + try { + totalEvents = await Event.count(); + } catch (error) { + console.log('Events failed to be count'); + console.log(error); + await closeConnections(db); + } + + console.log(`Total events: ${totalEvents}`); + + let i = 0; + let page = 0; + const pageLimit = 100; + do { + let events; + try { + events = await Event.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Teams failed to be found'); + console.log(error); + await closeConnections(db); + } + + const updateEvents = []; + for (let event of events) { + let eventReviews; + try { + eventReviews = await Review.find({ event: event.id }).count(); + } catch (err) { + console.log('Event reviews failed to be count'); + console.log(err); + await closeConnections(db); + } + + event.reviewsAmount = eventReviews; + updateEvents.push(event.save()); + } + + try { + await Promise.all(updateEvents); + } catch (err) { + console.log( + `Events failed to be updated.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(err); + await closeConnections(db); + } + + page = page + 1; + i = i + events.length; + console.log(i); + } while (i < totalEvents); + + await closeConnections(db); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); diff --git a/src/scripts/db/update-users-avatars.js b/src/scripts/db/update-users-avatars.js index 59e21c5..5df6f61 100644 --- a/src/scripts/db/update-users-avatars.js +++ b/src/scripts/db/update-users-avatars.js @@ -1,206 +1,206 @@ -const aws = require('aws-sdk'); -const jimp = require('jimp'); -const mongoose = require('mongoose'); -const randomstring = require('randomstring'); - -require('dotenv').config(); - -const { userSchema } = require('../../models/user'); - -const oldUserSchema = require('./old-schemas/user'); - -mongoose.Promise = global.Promise; - -async function closeConnections(db, oldDb) { - try { - await oldDb.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const oldUri = process.env.OLD_DB_URI; - const oldDb = mongoose.createConnection(oldUri, options); - - oldDb.on('connected', async () => { - console.log('Connection to old DB established successfully'); - - const OldUser = oldDb.model('users', oldUserSchema); - - let totalOldUsers; - try { - totalOldUsers = await OldUser.count(); - } catch (error) { - console.log('Old users failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total old users: ${totalOldUsers}`); - - let page = 0; - const pageLimit = 100; - let i = 0; - do { - let oldUsers; - try { - oldUsers = await OldUser.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Old users failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const User = db.model('User', userSchema); - - const getUsersImages = []; - const usersToUpdate = []; - for (let oldUser of oldUsers) { - if (oldUser.isactive) { - if (oldUser.image && !oldUser.image.includes('icon_guy.png')) { - getUsersImages.push(jimp.read(encodeURI(oldUser.image))); - usersToUpdate.push(oldUser.id); - } - } - } - - if (getUsersImages.length > 0) { - let usersImages; - try { - usersImages = await Promise.all(getUsersImages); - } catch (error) { - console.log( - `Old users images failed to be found.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(error); - await closeConnections(db, oldDb); - } - - const usersAvatars = []; - for (let i = 0; i < usersImages.length; i++) { - usersImages[i].cover(400, 400).quality(60); - usersImages[i].getBuffer( - usersImages[i].getMIME(), - (error, bufferImage) => { - if (error) { - console.log(error); - } - - const extension = usersImages[i].getExtension(); - if ( - extension === 'png' || - extension === 'jpeg' || - extension === 'jpg' || - extension === 'bmp' - ) { - usersAvatars.push({ - body: bufferImage, - extension: extension, - mime: usersImages[i].getMIME(), - userId: usersToUpdate[i] - }); - } - } - ); - } - - const s3 = new aws.S3(); - const uploadUsersAvatars = []; - const updateUsersAvatars = []; - for (let userAvatar of usersAvatars) { - let fileName = `${Date.now()}${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}.${userAvatar.extension}`; - - uploadUsersAvatars.push( - s3 - .putObject({ - ACL: 'public-read', - Body: userAvatar.body, - Bucket: process.env.AWS_S3_BUCKET, - ContentType: userAvatar.mime, - Key: `users/avatars/${fileName}` - }) - .promise() - ); - - let avatar = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/users/avatars/${fileName}`; - - updateUsersAvatars.push( - User.update({ _id: userAvatar.userId }, { $set: { avatar } }) - ); - } - - try { - await Promise.all([...uploadUsersAvatars, ...updateUsersAvatars]); - } catch (error) { - console.log( - `Users images failed to be uploaded or updated.\nData: ${JSON.stringify( - { - page, - i - } - )}` - ); - console.log(error); - await closeConnections(db, oldDb); - } - } - - page = page + 1; - i = i + oldUsers.length; - console.log(i); - } while (i < totalOldUsers); - - await closeConnections(db, oldDb); - }); - - oldDb.on('error', err => { - console.log('Connection to old DB failed ' + err); - process.exit(0); - }); - - oldDb.on('disconnected', () => { - console.log('Connection from old DB closed'); - }); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); - -process.on('SIGINT', () => db.close()); +const aws = require('aws-sdk'); +const jimp = require('jimp'); +const mongoose = require('mongoose'); +const randomstring = require('randomstring'); + +require('dotenv').config(); + +const { userSchema } = require('../../models/user'); + +const oldUserSchema = require('./old-schemas/user'); + +mongoose.Promise = global.Promise; + +async function closeConnections(db, oldDb) { + try { + await oldDb.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const oldUri = process.env.OLD_DB_URI; + const oldDb = mongoose.createConnection(oldUri, options); + + oldDb.on('connected', async () => { + console.log('Connection to old DB established successfully'); + + const OldUser = oldDb.model('users', oldUserSchema); + + let totalOldUsers; + try { + totalOldUsers = await OldUser.count(); + } catch (error) { + console.log('Old users failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total old users: ${totalOldUsers}`); + + let page = 0; + const pageLimit = 100; + let i = 0; + do { + let oldUsers; + try { + oldUsers = await OldUser.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Old users failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const User = db.model('User', userSchema); + + const getUsersImages = []; + const usersToUpdate = []; + for (let oldUser of oldUsers) { + if (oldUser.isactive) { + if (oldUser.image && !oldUser.image.includes('icon_guy.png')) { + getUsersImages.push(jimp.read(encodeURI(oldUser.image))); + usersToUpdate.push(oldUser.id); + } + } + } + + if (getUsersImages.length > 0) { + let usersImages; + try { + usersImages = await Promise.all(getUsersImages); + } catch (error) { + console.log( + `Old users images failed to be found.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(error); + await closeConnections(db, oldDb); + } + + const usersAvatars = []; + for (let i = 0; i < usersImages.length; i++) { + usersImages[i].cover(400, 400).quality(60); + usersImages[i].getBuffer( + usersImages[i].getMIME(), + (error, bufferImage) => { + if (error) { + console.log(error); + } + + const extension = usersImages[i].getExtension(); + if ( + extension === 'png' || + extension === 'jpeg' || + extension === 'jpg' || + extension === 'bmp' + ) { + usersAvatars.push({ + body: bufferImage, + extension: extension, + mime: usersImages[i].getMIME(), + userId: usersToUpdate[i] + }); + } + } + ); + } + + const s3 = new aws.S3(); + const uploadUsersAvatars = []; + const updateUsersAvatars = []; + for (let userAvatar of usersAvatars) { + let fileName = `${Date.now()}${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}.${userAvatar.extension}`; + + uploadUsersAvatars.push( + s3 + .putObject({ + ACL: 'public-read', + Body: userAvatar.body, + Bucket: process.env.AWS_S3_BUCKET, + ContentType: userAvatar.mime, + Key: `users/avatars/${fileName}` + }) + .promise() + ); + + let avatar = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/users/avatars/${fileName}`; + + updateUsersAvatars.push( + User.update({ _id: userAvatar.userId }, { $set: { avatar } }) + ); + } + + try { + await Promise.all([...uploadUsersAvatars, ...updateUsersAvatars]); + } catch (error) { + console.log( + `Users images failed to be uploaded or updated.\nData: ${JSON.stringify( + { + page, + i + } + )}` + ); + console.log(error); + await closeConnections(db, oldDb); + } + } + + page = page + 1; + i = i + oldUsers.length; + console.log(i); + } while (i < totalOldUsers); + + await closeConnections(db, oldDb); + }); + + oldDb.on('error', (err) => { + console.log('Connection to old DB failed ' + err); + process.exit(0); + }); + + oldDb.on('disconnected', () => { + console.log('Connection from old DB closed'); + }); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); + +process.on('SIGINT', () => db.close()); From 6e79fb2211717bfbd254127be6e6fe3dd868b25e Mon Sep 17 00:00:00 2001 From: abdul-rehman90 <> Date: Thu, 20 Feb 2025 19:42:12 +0500 Subject: [PATCH 02/67] minor issues fixed --- src/index.js | 84 +++++++------ src/routes/auth/sign-up.js | 54 ++++----- src/routes/events/list-events.js | 3 +- src/routes/photos/delete-photo.js | 18 +-- src/routes/photos/index.js | 12 +- src/routes/teams/list-teams.js | 32 ++--- src/routes/users/get-profile.js | 20 ++-- src/routes/venues/list-venues.js | 190 +++++++++++++++++------------- 8 files changed, 228 insertions(+), 185 deletions(-) diff --git a/src/index.js b/src/index.js index 6c650e1..efdd209 100644 --- a/src/index.js +++ b/src/index.js @@ -1,81 +1,89 @@ -const fs = require('fs'); -const https = require('https'); +const fs = require("fs"); +const https = require("https"); -const bodyParser = require('body-parser'); -const cors = require('cors'); -const express = require('express'); -const helmet = require('helmet'); -const ip = require('ip'); -const morgan = require('morgan'); -const raven = require('raven'); +const bodyParser = require("body-parser"); +const cors = require("cors"); +const express = require("express"); +const helmet = require("helmet"); +const ip = require("ip"); +const morgan = require("morgan"); +const raven = require("raven"); // Fill process.env with environment variables -require('dotenv').config(); +require("dotenv").config(); //console.log(process.env) const port = process.env.PORT || 8000; - -const connectToDB = require('./helpers/db-connector'); -const routes = require('./routes'); +const connectToDB = require("./helpers/db-connector"); +const routes = require("./routes"); function connectedToDB() { const app = express(); raven .config(process.env.SENTRY_URL, { - captureUnhandledRejections: true + captureUnhandledRejections: true, }) .install(); // Middlewares app.use(raven.requestHandler()); app.use(cors()); - app.use(morgan('dev')); + app.use(morgan("dev")); app.use(bodyParser.json()); app.use(helmet()); // Routes - app.set('strict routing', true); - app.use('/', routes); + app.set("strict routing", true); + app.get("/", (req, res) => { + console.log("calling / route"); + res.send("server is up"); + }); + app.use("/", routes); // Error handling app.use(raven.errorHandler()); - app.use((req, res) => res.status(404).json({ general: 'Not found' })); + app.use((req, res) => res.status(404).json({ general: "Not found" })); app.use((err, req, res) => { if (err instanceof SyntaxError) { - return res.status(400).json({ general: 'Invalid JSON format' }); + return res.status(400).json({ general: "Invalid JSON format" }); } console.error(err.stack); - return res.status(500).json({ general: 'Something went wrong' }); + return res.status(500).json({ general: "Something went wrong" }); }); - process.on('uncaughtException', (err) => { + process.on("uncaughtException", (err) => { console.error(err); raven.captureException(err); }); - process.on('unhandledRejection', (err) => { + process.on("unhandledRejection", (err) => { console.error(err); raven.captureException(err); }); - // App Initialization - if (process.env.NODE_ENV === 'production') { + app.listen(port, () => { console.log(`Listening on http://${ip.address()}:${port}`); - app.listen(port); - } else { - https - .createServer( - { - key: fs.readFileSync('./certificates/server.key'), - cert: fs.readFileSync('./certificates/server.crt') - }, - app - ) - .listen(port, () => - console.log(`Listening on https://${ip.address()}:${port}`) - ); - } + }); + + // App Initialization + // if (process.env.NODE_ENV === "production") { + // app.listen(port, () => { + // console.log(`Listening on http://${ip.address()}:${port}`); + // }); + // } else { + // https + // .createServer( + // { + // key: fs.readFileSync("./certificates/server.key"), + // cert: fs.readFileSync("./certificates/server.crt"), + // }, + // app + // ) + // .listen(port, () => + // console.log(`Listening on https://${ip.address()}:${port}`) + // ); + // } } connectToDB(connectedToDB); diff --git a/src/routes/auth/sign-up.js b/src/routes/auth/sign-up.js index 6bdf8a7..6367411 100644 --- a/src/routes/auth/sign-up.js +++ b/src/routes/auth/sign-up.js @@ -1,15 +1,15 @@ -const crypto = require('crypto'); +const crypto = require("crypto"); -const moment = require('moment'); -const { pick } = require('lodash'); -const randomstring = require('randomstring'); -const slugify = require('speakingurl'); +const moment = require("moment"); +const { pick } = require("lodash"); +const randomstring = require("randomstring"); +const slugify = require("speakingurl"); -const { ActivationTicket } = require('../../models/activation-ticket'); -const { cleanSpaces, sendEmail } = require('../../helpers'); -const { User } = require('../../models/user'); +const { ActivationTicket } = require("../../models/activation-ticket"); +const { cleanSpaces, sendEmail } = require("../../helpers"); +const { User } = require("../../models/user"); -const { validateSignUp } = require('./validations'); +const { validateSignUp } = require("./validations"); module.exports = async (req, res, next) => { const { errors, isValid } = validateSignUp(req.body); @@ -18,11 +18,11 @@ module.exports = async (req, res, next) => { } const data = pick(req.body, [ - 'email', - 'firstName', - 'isSubscribed', - 'lastName', - 'password' + "email", + "firstName", + "isSubscribed", + "lastName", + "password", ]); data.firstName = cleanSpaces(data.firstName); data.lastName = cleanSpaces(data.lastName); @@ -45,7 +45,7 @@ module.exports = async (req, res, next) => { const today = moment.utc(); if (expiresAt.isBefore(today)) { try { - await activationTicket.remove(); + await ActivationTicket.deleteOne({ _id: activationTicket._id }); } catch (err) { console.log( `Activation ticket with email ${ @@ -61,17 +61,17 @@ module.exports = async (req, res, next) => { try { repeatedUsers = await User.find({ $or: [{ email: data.email }, { username: data.username }], - isArchived: false + isArchived: false, }); } catch (err) { - console.log('Users failed to be found at sign-up.'); + console.log("Users failed to be found at sign-up."); return next(err); } if (repeatedUsers && repeatedUsers.length > 0) { for (const user of repeatedUsers) { if (user.email === data.email) { - return res.status(400).json({ email: 'Is already taken' }); + return res.status(400).json({ email: "Is already taken" }); } let repeatedUser; @@ -80,13 +80,13 @@ module.exports = async (req, res, next) => { data.lastName )}-${randomstring.generate({ length: 5, - capitalization: 'lowercase' + capitalization: "lowercase", })}`; try { repeatedUser = await User.findOne({ username: data.username, - isArchived: false + isArchived: false, }); } catch (err) { console.log( @@ -99,10 +99,10 @@ module.exports = async (req, res, next) => { } const today = moment.utc(); - const expiresAt = today.add(1, 'days').toDate(); + const expiresAt = today.add(1, "days").toDate(); const key = `${crypto .randomBytes(31) - .toString('hex')}${new Date().getTime().toString()}`; + .toString("hex")}${new Date().getTime().toString()}`; const activationTicketData = { email: data.email, @@ -113,8 +113,8 @@ module.exports = async (req, res, next) => { isSubscribed: data.isSubscribed, lastName: data.lastName, password: data.password, - username: data.username - } + username: data.username, + }, }; try { activationTicket = await ActivationTicket.create(activationTicketData); @@ -127,7 +127,7 @@ module.exports = async (req, res, next) => { return next(err); } - const subject = 'Activate Account'; + const subject = "Activate Account"; const htmlContent = `To activate your account use the link below:
@@ -151,8 +151,8 @@ module.exports = async (req, res, next) => { subject, htmlContent, textContent, - receiversEmails + receiversEmails, }); - return res.status(201).json({ general: 'Success' }); + return res.status(201).json({ general: "Success" }); }; diff --git a/src/routes/events/list-events.js b/src/routes/events/list-events.js index 7f75d82..3b29373 100644 --- a/src/routes/events/list-events.js +++ b/src/routes/events/list-events.js @@ -53,6 +53,7 @@ module.exports = async (req, res, next) => { reviewsAmount: 1, reviewsGoal: 1, startDate: 1, + location: 1, description: 1, }) .sort(sortBy) @@ -76,7 +77,7 @@ module.exports = async (req, res, next) => { page = null; lastPage = null; } - + console.log(events); return res.status(200).json({ page: page + 1, lastPage, diff --git a/src/routes/photos/delete-photo.js b/src/routes/photos/delete-photo.js index a859696..03152f1 100644 --- a/src/routes/photos/delete-photo.js +++ b/src/routes/photos/delete-photo.js @@ -1,6 +1,6 @@ -const aws = require('aws-sdk'); +const aws = require("aws-sdk"); -const { Photo } = require('../../models/photo'); +const { Photo } = require("../../models/photo"); module.exports = async (req, res, next) => { const photoFileName = req.params.photoFileName; @@ -9,8 +9,8 @@ module.exports = async (req, res, next) => { try { photo = await Photo.findOne({ fileName: photoFileName }); } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Photo not found' }); + if (err.name === "CastError") { + return res.status(404).json({ general: "Photo not found" }); } console.log(`Photo ${photoFileName} failed to be found at delete-photo`); @@ -19,7 +19,7 @@ module.exports = async (req, res, next) => { if (photo) { try { - await photo.remove(); + await photo.deleteOne({ fileName: photoFileName }); } catch (err) { console.log( `Photo ${photoFileName} failed to be deleted at delete-photo` @@ -28,20 +28,20 @@ module.exports = async (req, res, next) => { } } - if (!photoFileName.includes('default')) { + if (!photoFileName.includes("default")) { const s3 = new aws.S3(); try { await s3 .deleteObject({ Bucket: process.env.AWS_S3_BUCKET, - Key: `photos/${photoFileName}` + Key: `photos/${photoFileName}`, }) .promise(); } catch (err) { - console.log('Photo failed to be deleted at delete-photo'); + console.log("Photo failed to be deleted at delete-photo"); return next(err); } } - return res.status(204).json({ general: 'Success' }); + return res.status(204).json({ general: "Success" }); }; diff --git a/src/routes/photos/index.js b/src/routes/photos/index.js index c1c7280..d5640d2 100644 --- a/src/routes/photos/index.js +++ b/src/routes/photos/index.js @@ -1,15 +1,15 @@ -const express = require('express'); +const express = require("express"); -const { isAuthenticated } = require('../../helpers'); +const { isAuthenticated } = require("../../helpers"); -const createPhoto = require('./create-photo'); -const deletePhoto = require('./delete-photo'); +const createPhoto = require("./create-photo"); +const deletePhoto = require("./delete-photo"); const router = new express.Router(); -router.post('', isAuthenticated({ isOptional: false }), createPhoto); +router.post("", isAuthenticated({ isOptional: false }), createPhoto); router.delete( - '/:photoFileName', + "/:photoFileName", isAuthenticated({ isOptional: false }), deletePhoto ); diff --git a/src/routes/teams/list-teams.js b/src/routes/teams/list-teams.js index 605bcf6..f3a9938 100644 --- a/src/routes/teams/list-teams.js +++ b/src/routes/teams/list-teams.js @@ -1,9 +1,9 @@ -const mongoose = require('mongoose'); -const { toBoolean } = require('validator'); +const mongoose = require("mongoose"); +const { toBoolean } = require("validator"); -const { Team } = require('../../models/team'); +const { Team } = require("../../models/team"); -const { validateListTeams } = require('./validations'); +const { validateListTeams } = require("./validations"); module.exports = async (req, res, next) => { const queryParams = req.query; @@ -21,18 +21,20 @@ module.exports = async (req, res, next) => { if (!req.user) { return res .status(400) - .json({ general: 'You cannot use managed filter as anonymous' }); + .json({ general: "You cannot use managed filter as anonymous" }); } const managed = toBoolean(queryParams.managed); if (managed) { teamsQuery.managers = { $in: [new mongoose.Types.ObjectId(req.user.id)] }; } else { - teamsQuery.managers = { $nin: [new mongoose.Types.ObjectId(req.user.id)] }; + teamsQuery.managers = { + $nin: [new mongoose.Types.ObjectId(req.user.id)], + }; } } - let sortBy = queryParams.sortBy || '-reviewsAmount'; + let sortBy = queryParams.sortBy || "-reviewsAmount"; let page = queryParams.page ? Number(queryParams.page) - 1 : 0; const pageLimit = Number(queryParams.pageLimit) || 12; @@ -44,31 +46,31 @@ module.exports = async (req, res, next) => { .match(teamsQuery) .project({ _id: 0, - id: '$_id', + id: "$_id", avatar: 1, description: 1, name: 1, - reviewsAmount: 1 + reviewsAmount: 1, }) .sort(sortBy) .skip(page * pageLimit) .limit(pageLimit), - Team.find(teamsQuery).count() + Team.countDocuments(teamsQuery), ]); } catch (err) { - console.log('Teams failed to be found or count at list-teams'); + console.log("Teams failed to be found or count at list-teams"); return next(err); } const getTeamsRankings = teams.map((t) => - Team.find({ reviewsAmount: { $gt: t.reviewsAmount } }).count() + Team.countDocuments({ reviewsAmount: { $gt: t.reviewsAmount } }) ); let teamsRankings; try { teamsRankings = await Promise.all(getTeamsRankings); } catch (err) { - console.log('Teams rankings failed to be count at list-teams'); + console.log("Teams rankings failed to be count at list-teams"); return next(err); } @@ -78,7 +80,7 @@ module.exports = async (req, res, next) => { description: t.description, name: t.name, ranking: teamsRankings[i] + 1, - reviewsAmount: t.reviewsAmount + reviewsAmount: t.reviewsAmount, })); let lastPage = Math.ceil(total / pageLimit); @@ -99,6 +101,6 @@ module.exports = async (req, res, next) => { pageLimit, total, sortBy, - results: teams + results: teams, }); }; diff --git a/src/routes/users/get-profile.js b/src/routes/users/get-profile.js index f9685c0..a231a20 100644 --- a/src/routes/users/get-profile.js +++ b/src/routes/users/get-profile.js @@ -1,13 +1,14 @@ -const { Event } = require('../../models/event'); -const { Team } = require('../../models/team'); +const { Event } = require("../../models/event"); +const { Team } = require("../../models/team"); module.exports = async (req, res, next) => { + console.log(req.user.teams); const getUserTeams = req.user.teams.map((t) => Team.findOne({ _id: t })); let userTeams; try { userTeams = await Promise.all(getUserTeams); } catch (err) { - console.log('Teams failed to be found at get-profile'); + console.log("Teams failed to be found at get-profile"); return next(err); } @@ -20,13 +21,13 @@ module.exports = async (req, res, next) => { managedTeams.push({ id: t.id.toString(), avatar: t.avatar, - name: t.name + name: t.name, }); } else { teams.push({ id: t.id.toString(), avatar: t.avatar, - name: t.name + name: t.name, }); } } @@ -37,7 +38,7 @@ module.exports = async (req, res, next) => { try { userEvents = await Promise.all(getUserEvents); } catch (err) { - console.log('Events failed to be found at get-profile'); + console.log("Events failed to be found at get-profile"); return next(err); } @@ -52,7 +53,7 @@ module.exports = async (req, res, next) => { endDate: e.endDate, name: e.name, poster: e.poster, - startDate: e.startDate + startDate: e.startDate, }); } else { events.push({ @@ -60,7 +61,7 @@ module.exports = async (req, res, next) => { endDate: e.endDate, name: e.name, poster: e.poster, - startDate: e.startDate + startDate: e.startDate, }); } } @@ -87,7 +88,8 @@ module.exports = async (req, res, next) => { showPhone: req.user.showPhone, teams, username: req.user.username, - zip: req.user.zip + zip: req.user.zip, }; + console.log(userData); return res.status(200).json(userData); }; diff --git a/src/routes/venues/list-venues.js b/src/routes/venues/list-venues.js index 81b6821..ca7dd4b 100644 --- a/src/routes/venues/list-venues.js +++ b/src/routes/venues/list-venues.js @@ -1,24 +1,46 @@ -const axios = require('axios'); -const { find, isEmpty } = require('lodash'); -const slugify = require('speakingurl'); +const axios = require("axios"); +const { find, isEmpty } = require("lodash"); +const slugify = require("speakingurl"); -const { isNumber } = require('../../helpers'); -const { Venue } = require('../../models/venue'); +const { isNumber } = require("../../helpers"); +const { Venue } = require("../../models/venue"); -const { validateListVenues } = require('./validations'); -const venueReviewSummary = require('../../helpers/venue-review-summary.js'); +const { validateListVenues } = require("./validations"); +const venueReviewSummary = require("../../helpers/venue-review-summary.js"); + +function getDistanceFromLatLng(lat1, lng1, lat2, lng2) { + const R = 6371; // Earth’s radius in km + + const dLat = (lat2 - lat1) * (Math.PI / 180); + const dLng = (lng2 - lng1) * (Math.PI / 180); + + const a = + Math.sin(dLat / 2) * Math.sin(dLat / 2) + + Math.cos(lat1 * (Math.PI / 180)) * + Math.cos(lat2 * (Math.PI / 180)) * + Math.sin(dLng / 2) * + Math.sin(dLng / 2); + + const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + const distanceInMeter = R * c * 1000; + return `${distanceInMeter.toFixed(0)} ${ + distanceInMeter > 1000 ? "KiloMeter" : "Meter" + }`; // Distance in kilometers +} module.exports = async (req, res, next) => { const queryParams = req.query; + console.log(queryParams); + const { errors, isValid } = validateListVenues(queryParams); if (!isValid) return res.status(400).json(errors); - let coordinates = queryParams.location.split(','); + let coordinates = queryParams.location.split(","); //Legacy function from two-bar search, geocodes from string address if (queryParams.address && !queryParams.page) { - console.log('in address conditional, ', queryParams); + console.log("in address conditional, ", queryParams); queryParams.name = queryParams.address; const geocodeParams = `?key=${process.env.PLACES_API_KEY}&address=${slugify( queryParams.address @@ -39,21 +61,21 @@ module.exports = async (req, res, next) => { } const statusCode = geocodeResponse.data.status; - if (statusCode === 'ZERO_RESULTS') { - return res.status(404).json({ keywords: 'Address not found' }); - } else if (statusCode === 'OVER_QUERY_LIMIT') { - return next(new Error('Over query limit with Google Places API')); - } else if (statusCode === 'REQUEST_DENIED') { - return next(new Error('Request denied with Google Places API')); - } else if (statusCode === 'INVALID_REQUEST') { - return next(new Error('Invalid request with Google Places API')); - } else if (statusCode === 'UNKNOWN_ERROR') { - return next(new Error('Unknown error with Google Places API')); + if (statusCode === "ZERO_RESULTS") { + return res.status(404).json({ keywords: "Address not found" }); + } else if (statusCode === "OVER_QUERY_LIMIT") { + return next(new Error("Over query limit with Google Places API")); + } else if (statusCode === "REQUEST_DENIED") { + return next(new Error("Request denied with Google Places API")); + } else if (statusCode === "INVALID_REQUEST") { + return next(new Error("Invalid request with Google Places API")); + } else if (statusCode === "UNKNOWN_ERROR") { + return next(new Error("Unknown error with Google Places API")); } coordinates = [ geocodeResponse.data.results[0].geometry.location.lat, - geocodeResponse.data.results[0].geometry.location.lng + geocodeResponse.data.results[0].geometry.location.lng, ]; } //end address geocode @@ -86,9 +108,9 @@ module.exports = async (req, res, next) => { const allowsGuideDog = parseFloat(queryParams.allowsGuideDog) === 1; if (allowsGuideDog) { - dbVenuesFilters['allowsGuideDog.yes'] = { $gte: 1 }; + dbVenuesFilters["allowsGuideDog.yes"] = { $gte: 1 }; } else { - dbVenuesFilters['allowsGuideDog.no'] = { $gte: 1 }; + dbVenuesFilters["allowsGuideDog.no"] = { $gte: 1 }; } } @@ -97,9 +119,9 @@ module.exports = async (req, res, next) => { const hasParking = parseFloat(queryParams.hasParking) === 1; if (hasParking) { - dbVenuesFilters['hasParking.yes'] = { $gte: 1 }; + dbVenuesFilters["hasParking.yes"] = { $gte: 1 }; } else { - dbVenuesFilters['hasParking.no'] = { $gte: 1 }; + dbVenuesFilters["hasParking.no"] = { $gte: 1 }; } } @@ -173,7 +195,7 @@ module.exports = async (req, res, next) => { * UPDATED 05/2020 TO SUPPORT FILTER ONLY SELF SEARCH */ if (!isEmpty(venuesFilters) && isEmpty(queryParams.name)) { - console.log('>> Performing DB search'); + console.log(">> Performing DB search"); /* if (queryParams.name) { //performs literal name match against AXS Venue name @@ -184,11 +206,11 @@ module.exports = async (req, res, next) => { dbVenuesFilters.location = { $near: { $geometry: { - type: 'Point', - coordinates: [coordinates[1], coordinates[0]] + type: "Point", + coordinates: [coordinates[1], coordinates[0]], }, - $maxDistance: 50000 - } + $maxDistance: 50000, + }, }; if (queryParams.type) { @@ -203,9 +225,9 @@ module.exports = async (req, res, next) => { } const pageLimit = - 'entranceScore' in venuesFilters || - 'interiorScore' in venuesFilters || - 'restroomScore' in venuesFilters + "entranceScore" in venuesFilters || + "interiorScore" in venuesFilters || + "restroomScore" in venuesFilters ? 80 : 20; @@ -214,7 +236,7 @@ module.exports = async (req, res, next) => { } else { return res .status(400) - .json({ page: 'Should be equal to or greater than 1' }); + .json({ page: "Should be equal to or greater than 1" }); } let total; @@ -227,7 +249,7 @@ module.exports = async (req, res, next) => { ) .skip(page * pageLimit) .limit(pageLimit), - Venue.find(dbVenuesFilters).count() + (await Venue.find(dbVenuesFilters)).length, /*TODO: count is deprecated in favor of countDocuments, but that does not support $near would need to move to GeoWithin but that does not return sorted results */ @@ -246,28 +268,28 @@ module.exports = async (req, res, next) => { Object.assign({}, venue.toObject(), { id: venue._id, _id: undefined, - location: venue.coordinates + location: venue.coordinates, }) ); //+ADDED //Perform ratings logic on all returned venues - console.log('Raw venues count: ' + venues.length); + console.log("Raw venues count: " + venues.length); venues = venues.filter((venue) => { //console.log('In scoring assignment'); let scoring; //calculate entranceScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('entrance', venue); + scoring = venueReviewSummary.calculateRatingLevel("entrance", venue); venue.entranceScore = scoring.ratingLevel; venue.entranceGlyphs = scoring.ratingGlyphs; //calculate interiorScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('interior', venue); + scoring = venueReviewSummary.calculateRatingLevel("interior", venue); venue.interiorScore = scoring.ratingLevel; venue.interiorGlyphs = scoring.ratingGlyphs; //calculate restroomScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('restroom', venue); + scoring = venueReviewSummary.calculateRatingLevel("restroom", venue); venue.restroomScore = scoring.ratingLevel; venue.restroomGlyphs = scoring.ratingGlyphs; @@ -278,7 +300,7 @@ module.exports = async (req, res, next) => { ); let passesValidation = true; - if ('entranceScore' in venuesFilters) { + if ("entranceScore" in venuesFilters) { if ( !venue.entranceScore || venue.entranceScore < venuesFilters.entranceScore @@ -287,7 +309,7 @@ module.exports = async (req, res, next) => { } } - if (passesValidation && 'interiorScore' in venuesFilters) { + if (passesValidation && "interiorScore" in venuesFilters) { if ( !venue.interiorScore || venue.interiorScore < venuesFilters.interiorScore @@ -296,7 +318,7 @@ module.exports = async (req, res, next) => { } } - if (passesValidation && 'restroomScore' in venuesFilters) { + if (passesValidation && "restroomScore" in venuesFilters) { if ( !venue.restroomScore || venue.restroomScore < venuesFilters.restroomScore @@ -316,38 +338,35 @@ module.exports = async (req, res, next) => { page += 1; if (page > lastPage || page > 3) { return res.status(400).json({ - page: `Should be equal to or less than ${lastPage > 3 ? 3 : lastPage}` + page: `Should be equal to or less than ${lastPage > 3 ? 3 : lastPage}`, }); } } dataResponse = { nextPage, - results: venues + results: venues, }; /* * End legacy filter */ } else { - console.log('>> Performing Google search'); + console.log(">> Performing Google search"); /* * Perform Google search when there text entered or no filters selected */ let nearbyParams = `?key=${process.env.PLACES_API_KEY}`; - let searchType = queryParams.name ? 'textsearch' : 'nearbysearch'; + let searchType = queryParams.name ? "textsearch" : "nearbysearch"; if (!queryParams.page) { nearbyParams = `${nearbyParams}&location=${coordinates[0]},${ coordinates[1] - //}&rankby=distance`; }`; if (queryParams.name) { - //nearbyParams = `${nearbyParams}&keyword=${queryParams.name}`; nearbyParams = `${nearbyParams}&query=${queryParams.name}&radius=5000`; } else { - //empty search, such as on load nearbyParams = `${nearbyParams}&rankby=distance`; } @@ -359,7 +378,6 @@ module.exports = async (req, res, next) => { } else { nearbyParams = `${nearbyParams}&pagetoken=${queryParams.page}`; } - if (queryParams.rankby) { nearbyParams = `${nearbyParams}&rankby=${queryParams.rankby}`; } @@ -376,7 +394,7 @@ module.exports = async (req, res, next) => { let placesResponse; try { console.log( - 'performing google search: ' + + "performing google search: " + `https://maps.googleapis.com/maps/api/place/${searchType}/json${nearbyParams}` ); placesResponse = await axios.get( @@ -392,21 +410,21 @@ module.exports = async (req, res, next) => { } const statusCode = placesResponse.data.status; - if (statusCode === 'OVER_QUERY_LIMIT') { - return next(new Error('Over query limit with Google Places API')); - } else if (statusCode === 'REQUEST_DENIED') { - return next(new Error('Request denied with Google Places API')); - } else if (statusCode === 'INVALID_REQUEST') { - return next(new Error('Invalid request with Google Places API')); - } else if (statusCode === 'UNKNOWN_ERROR') { - return next(new Error('Unknown error with Google Places API')); + if (statusCode === "OVER_QUERY_LIMIT") { + return next(new Error("Over query limit with Google Places API")); + } else if (statusCode === "REQUEST_DENIED") { + return next(new Error("Request denied with Google Places API")); + } else if (statusCode === "INVALID_REQUEST") { + return next(new Error("Invalid request with Google Places API")); + } else if (statusCode === "UNKNOWN_ERROR") { + return next(new Error("Unknown error with Google Places API")); } //do we need to check for 0? if (placesResponse.data.results.length == 1) { - if (placesResponse.data.results[0].types[0] == 'locality') { + if (placesResponse.data.results[0].types[0] == "locality") { console.log( - 'Found a city only: ', + "Found a city only: ", placesResponse.data.results[0].geometry.location ); //TODO: redo search with new coordinates and no query/name or change/add "places in " to the first part of the string @@ -417,24 +435,36 @@ module.exports = async (req, res, next) => { let places = []; const placesIds = []; placesResponse.data.results.forEach((place) => { - let photo = ''; + let photo = ""; if (place.photos) { photo = `https://maps.googleapis.com/maps/api/place/photo?key=${ process.env.PLACES_API_KEY }&maxwidth=300&photoreference=${place.photos[0].photo_reference}`; } + console.log( + place.geometry.location.lat, + place.geometry.location.lng, + coordinates[0], + coordinates[1] + ); places.push({ //address: place.vicinity, address: place.formatted_address, location: { lat: place.geometry.location.lat, - lng: place.geometry.location.lng + lng: place.geometry.location.lng, }, + distance: getDistanceFromLatLng( + place.geometry.location.lat, + place.geometry.location.lng, + coordinates[0], + coordinates[1] + ), name: place.name, photo, placeId: place.place_id, - types: place.types + types: place.types, }); placesIds.push(place.place_id); }); @@ -455,17 +485,17 @@ module.exports = async (req, res, next) => { //console.log('In scoring assignment'); let scoring; //calculate entranceScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('entrance', venue); + scoring = venueReviewSummary.calculateRatingLevel("entrance", venue); venue.entranceScore = scoring.ratingLevel; venue.entranceGlyphs = scoring.ratingGlyphs; //calculate interiorScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('interior', venue); + scoring = venueReviewSummary.calculateRatingLevel("interior", venue); venue.interiorScore = scoring.ratingLevel; venue.interiorGlyphs = scoring.ratingGlyphs; //calculate restroomScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('restroom', venue); + scoring = venueReviewSummary.calculateRatingLevel("restroom", venue); venue.restroomScore = scoring.ratingLevel; venue.restroomGlyphs = scoring.ratingGlyphs; @@ -479,13 +509,13 @@ module.exports = async (req, res, next) => { //Filter out, remove, Google Places that are not AXS Venues // Can't use hasOwnProperty() on mongoose model objects // if (!isEmpty(venuesFilters)) { - console.log('>> Performing secondary DB filtering'); + console.log(">> Performing secondary DB filtering"); places = places.filter((place) => { const venue = find(venues, (venue) => venue.placeId === place.placeId); if (venue) { //console.log('In verification of filters'); let passesValidation = true; - if (passesValidation && 'allowsGuideDog' in venuesFilters) { + if (passesValidation && "allowsGuideDog" in venuesFilters) { if ( !venue.allowsGuideDog || venue.allowsGuideDog.yes < venue.allowsGuideDog.no || @@ -495,7 +525,7 @@ module.exports = async (req, res, next) => { } } - if (passesValidation && 'hasParking' in venuesFilters) { + if (passesValidation && "hasParking" in venuesFilters) { if ( !venue.hasParking || venue.hasParking.yes < venue.hasParking.no || @@ -505,7 +535,7 @@ module.exports = async (req, res, next) => { } } - if (passesValidation && 'entranceScore' in venuesFilters) { + if (passesValidation && "entranceScore" in venuesFilters) { if ( !venue.entranceScore || venue.entranceScore < venuesFilters.entranceScore @@ -514,7 +544,7 @@ module.exports = async (req, res, next) => { } } - if (passesValidation && 'interiorScore' in venuesFilters) { + if (passesValidation && "interiorScore" in venuesFilters) { if ( !venue.interiorScore || venue.interiorScore < venuesFilters.interiorScore @@ -523,7 +553,7 @@ module.exports = async (req, res, next) => { } } - if (passesValidation && 'restroomScore' in venuesFilters) { + if (passesValidation && "restroomScore" in venuesFilters) { if ( !venue.restroomScore || venue.restroomScore < venuesFilters.restroomScore @@ -574,7 +604,7 @@ module.exports = async (req, res, next) => { hasWellLit: venue.hasWellLit, isQuiet: venue.isQuiet, isSpacious: venue.isSpacious, - steps: venue.steps + steps: venue.steps, }); } @@ -593,11 +623,11 @@ module.exports = async (req, res, next) => { hasSupportAroundToilet: { yes: 0, no: 0 }, hasLoweredSinks: { yes: 0, no: 0 }, interiorScore: 0, - interiorGlyphs: 'interior', + interiorGlyphs: "interior", restroomScore: 0, - restroomGlyphs: 'restroom', + restroomGlyphs: "restroom", entranceScore: 0, - entranceGlyphs: 'entrylg', + entranceGlyphs: "entrylg", mapMarkerScore: 0, //original fields @@ -615,14 +645,14 @@ module.exports = async (req, res, next) => { zero: 0, one: 0, two: 0, - moreThanTwo: 0 - } + moreThanTwo: 0, + }, }); }); dataResponse = { nextPage: placesResponse.data.next_page_token, - results: places + results: places, }; } //ends legacy filter logic, false conditional From 22e2a73e688b5472f890f28c5af71359fc954ef5 Mon Sep 17 00:00:00 2001 From: abdul-rehman90 <> Date: Fri, 21 Feb 2025 19:09:13 +0500 Subject: [PATCH 03/67] change app listen flow --- src/index.js | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/src/index.js b/src/index.js index efdd209..7ebbd16 100644 --- a/src/index.js +++ b/src/index.js @@ -62,28 +62,24 @@ function connectedToDB() { raven.captureException(err); }); - app.listen(port, () => { - console.log(`Listening on http://${ip.address()}:${port}`); - }); - // App Initialization - // if (process.env.NODE_ENV === "production") { - // app.listen(port, () => { - // console.log(`Listening on http://${ip.address()}:${port}`); - // }); - // } else { - // https - // .createServer( - // { - // key: fs.readFileSync("./certificates/server.key"), - // cert: fs.readFileSync("./certificates/server.crt"), - // }, - // app - // ) - // .listen(port, () => - // console.log(`Listening on https://${ip.address()}:${port}`) - // ); - // } + if (process.env.NODE_ENV === "production") { + app.listen(port, () => { + console.log(`Listening on http://${ip.address()}:${port}`); + }); + } else { + https + .createServer( + { + key: fs.readFileSync("./certificates/server.key"), + cert: fs.readFileSync("./certificates/server.crt"), + }, + app + ) + .listen(port, () => + console.log(`Listening on https://${ip.address()}:${port}`) + ); + } } connectToDB(connectedToDB); From 2797761a45d4731a9e9d164be3fc8756d84d0e7a Mon Sep 17 00:00:00 2001 From: abdul-rehman90 <> Date: Tue, 25 Feb 2025 18:52:50 +0500 Subject: [PATCH 04/67] filter and location issue resolved --- src/index.js | 38 +++++++++--------- src/routes/auth/forgotten-password.js | 26 ++++++------- src/routes/users/edit-user.js | 41 ++++++++++---------- src/routes/venues/list-venues.js | 55 ++++++++++++++++++--------- 4 files changed, 92 insertions(+), 68 deletions(-) diff --git a/src/index.js b/src/index.js index 7ebbd16..98bb8e6 100644 --- a/src/index.js +++ b/src/index.js @@ -61,25 +61,27 @@ function connectedToDB() { console.error(err); raven.captureException(err); }); - + app.listen(port, () => { + console.log(`Listening on http://${ip.address()}:${port}`); + }); // App Initialization - if (process.env.NODE_ENV === "production") { - app.listen(port, () => { - console.log(`Listening on http://${ip.address()}:${port}`); - }); - } else { - https - .createServer( - { - key: fs.readFileSync("./certificates/server.key"), - cert: fs.readFileSync("./certificates/server.crt"), - }, - app - ) - .listen(port, () => - console.log(`Listening on https://${ip.address()}:${port}`) - ); - } + // if (process.env.NODE_ENV === "production") { + // app.listen(port, () => { + // console.log(`Listening on http://${ip.address()}:${port}`); + // }); + // } else { + // https + // .createServer( + // { + // key: fs.readFileSync("./certificates/server.key"), + // cert: fs.readFileSync("./certificates/server.crt"), + // }, + // app + // ) + // .listen(port, () => + // console.log(`Listening on https://${ip.address()}:${port}`) + // ); + // } } connectToDB(connectedToDB); diff --git a/src/routes/auth/forgotten-password.js b/src/routes/auth/forgotten-password.js index e1e18f7..ec73405 100644 --- a/src/routes/auth/forgotten-password.js +++ b/src/routes/auth/forgotten-password.js @@ -1,12 +1,12 @@ -const crypto = require('crypto'); +const crypto = require("crypto"); -const moment = require('moment'); +const moment = require("moment"); -const { PasswordTicket } = require('../../models/password-ticket'); -const { sendEmail } = require('../../helpers'); -const { User } = require('../../models/user'); +const { PasswordTicket } = require("../../models/password-ticket"); +const { sendEmail } = require("../../helpers"); +const { User } = require("../../models/user"); -const { validateForgottenPassword } = require('./validations'); +const { validateForgottenPassword } = require("./validations"); module.exports = async (req, res, next) => { const { errors, isValid } = validateForgottenPassword(req.body); @@ -27,11 +27,11 @@ module.exports = async (req, res, next) => { } if (!user) { - return res.status(200).json({ general: 'Success' }); + return res.status(200).json({ general: "Success" }); } try { - await PasswordTicket.remove({ email }); + await PasswordTicket.deleteOne({ email }); } catch (err) { console.log( `Password ticket with email ${email} failed to be removed at forgotten-password.` @@ -40,10 +40,10 @@ module.exports = async (req, res, next) => { } const today = moment.utc(); - const expiresAt = today.add(1, 'days').toDate(); + const expiresAt = today.add(1, "days").toDate(); const key = `${crypto .randomBytes(31) - .toString('hex')}${new Date().getTime().toString()}`; + .toString("hex")}${new Date().getTime().toString()}`; let passwordTicket; try { @@ -69,7 +69,7 @@ module.exports = async (req, res, next) => {Stay awesome.
`; const receiversEmails = [passwordTicket.email]; - const subject = 'Reset Password'; + const subject = "Reset Password"; const textContent = ` Hi from AXS Map! To reset your password use the link below: @@ -81,8 +81,8 @@ module.exports = async (req, res, next) => { receiversEmails, subject, htmlContent, - textContent + textContent, }); - return res.status(200).json({ general: 'Success' }); + return res.status(200).json({ general: "Success" }); }; diff --git a/src/routes/users/edit-user.js b/src/routes/users/edit-user.js index f0be2a1..40da38a 100644 --- a/src/routes/users/edit-user.js +++ b/src/routes/users/edit-user.js @@ -1,10 +1,10 @@ -const moment = require('moment'); +const moment = require("moment"); -const { cleanSpaces } = require('../../helpers'); -const { Photo } = require('../../models/photo'); -const { User } = require('../../models/user'); +const { cleanSpaces } = require("../../helpers"); +const { Photo } = require("../../models/photo"); +const { User } = require("../../models/user"); -const { validateEditUser } = require('./validations'); +const { validateEditUser } = require("./validations"); module.exports = async (req, res, next) => { const userId = req.params.userId; @@ -13,8 +13,8 @@ module.exports = async (req, res, next) => { try { user = await User.findOne({ _id: userId, isArchived: false }); } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'User not found' }); + if (err.name === "CastError") { + return res.status(404).json({ general: "User not found" }); } console.log(`User with Id ${userId} failed to be found at edit-user.`); @@ -22,11 +22,11 @@ module.exports = async (req, res, next) => { } if (!user) { - return res.status(404).json({ general: 'User not found' }); + return res.status(404).json({ general: "User not found" }); } if (user.id !== req.user.id && !req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); + return res.status(403).json({ general: "Forbidden action" }); } const data = req.body; @@ -36,7 +36,7 @@ module.exports = async (req, res, next) => { if ( data.avatar && - !data.avatar.includes('default') && + !data.avatar.includes("default") && data.avatar !== user.avatar ) { let avatar; @@ -48,11 +48,11 @@ module.exports = async (req, res, next) => { } if (!avatar) { - return res.status(404).json({ avatar: 'Not found' }); + return res.status(404).json({ avatar: "Not found" }); } user.avatar = data.avatar; - } else if (data.avatar === '') { + } else if (data.avatar === "") { user.avatar = `https://s3.amazonaws.com/${ process.env.AWS_S3_BUCKET }/users/avatars/default.png`; @@ -69,7 +69,7 @@ module.exports = async (req, res, next) => { user.gender = data.gender || user.gender; user.isSubscribed = - typeof data.isSubscribed !== 'undefined' + typeof data.isSubscribed !== "undefined" ? data.isSubscribed : user.isSubscribed; @@ -80,22 +80,22 @@ module.exports = async (req, res, next) => { user.phone = data.phone || user.phone; user.showDisabilities = - typeof data.showDisabilities !== 'undefined' + typeof data.showDisabilities !== "undefined" ? data.showDisabilities : user.showDisabilities; user.showEmail = - typeof data.showEmail !== 'undefined' ? data.showEmail : user.showEmail; + typeof data.showEmail !== "undefined" ? data.showEmail : user.showEmail; user.showPhone = - typeof data.showPhone !== 'undefined' ? data.showPhone : user.showPhone; + typeof data.showPhone !== "undefined" ? data.showPhone : user.showPhone; if (data.username && data.username !== user.username) { let repeatedUser; try { repeatedUser = await User.findOne({ username: data.username, - isArchived: false + isArchived: false, }); } catch (err) { console.log( @@ -105,7 +105,7 @@ module.exports = async (req, res, next) => { } if (repeatedUser) { - return res.status(400).json({ username: 'Is already taken' }); + return res.status(400).json({ username: "Is already taken" }); } user.username = data.username; @@ -118,7 +118,7 @@ module.exports = async (req, res, next) => { try { await user.save(); } catch (err) { - if (typeof err.errors === 'object') { + if (typeof err.errors === "object") { const validationErrors = {}; Object.keys(err.errors).forEach((key) => { @@ -146,6 +146,7 @@ module.exports = async (req, res, next) => { description: user.description, disabilities: user.disabilities, firstName: user.firstName, + email: user?.email, gender: user.gender, isSubscribed: user.isSubscribed, lastName: user.lastName, @@ -154,7 +155,7 @@ module.exports = async (req, res, next) => { showEmail: user.showEmail, showPhone: user.showPhone, username: user.username, - zip: user.zip + zip: user.zip, }; return res.status(200).json(dataResponse); }; diff --git a/src/routes/venues/list-venues.js b/src/routes/venues/list-venues.js index ca7dd4b..457693e 100644 --- a/src/routes/venues/list-venues.js +++ b/src/routes/venues/list-venues.js @@ -8,7 +8,22 @@ const { Venue } = require("../../models/venue"); const { validateListVenues } = require("./validations"); const venueReviewSummary = require("../../helpers/venue-review-summary.js"); +const milesTranslations = { + en: "Miles", // English + fr: "Milles", // French + es: "Millas", // Spanish + ja: "マイル", // Japanese +}; + +const feetTranslations = { + en: "Feet", // English + fr: "Pieds", // French + es: "Pies", // Spanish + ja: "フィート", // Japanese +}; + function getDistanceFromLatLng(lat1, lng1, lat2, lng2) { + console.log(lat1, lng1, lat2, lng2); const R = 6371; // Earth’s radius in km const dLat = (lat2 - lat1) * (Math.PI / 180); @@ -22,10 +37,17 @@ function getDistanceFromLatLng(lat1, lng1, lat2, lng2) { Math.sin(dLng / 2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); - const distanceInMeter = R * c * 1000; - return `${distanceInMeter.toFixed(0)} ${ - distanceInMeter > 1000 ? "KiloMeter" : "Meter" - }`; // Distance in kilometers + return R * c * 1000; +} + +function covertDistanceToFeet(distanceInMeter, language = "en") { + const distanceInFeet = distanceInMeter * 3.28084; + const distance = `${(distanceInFeet > 5280 ? distanceInFeet / 5280 : distanceInFeet).toFixed(distanceInFeet > 5280 ? 2 : 0)} ${ + distanceInFeet > 5280 + ? (milesTranslations[language] ?? "Miles") + : (feetTranslations[language] ?? "Feet") + }`; + return distance; } module.exports = async (req, res, next) => { @@ -365,7 +387,7 @@ module.exports = async (req, res, next) => { }`; if (queryParams.name) { - nearbyParams = `${nearbyParams}&query=${queryParams.name}&radius=5000`; + nearbyParams = `${nearbyParams}&query=${queryParams.name}&rankby=distance`; } else { nearbyParams = `${nearbyParams}&rankby=distance`; } @@ -384,6 +406,9 @@ module.exports = async (req, res, next) => { if (queryParams.opennow) { nearbyParams = `${nearbyParams}&opennow=${queryParams.opennow}`; } + if (queryParams.language) { + nearbyParams = `${nearbyParams}&language=${queryParams.language}`; + } if (queryParams.minprice) { nearbyParams = `${nearbyParams}&minprice=${queryParams.minprice}`; } @@ -441,12 +466,6 @@ module.exports = async (req, res, next) => { process.env.PLACES_API_KEY }&maxwidth=300&photoreference=${place.photos[0].photo_reference}`; } - console.log( - place.geometry.location.lat, - place.geometry.location.lng, - coordinates[0], - coordinates[1] - ); places.push({ //address: place.vicinity, @@ -455,11 +474,14 @@ module.exports = async (req, res, next) => { lat: place.geometry.location.lat, lng: place.geometry.location.lng, }, - distance: getDistanceFromLatLng( - place.geometry.location.lat, - place.geometry.location.lng, - coordinates[0], - coordinates[1] + distance: covertDistanceToFeet( + getDistanceFromLatLng( + place.geometry.location.lat, + place.geometry.location.lng, + coordinates[0], + coordinates[1] + ), + queryParams.language ), name: place.name, photo, @@ -509,7 +531,6 @@ module.exports = async (req, res, next) => { //Filter out, remove, Google Places that are not AXS Venues // Can't use hasOwnProperty() on mongoose model objects // if (!isEmpty(venuesFilters)) { - console.log(">> Performing secondary DB filtering"); places = places.filter((place) => { const venue = find(venues, (venue) => venue.placeId === place.placeId); if (venue) { From d26afcef69b45a2814dd3b86f67f79ffc261755b Mon Sep 17 00:00:00 2001 From: abdul-rehman90 <> Date: Thu, 27 Feb 2025 19:37:44 +0500 Subject: [PATCH 05/67] maphathon flow updated --- src/models/user.js | 159 +++++++++++++++++---------- src/routes/auth/activate-account.js | 40 +++---- src/routes/auth/facebook-sign-in.js | 66 +++++------ src/routes/auth/google-sign-in.js | 64 +++++------ src/routes/auth/sign-in.js | 2 +- src/routes/events/index.js | 34 +++--- src/routes/events/list-events.js | 10 +- src/routes/events/list-old-events.js | 79 +++++++++++++ src/routes/users/create-user.js | 99 +++++++++-------- src/routes/users/edit-user.js | 6 + src/routes/users/get-profile.js | 13 ++- src/routes/users/get-user.js | 87 ++++++++------- 12 files changed, 406 insertions(+), 253 deletions(-) create mode 100644 src/routes/events/list-old-events.js diff --git a/src/models/user.js b/src/models/user.js index 949b077..f501210 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -1,5 +1,5 @@ -const bcrypt = require('bcrypt-nodejs'); -const mongoose = require('mongoose'); +const bcrypt = require("bcrypt-nodejs"); +const mongoose = require("mongoose"); const userSchema = new mongoose.Schema( { @@ -8,152 +8,195 @@ const userSchema = new mongoose.Schema( default: `https://s3.amazonaws.com/${ process.env.AWS_S3_BUCKET }/users/avatars/default.png`, - maxlength: [2000, 'Should be less than 2001 characters'], - required: [true, 'Is required'] + maxlength: [2000, "Should be less than 2001 characters"], + required: [true, "Is required"], }, description: { type: String, - maxlength: [2000, 'Should be less than 2001 characters'] + maxlength: [2000, "Should be less than 2001 characters"], }, disabilities: { type: [String], - default: ['none'], + default: ["none"], enum: { values: [ - 'brain', - 'cognitive', - 'hearing', - 'invisible', - 'none', - 'other', - 'physical', - 'private', - 'psychological', - 'spinal-cord', - 'vision' + "brain", + "cognitive", + "hearing", + "invisible", + "none", + "other", + "physical", + "private", + "psychological", + "spinal-cord", + "vision", ], - general: 'Invalid type of disability' + general: "Invalid type of disability", }, - required: [true, 'Is required'] + required: [true, "Is required"], }, email: { type: String, - maxlength: [254, 'Should be less than 255 characters'] + maxlength: [254, "Should be less than 255 characters"], }, events: [ { type: mongoose.Schema.Types.ObjectId, - ref: 'Event' - } + ref: "Event", + }, ], facebookId: String, firstName: { type: String, - maxlength: [24, 'Should be less than 25 characters'], - required: [true, 'Is required'] + maxlength: [24, "Should be less than 25 characters"], + required: [true, "Is required"], }, gender: { type: String, - default: 'private', + default: "not-to-say", enum: { - values: ['female', 'male', 'other', 'private', 'transgender'], - general: 'Invalid type of gender' + values: [ + "female", + "male", + "other", + "private", + "transgender", + "non-binary", + "gender-fluid", + "agender", + "not-to-say", + ], + general: "Invalid type of gender", }, - required: [true, 'Is required'] + required: [true, "Is required"], }, googleId: String, hashedPassword: { type: String, - maxlength: [256, 'Should be less than 255 characters'] + maxlength: [256, "Should be less than 255 characters"], }, isAdmin: { type: Boolean, default: false, - required: [true, 'Is required'] + required: [true, "Is required"], }, isArchived: { type: Boolean, default: false, - required: [true, 'Is required'] + required: [true, "Is required"], }, isBlocked: { type: Boolean, default: false, - required: [true, 'Is required'] + required: [true, "Is required"], }, isSubscribed: { type: Boolean, default: false, - required: [true, 'Is required'] + required: [true, "Is required"], }, lastName: { type: String, - maxlength: [36, 'Should be less than 37 characters'], - required: [true, 'Is required'] + maxlength: [36, "Should be less than 37 characters"], + required: [true, "Is required"], }, language: { type: String, - default: 'en', + default: "en", enum: { - values: ['en', 'es'], - general: 'Invalid type of language' + values: ["en", "es"], + general: "Invalid type of language", }, - required: [true, 'Is required'] + required: [true, "Is required"], }, phone: { type: String, - maxlength: [50, 'Should be less than 51 characters'] + maxlength: [50, "Should be less than 51 characters"], }, reviewFieldsAmount: { type: Number, default: 0, - required: [true, 'Is required'] + required: [true, "Is required"], }, reviewsAmount: { type: Number, default: 0, - required: [true, 'Is required'] + required: [true, "Is required"], }, showDisabilities: { type: Boolean, default: false, - required: [true, 'Is required'] + required: [true, "Is required"], }, showEmail: { type: Boolean, default: false, - required: [true, 'Is required'] + required: [true, "Is required"], }, showPhone: { type: Boolean, default: false, - required: [true, 'Is required'] + required: [true, "Is required"], }, teams: [ { type: mongoose.Schema.Types.ObjectId, - ref: 'Team' - } + ref: "Team", + }, ], username: { type: String, - maxlength: [67, 'Should be less than 68 characters'] + maxlength: [67, "Should be less than 68 characters"], }, zip: { type: String, - maxlength: [32, 'Should be less than 33 characters'] - } + maxlength: [32, "Should be less than 33 characters"], + }, + birthday: { + type: Date, + default: null, + required: false, + }, + race: { + type: String, + default: "not-to-disclose", + enum: { + values: [ + "black/african american", + "caucasian", + "indigenous/first nation/native american", + "latino/hispanic", + "middle eastern/north african", + "native hawaiian/pacific islander", + "biracial/multiracial", + "non-naucasian", + "not-to-disclose", + ], + general: "Invalid type of Race", + }, + required: false, + }, + disability: { + type: String, + default: "not-to-say", + enum: { + values: ["yes", "No", "not-to-say"], + general: "Invalid type of Disability", + }, + required: false, + }, }, { timestamps: true } ); userSchema.index( { - email: 'text', - firstName: 'text', - lastName: 'text', - username: 'text', - reviewsAmount: 1 + email: "text", + firstName: "text", + lastName: "text", + username: "text", + reviewsAmount: 1, }, { weights: { email: 5, username: 5 } } ); @@ -184,10 +227,10 @@ function comparePassword(password) { return bcrypt.compareSync(password, this.hashedPassword); } -userSchema.virtual('password').set(hashPassword); +userSchema.virtual("password").set(hashPassword); userSchema.methods.comparePassword = comparePassword; module.exports = { - User: mongoose.model('User', userSchema), - userSchema + User: mongoose.model("User", userSchema), + userSchema, }; diff --git a/src/routes/auth/activate-account.js b/src/routes/auth/activate-account.js index e5a0655..d6885b3 100644 --- a/src/routes/auth/activate-account.js +++ b/src/routes/auth/activate-account.js @@ -1,12 +1,12 @@ -const crypto = require('crypto'); +const crypto = require("crypto"); -const moment = require('moment'); -const randomstring = require('randomstring'); -const slugify = require('speakingurl'); +const moment = require("moment"); +const randomstring = require("randomstring"); +const slugify = require("speakingurl"); -const { ActivationTicket } = require('../../models/activation-ticket'); -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); +const { ActivationTicket } = require("../../models/activation-ticket"); +const { RefreshToken } = require("../../models/refresh-token"); +const { User } = require("../../models/user"); module.exports = async (req, res, next) => { const key = req.params.key; @@ -15,8 +15,8 @@ module.exports = async (req, res, next) => { try { activationTicket = await ActivationTicket.findOne({ key }); } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Activation ticket not found' }); + if (err.name === "CastError") { + return res.status(404).json({ general: "Activation ticket not found" }); } console.log( @@ -26,7 +26,7 @@ module.exports = async (req, res, next) => { } if (!activationTicket) { - return res.status(404).json({ general: 'Activation ticket not found' }); + return res.status(404).json({ general: "Activation ticket not found" }); } let expiresAt = moment(activationTicket.expiresAt).utc(); @@ -43,28 +43,28 @@ module.exports = async (req, res, next) => { return next(err); } - return res.status(400).json({ general: 'Activation ticket expired' }); + return res.status(400).json({ general: "Activation ticket expired" }); } const userData = Object.assign({}, activationTicket.userData, { - email: activationTicket.email + email: activationTicket.email, }); let repeatedUsers; try { repeatedUsers = await User.find({ $or: [{ email: userData.email }, { username: userData.username }], - isArchived: false + isArchived: false, }); } catch (err) { - console.log('Users failed to be found at activate-account.'); + console.log("Users failed to be found at activate-account."); return next(err); } if (repeatedUsers && repeatedUsers.length > 0) { for (const user of repeatedUsers) { if (user.email === userData.email) { - return res.status(400).json({ email: 'Is already taken' }); + return res.status(400).json({ email: "Is already taken" }); } let repeatedUser; @@ -73,13 +73,13 @@ module.exports = async (req, res, next) => { userData.lastName )}-${randomstring.generate({ length: 5, - capitalization: 'lowercase' + capitalization: "lowercase", })}`; try { repeatedUser = await User.findOne({ username: userData.username, - isArchived: false + isArchived: false, }); } catch (err) { console.log( @@ -106,11 +106,11 @@ module.exports = async (req, res, next) => { } const today = moment.utc(); - expiresAt = today.add(14, 'days').toDate(); + expiresAt = today.add(30, "days").toDate(); const refreshTokenData = { expiresAt, - key: `${user.id}${crypto.randomBytes(28).toString('hex')}`, - userId: user.id + key: `${user.id}${crypto.randomBytes(28).toString("hex")}`, + userId: user.id, }; try { diff --git a/src/routes/auth/facebook-sign-in.js b/src/routes/auth/facebook-sign-in.js index d5477ac..3a06a1a 100644 --- a/src/routes/auth/facebook-sign-in.js +++ b/src/routes/auth/facebook-sign-in.js @@ -1,15 +1,15 @@ -const crypto = require('crypto'); +const crypto = require("crypto"); -const axios = require('axios'); -const jwt = require('jsonwebtoken'); -const moment = require('moment'); -const randomstring = require('randomstring'); -const slugify = require('speakingurl'); +const axios = require("axios"); +const jwt = require("jsonwebtoken"); +const moment = require("moment"); +const randomstring = require("randomstring"); +const slugify = require("speakingurl"); -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); +const { RefreshToken } = require("../../models/refresh-token"); +const { User } = require("../../models/user"); -const { validateFacebookSignIn } = require('./validations'); +const { validateFacebookSignIn } = require("./validations"); module.exports = async (req, res, next) => { const { errors, isValid } = validateFacebookSignIn(req.body); @@ -19,47 +19,47 @@ module.exports = async (req, res, next) => { const code = req.body.code; - const getTokenUrl = 'https://graph.facebook.com/v2.10/oauth/access_token'; + const getTokenUrl = "https://graph.facebook.com/v2.10/oauth/access_token"; const getTokenParams = { code, client_id: process.env.FACEBOOK_CLIENT_ID, client_secret: process.env.FACEBOOK_CLIENT_SECRET, - redirect_uri: `${process.env.APP_URL}/auth/facebook` + redirect_uri: `${process.env.APP_URL}/auth/facebook`, }; let getTokenResponse; try { getTokenResponse = await axios.get(getTokenUrl, { params: getTokenParams }); } catch (err) { console.err(err); - return res.status(400).json({ general: 'Invalid code' }); + return res.status(400).json({ general: "Invalid code" }); } const facebookToken = getTokenResponse.data.access_token; const getProfileUrl = - 'https://graph.facebook.com/v2.10/me?fields=id,email,first_name,last_name,locale'; + "https://graph.facebook.com/v2.10/me?fields=id,email,first_name,last_name,locale"; const getProfileOptions = { params: { - access_token: facebookToken - } + access_token: facebookToken, + }, }; let getProfileResponse; try { getProfileResponse = await axios.get(getProfileUrl, getProfileOptions); } catch (err) { - console.log('Profile data failed to be found at facebook-sign-in.'); + console.log("Profile data failed to be found at facebook-sign-in."); return next(err); } const email = getProfileResponse.data.email ? getProfileResponse.data.email - : ''; + : ""; const facebookId = getProfileResponse.data.id; let user; try { user = await User.findOne({ $or: [{ email }, { facebookId }], - isArchived: false + isArchived: false, }); } catch (err) { console.log( @@ -74,10 +74,10 @@ module.exports = async (req, res, next) => { if (!user) { console.log(getProfileResponse.data); const userData = { - email: getProfileResponse.data.email ? getProfileResponse.data.email : '', + email: getProfileResponse.data.email ? getProfileResponse.data.email : "", facebookId: getProfileResponse.data.id, firstName: getProfileResponse.data.first_name, - lastName: getProfileResponse.data.last_name + lastName: getProfileResponse.data.last_name, }; userData.username = `${slugify(userData.firstName)}-${slugify( userData.lastName @@ -87,10 +87,10 @@ module.exports = async (req, res, next) => { try { repeatedUsers = await User.find({ username: userData.username, - isArchived: false + isArchived: false, }); } catch (err) { - console.log('Users failed to be found at facebook-sign-in.'); + console.log("Users failed to be found at facebook-sign-in."); return next(err); } @@ -101,13 +101,13 @@ module.exports = async (req, res, next) => { userData.lastName )}-${randomstring.generate({ length: 5, - capitalization: 'lowercase' + capitalization: "lowercase", })}`; try { repeatedUser = await User.findOne({ username: userData.username, - isArchived: false + isArchived: false, }); } catch (err) { console.log( @@ -127,14 +127,14 @@ module.exports = async (req, res, next) => { params: { access_token: accessToken, redirect: false, - type: 'large' - } + type: "large", + }, }; let getPictureResponse; try { getPictureResponse = await axios.get(getPictureUrl, getPictureOptions); } catch (err) { - console.log('User picture failed to be found at facebook-sign-in.'); + console.log("User picture failed to be found at facebook-sign-in."); return next(err); } @@ -155,11 +155,11 @@ module.exports = async (req, res, next) => { } const today = moment.utc(); - const expiresAt = today.add(14, 'days').toDate(); + const expiresAt = today.add(30, "days").toDate(); const refreshTokenData = { expiresAt, - key: `${user.id}${crypto.randomBytes(28).toString('hex')}`, - userId: user.id + key: `${user.id}${crypto.randomBytes(28).toString("hex")}`, + userId: user.id, }; try { @@ -175,8 +175,8 @@ module.exports = async (req, res, next) => { } else { const userId = user.id; const today = moment.utc(); - const expiresAt = today.add(14, 'days').toDate(); - const key = `${userId}${crypto.randomBytes(28).toString('hex')}`; + const expiresAt = today.add(30, "days").toDate(); + const key = `${userId}${crypto.randomBytes(28).toString("hex")}`; try { refreshToken = await RefreshToken.findOneAndUpdate( @@ -193,7 +193,7 @@ module.exports = async (req, res, next) => { } const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { - expiresIn: 3600 + expiresIn: 3600, }); refreshToken = refreshToken.key; diff --git a/src/routes/auth/google-sign-in.js b/src/routes/auth/google-sign-in.js index 14c2a84..63f7106 100644 --- a/src/routes/auth/google-sign-in.js +++ b/src/routes/auth/google-sign-in.js @@ -1,17 +1,17 @@ -const crypto = require('crypto'); -const querystring = require('querystring'); +const crypto = require("crypto"); +const querystring = require("querystring"); -const axios = require('axios'); -const GoogleAuth = require('google-auth-library'); -const jwt = require('jsonwebtoken'); -const moment = require('moment'); -const randomstring = require('randomstring'); -const slugify = require('speakingurl'); +const axios = require("axios"); +const GoogleAuth = require("google-auth-library"); +const jwt = require("jsonwebtoken"); +const moment = require("moment"); +const randomstring = require("randomstring"); +const slugify = require("speakingurl"); -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); +const { RefreshToken } = require("../../models/refresh-token"); +const { User } = require("../../models/user"); -const { validateGoogleSignIn } = require('./validations'); +const { validateGoogleSignIn } = require("./validations"); module.exports = async (req, res, next) => { const { errors, isValid } = validateGoogleSignIn(req.body); @@ -21,13 +21,13 @@ module.exports = async (req, res, next) => { const code = req.body.code; - const getTokenUrl = 'https://www.googleapis.com/oauth2/v4/token'; + const getTokenUrl = "https://www.googleapis.com/oauth2/v4/token"; const getTokenParams = { code, client_id: process.env.GOOGLE_CLIENT_ID, client_secret: process.env.GOOGLE_CLIENT_SECRET, redirect_uri: `${process.env.APP_URL}/auth/google`, - grant_type: 'authorization_code' + grant_type: "authorization_code", }; let getTokenResponse; try { @@ -37,18 +37,18 @@ module.exports = async (req, res, next) => { ); } catch (err) { console.error(err); - return res.status(400).json({ general: 'Invalid code' }); + return res.status(400).json({ general: "Invalid code" }); } const auth = new GoogleAuth(); - const client = new auth.OAuth2(process.env.GOOGLE_CLIENT_ID, '', ''); + const client = new auth.OAuth2(process.env.GOOGLE_CLIENT_ID, "", ""); const idToken = getTokenResponse.data.id_token; client.verifyIdToken( idToken, process.env.GOOGLE_CLIENT_ID, async (err, login) => { if (err) { - return res.status(400).json({ general: 'Invalid token id' }); + return res.status(400).json({ general: "Invalid token id" }); } const payload = login.getPayload(); @@ -59,7 +59,7 @@ module.exports = async (req, res, next) => { try { user = await User.findOne({ $or: [{ email }, { googleId }], - isArchived: false + isArchived: false, }); } catch (err) { console.log( @@ -75,13 +75,13 @@ module.exports = async (req, res, next) => { email: payload.email, googleId: payload.sub, firstName: payload.given_name, - lastName: payload.family_name + lastName: payload.family_name, }; - if (payload.locale === 'en') { - userData.language = 'en'; - } else if (payload.locale === 'es') { - userData.language = 'es'; + if (payload.locale === "en") { + userData.language = "en"; + } else if (payload.locale === "es") { + userData.language = "es"; } if (payload.picture) { @@ -96,10 +96,10 @@ module.exports = async (req, res, next) => { try { repeatedUsers = await User.find({ username: userData.username, - isArchived: false + isArchived: false, }); } catch (err) { - console.log('Users failed to be found at google-sign-in.'); + console.log("Users failed to be found at google-sign-in."); return next(err); } @@ -110,13 +110,13 @@ module.exports = async (req, res, next) => { userData.lastName )}-${randomstring.generate({ length: 5, - capitalization: 'lowercase' + capitalization: "lowercase", })}`; try { repeatedUser = await User.findOne({ username: userData.username, - isArchived: false + isArchived: false, }); } catch (err) { console.log( @@ -141,11 +141,11 @@ module.exports = async (req, res, next) => { } const today = moment.utc(); - const expiresAt = today.add(14, 'days').toDate(); + const expiresAt = today.add(30, "days").toDate(); const refreshTokenData = { expiresAt, - key: `${user.id}${crypto.randomBytes(28).toString('hex')}`, - userId: user.id + key: `${user.id}${crypto.randomBytes(28).toString("hex")}`, + userId: user.id, }; try { @@ -161,8 +161,8 @@ module.exports = async (req, res, next) => { } else { const userId = user.id; const today = moment.utc(); - const expiresAt = today.add(14, 'days').toDate(); - const key = `${userId}${crypto.randomBytes(28).toString('hex')}`; + const expiresAt = today.add(30, "days").toDate(); + const key = `${userId}${crypto.randomBytes(28).toString("hex")}`; try { refreshToken = await RefreshToken.findOneAndUpdate( @@ -179,7 +179,7 @@ module.exports = async (req, res, next) => { } const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { - expiresIn: 3600 + expiresIn: 3600, }); refreshToken = refreshToken.key; diff --git a/src/routes/auth/sign-in.js b/src/routes/auth/sign-in.js index 3582e2f..15c4330 100644 --- a/src/routes/auth/sign-in.js +++ b/src/routes/auth/sign-in.js @@ -46,7 +46,7 @@ module.exports = async (req, res, next) => { const userId = user.id; const today = moment.utc(); - const expiresAt = today.add(14, "days").toDate(); + const expiresAt = today.add(30, "days").toDate(); const key = `${userId}${crypto.randomBytes(28).toString("hex")}`; let refreshToken; diff --git a/src/routes/events/index.js b/src/routes/events/index.js index 901a189..33728d3 100644 --- a/src/routes/events/index.js +++ b/src/routes/events/index.js @@ -1,29 +1,31 @@ -const express = require('express'); +const express = require("express"); -const { isAuthenticated } = require('../../helpers'); +const { isAuthenticated } = require("../../helpers"); -const createEvent = require('./create-event'); -const deleteEvent = require('./delete-event'); -const editEvent = require('./edit-event'); -const getEvent = require('./get-event'); -const leaveEvent = require('./leave-event'); -const listEvents = require('./list-events'); -const joinEvent = require('./join-event'); +const createEvent = require("./create-event"); +const deleteEvent = require("./delete-event"); +const editEvent = require("./edit-event"); +const getEvent = require("./get-event"); +const leaveEvent = require("./leave-event"); +const listEvents = require("./list-events"); +const listOldEvents = require("./list-old-events"); +const joinEvent = require("./join-event"); const router = new express.Router(); -router.get('', listEvents); -router.post('', isAuthenticated({ isOptional: false }), createEvent); -router.get('/:eventId', getEvent); -router.put('/:eventId', isAuthenticated({ isOptional: false }), editEvent); -router.delete('/:eventId', isAuthenticated({ isOptional: false }), deleteEvent); +router.get("", listEvents); +router.get("/old", isAuthenticated({ isOptional: false }), listOldEvents); +router.post("", isAuthenticated({ isOptional: false }), createEvent); +router.get("/:eventId", getEvent); +router.put("/:eventId", isAuthenticated({ isOptional: false }), editEvent); +router.delete("/:eventId", isAuthenticated({ isOptional: false }), deleteEvent); router.post( - '/:eventId/join', + "/:eventId/join", isAuthenticated({ isOptional: false }), joinEvent ); router.put( - '/:eventId/leave', + "/:eventId/leave", isAuthenticated({ isOptional: false }), leaveEvent ); diff --git a/src/routes/events/list-events.js b/src/routes/events/list-events.js index 3b29373..029bb73 100644 --- a/src/routes/events/list-events.js +++ b/src/routes/events/list-events.js @@ -7,12 +7,14 @@ const { validateListEvents } = require("./validations"); module.exports = async (req, res, next) => { const queryParams = req.query; + console.log(queryParams); + const { errors, isValid } = validateListEvents(queryParams); if (!isValid) return res.status(400).json(errors); const eventsQuery = {}; - if (queryParams.keywords) { + if (queryParams.keywords && queryParams.keywords !== "") { eventsQuery.$text = { $search: queryParams.keywords }; } @@ -33,9 +35,13 @@ module.exports = async (req, res, next) => { eventsQuery.startDate = { $lte: beforeDate }; } - let sortBy = queryParams.sortBy || "-startDate"; + let sortBy = "-startDate"; let page = queryParams.page ? queryParams.page - 1 : 0; const pageLimit = queryParams.pageLimit || 12; + const currentDate = moment().utc().toDate(); + + eventsQuery.startDate = { $gte: currentDate }; + eventsQuery.endDate = { $lte: currentDate }; let events; let total; diff --git a/src/routes/events/list-old-events.js b/src/routes/events/list-old-events.js new file mode 100644 index 0000000..37cfef8 --- /dev/null +++ b/src/routes/events/list-old-events.js @@ -0,0 +1,79 @@ +const moment = require("moment"); + +const { Event } = require("../../models/event"); + +const { validateListEvents } = require("./validations"); + +module.exports = async (req, res, next) => { + const queryParams = req.query; + + const { errors, isValid } = validateListEvents(queryParams); + if (!isValid) return res.status(400).json(errors); + + const eventsQuery = {}; + + if (queryParams.keywords && queryParams.keywords !== "") { + eventsQuery.$text = { $search: queryParams.keywords }; + } + + let sortBy = "-startDate"; + let page = queryParams.page ? queryParams.page - 1 : 0; + const pageLimit = queryParams.pageLimit || 12; + + const currentDate = moment().utc().toDate(); + eventsQuery.endDate = { $gt: currentDate }; + eventsQuery.$or = [ + { managers: req?.user?.id }, + { participants: req?.user?.id }, + ]; + + let events; + let total; + try { + [events, total] = await Promise.all([ + Event.aggregate() + .match(eventsQuery) + .project({ + _id: 0, + id: "$_id", + address: 1, + endDate: 1, + name: 1, + poster: 1, + reviewsAmount: 1, + reviewsGoal: 1, + startDate: 1, + location: 1, + description: 1, + }) + .sort(sortBy) + .skip(page * pageLimit) + .limit(pageLimit), + Event.countDocuments(eventsQuery), + ]); + } catch (err) { + console.log("Events failed to be found or count at list-events"); + return next(err); + } + + let lastPage = Math.ceil(total / pageLimit); + if (lastPage > 0) { + if (page > lastPage) { + return res + .status(400) + .json({ page: `Should be equal to or less than ${lastPage}` }); + } + } else { + page = null; + lastPage = null; + } + console.log(events); + return res.status(200).json({ + page: page + 1, + lastPage, + pageLimit, + total, + sortBy, + results: events, + }); +}; diff --git a/src/routes/users/create-user.js b/src/routes/users/create-user.js index 3fb3d2e..eccfd01 100644 --- a/src/routes/users/create-user.js +++ b/src/routes/users/create-user.js @@ -1,19 +1,19 @@ -const crypto = require('crypto'); +const crypto = require("crypto"); -const moment = require('moment'); -const { pick } = require('lodash'); -const randomstring = require('randomstring'); -const slugify = require('speakingurl'); +const moment = require("moment"); +const { pick } = require("lodash"); +const randomstring = require("randomstring"); +const slugify = require("speakingurl"); -const { cleanSpaces } = require('../../helpers'); -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); +const { cleanSpaces } = require("../../helpers"); +const { RefreshToken } = require("../../models/refresh-token"); +const { User } = require("../../models/user"); -const { validateCreateUser } = require('./validations'); +const { validateCreateUser } = require("./validations"); module.exports = async (req, res, next) => { if (!req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); + return res.status(403).json({ general: "Forbidden action" }); } const { errors, isValid } = validateCreateUser(req.body); @@ -22,20 +22,20 @@ module.exports = async (req, res, next) => { } const userData = pick(req.body, [ - 'description', - 'disabilities', - 'email', - 'firstName', - 'gender', - 'isSubscribed', - 'lastName', - 'password', - 'phone', - 'showDisabilities', - 'showEmail', - 'showPhone', - 'username', - 'zip' + "description", + "disabilities", + "email", + "firstName", + "gender", + "isSubscribed", + "lastName", + "password", + "phone", + "showDisabilities", + "showEmail", + "showPhone", + "username", + "zip", ]); userData.firstName = cleanSpaces(userData.firstName); userData.lastName = cleanSpaces(userData.lastName); @@ -53,19 +53,19 @@ module.exports = async (req, res, next) => { try { repeatedUsers = await User.find({ $or: [{ email: userData.email }, { username: userData.username }], - isArchived: false + isArchived: false, }); } catch (err) { - console.log('Users failed to be found at create-user.'); + console.log("Users failed to be found at create-user."); return next(err); } if (repeatedUsers && repeatedUsers.length > 0) { for (const user of repeatedUsers) { if (user.email === userData.email) { - return res.status(400).json({ email: 'Is already taken' }); + return res.status(400).json({ email: "Is already taken" }); } else if (usernameSent && user.username === userData.username) { - return res.status(400).json({ username: 'Is already taken' }); + return res.status(400).json({ username: "Is already taken" }); } let repeatedUser; @@ -74,13 +74,13 @@ module.exports = async (req, res, next) => { userData.lastName )}-${randomstring.generate({ length: 5, - capitalization: 'lowercase' + capitalization: "lowercase", })}`; try { repeatedUser = await User.findOne({ username: userData.username, - isArchived: false + isArchived: false, }); } catch (err) { console.log( @@ -98,7 +98,7 @@ module.exports = async (req, res, next) => { try { user = await User.create(userData); } catch (err) { - if (typeof err.errors === 'object') { + if (typeof err.errors === "object") { const validationErrors = {}; Object.keys(err.errors).forEach((key) => { @@ -115,9 +115,9 @@ module.exports = async (req, res, next) => { } const refreshTokenData = { - expiresAt: moment.utc().add(14, 'days').toDate(), - key: `${user.id}${crypto.randomBytes(40).toString('hex')}`, - userId: user.id + expiresAt: moment.utc().add(14, "days").toDate(), + key: `${user.id}${crypto.randomBytes(40).toString("hex")}`, + userId: user.id, }; try { await RefreshToken.create(refreshTokenData); @@ -131,20 +131,23 @@ module.exports = async (req, res, next) => { } const dataResponse = pick(user, [ - '_id', - 'description', - 'disabilities', - 'email', - 'firstName', - 'gender', - 'isSubscribed', - 'lastName', - 'phone', - 'showDisabilities', - 'showEmail', - 'showPhone', - 'username', - 'zip' + "_id", + "description", + "disabilities", + "email", + "firstName", + "gender", + "isSubscribed", + "lastName", + "race", + "birthday", + "disability", + "phone", + "showDisabilities", + "showEmail", + "showPhone", + "username", + "zip", ]); return res.status(201).json(dataResponse); }; diff --git a/src/routes/users/edit-user.js b/src/routes/users/edit-user.js index 40da38a..bfc0ca3 100644 --- a/src/routes/users/edit-user.js +++ b/src/routes/users/edit-user.js @@ -61,6 +61,9 @@ module.exports = async (req, res, next) => { user.description = data.description || user.description; user.disabilities = data.disabilities || user.disabilities; + user.disability = data.disability || user.disabilities; + user.birthday = data.birthday || user.birthday; + user.race = data.race || user.race; user.firstName = data.firstName ? cleanSpaces(data.firstName) @@ -144,8 +147,11 @@ module.exports = async (req, res, next) => { id: user.id, avatar: user.avatar, description: user.description, + race: user?.race, + birthday: user?.birthday, disabilities: user.disabilities, firstName: user.firstName, + disability: user.disability, email: user?.email, gender: user.gender, isSubscribed: user.isSubscribed, diff --git a/src/routes/users/get-profile.js b/src/routes/users/get-profile.js index a231a20..6e40fd4 100644 --- a/src/routes/users/get-profile.js +++ b/src/routes/users/get-profile.js @@ -1,5 +1,6 @@ const { Event } = require("../../models/event"); const { Team } = require("../../models/team"); +const { User } = require("../../models/user"); module.exports = async (req, res, next) => { console.log(req.user.teams); @@ -66,6 +67,12 @@ module.exports = async (req, res, next) => { } } }); + console.log(req.user.reviewsAmount, typeof req.user.reviewsAmount); + + const ranking = + (await User.countDocuments({ + reviewsAmount: { $gt: req.user.reviewsAmount ?? 0 }, + })) + 1; const userData = { id: req.user.id, @@ -89,7 +96,11 @@ module.exports = async (req, res, next) => { teams, username: req.user.username, zip: req.user.zip, + avatar: req.user.avatar, + race: req.user?.race, + birthday: req.user?.birthday, + disability: req.user.disability, + ranking, }; - console.log(userData); return res.status(200).json(userData); }; diff --git a/src/routes/users/get-user.js b/src/routes/users/get-user.js index f6d7a08..d4a3a21 100644 --- a/src/routes/users/get-user.js +++ b/src/routes/users/get-user.js @@ -1,6 +1,6 @@ -const mongoose = require('mongoose'); +const mongoose = require("mongoose"); -const { User } = require('../../models/user'); +const { User } = require("../../models/user"); module.exports = async (req, res, next) => { const userId = req.params.userId; @@ -10,81 +10,81 @@ module.exports = async (req, res, next) => { try { user = await User.aggregate([ { - $match: { _id: userIdObj } + $match: { _id: userIdObj }, }, { $lookup: { - from: 'events', - let: { events: '$events' }, + from: "events", + let: { events: "$events" }, pipeline: [ { $match: { $expr: { - $in: ['$_id', '$$events'] - } - } + $in: ["$_id", "$$events"], + }, + }, }, { $project: { _id: 0, - id: '$_id', + id: "$_id", endDate: 1, name: 1, poster: 1, - startDate: 1 - } - } + startDate: 1, + }, + }, ], - as: 'events' - } + as: "events", + }, }, { $lookup: { - from: 'teams', - let: { teams: '$teams' }, + from: "teams", + let: { teams: "$teams" }, pipeline: [ { $match: { $expr: { - $in: ['$_id', '$$teams'] - } - } + $in: ["$_id", "$$teams"], + }, + }, }, { $project: { _id: 0, - id: '$_id', + id: "$_id", avatar: 1, - name: 1 - } - } + name: 1, + }, + }, ], - as: 'teams' - } + as: "teams", + }, }, { $lookup: { - from: 'users', - let: { reviewsAmount: '$reviewsAmount' }, + from: "users", + let: { reviewsAmount: "$reviewsAmount" }, pipeline: [ { $match: { $expr: { - $gt: ['$reviewsAmount', '$$reviewsAmount'] - } - } + $gt: ["$reviewsAmount", "$$reviewsAmount"], + }, + }, }, { - $count: 'ranking' - } + $count: "ranking", + }, ], - as: 'ranking' - } + as: "ranking", + }, }, { $project: { _id: 0, - id: '$_id', + id: "$_id", avatar: 1, description: 1, disabilities: 1, @@ -96,6 +96,9 @@ module.exports = async (req, res, next) => { language: 1, lastName: 1, phone: 1, + race: 1, + birthday: 1, + disability: 1, ranking: 1, reviewsAmount: 1, showDisabilities: 1, @@ -103,13 +106,13 @@ module.exports = async (req, res, next) => { showPhone: 1, teams: 1, username: 1, - zip: 1 - } - } + zip: 1, + }, + }, ]); } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'User not found' }); + if (err.name === "CastError") { + return res.status(404).json({ general: "User not found" }); } console.log(`User ${userId} failed to be found at get-user`); @@ -117,11 +120,11 @@ module.exports = async (req, res, next) => { } if (!user) { - return res.status(404).json({ general: 'User not found' }); + return res.status(404).json({ general: "User not found" }); } const dataResponse = Object.assign({}, user[0], { - ranking: user[0].ranking.length ? user[0].ranking[0].ranking + 1 : 1 + ranking: user[0].ranking.length ? user[0].ranking[0].ranking + 1 : 1, }); return res.status(200).json(dataResponse); }; From 573f002c537bc6d4b7360e692589f9c2346909e2 Mon Sep 17 00:00:00 2001 From: abdul-rehman90 <> Date: Fri, 28 Feb 2025 19:21:21 +0500 Subject: [PATCH 06/67] add mapathon issue fix --- src/helpers/Error.js | 13 + src/models/user.js | 4 +- src/routes/events/create-event.js | 59 ++-- src/routes/events/list-events.js | 21 +- src/routes/events/list-old-events.js | 2 +- src/routes/events/validations.js | 385 +++++++++++++-------------- src/routes/venues/list-venues.js | 14 +- 7 files changed, 247 insertions(+), 251 deletions(-) create mode 100644 src/helpers/Error.js diff --git a/src/helpers/Error.js b/src/helpers/Error.js new file mode 100644 index 0000000..dc2e6e7 --- /dev/null +++ b/src/helpers/Error.js @@ -0,0 +1,13 @@ +function sendError(errors) { + let message = ""; + if (typeof errors === "object") { + let error = Object.entries(errors)[0]; + message = `${error[0]} ${error[1]}`; + } + if (typeof errors === "string") { + message = errors; + } + return { error: true, message, status: false }; +} + +module.exports = { sendError }; diff --git a/src/models/user.js b/src/models/user.js index f501210..9c3c00a 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -160,7 +160,7 @@ const userSchema = new mongoose.Schema( }, race: { type: String, - default: "not-to-disclose", + default: "", enum: { values: [ "black/african american", @@ -179,7 +179,7 @@ const userSchema = new mongoose.Schema( }, disability: { type: String, - default: "not-to-say", + default: "", enum: { values: ["yes", "No", "not-to-say"], general: "Invalid type of Disability", diff --git a/src/routes/events/create-event.js b/src/routes/events/create-event.js index 7787d3f..068fd02 100644 --- a/src/routes/events/create-event.js +++ b/src/routes/events/create-event.js @@ -1,13 +1,14 @@ -const axios = require('axios'); -const FormData = require('form-data'); -const moment = require('moment'); +const axios = require("axios"); +const FormData = require("form-data"); +const moment = require("moment"); -const { Event } = require('../../models/event'); -const { cleanSpaces } = require('../../helpers'); -const { Photo } = require('../../models/photo'); -const { Team } = require('../../models/team'); +const { Event } = require("../../models/event"); +const { cleanSpaces } = require("../../helpers"); +const { Photo } = require("../../models/photo"); +const { Team } = require("../../models/team"); -const { validateCreateEvent } = require('./validations'); +const { validateCreateEvent } = require("./validations"); +const { sendError } = require("../../helpers/Error"); module.exports = async (req, res, next) => { const data = { @@ -24,18 +25,18 @@ module.exports = async (req, res, next) => { poster: req.body.poster, reviewsGoal: req.body.reviewsGoal, startDate: req.body.startDate, - teamManager: req.body.teamManager + teamManager: req.body.teamManager, }; const { errors, isValid } = validateCreateEvent(data); - if (!isValid) return res.status(400).json(errors); + if (!isValid) return res.status(400).json(sendError(errors)); data.address = cleanSpaces(data.address); - data.endDate = moment(data.endDate).endOf('day').utc().toDate(); + data.endDate = moment(data.endDate).endOf("day").utc().toDate(); data.location = { - coordinates: [data.locationCoordinates[1], data.locationCoordinates[0]] + coordinates: [data.locationCoordinates[1], data.locationCoordinates[0]], }; delete data.locationCoordinates; @@ -49,9 +50,9 @@ module.exports = async (req, res, next) => { console.log(`Event ${data.name} failed to be found at create-event`); return next(err); } - + console.log("repeatedEvent", repeatedEvent); if (repeatedEvent) { - return res.status(400).json({ name: 'Is already taken' }); + return res.status(400).json(sendError({ name: "Is already taken" })); } if (data.poster) { @@ -64,11 +65,11 @@ module.exports = async (req, res, next) => { } if (!poster) { - return res.status(404).json({ poster: 'Not found' }); + return res.status(404).json(sendError({ poster: "Not found" })); } } - data.startDate = moment(data.startDate).startOf('day').utc().toDate(); + data.startDate = moment(data.startDate).startOf("day").utc().toDate(); if (data.teamManager) { let team; @@ -82,12 +83,12 @@ module.exports = async (req, res, next) => { } if (!team) { - return res.status(404).json({ teamManager: 'Not found' }); + return res.status(404).json(sendError({ teamManager: "Not found" })); } const teamManagers = team.managers.map((m) => m.toString()); if (!teamManagers.includes(req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); + return res.status(403).json(sendError({ general: "Forbidden action" })); } } else { data.teamManager = undefined; @@ -95,31 +96,31 @@ module.exports = async (req, res, next) => { if (data.donationEnabled) { const campaignData = new FormData(); - campaignData.append('title', data.name); - campaignData.append('goal_in_cents', data.donationGoal * 100); + campaignData.append("title", data.name); + campaignData.append("goal_in_cents", data.donationGoal * 100); let options = { - method: 'POST', + method: "POST", url: `https://${ process.env.DONATELY_SUBDOMAIN }.dntly.com/api/v1/admin/campaigns`, headers: { - 'Content-Type': `multipart/form-data; boundary=${ + "Content-Type": `multipart/form-data; boundary=${ campaignData._boundary - }` + }`, }, auth: { username: process.env.DONATELY_TOKEN, - password: '' + password: "", }, - data: campaignData + data: campaignData, }; let response; try { response = await axios(options); } catch (err) { - console.log('Donation campaign failed to be created at create-event.'); + console.log("Donation campaign failed to be created at create-event."); return next(err); } @@ -130,7 +131,7 @@ module.exports = async (req, res, next) => { try { event = await Event.create(data); } catch (err) { - if (typeof err.errors === 'object') { + if (typeof err.errors === "object") { const validationErrors = {}; Object.keys(err.errors).forEach((key) => { @@ -162,7 +163,7 @@ module.exports = async (req, res, next) => { if (event.location.coordinates) { eventLocation = { lat: event.location.coordinates[1], - lng: event.location.coordinates[0] + lng: event.location.coordinates[0], }; } const dataResponse = { @@ -177,7 +178,7 @@ module.exports = async (req, res, next) => { participantsGoal: event.participantsGoal, poster: event.poster, reviewsGoal: event.reviewsGoal, - teamManager: event.teamManager + teamManager: event.teamManager, }; return res.status(201).json(dataResponse); diff --git a/src/routes/events/list-events.js b/src/routes/events/list-events.js index 029bb73..9284de3 100644 --- a/src/routes/events/list-events.js +++ b/src/routes/events/list-events.js @@ -20,28 +20,13 @@ module.exports = async (req, res, next) => { eventsQuery.isArchived = false; - let afterDate; - let beforeDate; - if (queryParams.afterDate && queryParams.beforeDate) { - afterDate = moment(queryParams.afterDate).utc().toDate(); - beforeDate = moment(queryParams.beforeDate).utc().toDate(); - - eventsQuery.startDate = { $gte: afterDate, $lte: beforeDate }; - } else if (queryParams.afterDate) { - afterDate = moment(queryParams.afterDate).utc().toDate(); - eventsQuery.startDate = { $gte: afterDate }; - } else if (queryParams.beforeDate) { - beforeDate = moment(queryParams.beforeDate).utc().toDate(); - eventsQuery.startDate = { $lte: beforeDate }; - } - let sortBy = "-startDate"; let page = queryParams.page ? queryParams.page - 1 : 0; const pageLimit = queryParams.pageLimit || 12; - const currentDate = moment().utc().toDate(); + const currentDate = moment().startOf("day").utc().toDate(); - eventsQuery.startDate = { $gte: currentDate }; - eventsQuery.endDate = { $lte: currentDate }; + eventsQuery.startDate = { $lte: currentDate }; + eventsQuery.endDate = { $gte: currentDate }; let events; let total; diff --git a/src/routes/events/list-old-events.js b/src/routes/events/list-old-events.js index 37cfef8..ec024ff 100644 --- a/src/routes/events/list-old-events.js +++ b/src/routes/events/list-old-events.js @@ -21,7 +21,7 @@ module.exports = async (req, res, next) => { const pageLimit = queryParams.pageLimit || 12; const currentDate = moment().utc().toDate(); - eventsQuery.endDate = { $gt: currentDate }; + eventsQuery.endDate = { $lt: currentDate }; eventsQuery.$or = [ { managers: req?.user?.id }, { participants: req?.user?.id }, diff --git a/src/routes/events/validations.js b/src/routes/events/validations.js index 15b98be..8d47bf4 100644 --- a/src/routes/events/validations.js +++ b/src/routes/events/validations.js @@ -1,50 +1,50 @@ -const { isEmpty } = require('lodash'); -const { isInt, isMongoId } = require('validator'); -const moment = require('moment'); +const { isEmpty } = require("lodash"); +const { isInt, isMongoId } = require("validator"); +const moment = require("moment"); -const { isNumber } = require('../../helpers'); +const { isNumber } = require("../../helpers"); module.exports = { validateCreateEvent(data) { const errors = {}; - if (typeof data.address === 'undefined' || data.address === '') { - errors.address = 'Is required'; - } else if (typeof data.address !== 'string') { - errors.address = 'Should be a string'; + if (typeof data.address === "undefined" || data.address === "") { + errors.address = "Is required"; + } else if (typeof data.address !== "string") { + errors.address = "Should be a string"; } if ( - typeof data.description !== 'undefined' && - typeof data.description !== 'string' + typeof data.description !== "undefined" && + typeof data.description !== "string" ) { - errors.description = 'Should be a string'; + errors.description = "Should be a string"; } if (data.donationEnabled === true) { - if (typeof data.donationAmounts === 'undefined') { - errors.donationAmounts = 'Is required'; + if (typeof data.donationAmounts === "undefined") { + errors.donationAmounts = "Is required"; } - if (typeof data.donationGoal === 'undefined') { - errors.donationGoal = 'Is required'; + if (typeof data.donationGoal === "undefined") { + errors.donationGoal = "Is required"; } } - if (typeof data.donationAmounts !== 'undefined') { + if (typeof data.donationAmounts !== "undefined") { if (!Array.isArray(data.donationAmounts)) { - errors.donationAmounts = 'Should be an array'; + errors.donationAmounts = "Should be an array"; } else { data.donationAmounts.some((d) => { - if (typeof d.value === 'undefined') { + if (typeof d.value === "undefined") { errors.donationAmounts = - 'All elements should have a value property'; + "All elements should have a value property"; return true; - } else if (typeof d.value !== 'number') { - errors.donationAmounts = 'All value properties should be numbers'; + } else if (typeof d.value !== "number") { + errors.donationAmounts = "All value properties should be numbers"; return true; } else if (d < 5 || d > 10000) { errors.donationAmounts = - 'All value properties should be between 5 and 10000'; + "All value properties should be between 5 and 10000"; return true; } }); @@ -52,133 +52,132 @@ module.exports = { } if ( - typeof data.donationEnabled !== 'undefined' && - typeof data.donationEnabled !== 'boolean' + typeof data.donationEnabled !== "undefined" && + typeof data.donationEnabled !== "boolean" ) { - errors.donationEnabled = 'Should be a boolean'; + errors.donationEnabled = "Should be a boolean"; } - if (typeof data.donationGoal !== 'undefined') { - if (typeof data.donationGoal !== 'number') { - errors.donationGoal = 'Should be a number'; + if (typeof data.donationGoal !== "undefined") { + if (typeof data.donationGoal !== "number") { + errors.donationGoal = "Should be a number"; } else if (!isInt(data.donationGoal.toString())) { - errors.donationGoal = 'Should be a integer'; + errors.donationGoal = "Should be a integer"; } } let endDateIsValid = false; - if (typeof data.endDate === 'undefined' || data.endDate === '') { - errors.endDate = 'Is required'; - } else if (typeof data.endDate !== 'string') { - errors.endDate = 'Should be a string'; + if (typeof data.endDate === "undefined" || data.endDate === "") { + errors.endDate = "Is required"; + } else if (typeof data.endDate !== "string") { + errors.endDate = "Should be a string"; } else if (!moment(data.endDate).isValid()) { - errors.endDate = 'Should have a ISO-8601 format'; + errors.endDate = "Should have a ISO-8601 format"; } else { - const endDate = moment(data.endDate).endOf('day').utc(); - const today = moment().startOf('day').utc(); + const endDate = moment(data.endDate).endOf("day").utc(); + const today = moment().startOf("day").utc(); if (endDate.isBefore(today)) { - errors.endDate = 'Should be greater than or equal to today'; + errors.endDate = "Should be greater than or equal to today"; } else { endDateIsValid = true; } } if ( - typeof data.isOpen !== 'undefined' && - typeof data.isOpen !== 'boolean' + typeof data.isOpen !== "undefined" && + typeof data.isOpen !== "boolean" ) { - errors.isOpen = 'Should be a boolean'; + errors.isOpen = "Should be a boolean"; } - if (typeof data.locationCoordinates === 'undefined') { - errors.locationCoordinates = 'Is required'; + if (typeof data.locationCoordinates === "undefined") { + errors.locationCoordinates = "Is required"; } else if (!Array.isArray(data.locationCoordinates)) { - errors.locationCoordinates = 'Should be an array'; - } else if (typeof data.locationCoordinates[0] === 'undefined') { - errors.locationCoordinates = 'Latitude is required'; + errors.locationCoordinates = "Should be an array"; + } else if (typeof data.locationCoordinates[0] === "undefined") { + errors.locationCoordinates = "Latitude is required"; } else if (!isNumber(data.locationCoordinates[0])) { - errors.locationCoordinates = 'Latitude should be a number'; + errors.locationCoordinates = "Latitude should be a number"; } else if ( parseFloat(data.locationCoordinates[0]) < -90 || parseFloat(data.locationCoordinates[0]) > 90 ) { - errors.locationCoordinates = 'Latitude value is not valid'; - } else if (typeof data.locationCoordinates[1] === 'undefined') { - errors.locationCoordinates = 'Longitude is required'; + errors.locationCoordinates = "Latitude value is not valid"; + } else if (typeof data.locationCoordinates[1] === "undefined") { + errors.locationCoordinates = "Longitude is required"; } else if (!isNumber(data.locationCoordinates[1])) { - errors.locationCoordinates = 'Longitude should be a number'; + errors.locationCoordinates = "Longitude should be a number"; } else if ( parseFloat(data.locationCoordinates[1]) < -180 || parseFloat(data.locationCoordinates[1]) > 180 ) { - errors.locationCoordinates = 'Longitude value is not valid'; + errors.locationCoordinates = "Longitude value is not valid"; } else if (data.locationCoordinates.length > 2) { - errors.locationCoordinates = 'Should only have latitude and longitude'; + errors.locationCoordinates = "Should only have latitude and longitude"; } - - if (typeof data.name === 'undefined' || data.name === '') { - errors.name = 'Is required'; - } else if (typeof data.name !== 'string') { - errors.name = 'Should be a string'; + if (typeof data.name === "undefined" || data.name === "") { + errors.name = "Is required"; + } else if (typeof data.name !== "string") { + errors.name = "Should be a string"; } - if (typeof data.participantsGoal === 'undefined') { - errors.participantsGoal = 'Is required'; - } else if (typeof data.participantsGoal !== 'number') { - errors.participantsGoal = 'Should be a number'; + if (typeof data.participantsGoal === "undefined") { + errors.participantsGoal = "Is required"; + } else if (typeof data.participantsGoal !== "number") { + errors.participantsGoal = "Should be a number"; } else if (!isInt(data.participantsGoal.toString())) { - errors.participantsGoal = 'Should be a integer'; + errors.participantsGoal = "Should be a integer"; } - if (typeof data.poster !== 'undefined' && typeof data.poster !== 'string') { - errors.poster = 'Should be a string'; + if (typeof data.poster !== "undefined" && typeof data.poster !== "string") { + errors.poster = "Should be a string"; } - if (typeof data.reviewsGoal === 'undefined') { - errors.reviewsGoal = 'Is required'; - } else if (typeof data.reviewsGoal !== 'number') { - errors.reviewsGoal = 'Should be a number'; + if (typeof data.reviewsGoal === "undefined") { + errors.reviewsGoal = "Is required"; + } else if (typeof data.reviewsGoal !== "number") { + errors.reviewsGoal = "Should be a number"; } else if (!isInt(data.reviewsGoal.toString())) { - errors.reviewsGoal = 'Should be a integer'; + errors.reviewsGoal = "Should be a integer"; } let startDateIsValid = false; - if (typeof data.startDate === 'undefined' || data.startDate === '') { - errors.startDate = 'Is required'; - } else if (typeof data.startDate !== 'string') { - errors.startDate = 'Should be a string'; + if (typeof data.startDate === "undefined" || data.startDate === "") { + errors.startDate = "Is required"; + } else if (typeof data.startDate !== "string") { + errors.startDate = "Should be a string"; } else if (!moment(data.startDate).isValid()) { - errors.startDate = 'Should have a ISO-8601 format'; + errors.startDate = "Should have a ISO-8601 format"; } else { - const startDate = moment(data.startDate).startOf('day').utc(); - const today = moment().startOf('day').utc(); + const startDate = moment(data.startDate).startOf("day").utc(); + const today = moment().startOf("day").utc(); if (startDate.isBefore(today)) { - errors.startDate = 'Should be greater than or equal to today'; + errors.startDate = "Should be greater than or equal to today"; } else { startDateIsValid = true; } } if ( - typeof data.teamManager !== 'undefined' && - typeof data.teamManager !== 'string' + typeof data.teamManager !== "undefined" && + typeof data.teamManager !== "string" ) { - errors.teamManager = 'Should be a string'; + errors.teamManager = "Should be a string"; } else if (data.teamManager && !isMongoId(data.teamManager)) { - errors.teamManager = 'Should be a valid id'; + errors.teamManager = "Should be a valid id"; } if (endDateIsValid && startDateIsValid) { - const endDate = moment(data.endDate).endOf('day').utc(); - const startDate = moment(data.startDate).startOf('day').utc(); + const endDate = moment(data.endDate).endOf("day").utc(); + const startDate = moment(data.startDate).startOf("day").utc(); if (startDate.isAfter(endDate)) { - errors.endDate = 'Should be greater than or equal to startDate'; - errors.startDate = 'Should be less than or equal to endDate'; - } else if (endDate.diff(startDate, 'days') > 365) { - errors.endDate = 'Should last less than 365 days'; + errors.endDate = "Should be greater than or equal to startDate"; + errors.startDate = "Should be less than or equal to endDate"; + } else if (endDate.diff(startDate, "days") > 365) { + errors.endDate = "Should last less than 365 days"; } } @@ -187,35 +186,35 @@ module.exports = { validateEditEvent(data) { const errors = {}; - if (typeof data.address !== 'undefined') { - if (typeof data.address !== 'string') { - errors.address = 'Should be a string'; - } else if (data.address === '') { - errors.address = 'Is required'; + if (typeof data.address !== "undefined") { + if (typeof data.address !== "string") { + errors.address = "Should be a string"; + } else if (data.address === "") { + errors.address = "Is required"; } } if ( - typeof data.description !== 'undefined' && - typeof data.description !== 'string' + typeof data.description !== "undefined" && + typeof data.description !== "string" ) { - errors.description = 'Should be a string'; + errors.description = "Should be a string"; } let endDateIsValid = false; - if (typeof data.endDate !== 'undefined') { - if (typeof data.endDate !== 'string') { - errors.endDate = 'Should be a string'; - } else if (data.endDate === '') { - errors.endDate = 'Is required'; + if (typeof data.endDate !== "undefined") { + if (typeof data.endDate !== "string") { + errors.endDate = "Should be a string"; + } else if (data.endDate === "") { + errors.endDate = "Is required"; } else if (!moment(data.endDate).isValid()) { - errors.endDate = 'Should have a ISO-8601 format'; + errors.endDate = "Should have a ISO-8601 format"; } else { - const endDate = moment(data.endDate).endOf('day').utc(); - const today = moment().startOf('day').utc(); + const endDate = moment(data.endDate).endOf("day").utc(); + const today = moment().startOf("day").utc(); if (endDate.isBefore(today)) { - errors.endDate = 'Should be greater than or equal to today'; + errors.endDate = "Should be greater than or equal to today"; } else { endDateIsValid = true; } @@ -223,51 +222,51 @@ module.exports = { } if ( - typeof data.isOpen !== 'undefined' && - typeof data.isOpen !== 'boolean' + typeof data.isOpen !== "undefined" && + typeof data.isOpen !== "boolean" ) { - errors.isOpen = 'Should be a boolean'; + errors.isOpen = "Should be a boolean"; } - if (typeof data.locationCoordinates !== 'undefined') { + if (typeof data.locationCoordinates !== "undefined") { if (!Array.isArray(data.locationCoordinates)) { - errors.locationCoordinates = 'Should be an array'; - } else if (typeof data.locationCoordinates[0] === 'undefined') { - errors.locationCoordinates = 'Latitude is required'; + errors.locationCoordinates = "Should be an array"; + } else if (typeof data.locationCoordinates[0] === "undefined") { + errors.locationCoordinates = "Latitude is required"; } else if (!isNumber(data.locationCoordinates[0])) { - errors.locationCoordinates = 'Latitude should be a number'; + errors.locationCoordinates = "Latitude should be a number"; } else if ( parseFloat(data.locationCoordinates[0]) < -90 || parseFloat(data.locationCoordinates[0]) > 90 ) { - errors.locationCoordinates = 'Latitude value is not valid'; - } else if (typeof data.locationCoordinates[1] === 'undefined') { - errors.locationCoordinates = 'Longitude is required'; + errors.locationCoordinates = "Latitude value is not valid"; + } else if (typeof data.locationCoordinates[1] === "undefined") { + errors.locationCoordinates = "Longitude is required"; } else if (!isNumber(data.locationCoordinates[1])) { - errors.locationCoordinates = 'Longitude should be a number'; + errors.locationCoordinates = "Longitude should be a number"; } else if ( parseFloat(data.locationCoordinates[1]) < -180 || parseFloat(data.locationCoordinates[1]) > 180 ) { - errors.locationCoordinates = 'Longitude value is not valid'; + errors.locationCoordinates = "Longitude value is not valid"; } else if (data.locationCoordinates.length > 2) { - errors.locationCoordinates = 'Should only have latitude and longitude'; + errors.locationCoordinates = "Should only have latitude and longitude"; } } - if (typeof data.managers !== 'undefined') { + if (typeof data.managers !== "undefined") { if (!Array.isArray(data.managers)) { - errors.managers = 'Should be an array'; + errors.managers = "Should be an array"; } else { data.managers.some((m) => { - if (typeof m !== 'string') { - errors.managers = 'Should only have string values'; + if (typeof m !== "string") { + errors.managers = "Should only have string values"; return true; } else if (!m) { - errors.managers = 'Should not have empty values'; + errors.managers = "Should not have empty values"; return true; } else { - if (m.startsWith('-')) { + if (m.startsWith("-")) { m = m.substring(1); } @@ -280,26 +279,26 @@ module.exports = { } } - if (typeof data.name !== 'undefined') { - if (typeof data.name !== 'string') { - errors.name = 'Should be a string'; - } else if (data.name === '') { - errors.name = 'Is required'; + if (typeof data.name !== "undefined") { + if (typeof data.name !== "string") { + errors.name = "Should be a string"; + } else if (data.name === "") { + errors.name = "Is required"; } } - if (typeof data.participants !== 'undefined') { + if (typeof data.participants !== "undefined") { if (!Array.isArray(data.participants)) { - errors.participants = 'Should be an array'; + errors.participants = "Should be an array"; } else { data.participants.some((p) => { - if (typeof p !== 'string') { - errors.participants = 'Should only have string values'; + if (typeof p !== "string") { + errors.participants = "Should only have string values"; return true; } else if (!p) { - errors.participants = 'Should not have empty values'; + errors.participants = "Should not have empty values"; return true; - } else if (!p.startsWith('-')) { + } else if (!p.startsWith("-")) { errors.participants = `${p} should start with -`; return true; } else if (!isMongoId(p.substring(1))) { @@ -310,44 +309,44 @@ module.exports = { } } - if (typeof data.participantsGoal !== 'undefined') { + if (typeof data.participantsGoal !== "undefined") { if (data.participantsGoal === null) { - errors.participantsGoal = 'Is required'; - } else if (typeof data.participantsGoal !== 'number') { - errors.participantsGoal = 'Should be a number'; + errors.participantsGoal = "Is required"; + } else if (typeof data.participantsGoal !== "number") { + errors.participantsGoal = "Should be a number"; } else if (!isInt(data.participantsGoal.toString())) { - errors.participantsGoal = 'Should be a integer'; + errors.participantsGoal = "Should be a integer"; } } - if (typeof data.poster !== 'undefined' && typeof data.poster !== 'string') { - errors.poster = 'Should be a string'; + if (typeof data.poster !== "undefined" && typeof data.poster !== "string") { + errors.poster = "Should be a string"; } - if (typeof data.reviewsGoal !== 'undefined') { + if (typeof data.reviewsGoal !== "undefined") { if (data.reviewsGoal === null) { - errors.reviewsGoal = 'Is required'; - } else if (typeof data.reviewsGoal !== 'number') { - errors.reviewsGoal = 'Should be a number'; + errors.reviewsGoal = "Is required"; + } else if (typeof data.reviewsGoal !== "number") { + errors.reviewsGoal = "Should be a number"; } else if (!isInt(data.reviewsGoal.toString())) { - errors.reviewsGoal = 'Should be a integer'; + errors.reviewsGoal = "Should be a integer"; } } let startDateIsValid = false; - if (typeof data.startDate !== 'undefined') { - if (typeof data.startDate !== 'string') { - errors.startDate = 'Should be a string'; - } else if (data.startDate === '') { - errors.startDate = 'Is required'; + if (typeof data.startDate !== "undefined") { + if (typeof data.startDate !== "string") { + errors.startDate = "Should be a string"; + } else if (data.startDate === "") { + errors.startDate = "Is required"; } else if (!moment(data.startDate).isValid()) { - errors.startDate = 'Should have a ISO-8601 format'; + errors.startDate = "Should have a ISO-8601 format"; } else { - const startDate = moment(data.startDate).startOf('day').utc(); - const today = moment().startOf('day').utc(); + const startDate = moment(data.startDate).startOf("day").utc(); + const today = moment().startOf("day").utc(); if (startDate.isBefore(today)) { - errors.startDate = 'Should be greater than or equal to today'; + errors.startDate = "Should be greater than or equal to today"; } else { startDateIsValid = true; } @@ -355,26 +354,26 @@ module.exports = { } if ( - typeof data.teamManager !== 'undefined' && - typeof data.teamManager !== 'string' + typeof data.teamManager !== "undefined" && + typeof data.teamManager !== "string" ) { - errors.teamManager = 'Should be a string'; + errors.teamManager = "Should be a string"; } else if (data.teamManager && !isMongoId(data.teamManager)) { - errors.teamManager = 'Should be a valid id'; + errors.teamManager = "Should be a valid id"; } - if (typeof data.teams !== 'undefined') { + if (typeof data.teams !== "undefined") { if (!Array.isArray(data.teams)) { - errors.teams = 'Should be an array'; + errors.teams = "Should be an array"; } else { data.teams.some((t) => { - if (typeof t !== 'string') { - errors.teams = 'Should only have string values'; + if (typeof t !== "string") { + errors.teams = "Should only have string values"; return true; } else if (!t) { - errors.teams = 'Should not have empty values'; + errors.teams = "Should not have empty values"; return true; - } else if (!t.startsWith('-')) { + } else if (!t.startsWith("-")) { errors.teams = `${t} should start with -`; return true; } else if (!isMongoId(t.substring(1))) { @@ -386,14 +385,14 @@ module.exports = { } if (endDateIsValid && startDateIsValid) { - const endDate = moment(data.endDate).endOf('day').utc(); - const startDate = moment(data.startDate).startOf('day').utc(); + const endDate = moment(data.endDate).endOf("day").utc(); + const startDate = moment(data.startDate).startOf("day").utc(); if (startDate.isAfter(endDate)) { - errors.endDate = 'Should be greater than or equal to startDate'; - errors.startDate = 'Should be less than or equal to endDate'; - } else if (endDate.diff(startDate, 'days') > 365) { - errors.endDate = 'Should last less than 365 days'; + errors.endDate = "Should be greater than or equal to startDate"; + errors.startDate = "Should be less than or equal to endDate"; + } else if (endDate.diff(startDate, "days") > 365) { + errors.endDate = "Should last less than 365 days"; } } @@ -405,9 +404,9 @@ module.exports = { let isAfterDateValid = false; if ( queryParams.afterDate && - !moment(queryParams.afterDate, 'YYYY-MM-DD', true).isValid() + !moment(queryParams.afterDate, "YYYY-MM-DD", true).isValid() ) { - errors.afterDate = 'Should have YYYY-MM-DD format'; + errors.afterDate = "Should have YYYY-MM-DD format"; } else { isAfterDateValid = true; } @@ -415,52 +414,52 @@ module.exports = { let isBeforeDateValid = false; if ( queryParams.beforeDate && - !moment(queryParams.beforeDate, 'YYYY-MM-DD', true).isValid() + !moment(queryParams.beforeDate, "YYYY-MM-DD", true).isValid() ) { - errors.beforeDate = 'Should have YYYY-MM-DD format'; + errors.beforeDate = "Should have YYYY-MM-DD format"; } else { isBeforeDateValid = true; } if (isAfterDateValid && isBeforeDateValid) { - const afterDate = moment(queryParams.afterDate, 'YYYY-MM-DD').utc(); - const beforeDate = moment(queryParams.beforeDate, 'YYYY-MM-DD').utc(); + const afterDate = moment(queryParams.afterDate, "YYYY-MM-DD").utc(); + const beforeDate = moment(queryParams.beforeDate, "YYYY-MM-DD").utc(); if (afterDate.isAfter(beforeDate)) { - errors.afterDate = 'Should be less than beforeDate'; - errors.beforeDate = 'Should be greater than afterDate'; + errors.afterDate = "Should be less than beforeDate"; + errors.beforeDate = "Should be greater than afterDate"; } } const sortOptions = [ - 'name', - '-name', - 'reviewsAmount', - '-reviewsAmount', - 'startDate', - '-startDate' + "name", + "-name", + "reviewsAmount", + "-reviewsAmount", + "startDate", + "-startDate", ]; if (queryParams.sortBy && !sortOptions.includes(queryParams.sortBy)) { - errors.sortBy = 'Should be a valid sort'; + errors.sortBy = "Should be a valid sort"; } if (queryParams.page) { if (!isInt(queryParams.page)) { - errors.page = 'Should be a integer'; + errors.page = "Should be a integer"; } else if (parseInt(queryParams.page, 10) < 1) { - errors.page = 'Should be a positive integer'; + errors.page = "Should be a positive integer"; } } if (queryParams.pageLimit) { if (!isInt(queryParams.pageLimit)) { - errors.pageLimit = 'Should be a integer'; + errors.pageLimit = "Should be a integer"; } else if (parseInt(queryParams.pageLimit, 10) < 1) { - errors.pageLimit = 'Should be a positive integer'; + errors.pageLimit = "Should be a positive integer"; } else if (parseInt(queryParams.pageLimit, 10) > 12) { - errors.pageLimit = 'Should be less than 13'; + errors.pageLimit = "Should be less than 13"; } } return { errors, isValid: isEmpty(errors) }; - } + }, }; diff --git a/src/routes/venues/list-venues.js b/src/routes/venues/list-venues.js index 457693e..6f6b77d 100644 --- a/src/routes/venues/list-venues.js +++ b/src/routes/venues/list-venues.js @@ -53,8 +53,6 @@ function covertDistanceToFeet(distanceInMeter, language = "en") { module.exports = async (req, res, next) => { const queryParams = req.query; - console.log(queryParams); - const { errors, isValid } = validateListVenues(queryParams); if (!isValid) return res.status(400).json(errors); @@ -271,11 +269,9 @@ module.exports = async (req, res, next) => { ) .skip(page * pageLimit) .limit(pageLimit), - (await Venue.find(dbVenuesFilters)).length, - /*TODO: count is deprecated in favor of countDocuments, but that does not support $near - would need to move to GeoWithin but that does not return sorted results - */ + (await Venue.find(dbVenuesFilters))?.length, ]); + console.log({ total }); } catch (err) { console.log( `Venues failed to be found or count at list-venues.\nvenuesQuery: ${JSON.stringify( @@ -446,7 +442,7 @@ module.exports = async (req, res, next) => { } //do we need to check for 0? - if (placesResponse.data.results.length == 1) { + if (placesResponse.data.results?.length == 1) { if (placesResponse.data.results[0].types[0] == "locality") { console.log( "Found a city only: ", @@ -491,6 +487,7 @@ module.exports = async (req, res, next) => { placesIds.push(place.place_id); }); + console.log("calling venues"); //Use array of Google Place IDs to find AXS Venues let venues; try { @@ -501,7 +498,7 @@ module.exports = async (req, res, next) => { ); return next(err); } - + console.log("venues length", venues.length); //Perform ratings logic on all returned venues venues.forEach((venue) => { //console.log('In scoring assignment'); @@ -593,6 +590,7 @@ module.exports = async (req, res, next) => { // places = places.map((place) => { const venue = find(venues, (venue) => venue.placeId === place.placeId); + console.log(venue); if (venue) { return Object.assign({}, place, { //new expanded fields From 03244298df7b4b84d9bc816886fce7ae7d02558b Mon Sep 17 00:00:00 2001 From: abdul-rehman90 <> Date: Mon, 3 Mar 2025 18:46:56 +0500 Subject: [PATCH 07/67] mapathin date validation fixed --- src/routes/events/validations.js | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/routes/events/validations.js b/src/routes/events/validations.js index 8d47bf4..4dc0762 100644 --- a/src/routes/events/validations.js +++ b/src/routes/events/validations.js @@ -74,14 +74,7 @@ module.exports = { } else if (!moment(data.endDate).isValid()) { errors.endDate = "Should have a ISO-8601 format"; } else { - const endDate = moment(data.endDate).endOf("day").utc(); - const today = moment().startOf("day").utc(); - - if (endDate.isBefore(today)) { - errors.endDate = "Should be greater than or equal to today"; - } else { - endDateIsValid = true; - } + endDateIsValid = true; } if ( @@ -150,14 +143,7 @@ module.exports = { } else if (!moment(data.startDate).isValid()) { errors.startDate = "Should have a ISO-8601 format"; } else { - const startDate = moment(data.startDate).startOf("day").utc(); - const today = moment().startOf("day").utc(); - - if (startDate.isBefore(today)) { - errors.startDate = "Should be greater than or equal to today"; - } else { - startDateIsValid = true; - } + startDateIsValid = true; } if ( From b7be5eae00ec139b95fe9283b7388932f1c07eb0 Mon Sep 17 00:00:00 2001 From: abdul-rehman90 <> Date: Mon, 3 Mar 2025 18:58:49 +0500 Subject: [PATCH 08/67] user schema updated --- src/models/user.js | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/src/models/user.js b/src/models/user.js index 9c3c00a..72de29f 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -161,29 +161,24 @@ const userSchema = new mongoose.Schema( race: { type: String, default: "", - enum: { - values: [ - "black/african american", - "caucasian", - "indigenous/first nation/native american", - "latino/hispanic", - "middle eastern/north african", - "native hawaiian/pacific islander", - "biracial/multiracial", - "non-naucasian", - "not-to-disclose", - ], - general: "Invalid type of Race", - }, + enum: [ + "black/african american", + "caucasian", + "indigenous/first nation/native american", + "latino/hispanic", + "middle eastern/north african", + "native hawaiian/pacific islander", + "biracial/multiracial", + "non-naucasian", + "not-to-disclose", + "", + ], required: false, }, disability: { type: String, default: "", - enum: { - values: ["yes", "No", "not-to-say"], - general: "Invalid type of Disability", - }, + enum: ["yes", "No", "not-to-say", ""], required: false, }, }, From 3bbaf85a0d4612e6ce3027e6cf02eb3948a22b6e Mon Sep 17 00:00:00 2001 From: abdul-rehman90 <> Date: Mon, 3 Mar 2025 19:12:03 +0500 Subject: [PATCH 09/67] update user profile resolvedd --- src/routes/users/edit-user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/users/edit-user.js b/src/routes/users/edit-user.js index bfc0ca3..56e3036 100644 --- a/src/routes/users/edit-user.js +++ b/src/routes/users/edit-user.js @@ -61,9 +61,9 @@ module.exports = async (req, res, next) => { user.description = data.description || user.description; user.disabilities = data.disabilities || user.disabilities; - user.disability = data.disability || user.disabilities; + user.disability = data.disability || ""; user.birthday = data.birthday || user.birthday; - user.race = data.race || user.race; + user.race = data.race || ""; user.firstName = data.firstName ? cleanSpaces(data.firstName) From 7328f7e17719d7e41d1b7b30a52152a835e8a2f3 Mon Sep 17 00:00:00 2001 From: abdul-rehman90 <> Date: Thu, 20 Mar 2025 16:46:11 +0500 Subject: [PATCH 10/67] asian race added --- src/models/user.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/models/user.js b/src/models/user.js index 72de29f..84971d1 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -169,6 +169,7 @@ const userSchema = new mongoose.Schema( "middle eastern/north african", "native hawaiian/pacific islander", "biracial/multiracial", + "asian", "non-naucasian", "not-to-disclose", "", From 0d503a3d926b7750c381a517744e70e9688e550d Mon Sep 17 00:00:00 2001 From: abdul-rehman90 <> Date: Wed, 26 Mar 2025 21:04:56 +0500 Subject: [PATCH 11/67] forgot password link updated --- src/routes/auth/forgotten-password.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/auth/forgotten-password.js b/src/routes/auth/forgotten-password.js index ec73405..c2cd4fd 100644 --- a/src/routes/auth/forgotten-password.js +++ b/src/routes/auth/forgotten-password.js @@ -62,8 +62,8 @@ module.exports = async (req, res, next) => {To reset your password use the link below:
Stay awesome.
From c65fbd5cac4b9448baa1cd7ce3b48dc56748eb19 Mon Sep 17 00:00:00 2001 From: abdul-rehman90 <> Date: Wed, 2 Apr 2025 16:39:05 +0500 Subject: [PATCH 12/67] resolve forgot password issues and activate user flow --- src/routes/auth/activate-account.js | 7 ++++--- src/routes/auth/forgotten-password.js | 1 + src/routes/auth/reset-password.js | 30 +++++++++++++-------------- src/routes/auth/sign-up.js | 5 +++-- 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/routes/auth/activate-account.js b/src/routes/auth/activate-account.js index d6885b3..798c29d 100644 --- a/src/routes/auth/activate-account.js +++ b/src/routes/auth/activate-account.js @@ -33,7 +33,7 @@ module.exports = async (req, res, next) => { const now = moment.utc(); if (expiresAt.isBefore(now)) { try { - await activationTicket.remove(); + await ActivationTicket.deleteOne({ key }); } catch (err) { console.log( `Activation ticket with key ${ @@ -125,7 +125,7 @@ module.exports = async (req, res, next) => { } try { - await activationTicket.remove(); + await ActivationTicket.deleteOne({ key }); } catch (err) { console.log( `Activation ticket with key ${ @@ -134,6 +134,7 @@ module.exports = async (req, res, next) => { ); return next(err); } + // TODO change base URL - return res.redirect(`${process.env.APP_URL}/sign-in`); + return res.redirect(`https://axsmap.com/sign-in`); }; diff --git a/src/routes/auth/forgotten-password.js b/src/routes/auth/forgotten-password.js index c2cd4fd..c782c05 100644 --- a/src/routes/auth/forgotten-password.js +++ b/src/routes/auth/forgotten-password.js @@ -56,6 +56,7 @@ module.exports = async (req, res, next) => { ); return next(err); } + console.log(passwordTicket); const htmlContent = `To activate your account use the link below:
Stay awesome.
From abc8213345c53ed8b44a0288a181d77ba46df465 Mon Sep 17 00:00:00 2001 From: abdul-rehman90 <> Date: Wed, 2 Apr 2025 19:02:17 +0500 Subject: [PATCH 13/67] replace remove function with delete one --- src/routes/auth/generate-token.js | 16 +-- src/routes/auth/sign-out.js | 10 +- src/routes/events/delete-event.js | 34 ++--- src/routes/events/join-event.js | 40 +++--- src/routes/petitions/create-petition.js | 164 +++++++++++++--------- src/routes/petitions/edit-petition.js | 152 ++++++++++---------- src/routes/teams/delete-team.js | 28 ++-- src/routes/teams/join-team.js | 34 +++-- src/routes/users/archive-user.js | 28 ++-- src/routes/users/change-password.js | 14 +- src/routes/users/deactivate-user.js | 26 ++-- src/routes/users/delete-user.js | 14 +- src/scripts/db/update-events-locations.js | 44 +++--- 13 files changed, 318 insertions(+), 286 deletions(-) diff --git a/src/routes/auth/generate-token.js b/src/routes/auth/generate-token.js index 689e2d2..ff40108 100644 --- a/src/routes/auth/generate-token.js +++ b/src/routes/auth/generate-token.js @@ -1,9 +1,9 @@ -const jwt = require('jsonwebtoken'); -const moment = require('moment'); +const jwt = require("jsonwebtoken"); +const moment = require("moment"); -const { RefreshToken } = require('../../models/refresh-token'); +const { RefreshToken } = require("../../models/refresh-token"); -const { validateGenerateToken } = require('./validations'); +const { validateGenerateToken } = require("./validations"); module.exports = async (req, res, next) => { const { errors, isValid } = validateGenerateToken(req.body); @@ -24,14 +24,14 @@ module.exports = async (req, res, next) => { } if (!refreshToken) { - return res.status(404).json({ general: 'Refresh Token not found' }); + return res.status(404).json({ general: "Refresh Token not found" }); } const expiresAt = moment(refreshToken.expiresAt).utc(); const today = moment.utc(); if (expiresAt.isBefore(today)) { try { - await refreshToken.remove(); + await RefreshToken.deleteOne({ key }); } catch (err) { console.log( `Refresh Token with key ${ @@ -41,14 +41,14 @@ module.exports = async (req, res, next) => { return next(err); } - return res.status(401).json({ general: 'Refresh Token expired' }); + return res.status(401).json({ general: "Refresh Token expired" }); } const token = jwt.sign( { userId: refreshToken.userId }, process.env.JWT_SECRET, { - expiresIn: 3600 + expiresIn: 3600, } ); return res.status(200).json({ token }); diff --git a/src/routes/auth/sign-out.js b/src/routes/auth/sign-out.js index 6810f6b..57ada88 100644 --- a/src/routes/auth/sign-out.js +++ b/src/routes/auth/sign-out.js @@ -1,8 +1,8 @@ -const { RefreshToken } = require('../../models/refresh-token'); +const { RefreshToken } = require("../../models/refresh-token"); module.exports = async (req, res, next) => { if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); + return res.status(423).json({ general: "You are blocked" }); } let refreshToken; @@ -16,11 +16,11 @@ module.exports = async (req, res, next) => { } if (!refreshToken) { - return res.status(204).json({ general: 'Success' }); + return res.status(204).json({ general: "Success" }); } try { - await refreshToken.remove(); + await RefreshToken.deleteOne({ userId: req.user.id }); } catch (err) { console.log( `Refresh token with userId ${ @@ -30,5 +30,5 @@ module.exports = async (req, res, next) => { return next(err); } - return res.status(204).json({ general: 'Success' }); + return res.status(204).json({ general: "Success" }); }; diff --git a/src/routes/events/delete-event.js b/src/routes/events/delete-event.js index ca305ae..ec69388 100644 --- a/src/routes/events/delete-event.js +++ b/src/routes/events/delete-event.js @@ -1,16 +1,16 @@ -const aws = require('aws-sdk'); -const { last } = require('lodash'); -const moment = require('moment'); +const aws = require("aws-sdk"); +const { last } = require("lodash"); +const moment = require("moment"); -const { Event } = require('../../models/event'); -const { Team } = require('../../models/team'); -const { User } = require('../../models/user'); +const { Event } = require("../../models/event"); +const { Team } = require("../../models/team"); +const { User } = require("../../models/user"); const s3 = new aws.S3(); module.exports = async (req, res, next) => { if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); + return res.status(423).json({ general: "You are blocked" }); } const eventId = req.params.eventId; @@ -19,22 +19,22 @@ module.exports = async (req, res, next) => { try { event = await Event.findOne({ _id: eventId }); } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Event not found' }); + if (err.name === "CastError") { + return res.status(404).json({ general: "Event not found" }); } console.log(`Event ${eventId} failed to be found at delete-event`); return next(err); } if (!event) { - return res.status(404).json({ general: 'Event not found' }); + return res.status(404).json({ general: "Event not found" }); } if ( !event.managers.find((m) => m.toString() === req.user.id) && !req.user.isAdmin ) { - return res.status(403).json({ general: 'Forbidden action' }); + return res.status(403).json({ general: "Forbidden action" }); } const endDate = moment(event.endDate).utc(); @@ -43,7 +43,7 @@ module.exports = async (req, res, next) => { if (endDate.isBefore(today) && event.reviews > 0) { return res.status(423).json({ general: - 'It cannot be removed because it already ended and has one or more reviews' + "It cannot be removed because it already ended and has one or more reviews", }); } @@ -55,7 +55,7 @@ module.exports = async (req, res, next) => { try { participants = await Promise.all(participantsPromises); } catch (err) { - console.log('A participant failed to be found at delete-event'); + console.log("A participant failed to be found at delete-event"); return next(err); } @@ -79,7 +79,7 @@ module.exports = async (req, res, next) => { for (const photo of event.photos) { const photoParams = { Bucket: process.env.AWS_S3_BUCKET, - Key: `events/photos/${last(photo.url.split('/'))}` + Key: `events/photos/${last(photo.url.split("/"))}`, }; try { @@ -102,7 +102,7 @@ module.exports = async (req, res, next) => { try { teams = await Promise.all(teamsPromises); } catch (err) { - console.log('A team failed to be found at delete-event'); + console.log("A team failed to be found at delete-event"); return next(err); } @@ -120,11 +120,11 @@ module.exports = async (req, res, next) => { } try { - await event.remove(); + await Event.deleteOne({ _id: eventId }); } catch (err) { console.log(`Event ${event.id} failed to be removed at delete-event`); return next(err); } - return res.status(204).json({ general: 'Success' }); + return res.status(204).json({ general: "Success" }); }; diff --git a/src/routes/events/join-event.js b/src/routes/events/join-event.js index f3b6378..3248f3a 100644 --- a/src/routes/events/join-event.js +++ b/src/routes/events/join-event.js @@ -1,7 +1,7 @@ -const moment = require('moment'); +const moment = require("moment"); -const { Event } = require('../../models/event'); -const { Petition } = require('../../models/petition'); +const { Event } = require("../../models/event"); +const { Petition } = require("../../models/petition"); module.exports = async (req, res, next) => { const eventId = req.params.eventId; @@ -10,8 +10,8 @@ module.exports = async (req, res, next) => { try { event = await Event.findOne({ _id: eventId, isArchived: false }); } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Event not found' }); + if (err.name === "CastError") { + return res.status(404).json({ general: "Event not found" }); } console.log(`Event ${eventId} failed to be found at join-event`); @@ -19,21 +19,21 @@ module.exports = async (req, res, next) => { } if (!event) { - return res.status(404).json({ general: 'Event not found' }); + return res.status(404).json({ general: "Event not found" }); } const eventParticipants = event.participants.map((p) => p.toString()); if (eventParticipants.includes(req.user.id)) { return res .status(400) - .json({ general: 'You already are a participant in this event' }); + .json({ general: "You already are a participant in this event" }); } const eventManagers = event.managers.map((m) => m.toString()); if (eventManagers.includes(req.user.id)) { return res .status(400) - .json({ general: 'You already are a participant in this event' }); + .json({ general: "You already are a participant in this event" }); } if (event.isOpen) { @@ -57,14 +57,14 @@ module.exports = async (req, res, next) => { return next(err); } - return res.status(200).json({ general: 'Joined' }); + return res.status(200).json({ general: "Joined" }); } else { let petition; try { petition = await Petition.findOne({ event: event.id, sender: req.user.id, - type: 'request-user-event' + type: "request-user-event", }); } catch (err) { console.log( @@ -75,18 +75,22 @@ module.exports = async (req, res, next) => { return next(err); } - if (petition && petition.state === 'pending') { + if (petition && petition.state === "pending") { return res.status(400).json({ - general: 'You already have a pending petition with this event' + general: "You already have a pending petition with this event", }); } if ( petition && - (petition.state === 'rejected' || petition.state === 'canceled') + (petition.state === "rejected" || petition.state === "canceled") ) { try { - await petition.remove(); + await Petition.deleteOne({ + event: event.id, + sender: req.user.id, + type: "request-user-event", + }); } catch (err) { console.log( `Petition ${petition.id} failed to be removed at join-event` @@ -100,18 +104,18 @@ module.exports = async (req, res, next) => { if (endDate.isBefore(today)) { return res .status(423) - .json({ general: 'This event has already finished' }); + .json({ general: "This event has already finished" }); } const petitionData = { event: event.id, sender: req.user.id, - type: 'request-user-event' + type: "request-user-event", }; try { await Petition.create(petitionData); } catch (err) { - if (typeof err.errors === 'object') { + if (typeof err.errors === "object") { const validationErrors = {}; Object.keys(err.errors).forEach((key) => { @@ -129,6 +133,6 @@ module.exports = async (req, res, next) => { return next(err); } - return res.status(200).json({ general: 'Requested' }); + return res.status(200).json({ general: "Requested" }); } }; diff --git a/src/routes/petitions/create-petition.js b/src/routes/petitions/create-petition.js index 3e1b5d8..dc270d9 100644 --- a/src/routes/petitions/create-petition.js +++ b/src/routes/petitions/create-petition.js @@ -1,11 +1,11 @@ -const moment = require('moment'); +const moment = require("moment"); -const { Event } = require('../../models/event'); -const { Petition } = require('../../models/petition'); -const { Team } = require('../../models/team'); -const { User } = require('../../models/user'); +const { Event } = require("../../models/event"); +const { Petition } = require("../../models/petition"); +const { Team } = require("../../models/team"); +const { User } = require("../../models/user"); -const { validateCreatePetition } = require('./validations'); +const { validateCreatePetition } = require("./validations"); module.exports = async (req, res, next) => { const { errors, isValid } = validateCreatePetition(req.body); @@ -18,13 +18,13 @@ module.exports = async (req, res, next) => { message: req.body.message, team: req.body.team, type: req.body.type, - user: req.body.user + user: req.body.user, } ); data.sender = req.user.id.toString(); const today = moment.utc(); - if (data.type === 'invite-team-event') { + if (data.type === "invite-team-event") { delete data.user; let petition; @@ -32,7 +32,7 @@ module.exports = async (req, res, next) => { petition = await Petition.findOne({ event: data.event, team: data.team, - type: data.type + type: data.type, }); } catch (err) { console.log( @@ -43,18 +43,22 @@ module.exports = async (req, res, next) => { return next(err); } - if (petition && petition.state === 'pending') { + if (petition && petition.state === "pending") { return res.status(400).json({ - general: 'Team already has a pending invitation to event' + general: "Team already has a pending invitation to event", }); } if ( petition && - (petition.state === 'rejected' || petition.state === 'canceled') + (petition.state === "rejected" || petition.state === "canceled") ) { try { - await petition.remove(); + await Petition.deleteOne({ + event: data.event, + team: data.team, + type: data.type, + }); } catch (err) { console.log( `Petition ${petition.id} failed to be removed at create-petition` @@ -71,21 +75,21 @@ module.exports = async (req, res, next) => { return next(err); } - if (!event) return res.status(404).json({ event: 'Not found' }); + if (!event) return res.status(404).json({ event: "Not found" }); if (!event.managers.find((m) => m.toString() === data.sender)) { - return res.status(403).json({ general: 'Forbidden action' }); + return res.status(403).json({ general: "Forbidden action" }); } if (event.teams.find((t) => t.toString() === data.team)) { return res.status(400).json({ - general: 'Team is already participant of event' + general: "Team is already participant of event", }); } const endDate = moment(event.endDate).utc(); if (endDate.isBefore(today)) { - return res.status(400).json({ general: 'Event has already finished' }); + return res.status(400).json({ general: "Event has already finished" }); } let team; @@ -96,8 +100,8 @@ module.exports = async (req, res, next) => { return next(err); } - if (!team) return res.status(404).json({ general: 'Team not found' }); - } else if (data.type === 'invite-user-event') { + if (!team) return res.status(404).json({ general: "Team not found" }); + } else if (data.type === "invite-user-event") { delete data.team; let petition; @@ -105,7 +109,7 @@ module.exports = async (req, res, next) => { petition = await Petition.findOne({ event: data.event, type: data.type, - user: data.user + user: data.user, }); } catch (err) { console.log( @@ -116,18 +120,22 @@ module.exports = async (req, res, next) => { return next(err); } - if (petition && petition.state === 'pending') { + if (petition && petition.state === "pending") { return res.status(400).json({ - general: 'User already has a pending invitation to event' + general: "User already has a pending invitation to event", }); } if ( petition && - (petition.state === 'rejected' || petition.state === 'canceled') + (petition.state === "rejected" || petition.state === "canceled") ) { try { - await petition.remove(); + await Petition.findOne({ + event: data.event, + type: data.type, + user: data.user, + }); } catch (err) { console.log( `Petition ${petition.id} failed to be removed at create-petition` @@ -137,7 +145,7 @@ module.exports = async (req, res, next) => { } if (data.sender === data.user) { - return res.status(400).json({ general: 'User should not be you' }); + return res.status(400).json({ general: "User should not be you" }); } let event; @@ -148,21 +156,21 @@ module.exports = async (req, res, next) => { return next(err); } - if (!event) return res.status(404).json({ general: 'Event not found' }); + if (!event) return res.status(404).json({ general: "Event not found" }); if (!event.managers.find((m) => m.toString() === data.sender)) { - return res.status(403).json({ general: 'Forbidden action' }); + return res.status(403).json({ general: "Forbidden action" }); } if (event.participants.find((p) => p.toString() === data.user)) { return res.status(400).json({ - general: 'User is already participant of event' + general: "User is already participant of event", }); } const endDate = moment(event.endDate).utc(); if (endDate.isBefore(today)) { - return res.status(400).json({ general: 'Event has already finished' }); + return res.status(400).json({ general: "Event has already finished" }); } let user; @@ -173,8 +181,8 @@ module.exports = async (req, res, next) => { return next(err); } - if (!user) return res.status(404).json({ general: 'User not found' }); - } else if (data.type === 'invite-user-team') { + if (!user) return res.status(404).json({ general: "User not found" }); + } else if (data.type === "invite-user-team") { delete data.event; let petition; @@ -182,7 +190,7 @@ module.exports = async (req, res, next) => { petition = await Petition.findOne({ team: data.team, type: data.type, - user: data.user + user: data.user, }); } catch (err) { console.log( @@ -193,18 +201,22 @@ module.exports = async (req, res, next) => { return next(err); } - if (petition && petition.state === 'pending') { + if (petition && petition.state === "pending") { return res.status(400).json({ - general: 'User already has a pending invitation to team' + general: "User already has a pending invitation to team", }); } if ( petition && - (petition.state === 'rejected' || petition.state === 'canceled') + (petition.state === "rejected" || petition.state === "canceled") ) { try { - await petition.remove(); + await Petition.deleteOne({ + team: data.team, + type: data.type, + user: data.user, + }); } catch (err) { console.log( `Petition ${petition.id} failed to be removed at create-petition` @@ -214,7 +226,7 @@ module.exports = async (req, res, next) => { } if (req.sender === data.user) { - return res.status(400).json({ general: 'User should not be you' }); + return res.status(400).json({ general: "User should not be you" }); } let team; @@ -225,15 +237,15 @@ module.exports = async (req, res, next) => { return next(err); } - if (!team) return res.status(404).json({ general: 'Team not found' }); + if (!team) return res.status(404).json({ general: "Team not found" }); if (!team.managers.find((m) => m.toString() === data.sender)) { - return res.status(403).json({ general: 'Forbidden action' }); + return res.status(403).json({ general: "Forbidden action" }); } if (team.members.find((m) => m.toString() === data.user)) { return res.status(400).json({ - general: 'User is already member of team' + general: "User is already member of team", }); } @@ -245,8 +257,8 @@ module.exports = async (req, res, next) => { return next(err); } - if (!user) return res.status(404).json({ general: 'User not found' }); - } else if (data.type === 'request-team-event') { + if (!user) return res.status(404).json({ general: "User not found" }); + } else if (data.type === "request-team-event") { delete data.user; let petition; @@ -254,7 +266,7 @@ module.exports = async (req, res, next) => { petition = await Petition.findOne({ event: data.event, team: data.team, - type: data.type + type: data.type, }); } catch (err) { console.log( @@ -265,18 +277,22 @@ module.exports = async (req, res, next) => { return next(err); } - if (petition && petition.state === 'pending') { + if (petition && petition.state === "pending") { return res.status(400).json({ - general: 'Team already has a pending request with event' + general: "Team already has a pending request with event", }); } if ( petition && - (petition.state === 'rejected' || petition.state === 'canceled') + (petition.state === "rejected" || petition.state === "canceled") ) { try { - await petition.remove(); + await Petition.deleteOne({ + event: data.event, + team: data.team, + type: data.type, + }); } catch (err) { console.log( `Petition ${petition.id} failed to be removed at create-petition` @@ -293,17 +309,17 @@ module.exports = async (req, res, next) => { return next(err); } - if (!event) return res.status(404).json({ general: 'Event not found' }); + if (!event) return res.status(404).json({ general: "Event not found" }); if (event.teams.find((t) => t.toString() === data.sender)) { return res.status(400).json({ - general: 'Team is already participant of event ' + general: "Team is already participant of event ", }); } const endDate = moment(event.endDate).utc(); if (endDate.isBefore(today)) { - return res.status(400).json({ general: 'Event has already finished' }); + return res.status(400).json({ general: "Event has already finished" }); } let team; @@ -314,12 +330,12 @@ module.exports = async (req, res, next) => { return next(err); } - if (!team) return res.status(404).json({ general: 'Team not found' }); + if (!team) return res.status(404).json({ general: "Team not found" }); if (!team.managers.find((m) => m.toString() === data.sender)) { - return res.status(403).json({ general: 'Forbidden action' }); + return res.status(403).json({ general: "Forbidden action" }); } - } else if (data.type === 'request-user-event') { + } else if (data.type === "request-user-event") { delete data.team; let petition; @@ -327,7 +343,7 @@ module.exports = async (req, res, next) => { petition = await Petition.findOne({ event: data.event, sender: data.sender, - type: data.type + type: data.type, }); } catch (err) { console.log( @@ -338,18 +354,22 @@ module.exports = async (req, res, next) => { return next(err); } - if (petition && petition.state === 'pending') { + if (petition && petition.state === "pending") { return res.status(400).json({ - general: 'User already have a pending request with event' + general: "User already have a pending request with event", }); } if ( petition && - (petition.state === 'rejected' || petition.state === 'canceled') + (petition.state === "rejected" || petition.state === "canceled") ) { try { - await petition.remove(); + await Petition.deleteOne({ + event: data.event, + sender: data.sender, + type: data.type, + }); } catch (err) { console.log( `Petition ${petition.id} failed to be removed at create-petition` @@ -366,17 +386,17 @@ module.exports = async (req, res, next) => { return next(err); } - if (!event) return res.status(404).json({ general: 'Event not found' }); + if (!event) return res.status(404).json({ general: "Event not found" }); if (event.participants.find((p) => p.toString() === data.sender)) { return res.status(400).json({ - general: 'User already is participant of event' + general: "User already is participant of event", }); } const endDate = moment(event.endDate).utc(); if (endDate.isBefore(today)) { - return res.status(400).json({ general: 'Event has already finished' }); + return res.status(400).json({ general: "Event has already finished" }); } } else { // data.type === request-user-team @@ -387,7 +407,7 @@ module.exports = async (req, res, next) => { petition = await Petition.findOne({ team: data.team, sender: data.sender, - type: data.type + type: data.type, }); } catch (err) { console.log( @@ -398,18 +418,22 @@ module.exports = async (req, res, next) => { return next(err); } - if (petition && petition.state === 'pending') { + if (petition && petition.state === "pending") { return res.status(400).json({ - general: 'User already have a pending request with team' + general: "User already have a pending request with team", }); } if ( petition && - (petition.state === 'rejected' || petition.state === 'canceled') + (petition.state === "rejected" || petition.state === "canceled") ) { try { - await petition.remove(); + await Petition.deleteOne({ + team: data.team, + sender: data.sender, + type: data.type, + }); } catch (err) { console.log( `Petition ${petition.id} failed to be removed at create-petition` @@ -426,11 +450,11 @@ module.exports = async (req, res, next) => { return next(err); } - if (!team) return res.status(404).json({ general: 'Team not found' }); + if (!team) return res.status(404).json({ general: "Team not found" }); if (team.members.find((m) => m.toString() === data.sender)) { return res.status(400).json({ - general: 'User already is member of team' + general: "User already is member of team", }); } } @@ -439,7 +463,7 @@ module.exports = async (req, res, next) => { try { petition = await Petition.create(data); } catch (err) { - if (typeof err.errors === 'object') { + if (typeof err.errors === "object") { const validationErrors = {}; Object.keys(err.errors).forEach((key) => { @@ -467,7 +491,7 @@ module.exports = async (req, res, next) => { state: petition.state, team: petition.team, type: petition.type, - user: petition.user + user: petition.user, } ); return res.status(201).json(dataResponse); diff --git a/src/routes/petitions/edit-petition.js b/src/routes/petitions/edit-petition.js index b3adcfa..f837db2 100644 --- a/src/routes/petitions/edit-petition.js +++ b/src/routes/petitions/edit-petition.js @@ -1,11 +1,11 @@ -const moment = require('moment'); +const moment = require("moment"); -const { Event } = require('../../models/event'); -const { Petition } = require('../../models/petition'); -const { Team } = require('../../models/team'); -const { User } = require('../../models/user'); +const { Event } = require("../../models/event"); +const { Petition } = require("../../models/petition"); +const { Team } = require("../../models/team"); +const { User } = require("../../models/user"); -const { validateEditPetition } = require('./validations'); +const { validateEditPetition } = require("./validations"); module.exports = async (req, res, next) => { const petitionId = req.params.petitionId; @@ -14,8 +14,8 @@ module.exports = async (req, res, next) => { try { petition = await Petition.findOne({ _id: petitionId }); } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Petition not found' }); + if (err.name === "CastError") { + return res.status(404).json({ general: "Petition not found" }); } console.log(`Petition ${petitionId} failed to be found at edit-petition`); @@ -23,19 +23,19 @@ module.exports = async (req, res, next) => { } if (!petition) { - return res.status(404).json({ general: 'Petition not found' }); + return res.status(404).json({ general: "Petition not found" }); } - if (petition.state === 'accepted') { - return res.status(400).json({ general: 'Is already accepted' }); + if (petition.state === "accepted") { + return res.status(400).json({ general: "Is already accepted" }); } - if (petition.state === 'canceled') { - return res.status(400).json({ general: 'Is already canceled' }); + if (petition.state === "canceled") { + return res.status(400).json({ general: "Is already canceled" }); } - if (petition.state === 'rejected') { - return res.status(400).json({ general: 'Is already rejected' }); + if (petition.state === "rejected") { + return res.status(400).json({ general: "Is already rejected" }); } const { errors, isValid } = validateEditPetition(req.body); @@ -45,14 +45,14 @@ module.exports = async (req, res, next) => { if (petition.sender.toString() === req.user.id) { isSender = true; - if (req.body.state === 'canceled') { - petition.state = 'canceled'; + if (req.body.state === "canceled") { + petition.state = "canceled"; } else { - return res.status(400).json({ state: 'Should only be canceled' }); + return res.status(400).json({ state: "Should only be canceled" }); } } - if (petition.type.endsWith('event')) { + if (petition.type.endsWith("event")) { let event; try { event = await Event.findOne({ _id: petition.event }); @@ -65,7 +65,7 @@ module.exports = async (req, res, next) => { if (!event) { try { - await petition.remove(); + await Petition.deleteOne({ _id: petitionId }); } catch (err) { console.log( `Petition ${petition.id} failed to be removed at edit-petition` @@ -74,11 +74,11 @@ module.exports = async (req, res, next) => { } return res.status(400).json({ - general: 'Event is already removed. Petition was removed' + general: "Event is already removed. Petition was removed", }); } - if (petition.type === 'invite-team-event') { + if (petition.type === "invite-team-event") { let team; try { team = await Team.findOne({ _id: petition.team }); @@ -91,7 +91,7 @@ module.exports = async (req, res, next) => { if (!team) { try { - await petition.remove(); + await Petition.deleteOne({ _id: petitionId }); } catch (err) { console.log( `Petition ${petition.id} failed to be removed at edit-petition` @@ -100,13 +100,13 @@ module.exports = async (req, res, next) => { } return res.status(400).json({ - general: 'Team is already removed. Petition was removed' + general: "Team is already removed. Petition was removed", }); } if (event.teams.find((t) => t.toString() === team.id)) { try { - await petition.remove(); + await Petition.deleteOne({ _id: petitionId }); } catch (err) { console.log( `Petition ${petition.id} failed to be removed at edit-petition` @@ -116,20 +116,20 @@ module.exports = async (req, res, next) => { return res.status(400).json({ general: - 'Team is already a participant of event. Petition was removed' + "Team is already a participant of event. Petition was removed", }); } if (isSender) { if (!event.managers.find((m) => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); + return res.status(403).json({ general: "Forbidden action" }); } } else { if (!team.managers.find((m) => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); + return res.status(403).json({ general: "Forbidden action" }); } - if (req.body.state === 'accepted') { + if (req.body.state === "accepted") { event.teams = [...event.teams, team.id]; event.updatedAt = moment.utc().toDate(); @@ -154,19 +154,19 @@ module.exports = async (req, res, next) => { return next(err); } - petition.state = 'accepted'; + petition.state = "accepted"; } else { - petition.state = 'rejected'; + petition.state = "rejected"; } } - } else if (petition.type === 'invite-user-event') { + } else if (petition.type === "invite-user-event") { if ( event.participants.find( (p) => p.toString() === petition.user.toString() ) ) { try { - await petition.remove(); + await Petition.deleteOne({ _id: petitionId }); } catch (err) { console.log( `Petition ${petition.id} failed to be removed at edit-petition` @@ -176,20 +176,20 @@ module.exports = async (req, res, next) => { return res.status(400).json({ general: - 'User is already a participant of event. Petition was removed' + "User is already a participant of event. Petition was removed", }); } if (isSender) { if (!event.managers.find((m) => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); + return res.status(403).json({ general: "Forbidden action" }); } } else { if (petition.user.toString() !== req.user.id) { - return res.status(403).json({ general: 'Forbidden action' }); + return res.status(403).json({ general: "Forbidden action" }); } - if (req.body.state === 'accepted') { + if (req.body.state === "accepted") { event.participants = [...event.participants, req.user.id]; event.updatedAt = moment.utc().toDate(); @@ -214,12 +214,12 @@ module.exports = async (req, res, next) => { return next(err); } - petition.state = 'accepted'; + petition.state = "accepted"; } else { - petition.state = 'rejected'; + petition.state = "rejected"; } } - } else if (petition.type === 'request-team-event') { + } else if (petition.type === "request-team-event") { let team; try { team = await Team.findOne({ _id: petition.team }); @@ -232,7 +232,7 @@ module.exports = async (req, res, next) => { if (!team) { try { - await petition.remove(); + await Petition.deleteOne({ _id: petitionId }); } catch (err) { console.log( `Petition ${petition.id} failed to be removed at edit-petition` @@ -241,13 +241,13 @@ module.exports = async (req, res, next) => { } return res.status(400).json({ - general: 'Team is already removed. Petition was removed' + general: "Team is already removed. Petition was removed", }); } if (event.teams.find((t) => t.toString() === team.id)) { try { - await petition.remove(); + await Petition.deleteOne({ _id: petitionId }); } catch (err) { console.log( `Petition ${petition.id} failed to be removed at edit-petition` @@ -257,20 +257,20 @@ module.exports = async (req, res, next) => { return res.status(400).json({ general: - 'Team is already a participant of event. Petition was removed' + "Team is already a participant of event. Petition was removed", }); } if (isSender) { if (!team.managers.find((m) => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); + return res.status(403).json({ general: "Forbidden action" }); } } else { if (!event.managers.find((m) => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); + return res.status(403).json({ general: "Forbidden action" }); } - if (req.body.state === 'accepted') { + if (req.body.state === "accepted") { event.teams = [...event.teams, team.id]; event.updatedAt = moment.utc().toDate(); @@ -295,9 +295,9 @@ module.exports = async (req, res, next) => { return next(err); } - petition.state = 'accepted'; + petition.state = "accepted"; } else { - petition.state = 'rejected'; + petition.state = "rejected"; } } } else { @@ -314,7 +314,7 @@ module.exports = async (req, res, next) => { if (!user) { try { - await petition.remove(); + await Petition.deleteOne({ _id: petitionId }); } catch (err) { console.log( `Petition ${petition.id} failed to be removed at edit-petition` @@ -323,13 +323,13 @@ module.exports = async (req, res, next) => { } return res.status(400).json({ - general: 'User is already removed. Petition was removed' + general: "User is already removed. Petition was removed", }); } if (event.participants.find((p) => p.toString() === user.id)) { try { - await petition.remove(); + await Petition.deleteOne({ _id: petitionId }); } catch (err) { console.log( `Petition ${petition.id} failed to be removed at edit-petition` @@ -339,16 +339,16 @@ module.exports = async (req, res, next) => { return res.status(400).json({ general: - 'User is already a participant of event. Petition was removed' + "User is already a participant of event. Petition was removed", }); } if (!isSender) { if (!event.managers.find((m) => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); + return res.status(403).json({ general: "Forbidden action" }); } - if (req.body.state === 'accepted') { + if (req.body.state === "accepted") { event.participants = [...event.participants, user.id]; event.updatedAt = moment.utc().toDate(); @@ -373,9 +373,9 @@ module.exports = async (req, res, next) => { return next(err); } - petition.state = 'accepted'; + petition.state = "accepted"; } else { - petition.state = 'rejected'; + petition.state = "rejected"; } } } @@ -393,7 +393,7 @@ module.exports = async (req, res, next) => { if (!team) { try { - await petition.remove(); + await Petition.deleteOne({ _id: petitionId }); } catch (err) { console.log( `Petition ${petition.id} failed to be removed at edit-petition` @@ -402,14 +402,14 @@ module.exports = async (req, res, next) => { } return res.status(400).json({ - general: 'Team is already removed. Petition was removed' + general: "Team is already removed. Petition was removed", }); } - if (petition.type === 'invite-user-team') { + if (petition.type === "invite-user-team") { if (team.members.find((m) => m.toString() === petition.user.toString())) { try { - await petition.remove(); + await Petition.deleteOne({ _id: petitionId }); } catch (err) { console.log( `Petition ${petition.id} failed to be removed at edit-petition` @@ -418,20 +418,20 @@ module.exports = async (req, res, next) => { } return res.status(400).json({ - general: 'User is already a member of team. Petition was removed' + general: "User is already a member of team. Petition was removed", }); } if (isSender) { if (!team.managers.find((m) => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); + return res.status(403).json({ general: "Forbidden action" }); } } else { if (petition.user.toString() !== req.user.id) { - return res.status(403).json({ general: 'Forbidden action' }); + return res.status(403).json({ general: "Forbidden action" }); } - if (req.body.state === 'accepted') { + if (req.body.state === "accepted") { team.members = [...team.members, req.user.id]; team.updatedAt = moment.utc().toDate(); @@ -456,9 +456,9 @@ module.exports = async (req, res, next) => { return next(err); } - petition.state = 'accepted'; + petition.state = "accepted"; } else { - petition.state = 'rejected'; + petition.state = "rejected"; } } } else { @@ -476,7 +476,7 @@ module.exports = async (req, res, next) => { if (!user) { try { - await petition.remove(); + await Petition.deleteOne({ _id: petitionId }); } catch (err) { console.log( `Petition ${petition.id} failed to be removed at edit-petition` @@ -485,13 +485,13 @@ module.exports = async (req, res, next) => { } return res.status(400).json({ - general: 'User is already removed. Petition was removed' + general: "User is already removed. Petition was removed", }); } if (team.members.find((m) => m.toString() === user.id)) { try { - await petition.remove(); + await Petition.deleteOne({ _id: petitionId }); } catch (err) { console.log( `Petition ${petition.id} failed to be removed at edit-petition` @@ -500,16 +500,16 @@ module.exports = async (req, res, next) => { } return res.status(400).json({ - general: 'User is already a member of team. Petition was removed' + general: "User is already a member of team. Petition was removed", }); } if (!isSender) { if (!team.managers.find((m) => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); + return res.status(403).json({ general: "Forbidden action" }); } - if (req.body.state === 'accepted') { + if (req.body.state === "accepted") { team.members = [...team.members, user.id]; team.updatedAt = moment.utc().toDate(); @@ -534,9 +534,9 @@ module.exports = async (req, res, next) => { return next(err); } - petition.state = 'accepted'; + petition.state = "accepted"; } else { - petition.state = 'rejected'; + petition.state = "rejected"; } } } @@ -553,5 +553,5 @@ module.exports = async (req, res, next) => { return next(err); } - return res.status(200).json({ general: 'Success' }); + return res.status(200).json({ general: "Success" }); }; diff --git a/src/routes/teams/delete-team.js b/src/routes/teams/delete-team.js index 912b7a1..14e4f76 100644 --- a/src/routes/teams/delete-team.js +++ b/src/routes/teams/delete-team.js @@ -1,12 +1,12 @@ -const moment = require('moment'); +const moment = require("moment"); -const { Event } = require('../../models/event'); -const { Team } = require('../../models/team'); -const { User } = require('../../models/user'); +const { Event } = require("../../models/event"); +const { Team } = require("../../models/team"); +const { User } = require("../../models/user"); module.exports = async (req, res, next) => { if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); + return res.status(423).json({ general: "You are blocked" }); } const teamId = req.params.teamId; @@ -15,8 +15,8 @@ module.exports = async (req, res, next) => { try { team = await Team.findOne({ _id: teamId, isArchived: false }); } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Team not found' }); + if (err.name === "CastError") { + return res.status(404).json({ general: "Team not found" }); } console.log(`Team ${teamId} failed to be found at delete-team`); @@ -24,14 +24,14 @@ module.exports = async (req, res, next) => { } if (!team) { - return res.status(404).json({ general: 'Team not found' }); + return res.status(404).json({ general: "Team not found" }); } if ( !team.managers.find((m) => m.toString() === req.user.id) && !req.user.isAdmin ) { - return res.status(403).json({ general: 'Forbidden action' }); + return res.status(403).json({ general: "Forbidden action" }); } let archiveTeam = false; @@ -45,13 +45,13 @@ module.exports = async (req, res, next) => { try { teamEvents = await Promise.all(teamEventsPromises); } catch (err) { - console.log('A team event failed to be found at delete-team'); + console.log("A team event failed to be found at delete-team"); return next(err); } for (const event of teamEvents) { const endDate = moment(event.endDate).utc(); - const endOfToday = moment.utc().endOf('day'); + const endOfToday = moment.utc().endOf("day"); if (endDate.isBefore(endOfToday)) { event.teams = event.teams.filter((t) => t.toString() !== team.id); event.updatedAt = moment.utc().toDate(); @@ -76,7 +76,7 @@ module.exports = async (req, res, next) => { try { teamMembers = await Promise.all(teamMembersPromises); } catch (err) { - console.log('A team member failed to be found at delete-team'); + console.log("A team member failed to be found at delete-team"); return next(err); } @@ -104,12 +104,12 @@ module.exports = async (req, res, next) => { } } else { try { - await team.remove(); + await Team.deleteOne({ _id: teamId, isArchived: false }); } catch (err) { console.log(`Team ${team.id} failed to be removed at delete-team`); return next(err); } } - return res.status(204).json({ general: 'Success' }); + return res.status(204).json({ general: "Success" }); }; diff --git a/src/routes/teams/join-team.js b/src/routes/teams/join-team.js index c2de2e4..e847fa4 100644 --- a/src/routes/teams/join-team.js +++ b/src/routes/teams/join-team.js @@ -1,5 +1,5 @@ -const { Petition } = require('../../models/petition'); -const { Team } = require('../../models/team'); +const { Petition } = require("../../models/petition"); +const { Team } = require("../../models/team"); module.exports = async (req, res, next) => { const teamId = req.params.teamId; @@ -8,8 +8,8 @@ module.exports = async (req, res, next) => { try { team = await Team.findOne({ _id: teamId, isArchived: false }); } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Team not found' }); + if (err.name === "CastError") { + return res.status(404).json({ general: "Team not found" }); } console.log(`Team ${teamId} failed to be found at join-team`); @@ -17,21 +17,21 @@ module.exports = async (req, res, next) => { } if (!team) { - return res.status(404).json({ general: 'Team not found' }); + return res.status(404).json({ general: "Team not found" }); } const eventMembers = team.members.map((m) => m.toString()); if (eventMembers.includes(req.user.id)) { return res .status(400) - .json({ general: 'You already are a member in this team' }); + .json({ general: "You already are a member in this team" }); } const eventManagers = team.managers.map((m) => m.toString()); if (eventManagers.includes(req.user.id)) { return res .status(400) - .json({ general: 'You already are a member in this team' }); + .json({ general: "You already are a member in this team" }); } let petition; @@ -39,7 +39,7 @@ module.exports = async (req, res, next) => { petition = await Petition.findOne({ team: team.id, sender: req.user.id, - type: 'request-user-team' + type: "request-user-team", }); } catch (err) { console.log( @@ -50,18 +50,22 @@ module.exports = async (req, res, next) => { return next(err); } - if (petition && petition.state === 'pending') { + if (petition && petition.state === "pending") { return res.status(400).json({ - general: 'You already have a pending petition with this team' + general: "You already have a pending petition with this team", }); } if ( petition && - (petition.state === 'rejected' || petition.state === 'canceled') + (petition.state === "rejected" || petition.state === "canceled") ) { try { - await petition.remove(); + await Petition.deleteOne({ + team: team.id, + sender: req.user.id, + type: "request-user-team", + }); } catch (err) { console.log(`Petition ${petition.id} failed to be removed at join-team`); return next(err); @@ -71,12 +75,12 @@ module.exports = async (req, res, next) => { const petitionData = { team: team.id, sender: req.user.id, - type: 'request-user-team' + type: "request-user-team", }; try { await Petition.create(petitionData); } catch (err) { - if (typeof err.errors === 'object') { + if (typeof err.errors === "object") { const validationErrors = {}; Object.keys(err.errors).forEach((key) => { @@ -94,5 +98,5 @@ module.exports = async (req, res, next) => { return next(err); } - return res.status(200).json({ general: 'Requested' }); + return res.status(200).json({ general: "Requested" }); }; diff --git a/src/routes/users/archive-user.js b/src/routes/users/archive-user.js index 4d19eba..9bf62e2 100644 --- a/src/routes/users/archive-user.js +++ b/src/routes/users/archive-user.js @@ -1,9 +1,9 @@ -const moment = require('moment'); +const moment = require("moment"); -const { ActivationTicket } = require('../../models/activation-ticket'); -const { PasswordTicket } = require('../../models/password-ticket'); -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); +const { ActivationTicket } = require("../../models/activation-ticket"); +const { PasswordTicket } = require("../../models/password-ticket"); +const { RefreshToken } = require("../../models/refresh-token"); +const { User } = require("../../models/user"); module.exports = async (req, res, next) => { const userId = req.params.userId; @@ -12,8 +12,8 @@ module.exports = async (req, res, next) => { try { user = await User.findOne({ _id: userId, isArchived: false }); } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'User not found' }); + if (err.name === "CastError") { + return res.status(404).json({ general: "User not found" }); } console.log(`User with Id ${userId} failed to be found at archive-user.`); @@ -21,11 +21,11 @@ module.exports = async (req, res, next) => { } if (!user) { - return res.status(404).json({ general: 'User not found' }); + return res.status(404).json({ general: "User not found" }); } if (user.id !== req.user.id && !req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); + return res.status(403).json({ general: "Forbidden action" }); } let activateAccountTicket; @@ -35,7 +35,7 @@ module.exports = async (req, res, next) => { [activateAccountTicket, passwordTicket, refreshToken] = await Promise.all([ ActivationTicket.findOne({ email: user.email }), PasswordTicket.findOne({ email: user.email }), - RefreshToken.findOne({ userId: user.id }) + RefreshToken.findOne({ userId: user.id }), ]); } catch (err) { console.log( @@ -48,7 +48,7 @@ module.exports = async (req, res, next) => { if (activateAccountTicket) { try { - await activateAccountTicket.remove(); + await ActivationTicket.deleteOne({ email: user.email }); } catch (err) { console.log( `Activate user ticket with key ${ @@ -61,7 +61,7 @@ module.exports = async (req, res, next) => { if (passwordTicket) { try { - await passwordTicket.remove(); + await PasswordTicket.deleteOne({ email: user.email }); } catch (err) { console.log( `Password ticket with key ${ @@ -74,7 +74,7 @@ module.exports = async (req, res, next) => { if (refreshToken) { try { - await refreshToken.remove(); + await RefreshToken.deleteOne({ userId: user.id }); } catch (err) { console.log( `Refresh token with key ${ @@ -97,5 +97,5 @@ module.exports = async (req, res, next) => { return next(err); } - return res.status(200).json({ general: 'Success' }); + return res.status(200).json({ general: "Success" }); }; diff --git a/src/routes/users/change-password.js b/src/routes/users/change-password.js index 2c88231..db7dbed 100644 --- a/src/routes/users/change-password.js +++ b/src/routes/users/change-password.js @@ -1,12 +1,12 @@ -const moment = require('moment'); +const moment = require("moment"); -const { RefreshToken } = require('../../models/refresh-token'); +const { RefreshToken } = require("../../models/refresh-token"); -const { validateChangePassword } = require('./validations'); +const { validateChangePassword } = require("./validations"); module.exports = async (req, res, next) => { if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); + return res.status(423).json({ general: "You are blocked" }); } const { errors, isValid } = validateChangePassword(req.body); @@ -20,7 +20,7 @@ module.exports = async (req, res, next) => { const passwordMatches = req.user.comparePassword(oldPassword); if (!passwordMatches) { - return res.status(400).json({ oldPassword: 'Wrong password' }); + return res.status(400).json({ oldPassword: "Wrong password" }); } let refreshToken; @@ -37,7 +37,7 @@ module.exports = async (req, res, next) => { if (refreshToken) { try { - await refreshToken.remove(); + await RefreshToken.deleteOne({ userId: req.user.id }); } catch (err) { console.log( `Refresh Token with key ${ @@ -60,5 +60,5 @@ module.exports = async (req, res, next) => { return next(err); } - return res.status(200).json({ general: 'Success' }); + return res.status(200).json({ general: "Success" }); }; diff --git a/src/routes/users/deactivate-user.js b/src/routes/users/deactivate-user.js index 880289f..642930a 100644 --- a/src/routes/users/deactivate-user.js +++ b/src/routes/users/deactivate-user.js @@ -1,9 +1,9 @@ -const moment = require('moment'); +const moment = require("moment"); -const { ActivationTicket } = require('../../models/activation-ticket'); -const { PasswordTicket } = require('../../models/password-ticket'); -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); +const { ActivationTicket } = require("../../models/activation-ticket"); +const { PasswordTicket } = require("../../models/password-ticket"); +const { RefreshToken } = require("../../models/refresh-token"); +const { User } = require("../../models/user"); module.exports = async (req, res, next) => { const userId = req.user._id; @@ -12,8 +12,8 @@ module.exports = async (req, res, next) => { try { user = await User.findOne({ _id: userId, isArchived: false }); } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'User not found' }); + if (err.name === "CastError") { + return res.status(404).json({ general: "User not found" }); } console.log(`User with Id ${userId} failed to be found at archive-user.`); @@ -21,7 +21,7 @@ module.exports = async (req, res, next) => { } if (!user) { - return res.status(404).json({ general: 'User not found' }); + return res.status(404).json({ general: "User not found" }); } let activateAccountTicket; @@ -31,7 +31,7 @@ module.exports = async (req, res, next) => { [activateAccountTicket, passwordTicket, refreshToken] = await Promise.all([ ActivationTicket.findOne({ email: user.email }), PasswordTicket.findOne({ email: user.email }), - RefreshToken.findOne({ userId: user.id }) + RefreshToken.findOne({ userId: user.id }), ]); } catch (err) { console.log( @@ -44,7 +44,7 @@ module.exports = async (req, res, next) => { if (activateAccountTicket) { try { - await activateAccountTicket.remove(); + await ActivationTicket.deleteOne({ email: user.email }); } catch (err) { console.log( `Activate user ticket with key ${ @@ -57,7 +57,7 @@ module.exports = async (req, res, next) => { if (passwordTicket) { try { - await passwordTicket.remove(); + await PasswordTicket.deleteOne({ email: user.email }); } catch (err) { console.log( `Password ticket with key ${ @@ -70,7 +70,7 @@ module.exports = async (req, res, next) => { if (refreshToken) { try { - await refreshToken.remove(); + await RefreshToken.deleteOne({ userId: user.id }); } catch (err) { console.log( `Refresh token with key ${ @@ -93,5 +93,5 @@ module.exports = async (req, res, next) => { return next(err); } - return res.status(200).json({ general: 'Success' }); + return res.status(200).json({ general: "Success" }); }; diff --git a/src/routes/users/delete-user.js b/src/routes/users/delete-user.js index 401e7e4..6b32ce3 100644 --- a/src/routes/users/delete-user.js +++ b/src/routes/users/delete-user.js @@ -1,8 +1,8 @@ -const { User } = require('../../models/user'); +const { User } = require("../../models/user"); module.exports = async (req, res, next) => { if (!req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); + return res.status(403).json({ general: "Forbidden action" }); } const userId = req.params.userId; @@ -11,8 +11,8 @@ module.exports = async (req, res, next) => { try { user = await User.findOne({ _id: userId, isArchived: true }); } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Archived user not found' }); + if (err.name === "CastError") { + return res.status(404).json({ general: "Archived user not found" }); } console.log(`User with Id ${userId} failed to be found at delete-user.`); @@ -20,11 +20,11 @@ module.exports = async (req, res, next) => { } if (!user) { - return res.status(404).json({ general: 'Archived user not found' }); + return res.status(404).json({ general: "Archived user not found" }); } try { - await user.remove(); + await User.deleteOne({ _id: userId, isArchived: true }); } catch (err) { console.log( `User with email ${user.email} failed to be deleted at delete-user.` @@ -32,5 +32,5 @@ module.exports = async (req, res, next) => { return next(err); } - return res.status(204).json({ general: 'Success' }); + return res.status(204).json({ general: "Success" }); }; diff --git a/src/scripts/db/update-events-locations.js b/src/scripts/db/update-events-locations.js index ead1a7f..f5e2455 100644 --- a/src/scripts/db/update-events-locations.js +++ b/src/scripts/db/update-events-locations.js @@ -1,10 +1,10 @@ -const axios = require('axios'); -const mongoose = require('mongoose'); +const axios = require("axios"); +const mongoose = require("mongoose"); -require('dotenv').config(); +require("dotenv").config(); -const { eventSchema } = require('../../models/event'); -const { venueSchema } = require('../../models/venue'); +const { eventSchema } = require("../../models/event"); +const { venueSchema } = require("../../models/venue"); mongoose.Promise = global.Promise; @@ -23,21 +23,21 @@ const uri = process.env.MONGODB_URI; const options = { useMongoClient: true, socketTimeoutMS: 0, - keepAlive: 2000 + keepAlive: 2000, }; const db = mongoose.createConnection(uri, options); -db.on('connected', async () => { - console.log('Connection to DB established successfully'); +db.on("connected", async () => { + console.log("Connection to DB established successfully"); - const Event = db.model('Event', eventSchema); - const Venue = db.model('Venue', venueSchema); + const Event = db.model("Event", eventSchema); + const Venue = db.model("Venue", venueSchema); let totalEvents; try { totalEvents = await Event.count(); } catch (error) { - console.log('Events failed to be count'); + console.log("Events failed to be count"); console.log(error); await closeConnections(db); } @@ -54,7 +54,7 @@ db.on('connected', async () => { .skip(page * pageLimit) .limit(pageLimit); } catch (error) { - console.log('Events failed to be found'); + console.log("Events failed to be found"); console.log(error); await closeConnections(db); } @@ -66,7 +66,7 @@ db.on('connected', async () => { try { venues = await Promise.all(getVenues); } catch (err) { - console.log('Venues failed to be found'); + console.log("Venues failed to be found"); console.log(err); await closeConnections(db); } @@ -86,7 +86,7 @@ db.on('connected', async () => { try { places = await Promise.all(getPlaces); } catch (err) { - console.log('Places failed to be found'); + console.log("Places failed to be found"); console.log(err); await closeConnections(db); } @@ -106,7 +106,7 @@ db.on('connected', async () => { updateEvents.push(event.save()); } else { const event = events[i]; - removeEvents.push(event.remove()); + removeEvents.push(Event.deleteOne({ _id: event?._id })); } }); try { @@ -115,14 +115,14 @@ db.on('connected', async () => { console.log( `Events failed to be updated.\nData: ${JSON.stringify({ page, - i + i, })}` ); console.log(err); await closeConnections(db); } - console.log('Events updated'); + console.log("Events updated"); page = page + 1; i = i + events.length; @@ -131,7 +131,7 @@ db.on('connected', async () => { try { totalEvents = await Event.count(); } catch (error) { - console.log('Events failed to be count'); + console.log("Events failed to be count"); console.log(error); await closeConnections(db); } @@ -140,11 +140,11 @@ db.on('connected', async () => { await closeConnections(db); }); -db.on('error', (err) => { - console.log('Connection to DB failed ' + err); +db.on("error", (err) => { + console.log("Connection to DB failed " + err); process.exit(0); }); -db.on('disconnected', () => { - console.log('Connection from DB closed'); +db.on("disconnected", () => { + console.log("Connection from DB closed"); }); From 05cb0dab85a57970acb710ab0125257e6243351b Mon Sep 17 00:00:00 2001 From: abdul-rehman90 <> Date: Wed, 2 Apr 2025 19:06:50 +0500 Subject: [PATCH 14/67] replace remove function with delete one --- src/routes/petitions/create-petition.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/petitions/create-petition.js b/src/routes/petitions/create-petition.js index dc270d9..69a8474 100644 --- a/src/routes/petitions/create-petition.js +++ b/src/routes/petitions/create-petition.js @@ -131,7 +131,7 @@ module.exports = async (req, res, next) => { (petition.state === "rejected" || petition.state === "canceled") ) { try { - await Petition.findOne({ + await Petition.deleteOne({ event: data.event, type: data.type, user: data.user, From 26a4ae165189a7abfaad1c0ce3ec6dbc745fb9f9 Mon Sep 17 00:00:00 2001 From: abdul-rehman90 <> Date: Mon, 7 Apr 2025 19:24:27 +0500 Subject: [PATCH 15/67] resolve activation account issue --- src/routes/auth/sign-up.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/auth/sign-up.js b/src/routes/auth/sign-up.js index b31b6b6..15acf14 100644 --- a/src/routes/auth/sign-up.js +++ b/src/routes/auth/sign-up.js @@ -134,8 +134,8 @@ module.exports = async (req, res, next) => {To activate your account use the link below:
Stay awesome.
From 249e8e4441fb7e2fa493af99c1199a331b214e81 Mon Sep 17 00:00:00 2001 From: abdul-rehman90 <> Date: Wed, 9 Apr 2025 23:49:18 +0500 Subject: [PATCH 16/67] new fields added in user model lastLocation lastActivityTime and device --- src/helpers/index.js | 62 ++++++++++++++++++++++++-------------- src/models/user.js | 22 ++++++++++++++ src/routes/venues/index.js | 16 +++++----- 3 files changed, 70 insertions(+), 30 deletions(-) diff --git a/src/helpers/index.js b/src/helpers/index.js index 94f26fc..a401165 100644 --- a/src/helpers/index.js +++ b/src/helpers/index.js @@ -1,15 +1,15 @@ -const aws = require('aws-sdk'); -const { camelCase } = require('lodash'); -const jwt = require('jsonwebtoken'); -const { mapKeys, pickBy } = require('lodash'); -const nodemailer = require('nodemailer'); -const { snakeCase } = require('lodash'); +const aws = require("aws-sdk"); +const { camelCase } = require("lodash"); +const jwt = require("jsonwebtoken"); +const { mapKeys, pickBy } = require("lodash"); +const nodemailer = require("nodemailer"); +const { snakeCase } = require("lodash"); -const { User } = require('../models/user'); +const { User } = require("../models/user"); module.exports = { cleanSpaces(string) { - return string.replace(/\s+/g, ' ').trim(); + return string.replace(/\s+/g, " ").trim(); }, deleteUnusedProperties(obj) { return pickBy(obj, (prop) => prop); @@ -18,10 +18,13 @@ module.exports = { ({ isOptional }) => async (req, res, next) => { const authorizationHeader = req.headers.authorization; + const deviceType = req.headers["x-device-type"]; + const userAgent = req.headers["user-agent"]; + let token; if (authorizationHeader) { - token = authorizationHeader.split(' ')[1]; + token = authorizationHeader.split(" ")[1]; } if (token) { @@ -30,17 +33,32 @@ module.exports = { decoded = await jwt.verify(token, process.env.JWT_SECRET); } catch (err) { console.log(err); - return res.status(401).json({ general: 'Failed to authenticate' }); + return res.status(401).json({ general: "Failed to authenticate" }); } let user; try { user = await User.findOne({ _id: decoded.userId, - isArchived: false + isArchived: false, }).select( - '-__v -createdAt -isAdmin -isArchived -isBlocked -hashedPassword -updatedAt' + "-__v -createdAt -isAdmin -isArchived -isBlocked -hashedPassword -updatedAt" ); + if (req.originalUrl.startsWith("/venues?") && req.method === "GET") { + const location = req.query.location; + if (location) { + const [lat, lng] = location + .split(",") + .map((coord) => coord.trim()); + user.lastLocation = { + lat, + lng, + }; + } + } + user.lastActivityTime = new Date().toISOString(); + user.device = deviceType || userAgent || ""; + user.save(); } catch (err) { console.log( `User ${decoded.userId} failed to be found at authenticate` @@ -55,20 +73,20 @@ module.exports = { (isOptional && req.user && req.user.isBlocked) || (!isOptional && req.user.isBlocked) ) { - return res.status(423).json({ general: 'You are blocked' }); + return res.status(423).json({ general: "You are blocked" }); } return next(); } - return res.status(404).json({ general: 'User not found' }); + return res.status(404).json({ general: "User not found" }); } if (isOptional) { return next(); } - return res.status(401).json({ general: 'No token provided' }); + return res.status(401).json({ general: "No token provided" }); }, isNumber(number) { return !isNaN(parseFloat(number)) && isFinite(number); @@ -80,30 +98,30 @@ module.exports = { return mapKeys(obj, (value, key) => snakeCase(key)); }, removeSpaces(string) { - return string.replace(/\s/g, ''); + return string.replace(/\s/g, ""); }, sendEmail({ senderEmail = process.env.SENDER_EMAIL, receiversEmails, subject, htmlContent, - textContent + textContent, }) { const transporter = nodemailer.createTransport({ SES: new aws.SES({ - apiVersion: '2010-12-01' - }) + apiVersion: "2010-12-01", + }), }); return transporter.sendMail({ from: `"AXS Map" <${senderEmail}>`, - to: receiversEmails.join(', '), + to: receiversEmails.join(", "), subject, text: textContent, - html: htmlContent + html: htmlContent, }); }, toJSON(obj) { return JSON.parse(JSON.stringify(obj)); - } + }, }; diff --git a/src/models/user.js b/src/models/user.js index 84971d1..d9cfe87 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -129,6 +129,28 @@ const userSchema = new mongoose.Schema( default: false, required: [true, "Is required"], }, + lastActivityTime: { + type: Date, + default: null, + }, + lastLocation: { + type: { + lat: { + type: Number, + }, + lng: { + type: Number, + }, + }, + default: { + lat: null, + lng: null, + }, + }, + device: { + type: String, + default: "", + }, showEmail: { type: Boolean, default: false, diff --git a/src/routes/venues/index.js b/src/routes/venues/index.js index 94fec3d..a66f887 100644 --- a/src/routes/venues/index.js +++ b/src/routes/venues/index.js @@ -1,17 +1,17 @@ -const express = require('express'); +const express = require("express"); -const { isAuthenticated } = require('../../helpers'); +const { isAuthenticated } = require("../../helpers"); -const archiveVenue = require('./archive-venue'); -const getVenue = require('./get-venue'); -const listVenues = require('./list-venues'); +const archiveVenue = require("./archive-venue"); +const getVenue = require("./get-venue"); +const listVenues = require("./list-venues"); const router = new express.Router(); -router.get('', listVenues); -router.get('/:placeId', getVenue); +router.get("", isAuthenticated({ isOptional: true }), listVenues); +router.get("/:placeId", getVenue); router.put( - '/:venueId/archive', + "/:venueId/archive", isAuthenticated({ isOptional: false }), archiveVenue ); From e5ed491acd99c0568decafcb5fe914286db51893 Mon Sep 17 00:00:00 2001 From: abdul-rehman90 <> Date: Thu, 10 Apr 2025 18:23:08 +0500 Subject: [PATCH 17/67] upComing mapathons added --- src/routes/events/index.js | 2 + src/routes/events/list-upcoimg-events.js | 77 ++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 src/routes/events/list-upcoimg-events.js diff --git a/src/routes/events/index.js b/src/routes/events/index.js index 33728d3..c64a0b3 100644 --- a/src/routes/events/index.js +++ b/src/routes/events/index.js @@ -10,11 +10,13 @@ const leaveEvent = require("./leave-event"); const listEvents = require("./list-events"); const listOldEvents = require("./list-old-events"); const joinEvent = require("./join-event"); +const listUpcoimgEvents = require("./list-upcoimg-events"); const router = new express.Router(); router.get("", listEvents); router.get("/old", isAuthenticated({ isOptional: false }), listOldEvents); +router.get("/upComing", listUpcoimgEvents); router.post("", isAuthenticated({ isOptional: false }), createEvent); router.get("/:eventId", getEvent); router.put("/:eventId", isAuthenticated({ isOptional: false }), editEvent); diff --git a/src/routes/events/list-upcoimg-events.js b/src/routes/events/list-upcoimg-events.js new file mode 100644 index 0000000..e2ef12d --- /dev/null +++ b/src/routes/events/list-upcoimg-events.js @@ -0,0 +1,77 @@ +const moment = require("moment"); + +const { Event } = require("../../models/event"); + +const { validateListEvents } = require("./validations"); + +module.exports = async (req, res, next) => { + const queryParams = req.query; + + const { errors, isValid } = validateListEvents(queryParams); + if (!isValid) return res.status(400).json(errors); + + const eventsQuery = {}; + + if (queryParams.keywords && queryParams.keywords !== "") { + eventsQuery.$text = { $search: queryParams.keywords }; + } + + eventsQuery.isArchived = false; + + let sortBy = "-startDate"; + let page = queryParams.page ? queryParams.page - 1 : 0; + const pageLimit = queryParams.pageLimit || 12; + const currentDate = moment().startOf("day").utc().toDate(); + + eventsQuery.startDate = { $gte: currentDate }; + + let events; + let total; + try { + [events, total] = await Promise.all([ + Event.aggregate() + .match(eventsQuery) + .project({ + _id: 0, + id: "$_id", + address: 1, + endDate: 1, + name: 1, + poster: 1, + reviewsAmount: 1, + reviewsGoal: 1, + startDate: 1, + location: 1, + description: 1, + }) + .sort(sortBy) + .skip(page * pageLimit) + .limit(pageLimit), + Event.countDocuments(eventsQuery), + ]); + } catch (err) { + console.log("Events failed to be found or count at list-events"); + return next(err); + } + + let lastPage = Math.ceil(total / pageLimit); + if (lastPage > 0) { + if (page > lastPage) { + return res + .status(400) + .json({ page: `Should be equal to or less than ${lastPage}` }); + } + } else { + page = null; + lastPage = null; + } + console.log(events); + return res.status(200).json({ + page: page + 1, + lastPage, + pageLimit, + total, + sortBy, + results: events, + }); +}; From e8474111be7fa6d8a3264032b5677ebd0df5cb49 Mon Sep 17 00:00:00 2001 From: abdul-rehman90 <> Date: Tue, 22 Apr 2025 21:34:34 +0500 Subject: [PATCH 18/67] change review logic --- src/helpers/mail-template.js | 52 +++ src/helpers/venue-review-summary.js | 131 +++++-- src/models/activation-ticket.js | 27 +- src/models/review.js | 73 ++-- src/models/user.js | 3 + src/models/venue.js | 30 ++ src/routes/auth/sign-in.js | 4 +- src/routes/auth/sign-up.js | 16 +- src/routes/auth/validations.js | 1 + src/routes/reviews/create-review.js | 523 +++++++++++++++------------- src/routes/reviews/validations.js | 7 - src/routes/users/edit-user.js | 2 + src/routes/users/get-profile.js | 2 +- src/routes/venues/list-venues.js | 73 ++-- 14 files changed, 587 insertions(+), 357 deletions(-) create mode 100644 src/helpers/mail-template.js diff --git a/src/helpers/mail-template.js b/src/helpers/mail-template.js new file mode 100644 index 0000000..402e636 --- /dev/null +++ b/src/helpers/mail-template.js @@ -0,0 +1,52 @@ +export const activationEmailTemplate = (link,name) => { + return ` + + + +| + + | +
- If you didn’t sign up for [Your App Name], no worries — you can safely ignore this email. + If you didn’t sign up for AXS Map, no worries — you can safely ignore this email.
diff --git a/src/routes/auth/forgotten-password.js b/src/routes/auth/forgotten-password.js index c782c05..7e4c61b 100644 --- a/src/routes/auth/forgotten-password.js +++ b/src/routes/auth/forgotten-password.js @@ -49,14 +49,8 @@ module.exports = async (req, res, next) => { try { passwordTicket = await PasswordTicket.create({ email, expiresAt, key }); } catch (err) { - console.log( - `Password ticket failed to be created at forgotten-password.\nData: ${JSON.stringify( - { email, expiresAt, key } - )}` - ); return next(err); } - console.log(passwordTicket); const htmlContent = `To activate your account use the link below:
-Stay awesome.
- `; const textContent = ` Welcome to AXS Map! To activate your account use the link below: diff --git a/src/routes/reviews/create-review.js b/src/routes/reviews/create-review.js index 211c6ba..56619e3 100644 --- a/src/routes/reviews/create-review.js +++ b/src/routes/reviews/create-review.js @@ -50,7 +50,6 @@ module.exports = async (req, res, next) => { comments: req.body.comments, }; - console.log(data); let event; if (data.event) { From fe7d14c004d87e0d3214424fc43fa60c932297c4 Mon Sep 17 00:00:00 2001 From: abdul-rehman90 <> Date: Thu, 19 Jun 2025 17:28:17 +0500 Subject: [PATCH 42/67] fix google login for mobile --- src/routes/auth/facebook-sign-in.js | 68 ++++++++++++++++------------- src/routes/auth/google-sign-in.js | 13 +++--- 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/src/routes/auth/facebook-sign-in.js b/src/routes/auth/facebook-sign-in.js index e12fe2a..949ad89 100644 --- a/src/routes/auth/facebook-sign-in.js +++ b/src/routes/auth/facebook-sign-in.js @@ -3,8 +3,6 @@ const crypto = require("crypto"); const axios = require("axios"); const jwt = require("jsonwebtoken"); const moment = require("moment"); -const randomstring = require("randomstring"); -const slugify = require("speakingurl"); const { RefreshToken } = require("../../models/refresh-token"); const { User } = require("../../models/user"); @@ -27,42 +25,50 @@ module.exports = async (req, res, next) => { }); const fbUser = fbUserResponse.data; + if (fbUser.email) { + const email = fbUser.email; - const email = fbUser.email || "No email available"; + let user = await User.findOne({ facebookId: fbUser.id }); - let user = await User.findOne({ facebookId: fbUser.id }); + const [firstName, lastName] = fbUser.name.split(" "); - const [firstName, lastName] = fbUser.name.split(" "); + if (!user) { + user = new User({ + fbId: fbUser.id, + email, + firstName: firstName || "", + lastName: lastName || "", + picture: fbUser.picture.data.url, + }); - if (!user) { - user = new User({ - fbId: fbUser.id, - email, - firstName: firstName || "", - lastName: lastName || "", - picture: fbUser.picture.data.url, + await user.save(); + } + const userId = user._id; + const today = moment.utc(); + const expiresAt = today.add(30, "days").toDate(); + const key = `${userId}${crypto.randomBytes(28).toString("hex")}`; + + let refreshToken = await RefreshToken.findOneAndUpdate( + { userId }, + { expiresAt, key, userId }, + { new: true, setDefaultsOnInsert: true, upsert: true } + ); + const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET, { + expiresIn: "30d", }); - await user.save(); + res.json({ + refreshToken: refreshToken.key, + token, + }); + } else { + res + .status(400) + .json({ + success: false, + error: "Email is not linked with this account", + }); } - const userId = user._id; - const today = moment.utc(); - const expiresAt = today.add(30, "days").toDate(); - const key = `${userId}${crypto.randomBytes(28).toString("hex")}`; - - let refreshToken = await RefreshToken.findOneAndUpdate( - { userId }, - { expiresAt, key, userId }, - { new: true, setDefaultsOnInsert: true, upsert: true } - ); - const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET, { - expiresIn: "30d", - }); - - res.json({ - refreshToken: refreshToken.key, - token, - }); } catch (err) { res.status(401).json({ success: false, error: "Invalid Facebook token" }); } diff --git a/src/routes/auth/google-sign-in.js b/src/routes/auth/google-sign-in.js index 17e86ac..5ea383b 100644 --- a/src/routes/auth/google-sign-in.js +++ b/src/routes/auth/google-sign-in.js @@ -23,18 +23,17 @@ module.exports = async (req, res) => { return res.status(400).json(errors); } + const code = req.body.code; - const oauth2Client = new OAuth2Client(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI); + const oauth2Client = new OAuth2Client(CLIENT_ID); try { - const { tokens } = await oauth2Client.getToken(code); - oauth2Client.setCredentials(tokens); const ticket = await oauth2Client.verifyIdToken({ - idToken: tokens.id_token, + idToken: code, audience: CLIENT_ID, }); const payload = ticket.getPayload(); - const { sub: googleId, email, name, picture } = payload; + const { email, name, picture } = payload; const [firstName, lastName] = name.split(" "); @@ -45,6 +44,7 @@ module.exports = async (req, res) => { firstName: firstName || name, lastName: lastName || "", createdAt: new Date(), + avatar:picture }); await user.save(); } @@ -69,6 +69,7 @@ module.exports = async (req, res) => { refreshToken: refreshToken.key, }); } catch (err) { - return res.status(401).json({ error: "Invalid ID token" }); + console.log(err) + return res.status(500).json({ error: "Something went wrong" }); } }; From 22f49e22ac5e845915ff004a93b5da790da2b7a5 Mon Sep 17 00:00:00 2001 From: abdul-rehman90 <> Date: Sat, 21 Jun 2025 02:25:11 +0500 Subject: [PATCH 43/67] google env updates --- src/routes/auth/google-sign-in.js | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/routes/auth/google-sign-in.js b/src/routes/auth/google-sign-in.js index 5ea383b..8b2e992 100644 --- a/src/routes/auth/google-sign-in.js +++ b/src/routes/auth/google-sign-in.js @@ -14,8 +14,6 @@ const { User } = require("../../models/user"); const { validateGoogleSignIn } = require("./validations"); const CLIENT_ID = process.env.GOOGLE_CLIENT_ID; -const CLIENT_SECRET = process.env.GOOGLE_CLIENT_SECRET; -const REDIRECT_URI = process.env.GOOGLE_REDIRECT_URI; module.exports = async (req, res) => { const { errors, isValid } = validateGoogleSignIn(req.body); @@ -23,12 +21,27 @@ module.exports = async (req, res) => { return res.status(400).json(errors); } - - const code = req.body.code; + let token = req.body.code; const oauth2Client = new OAuth2Client(CLIENT_ID); try { + const deviceType = req.headers["x-device-type"]; + if (deviceType === "web") { + const tokenRes = await fetch("https://oauth2.googleapis.com/token", { + method: "POST", + headers: { "Content-Type": "application/x-www-form-urlencoded" }, + body: new URLSearchParams({ + code: token, + client_id: process.env.GOOGLE_CLIENT_ID, + client_secret: process.env.GOOGLE_CLIENT_SECRET, + redirect_uri: process.env.GOOGLE_REDIRECT_URI, + grant_type: "authorization_code", + }), + }); + token = await tokenRes.json(); + } + const ticket = await oauth2Client.verifyIdToken({ - idToken: code, + idToken: token, audience: CLIENT_ID, }); @@ -44,7 +57,7 @@ module.exports = async (req, res) => { firstName: firstName || name, lastName: lastName || "", createdAt: new Date(), - avatar:picture + avatar: picture, }); await user.save(); } @@ -69,7 +82,7 @@ module.exports = async (req, res) => { refreshToken: refreshToken.key, }); } catch (err) { - console.log(err) + console.log(err); return res.status(500).json({ error: "Something went wrong" }); } }; From 569871b43d5d1de7e1c41850cf717d69b8375c16 Mon Sep 17 00:00:00 2001 From: abdul-rehman90 <> Date: Sat, 21 Jun 2025 02:31:44 +0500 Subject: [PATCH 44/67] google env updates --- src/routes/auth/google-sign-in.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/routes/auth/google-sign-in.js b/src/routes/auth/google-sign-in.js index 8b2e992..ef84ab5 100644 --- a/src/routes/auth/google-sign-in.js +++ b/src/routes/auth/google-sign-in.js @@ -25,6 +25,7 @@ module.exports = async (req, res) => { const oauth2Client = new OAuth2Client(CLIENT_ID); try { const deviceType = req.headers["x-device-type"]; + console.log(deviceType === "web",deviceType) if (deviceType === "web") { const tokenRes = await fetch("https://oauth2.googleapis.com/token", { method: "POST", From cd5f496c6caf0982fc46965db2983421abeb0724 Mon Sep 17 00:00:00 2001 From: abdul-rehman90 <> Date: Sat, 21 Jun 2025 02:33:29 +0500 Subject: [PATCH 45/67] google env updates --- src/routes/auth/google-sign-in.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/routes/auth/google-sign-in.js b/src/routes/auth/google-sign-in.js index ef84ab5..b3624b4 100644 --- a/src/routes/auth/google-sign-in.js +++ b/src/routes/auth/google-sign-in.js @@ -21,7 +21,7 @@ module.exports = async (req, res) => { return res.status(400).json(errors); } - let token = req.body.code; + let code = req.body.code; const oauth2Client = new OAuth2Client(CLIENT_ID); try { const deviceType = req.headers["x-device-type"]; @@ -38,11 +38,11 @@ module.exports = async (req, res) => { grant_type: "authorization_code", }), }); - token = await tokenRes.json(); + code = await tokenRes.json(); } const ticket = await oauth2Client.verifyIdToken({ - idToken: token, + idToken: code, audience: CLIENT_ID, }); From 6479dec9a9c91edefe39569fe7fc60efd6c8cdac Mon Sep 17 00:00:00 2001 From: abdul-rehman90 <> Date: Sat, 21 Jun 2025 02:35:42 +0500 Subject: [PATCH 46/67] google env updates --- src/routes/auth/google-sign-in.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/auth/google-sign-in.js b/src/routes/auth/google-sign-in.js index b3624b4..8dd0554 100644 --- a/src/routes/auth/google-sign-in.js +++ b/src/routes/auth/google-sign-in.js @@ -31,7 +31,7 @@ module.exports = async (req, res) => { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: new URLSearchParams({ - code: token, + code, client_id: process.env.GOOGLE_CLIENT_ID, client_secret: process.env.GOOGLE_CLIENT_SECRET, redirect_uri: process.env.GOOGLE_REDIRECT_URI, From 95253e27d27cbb9e3fc5f7713b4bbeb01617b302 Mon Sep 17 00:00:00 2001 From: abdul-rehman90 <> Date: Mon, 23 Jun 2025 12:51:34 +0500 Subject: [PATCH 47/67] servey submission user added and mail configred --- src/helpers/mail-template.js | 113 ++++++++++++++++++++++++++++-- src/models/survey.js | 5 ++ src/routes/auth/google-sign-in.js | 1 - src/routes/others/index.js | 3 +- src/routes/others/survey.js | 48 +++++++++++++ 5 files changed, 164 insertions(+), 6 deletions(-) diff --git a/src/helpers/mail-template.js b/src/helpers/mail-template.js index b1e7deb..6cdd100 100644 --- a/src/helpers/mail-template.js +++ b/src/helpers/mail-template.js @@ -1,4 +1,4 @@ -const activationEmailTemplate = (link,name) => { +const activationEmailTemplate = (link, name) => { return ` @@ -51,7 +51,112 @@ const activationEmailTemplate = (link,name) => { `; }; +const submitServeyUserMailTemplate = (userName) => { + return ` + + + +| + + | +
| + + | +
| + + | +