diff --git a/.env.example b/.env.example index aa85fe4..168115f 100644 --- a/.env.example +++ b/.env.example @@ -60,6 +60,14 @@ SMTP_PASS=YOUR_SMTP_PASS # SENDER_NAME: Sender of emails that will be sent by the service. SENDER_NAME=YOUR_SENDER_NAME +# EMAIL_TEMPLATES_PATH Email templates path. +# If there are no customized email templates, the variable does not need +# to be configured, so the default templates will be used. +# +# If it exists, the configured path must have at least 3 directories with +# the template files: reset-password, updated-password and welcome. +EMAIL_TEMPLATES_PATH=YOUR_EMAIL_TEMPLATES_PATH + ################################################################################################# ##################################### MONGO DATABASE SETUP ##################################### ################################################################################################# diff --git a/package-lock.json b/package-lock.json index 6460a85..ae48b8d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "notification", - "version": "1.3.1", + "version": "1.3.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -14,19 +14,19 @@ } }, "@babel/core": { - "version": "7.12.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.3.tgz", - "integrity": "sha512-0qXcZYKZp3/6N2jKYVxZv0aNCsxTSVCiK72DTiTYZAu7sjg73W0/aynWjMbiGd87EQL4WyA8reiJVh92AVla9g==", + "version": "7.12.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", + "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", "dev": true, "requires": { "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.1", + "@babel/generator": "^7.12.5", "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.1", - "@babel/parser": "^7.12.3", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.1", - "@babel/types": "^7.12.1", + "@babel/helpers": "^7.12.5", + "@babel/parser": "^7.12.7", + "@babel/template": "^7.12.7", + "@babel/traverse": "^7.12.9", + "@babel/types": "^7.12.7", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.1", @@ -57,12 +57,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true } } }, @@ -75,14 +69,6 @@ "@babel/types": "^7.12.5", "jsesc": "^2.5.1", "source-map": "^0.5.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } } }, "@babel/helper-function-name": { @@ -106,12 +92,12 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.1.tgz", - "integrity": "sha512-k0CIe3tXUKTRSoEx1LQEPFU9vRQfqHtl+kf8eNnDqb4AUJEy5pz6aIiog+YWtVm2jpggjS1laH68bPsR+KWWPQ==", + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz", + "integrity": "sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw==", "dev": true, "requires": { - "@babel/types": "^7.12.1" + "@babel/types": "^7.12.7" } }, "@babel/helper-module-imports": { @@ -141,12 +127,12 @@ } }, "@babel/helper-optimise-call-expression": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz", - "integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==", + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.7.tgz", + "integrity": "sha512-I5xc9oSJ2h59OwyUqjv95HRyzxj53DAubUERgQMrpcCEYQyToeHA+NEcUEsVWB4j53RDeskeBJ0SgRAYHDBckw==", "dev": true, "requires": { - "@babel/types": "^7.10.4" + "@babel/types": "^7.12.7" } }, "@babel/helper-replace-supers": { @@ -182,8 +168,7 @@ "@babel/helper-validator-identifier": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", - "dev": true + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==" }, "@babel/helpers": { "version": "7.12.5", @@ -236,42 +221,33 @@ } }, "@babel/parser": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.5.tgz", - "integrity": "sha512-FVM6RZQ0mn2KCf1VUED7KepYeUWoVShczewOCfm3nzoBybaih51h+sYVVGthW9M6lPByEPTQf+xm27PBdlpwmQ==", - "dev": true - }, - "@babel/runtime": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz", - "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==", - "requires": { - "regenerator-runtime": "^0.13.4" - } + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz", + "integrity": "sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==" }, "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", - "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz", + "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==", "dev": true, "requires": { "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/parser": "^7.12.7", + "@babel/types": "^7.12.7" } }, "@babel/traverse": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.5.tgz", - "integrity": "sha512-xa15FbQnias7z9a62LwYAA5SZZPkHIXpd42C6uW68o8uTuua96FHZy1y61Va5P/i83FAAcMpW8+A/QayntzuqA==", + "version": "7.12.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.9.tgz", + "integrity": "sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==", "dev": true, "requires": { "@babel/code-frame": "^7.10.4", "@babel/generator": "^7.12.5", "@babel/helper-function-name": "^7.10.4", "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/parser": "^7.12.5", - "@babel/types": "^7.12.5", + "@babel/parser": "^7.12.7", + "@babel/types": "^7.12.7", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.19" @@ -295,22 +271,13 @@ } }, "@babel/types": { - "version": "7.12.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.6.tgz", - "integrity": "sha512-hwyjw6GvjBLiyy3W0YQf0Z5Zf4NpYejUnKFcfcUhZCSffoBBp30w6wP2Wn6pk31jMYZvcOrB/1b7cGXvEoKogA==", - "dev": true, + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz", + "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==", "requires": { "@babel/helper-validator-identifier": "^7.10.4", "lodash": "^4.17.19", "to-fast-properties": "^2.0.0" - }, - "dependencies": { - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - } } }, "@dabh/diagnostics": { @@ -456,12 +423,12 @@ }, "dependencies": { "p-limit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", - "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "optional": true, "requires": { - "p-try": "^2.0.0" + "yocto-queue": "^0.1.0" } } } @@ -492,40 +459,10 @@ } }, "@types/node": { - "version": "12.19.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.6.tgz", - "integrity": "sha512-U2VopDdmBoYBmtm8Rz340mvvSz34VgX/K9+XCuckvcLGMkt3rbMX8soqFOikIPlPBc5lmw8By9NUK7bEFSBFlQ==", + "version": "12.19.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.8.tgz", + "integrity": "sha512-D4k2kNi0URNBxIRCb1khTnkWNHv8KSL1owPmS/K5e5t8B2GzMReY7AsJIY1BnP5KdlgC4rj9jk2IkDMasIE7xg==", "optional": true - }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "optional": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "optional": true, - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - } } } }, @@ -565,12 +502,6 @@ "resolve-from": "^5.0.0" }, "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, "resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -586,12 +517,12 @@ "dev": true }, "@ladjs/i18n": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/@ladjs/i18n/-/i18n-6.0.5.tgz", - "integrity": "sha512-l9Bkdo67dKcrWDyCkoEVpLEPMa8hdJbwe1gv0VWwD0fHIlvEAiNIAmka0ELF7H0ccNLqbKZx4vWKvkp0ufYFvw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@ladjs/i18n/-/i18n-7.0.1.tgz", + "integrity": "sha512-3z73ONQFBicQzkvwgcFNc7+wTn7srqragx3nKBlUAE1cDgK9mOwd1AdkTZwOFy7Nlzfemd1gs8wq7GAkyC+qQg==", "requires": { "@hapi/boom": "^9.1.0", - "boolean": "3.0.1", + "boolean": "3.0.2", "country-language": "^0.1.7", "debug": "^4.2.0", "i18n": "^0.13.2", @@ -745,19 +676,6 @@ "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", "optional": true }, - "@types/babel-types": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.9.tgz", - "integrity": "sha512-qZLoYeXSTgQuK1h7QQS16hqLGdmqtRmN8w/rl3Au/l5x/zkHx+a4VHrHyBsi1I1vtK2oBHxSzKIu0R5p6spdOA==" - }, - "@types/babylon": { - "version": "6.16.5", - "resolved": "https://registry.npmjs.org/@types/babylon/-/babylon-6.16.5.tgz", - "integrity": "sha512-xH2e58elpj1X4ynnKp9qSnWlsRTIs6n3tgLGNfwAGHwePw0mulHQllV34n0T25uYSu1k0hRKkWXF890B1yS47w==", - "requires": { - "@types/babel-types": "*" - } - }, "@types/body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", @@ -805,9 +723,9 @@ } }, "@types/express-serve-static-core": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.13.tgz", - "integrity": "sha512-RgDi5a4nuzam073lRGKTUIaL3eF2+H7LJvJ8eUnCI0wA6SNjXc44DCmWNiTLs/AZ7QlsFWZiw/gTG3nSQGL0fA==", + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.14.tgz", + "integrity": "sha512-uFTLwu94TfUFMToXNgRZikwPuZdOtDgs3syBtAIr/OXorL1kJqUJT9qCLnRZ5KBOWfZQikQ2xKgR2tnDj1OgDA==", "dev": true, "requires": { "@types/node": "*", @@ -883,9 +801,9 @@ } }, "@types/node": { - "version": "14.14.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.9.tgz", - "integrity": "sha512-JsoLXFppG62tWTklIoO4knA+oDTYsmqWxHRvd4lpmfQRNhX6osheUOWETP2jMoV/2bEHuMra8Pp3Dmo/stBFcw==" + "version": "14.14.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.10.tgz", + "integrity": "sha512-J32dgx2hw8vXrSbu4ZlVhn1Nm3GbeCFNw2FWL8S5QKucHGY0cyNwjdQdO+KMBZ4wpmC7KhLCiNsdk1RFRIYUQQ==" }, "@types/qs": { "version": "6.9.5", @@ -950,24 +868,9 @@ } }, "acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=" - }, - "acorn-globals": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz", - "integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=", - "requires": { - "acorn": "^4.0.4" - }, - "dependencies": { - "acorn": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=" - } - } + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" }, "agent-base": { "version": "6.0.2", @@ -1005,16 +908,6 @@ "indent-string": "^4.0.0" } }, - "align-text": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", - "requires": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" - } - }, "amqp-client-node": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/amqp-client-node/-/amqp-client-node-1.0.10.tgz", @@ -1348,6 +1241,11 @@ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" }, + "assert-never": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.2.1.tgz", + "integrity": "sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==" + }, "assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -1410,38 +1308,14 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, - "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=", + "babel-walk": { + "version": "3.0.0-canary-5", + "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", + "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - } - } - }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "@babel/types": "^7.9.6" } }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" - }, "bach": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", @@ -1516,12 +1390,6 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "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 } } }, @@ -1637,9 +1505,9 @@ "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" }, "boolean": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.1.tgz", - "integrity": "sha512-HRZPIjPcbwAVQvOTxR4YE3o8Xs98NqbbL1iEZDCz7CL8ql0Lt5iOyJFxfnAB0oFs8Oh02F/lLlg30Mexv46LjA==" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.2.tgz", + "integrity": "sha512-RwywHlpCRc3/Wh81MiCKun4ydaIFyW5Ea6JbL6sRCVx5q5irDw7pMXBUFYF/jArQ6YrG36q0kpovc9P/Kd3I4g==" }, "bowser": { "version": "2.9.0", @@ -1660,14 +1528,6 @@ "term-size": "^2.1.0", "type-fest": "^0.8.1", "widest-line": "^3.1.0" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - } } }, "brace-expansion": { @@ -1843,24 +1703,15 @@ } }, "camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" }, "camelize": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" }, - "center-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", - "requires": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" - } - }, "chai": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", @@ -1937,6 +1788,69 @@ "domelementtype": "^1.3.0", "entities": "^1.1.1" } + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + }, + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "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==" + }, + "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==", + "requires": { + "safe-buffer": "~5.2.0" + } } } }, @@ -1989,14 +1903,6 @@ } } }, - "clean-css": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", - "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", - "requires": { - "source-map": "~0.6.0" - } - }, "clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -2010,13 +1916,13 @@ "dev": true }, "cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" } }, "clone": { @@ -2269,14 +2175,12 @@ } }, "constantinople": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-3.1.2.tgz", - "integrity": "sha512-yePcBqEFhLOqSBtwYOGGS1exHo/s1xjekXiinh4itpNQGCu4KA1euPh1fg07N2wMITZXQkBz75Ntdt1ctGZouw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", + "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==", "requires": { - "@types/babel-types": "^7.0.0", - "@types/babylon": "^6.16.2", - "babel-types": "^6.26.0", - "babylon": "^6.18.0" + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.1" } }, "content-disposition": { @@ -2338,11 +2242,6 @@ "is-plain-object": "^2.0.1" } }, - "core-js": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", - "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" - }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -2395,6 +2294,27 @@ "nth-check": "~1.0.1" }, "dependencies": { + "dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "requires": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.2.tgz", + "integrity": "sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA==" + } + } + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + }, "domutils": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", @@ -2480,6 +2400,11 @@ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" + }, "default-compare": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", @@ -2573,12 +2498,6 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "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 } } }, @@ -2629,46 +2548,36 @@ "integrity": "sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk=" }, "dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.1.0.tgz", + "integrity": "sha512-ox7bvGXt2n+uLWtCRLybYx60IrOlWL/aCebWJk1T0d4m3y2tzf4U3ij9wBMUb6YJZpz06HCCYuyCDveE2xXmzQ==", "requires": { "domelementtype": "^2.0.1", + "domhandler": "^3.0.0", "entities": "^2.0.0" - }, - "dependencies": { - "domelementtype": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.2.tgz", - "integrity": "sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA==" - }, - "entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==" - } } }, "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.2.tgz", + "integrity": "sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA==" }, "domhandler": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", + "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", "requires": { - "domelementtype": "1" + "domelementtype": "^2.0.1" } }, "domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.4.2.tgz", + "integrity": "sha512-NKbgaM8ZJOecTZsIzW5gSuplsX2IWW2mIK7xVr8hTQF2v1CJWTmLZ1HOCh5sH+IzVPAGE5IucooOkvwBRAdowA==", "requires": { - "dom-serializer": "0", - "domelementtype": "1" + "dom-serializer": "^1.0.1", + "domelementtype": "^2.0.1", + "domhandler": "^3.3.0" } }, "dont-sniff-mimetype": { @@ -2759,19 +2668,19 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "email-templates": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/email-templates/-/email-templates-7.2.0.tgz", - "integrity": "sha512-BFZysF/uiLz+KT09YowdlXtQ1Ms7Zqk1H+vg7QE3La8+hBlpYpjv0f95Ljro4RohOesYmTNzoaWkrkXK6O4+Tw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/email-templates/-/email-templates-8.0.1.tgz", + "integrity": "sha512-R717oSi/8OnwCOCgynhoKO0Ak5GvDYH53lSRQ4IO79lH+Df2196/YA+GFv17c0r9Hy8FtGrPzaGio5vCiffiTA==", "requires": { - "@ladjs/i18n": "^6.0.5", + "@ladjs/i18n": "^7.0.1", "consolidate": "^0.16.0", - "debug": "^4.2.0", + "debug": "^4.3.1", "get-paths": "^0.0.7", - "html-to-text": "^5.1.1", + "html-to-text": "^6.0.0", "juice": "^7.0.0", "lodash": "^4.17.20", - "nodemailer": "^6.4.14", - "preview-email": "^2.0.2" + "nodemailer": "^6.4.16", + "preview-email": "^3.0.2" }, "dependencies": { "debug": { @@ -2824,9 +2733,9 @@ "optional": true }, "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==" }, "error-ex": { "version": "1.3.2", @@ -2917,11 +2826,6 @@ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" - }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -3119,12 +3023,6 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "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 } } }, @@ -3294,9 +3192,9 @@ }, "dependencies": { "@types/node": { - "version": "10.17.46", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.46.tgz", - "integrity": "sha512-Tice8a+sJtlP9C1EUo0DYyjq52T37b3LexVu3p871+kfIBIN+OQ7PKPei1oF3MgF39olEpUfxaLtD+QFc1k69Q==" + "version": "10.17.48", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.48.tgz", + "integrity": "sha512-Agl6xbYP6FOMDeAsr3QVZ+g7Yzg0uhPHWx0j5g4LFdUBHVtqtU+gH660k/lCEe506jJLOGbEzsnqPDTZGJQLag==" } } }, @@ -4143,17 +4041,10 @@ "wordwrap": "^1.0.0" }, "dependencies": { - "uglify-js": { - "version": "3.11.6", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.11.6.tgz", - "integrity": "sha512-oASI1FOJ7BBFkSCNDZ446EgkSuHkOZBuqRFrwXIKWCoXw8ZXQETooTQjkAcBS03Acab7ubCKsXnwuV2svy061g==", - "dev": true, - "optional": true - }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } @@ -4330,52 +4221,26 @@ "dev": true }, "html-to-text": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-5.1.1.tgz", - "integrity": "sha512-Bci6bD/JIfZSvG4s0gW/9mMKwBRoe/1RWLxUME/d6WUSZCdY7T60bssf/jFf7EYXRyqU4P5xdClVqiYU0/ypdA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-6.0.0.tgz", + "integrity": "sha512-r0KNC5aqCAItsjlgtirW6RW25c92Ee3ybQj8z//4Sl4suE3HIPqM4deGpYCUJULLjtVPEP1+Ma+1ZeX1iMsCiA==", "requires": { + "deepmerge": "^4.2.2", "he": "^1.2.0", - "htmlparser2": "^3.10.1", - "lodash": "^4.17.11", - "minimist": "^1.2.0" + "htmlparser2": "^4.1.0", + "lodash": "^4.17.20", + "minimist": "^1.2.5" } }, "htmlparser2": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", - "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", - "requires": { - "domelementtype": "^1.3.1", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^3.1.1" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "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==" - }, - "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==", - "requires": { - "safe-buffer": "~5.2.0" - } - } + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", + "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^3.0.0", + "domutils": "^2.0.0", + "entities": "^2.0.0" } }, "http-cache-semantics": { @@ -4807,6 +4672,17 @@ "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-arrayish": { @@ -4826,7 +4702,8 @@ "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true }, "is-ci": { "version": "2.0.0", @@ -4838,9 +4715,9 @@ } }, "is-core-module": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz", - "integrity": "sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", "requires": { "has": "^1.0.3" } @@ -4852,6 +4729,17 @@ "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": { @@ -4873,20 +4761,18 @@ } } }, + "is-docker": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz", + "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==" + }, "is-expression": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-3.0.0.tgz", - "integrity": "sha1-Oayqa+f9HzRx3ELHQW5hwkMXrJ8=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", + "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", "requires": { - "acorn": "~4.0.2", - "object-assign": "^4.0.1" - }, - "dependencies": { - "acorn": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=" - } + "acorn": "^7.1.1", + "object-assign": "^4.1.1" } }, "is-extendable": { @@ -4944,6 +4830,17 @@ "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-obj": { @@ -5038,9 +4935,12 @@ "dev": true }, "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "requires": { + "is-docker": "^2.0.0" + } }, "is-yarn-global": { "version": "0.3.0", @@ -5105,6 +5005,14 @@ "p-map": "^3.0.0", "rimraf": "^3.0.0", "uuid": "^3.3.3" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } } }, "istanbul-lib-report": { @@ -5160,6 +5068,12 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true } } }, @@ -5365,12 +5279,10 @@ } }, "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } + "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 }, "kuler": { "version": "2.0.0", @@ -5396,11 +5308,6 @@ "package-json": "^6.3.0" } }, - "lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" - }, "lazystream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", @@ -5663,11 +5570,6 @@ "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", "optional": true }, - "longest": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" - }, "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", @@ -5705,6 +5607,78 @@ "tlds": "1.208.0" }, "dependencies": { + "dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "requires": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.2.tgz", + "integrity": "sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA==" + }, + "entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==" + } + } + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + }, + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + }, + "html-to-text": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-5.1.1.tgz", + "integrity": "sha512-Bci6bD/JIfZSvG4s0gW/9mMKwBRoe/1RWLxUME/d6WUSZCdY7T60bssf/jFf7EYXRyqU4P5xdClVqiYU0/ypdA==", + "requires": { + "he": "^1.2.0", + "htmlparser2": "^3.10.1", + "lodash": "^4.17.11", + "minimist": "^1.2.0" + } + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + } + }, "iconv-lite": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", @@ -5718,6 +5692,29 @@ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.4.11.tgz", "integrity": "sha512-BVZBDi+aJV4O38rxsUh164Dk1NCqgh6Cm0rQSb9SK/DHGll/DrCMnycVDD7msJgZCnmVa8ASo8EZzR7jsgTukQ==" }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "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==" + }, + "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==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, "tlds": { "version": "1.208.0", "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.208.0.tgz", @@ -5777,14 +5774,6 @@ "dev": true, "requires": { "kind-of": "^6.0.2" - }, - "dependencies": { - "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 - } } }, "make-plural": { @@ -5934,14 +5923,6 @@ "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.2" - }, - "dependencies": { - "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 - } } }, "mime": { @@ -6089,12 +6070,6 @@ "fill-range": "^7.0.1" } }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, "chokidar": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", @@ -6215,12 +6190,12 @@ "dev": true }, "p-limit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", - "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", + "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": { - "p-try": "^2.0.0" + "yocto-queue": "^0.1.0" } }, "p-locate": { @@ -6399,9 +6374,9 @@ } }, "mongoose": { - "version": "5.10.15", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.10.15.tgz", - "integrity": "sha512-3QUWCpMRdFCPIBZkjG/B2OkfMY2WLkR+hv335o4T2mn3ta9kx8qVvXeUDojp3OHMxBZVUyCA+hDyyP4/aKmHuA==", + "version": "5.10.19", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.10.19.tgz", + "integrity": "sha512-SuJwbhQpfZ6WZFM6H2v0Hv1wQNLDeBDLZwOHR3UnR6IlPLKjuLyEx4OLI0vFQihv+JWJKWqJt+LcRRbRyL9PCg==", "requires": { "bson": "^1.1.4", "kareem": "2.3.1", @@ -6557,14 +6532,6 @@ "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.1" - }, - "dependencies": { - "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 - } } }, "negotiator": { @@ -6885,41 +6852,11 @@ "yargs": "^15.0.2" }, "dependencies": { - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, "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 - }, - "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - } } } }, @@ -6947,6 +6884,15 @@ "requires": { "is-descriptor": "^0.1.0" } + }, + "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" + } } } }, @@ -7062,11 +7008,12 @@ } }, "open": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz", - "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/open/-/open-7.3.0.tgz", + "integrity": "sha512-mgLwQIx2F/ye9SmbrUkurZCnkoXyXyu9EbHtJZrICjVAJfyMArdHp3KkixGdZx1ZHFPNIwl0DDM1dFFqXbTLZw==", "requires": { - "is-wsl": "^1.1.0" + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" } }, "ordered-read-streams": { @@ -7380,19 +7327,17 @@ "dev": true }, "preview-email": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/preview-email/-/preview-email-2.0.2.tgz", - "integrity": "sha512-FADpJ1p5VX0F/V57gcxc8IoxX63JuyDOOMN4Y7tJwil8K1/lvN0HtO7mZHIP2kgwhMMehjYTxqnjFtSGg1/LXw==", - "requires": { - "@babel/runtime": "^7.6.3", - "dayjs": "^1.8.16", - "debug": "^4.1.1", - "mailparser": "^2.7.7", - "nodemailer": "^6.3.1", - "open": "^6.4.0", - "pify": "^4.0.1", - "pug": "^2.0.4", - "uuid": "^3.3.3" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/preview-email/-/preview-email-3.0.2.tgz", + "integrity": "sha512-yHMqclooam/SViaSmmkJR5rUoO3kf6XG3hmII4s5gnz4iHowFSifgzBIz61wvX4JonbE0pN6XRibC4yR11bOgQ==", + "requires": { + "dayjs": "^1.9.6", + "debug": "^4.3.1", + "mailparser": "2", + "nodemailer": "^6.4.16", + "open": "^7.3.0", + "pug": "^3.0.0", + "uuid": "^8.3.1" }, "dependencies": { "debug": { @@ -7460,9 +7405,9 @@ }, "dependencies": { "@types/node": { - "version": "13.13.32", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.32.tgz", - "integrity": "sha512-sPBvDnrwZE1uePhkCEyI/qQlgZM5kePPAhHIFDWNsOrWBFRBOk3LKJYmVCLeLZlL9Ub/FzMJb31OTWCg2F+06g==", + "version": "13.13.34", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.34.tgz", + "integrity": "sha512-g8D1HF2dMDKYSDl5+79izRwRgNPsSynmWMbj50mj7GZ0b7Lv4p8EmZjbo3h0h+6iLr6YmVz9VnF6XVZ3O6V1Ug==", "optional": true } } @@ -7483,118 +7428,116 @@ "dev": true }, "pug": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pug/-/pug-2.0.4.tgz", - "integrity": "sha512-XhoaDlvi6NIzL49nu094R2NA6P37ijtgMDuWE+ofekDChvfKnzFal60bhSdiy8y2PBO6fmz3oMEIcfpBVRUdvw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.0.tgz", + "integrity": "sha512-inmsJyFBSHZaiGLaguoFgJGViX0If6AcfcElimvwj9perqjDpUpw79UIEDZbWFmoGVidh08aoE+e8tVkjVJPCw==", "requires": { - "pug-code-gen": "^2.0.2", - "pug-filters": "^3.1.1", - "pug-lexer": "^4.1.0", - "pug-linker": "^3.0.6", - "pug-load": "^2.0.12", - "pug-parser": "^5.0.1", - "pug-runtime": "^2.0.5", - "pug-strip-comments": "^1.0.4" + "pug-code-gen": "^3.0.0", + "pug-filters": "^4.0.0", + "pug-lexer": "^5.0.0", + "pug-linker": "^4.0.0", + "pug-load": "^3.0.0", + "pug-parser": "^6.0.0", + "pug-runtime": "^3.0.0", + "pug-strip-comments": "^2.0.0" } }, "pug-attrs": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-2.0.4.tgz", - "integrity": "sha512-TaZ4Z2TWUPDJcV3wjU3RtUXMrd3kM4Wzjbe3EWnSsZPsJ3LDI0F3yCnf2/W7PPFF+edUFQ0HgDL1IoxSz5K8EQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", + "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", "requires": { - "constantinople": "^3.0.1", - "js-stringify": "^1.0.1", - "pug-runtime": "^2.0.5" + "constantinople": "^4.0.1", + "js-stringify": "^1.0.2", + "pug-runtime": "^3.0.0" } }, "pug-code-gen": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-2.0.2.tgz", - "integrity": "sha512-kROFWv/AHx/9CRgoGJeRSm+4mLWchbgpRzTEn8XCiwwOy6Vh0gAClS8Vh5TEJ9DBjaP8wCjS3J6HKsEsYdvaCw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.1.tgz", + "integrity": "sha512-xJIGvmXTQlkJllq6hqxxjRWcay2F9CU69TuAuiVZgHK0afOhG5txrQOcZyaPHBvSWCU/QQOqEp5XCH94rRZpBQ==", "requires": { - "constantinople": "^3.1.2", + "constantinople": "^4.0.1", "doctypes": "^1.1.0", - "js-stringify": "^1.0.1", - "pug-attrs": "^2.0.4", - "pug-error": "^1.3.3", - "pug-runtime": "^2.0.5", - "void-elements": "^2.0.1", - "with": "^5.0.0" + "js-stringify": "^1.0.2", + "pug-attrs": "^3.0.0", + "pug-error": "^2.0.0", + "pug-runtime": "^3.0.0", + "void-elements": "^3.1.0", + "with": "^7.0.0" } }, "pug-error": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-1.3.3.tgz", - "integrity": "sha512-qE3YhESP2mRAWMFJgKdtT5D7ckThRScXRwkfo+Erqga7dyJdY3ZquspprMCj/9sJ2ijm5hXFWQE/A3l4poMWiQ==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.0.0.tgz", + "integrity": "sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==" }, "pug-filters": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-3.1.1.tgz", - "integrity": "sha512-lFfjNyGEyVWC4BwX0WyvkoWLapI5xHSM3xZJFUhx4JM4XyyRdO8Aucc6pCygnqV2uSgJFaJWW3Ft1wCWSoQkQg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz", + "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==", "requires": { - "clean-css": "^4.1.11", - "constantinople": "^3.0.1", + "constantinople": "^4.0.1", "jstransformer": "1.0.0", - "pug-error": "^1.3.3", - "pug-walk": "^1.1.8", - "resolve": "^1.1.6", - "uglify-js": "^2.6.1" + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0", + "resolve": "^1.15.1" } }, "pug-lexer": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-4.1.0.tgz", - "integrity": "sha512-i55yzEBtjm0mlplW4LoANq7k3S8gDdfC6+LThGEvsK4FuobcKfDAwt6V4jKPH9RtiE3a2Akfg5UpafZ1OksaPA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.0.tgz", + "integrity": "sha512-52xMk8nNpuyQ/M2wjZBN5gXQLIylaGkAoTk5Y1pBhVqaopaoj8Z0iVzpbFZAqitL4RHNVDZRnJDsqEYe99Ti0A==", "requires": { - "character-parser": "^2.1.1", - "is-expression": "^3.0.0", - "pug-error": "^1.3.3" + "character-parser": "^2.2.0", + "is-expression": "^4.0.0", + "pug-error": "^2.0.0" } }, "pug-linker": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-3.0.6.tgz", - "integrity": "sha512-bagfuHttfQOpANGy1Y6NJ+0mNb7dD2MswFG2ZKj22s8g0wVsojpRlqveEQHmgXXcfROB2RT6oqbPYr9EN2ZWzg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz", + "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==", "requires": { - "pug-error": "^1.3.3", - "pug-walk": "^1.1.8" + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0" } }, "pug-load": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-2.0.12.tgz", - "integrity": "sha512-UqpgGpyyXRYgJs/X60sE6SIf8UBsmcHYKNaOccyVLEuT6OPBIMo6xMPhoJnqtB3Q3BbO4Z3Bjz5qDsUWh4rXsg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz", + "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==", "requires": { - "object-assign": "^4.1.0", - "pug-walk": "^1.1.8" + "object-assign": "^4.1.1", + "pug-walk": "^2.0.0" } }, "pug-parser": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-5.0.1.tgz", - "integrity": "sha512-nGHqK+w07p5/PsPIyzkTQfzlYfuqoiGjaoqHv1LjOv2ZLXmGX1O+4Vcvps+P4LhxZ3drYSljjq4b+Naid126wA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", + "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", "requires": { - "pug-error": "^1.3.3", - "token-stream": "0.0.1" + "pug-error": "^2.0.0", + "token-stream": "1.0.0" } }, "pug-runtime": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-2.0.5.tgz", - "integrity": "sha512-P+rXKn9un4fQY77wtpcuFyvFaBww7/91f3jHa154qU26qFAnOe6SW1CbIDcxiG5lLK9HazYrMCCuDvNgDQNptw==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.0.tgz", + "integrity": "sha512-GoEPcmQNnaTsePEdVA05bDpY+Op5VLHKayg08AQiqJBWU/yIaywEYv7TetC5dEQS3fzBBoyb2InDcZEg3mPTIA==" }, "pug-strip-comments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-1.0.4.tgz", - "integrity": "sha512-i5j/9CS4yFhSxHp5iKPHwigaig/VV9g+FgReLJWWHEHbvKsbqL0oP/K5ubuLco6Wu3Kan5p7u7qk8A4oLLh6vw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz", + "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==", "requires": { - "pug-error": "^1.3.3" + "pug-error": "^2.0.0" } }, "pug-walk": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-1.1.8.tgz", - "integrity": "sha512-GMu3M5nUL3fju4/egXwZO0XLi6fW/K3T3VTgFQ14GxNi8btlxgT5qZL//JwZFm/2Fa64J/PNS8AZeys3wiMkVA==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz", + "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==" }, "pump": { "version": "3.0.0", @@ -7805,11 +7748,6 @@ "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" }, - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" - }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -7888,7 +7826,8 @@ "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true }, "replace-ext": { "version": "1.0.1", @@ -8018,14 +7957,6 @@ } } }, - "right-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", - "requires": { - "align-text": "^0.1.1" - } - }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -8293,12 +8224,6 @@ "requires": { "is-extendable": "^0.1.0" } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true } } }, @@ -8350,12 +8275,6 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "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 } } }, @@ -8366,12 +8285,24 @@ "dev": true, "requires": { "kind-of": "^3.2.0" + }, + "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" + } + } } }, "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true }, "source-map-resolve": { "version": "0.5.3", @@ -8394,6 +8325,14 @@ "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } } }, "source-map-url": { @@ -8469,9 +8408,9 @@ } }, "spdx-license-ids": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz", - "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", + "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", "dev": true }, "split-string": { @@ -8692,9 +8631,9 @@ } }, "swagger-ui-dist": { - "version": "3.37.0", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.37.0.tgz", - "integrity": "sha512-ySYfsGTSxuyIAAynncQew9WLRsKu6bI3/tWTqcuXYSqTLCjz3ROtUbNj2zRNs7i37V8CteKE9CUMkYnNklGi2g==" + "version": "3.37.2", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.37.2.tgz", + "integrity": "sha512-XIT4asxgeL4GUNPPsqpEqLt20M/u6OhFYqTh42IoEAvAyv5e9EGw5uhP9dLAD10opcMYqdkJ5qU+MpN2HZ5xyA==" }, "swagger-ui-express": { "version": "4.1.5", @@ -8715,14 +8654,6 @@ "node-fetch": "^2.6.1", "stream-events": "^1.0.5", "uuid": "^8.0.0" - }, - "dependencies": { - "uuid": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", - "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==", - "optional": true - } } }, "term-size": { @@ -8817,9 +8748,9 @@ "integrity": "sha512-m+apkYlfiQTKLW+sI4vqUkwMEzfgEUEYSqljx1voUE3Wz/z1ZsxyzSxvH2X8uKVrOp7QkByWt0rA6+gvhCKy6g==" }, "tlds": { - "version": "1.212.0", - "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.212.0.tgz", - "integrity": "sha512-03rYYO1rGhOYpdYB+wlLY2d0xza6hdN/S67ol2ZpaH+CtFedMVAVhj8ft0rwxEkr90zatou8opBv7Xp6X4cK6g==" + "version": "1.214.0", + "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.214.0.tgz", + "integrity": "sha512-+i48KYsrCkkIZnsj31cTIj9cu5NtFxKo7xlNIB7jg8kXi//b4Ertl5qaHgqFF+y+g0nFwt/k+eph2uUNQJgfwg==" }, "to-absolute-glob": { "version": "2.0.2", @@ -8832,9 +8763,9 @@ } }, "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" }, "to-object-path": { "version": "0.3.0", @@ -8843,6 +8774,17 @@ "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" + } + } } }, "to-readable-stream": { @@ -8888,9 +8830,9 @@ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, "token-stream": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-0.0.1.tgz", - "integrity": "sha1-zu78cXp2xDFvEm0LnbqlXX598Bo=" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", + "integrity": "sha1-zCAOqyYT9BZtJ/+a/HylbUnfbrQ=" }, "touch": { "version": "3.1.0", @@ -9079,26 +9021,10 @@ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" }, "uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", - "requires": { - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - } - } - }, - "uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.12.1.tgz", + "integrity": "sha512-o8lHP20KjIiQe5b/67Rh68xEGRrc2SRsCuuoYclXXoC74AfSRGblU1HKzJWH3HxPZ+Ort85fWHpSX7KwBUC9CQ==", + "dev": true, "optional": true }, "unc-path-regex": { @@ -9305,9 +9231,9 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", + "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==" }, "v8flags": { "version": "3.2.0", @@ -9475,9 +9401,9 @@ } }, "void-elements": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=" }, "web-resource-inliner": { "version": "5.0.0", @@ -9490,57 +9416,6 @@ "mime": "^2.4.6", "node-fetch": "^2.6.0", "valid-data-url": "^3.0.0" - }, - "dependencies": { - "dom-serializer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.1.0.tgz", - "integrity": "sha512-ox7bvGXt2n+uLWtCRLybYx60IrOlWL/aCebWJk1T0d4m3y2tzf4U3ij9wBMUb6YJZpz06HCCYuyCDveE2xXmzQ==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^3.0.0", - "entities": "^2.0.0" - } - }, - "domelementtype": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.2.tgz", - "integrity": "sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA==" - }, - "domhandler": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", - "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", - "requires": { - "domelementtype": "^2.0.1" - } - }, - "domutils": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.4.2.tgz", - "integrity": "sha512-NKbgaM8ZJOecTZsIzW5gSuplsX2IWW2mIK7xVr8hTQF2v1CJWTmLZ1HOCh5sH+IzVPAGE5IucooOkvwBRAdowA==", - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.0.1", - "domhandler": "^3.3.0" - } - }, - "entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==" - }, - "htmlparser2": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", - "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^3.0.0", - "domutils": "^2.0.0", - "entities": "^2.0.0" - } - } } }, "websocket-driver": { @@ -9623,11 +9498,6 @@ "string-width": "^4.0.0" } }, - "window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=" - }, "winston": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", @@ -9719,18 +9589,21 @@ } }, "with": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/with/-/with-5.1.1.tgz", - "integrity": "sha1-+k2qktrzLE6pTtRTyB8EaGtXXf4=", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", + "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", "requires": { - "acorn": "^3.1.0", - "acorn-globals": "^3.0.0" + "@babel/parser": "^7.9.6", + "@babel/types": "^7.9.6", + "assert-never": "^1.2.1", + "babel-walk": "3.0.0-canary-5" } }, "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true }, "workerpool": { "version": "6.0.2", @@ -9791,14 +9664,21 @@ "optional": true }, "yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" } }, "yargs-parser": { @@ -9808,13 +9688,6 @@ "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" - } } }, "yargs-unparser": { @@ -9848,6 +9721,11 @@ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true + }, + "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==" } } } diff --git a/package.json b/package.json index 404b1e6..378168b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "notification", - "version": "1.3.1", + "version": "1.3.2", "description": "Microservice for sending messages: email, sms or push. In this version only the sending of email will be available.", "main": "dist/server.js", "scripts": { @@ -56,13 +56,13 @@ "amqp-client-node": "^1.0.10", "body-parser": "^1.19.0", "dotenv": "^8.2.0", - "email-templates": "^7.2.0", + "email-templates": "^8.0.1", "express": "^4.17.1", "firebase-admin": "^9.4.1", "helmet": "^3.23.3", "inversify": "^5.0.1", "inversify-express-utils": "^6.3.2", - "mongoose": "^5.10.15", + "mongoose": "^5.10.19", "morgan": "^1.10.0", "multer": "^1.4.2", "nodemailer": "^6.4.16", diff --git a/src/application/domain/model/address.ts b/src/application/domain/model/address.ts index 62b0305..d11a50d 100644 --- a/src/application/domain/model/address.ts +++ b/src/application/domain/model/address.ts @@ -34,6 +34,7 @@ export class Address implements IJSONSerializable, IJSONDeserializable
} public fromJSON(json: any): Address { + if (!json) return this if (JsonUtils.isJsonString(json)) { json = JSON.parse(json) } diff --git a/src/application/domain/model/attachment.ts b/src/application/domain/model/attachment.ts index 2038939..fea53d5 100644 --- a/src/application/domain/model/attachment.ts +++ b/src/application/domain/model/attachment.ts @@ -42,6 +42,7 @@ export class Attachment implements IJSONSerializable, IJSONDeserializable { private _type?: string @@ -18,6 +19,12 @@ export class User extends Entity implements IJSONSerializable, IJSONDeserializab } public fromJSON(json: any): User { + if (!json) return this + + if (typeof json === 'string' && JsonUtils.isJsonString(json)) { + json = JSON.parse(json) + } + if (json.id) super.id = json.id if (json.type) this.type = json.type return this diff --git a/src/application/domain/validator/email.pilot.study.data.validator.ts b/src/application/domain/validator/email.pilot.study.data.validator.ts index 9348f79..97f0ff6 100644 --- a/src/application/domain/validator/email.pilot.study.data.validator.ts +++ b/src/application/domain/validator/email.pilot.study.data.validator.ts @@ -1,5 +1,6 @@ import { ValidationException } from '../exception/validation.exception' import { EmailToValidator } from './email.to.validator' +import { Strings } from '../../../utils/strings' export class EmailPilotStudyDataValidator { public static validate(email: any): void | ValidationException { @@ -15,7 +16,7 @@ export class EmailPilotStudyDataValidator { if (!email.attachments) fields.push('attachments') else if (!email.attachments.length) { - throw new ValidationException('At least one file is required in attachments') + throw new ValidationException(Strings.ERROR_MESSAGE.VALIDATE.EMPTY_ATTACHMENTS) } else { for (const item of email.attachments) { if (!item.filename) fields.push('attachments.filename') @@ -25,8 +26,10 @@ export class EmailPilotStudyDataValidator { } if (fields.length > 0) { - throw new ValidationException('Required fields were not provided...', - 'Email validation: '.concat(fields.join(', ')).concat(' is required!')) + throw new ValidationException( + Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS, + Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS_DESC.replace('{0}', fields.join(', ')) + ) } } } diff --git a/src/application/domain/validator/email.reset.password.validator.ts b/src/application/domain/validator/email.reset.password.validator.ts index 029a86c..282a93d 100644 --- a/src/application/domain/validator/email.reset.password.validator.ts +++ b/src/application/domain/validator/email.reset.password.validator.ts @@ -1,5 +1,6 @@ import { ValidationException } from '../exception/validation.exception' import { EmailToValidator } from './email.to.validator' +import { Strings } from '../../../utils/strings' export class EmailResetPasswordValidator { public static validate(email: any): void | ValidationException { @@ -12,8 +13,10 @@ export class EmailResetPasswordValidator { if (!email.action_url) fields.push('action_url') if (fields.length > 0) { - throw new ValidationException('Required fields were not provided...', - 'Email validation: '.concat(fields.join(', ')).concat(' is required!')) + throw new ValidationException( + Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS, + Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS_DESC.replace('{0}', fields.join(', ')) + ) } } } diff --git a/src/application/domain/validator/email.send.validator.ts b/src/application/domain/validator/email.send.validator.ts index 929374f..1236564 100644 --- a/src/application/domain/validator/email.send.validator.ts +++ b/src/application/domain/validator/email.send.validator.ts @@ -1,6 +1,7 @@ import { ValidationException } from '../exception/validation.exception' import { Email } from '../model/email' import { EmailValidator } from './email.validator' +import { Strings } from '../../../utils/strings' export class EmailSendValidator { public static validate(email: Email): void | ValidationException { @@ -10,19 +11,17 @@ export class EmailSendValidator { if (!email.subject) fields.push('subject') if (email.reply) { if (!email.reply.email) { - throw new ValidationException('The reply field requires that the object have email!') + throw new ValidationException(Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_REPLY_EMAIL) } EmailValidator.validate(email.reply.email) } if (!email.to) fields.push('to') - if (!email.to.length) { - throw new ValidationException('The to field requires at least one recipient with ' + - 'and an email address!') + else if (!email.to.length) { + throw new ValidationException(Strings.ERROR_MESSAGE.VALIDATE.EMPTY_TO) } else { for (const item of email.to) { if (!item.email) { - throw new ValidationException('The to field requires an array of recipients ' + - 'with a email address!.') + throw new ValidationException(Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_TO_EMAIL) } else { EmailValidator.validate(item.email) } @@ -31,8 +30,7 @@ export class EmailSendValidator { if (email.cc && email.cc.length) { for (const item of email.cc) { if (!item.email) { - throw new ValidationException('The cc field requires an array of recipients ' + - ' with a email address.') + throw new ValidationException(Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_CC_EMAIL) } else { EmailValidator.validate(item.email) } @@ -41,8 +39,7 @@ export class EmailSendValidator { if (email.bcc && email.bcc.length) { for (const item of email.bcc) { if (!item.email) { - throw new ValidationException('The bcc field requires an array of recipients ' + - 'with a email address.') + throw new ValidationException(Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_BCC_EMAIL) } else { EmailValidator.validate(item.email) } @@ -51,15 +48,16 @@ export class EmailSendValidator { if (email.attachments && email.attachments.length) { for (const item of email.attachments) { if (!item.path) { - throw new ValidationException('The attachment field requires a variety of ' + - 'attachments with at least the file path or URL.') + throw new ValidationException(Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_ATTACHMENTS_PATH) } } } if (fields.length > 0) { - throw new ValidationException('Required fields were not provided...', - 'Email validation: '.concat(fields.join(', ')).concat(' is required!')) + throw new ValidationException( + Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS, + Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS_DESC.replace('{0}', fields.join(', ')) + ) } } } diff --git a/src/application/domain/validator/email.to.validator.ts b/src/application/domain/validator/email.to.validator.ts index 39b3db8..eb9c993 100644 --- a/src/application/domain/validator/email.to.validator.ts +++ b/src/application/domain/validator/email.to.validator.ts @@ -1,15 +1,20 @@ import { ValidationException } from '../exception/validation.exception' import { EmailValidator } from './email.validator' +import { Strings } from '../../../utils/strings' export class EmailToValidator { public static validate(email: any): void | ValidationException { - const INVALID_TO: string = 'The "to" field is not in valid format!' - if (!email.name) { - throw new ValidationException(INVALID_TO, 'The name attribute is required.') + throw new ValidationException( + Strings.ERROR_MESSAGE.VALIDATE.INVALID_TO, + Strings.ERROR_MESSAGE.VALIDATE.INVALID_TO_DESC.replace('{0}', 'name') + ) } if (!email.email) { - throw new ValidationException(INVALID_TO, 'The email attribute is required.') + throw new ValidationException( + Strings.ERROR_MESSAGE.VALIDATE.INVALID_TO, + Strings.ERROR_MESSAGE.VALIDATE.INVALID_TO_DESC.replace('{0}', 'email') + ) } EmailValidator.validate(email.email) } diff --git a/src/application/domain/validator/email.update.password.validator.ts b/src/application/domain/validator/email.update.password.validator.ts index 631f434..55601d4 100644 --- a/src/application/domain/validator/email.update.password.validator.ts +++ b/src/application/domain/validator/email.update.password.validator.ts @@ -1,5 +1,6 @@ import { ValidationException } from '../exception/validation.exception' import { EmailToValidator } from './email.to.validator' +import { Strings } from '../../../utils/strings' export class EmailUpdatePasswordValidator { public static validate(email: any): void | ValidationException { @@ -10,8 +11,10 @@ export class EmailUpdatePasswordValidator { else EmailToValidator.validate(email.to) if (fields.length > 0) { - throw new ValidationException('Required fields were not provided...', - 'Email validation: '.concat(fields.join(', ')).concat(' is required!')) + throw new ValidationException( + Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS, + Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS_DESC.replace('{0}', fields.join(', ')) + ) } } } diff --git a/src/application/domain/validator/email.validator.ts b/src/application/domain/validator/email.validator.ts index 0d2c389..535c397 100644 --- a/src/application/domain/validator/email.validator.ts +++ b/src/application/domain/validator/email.validator.ts @@ -1,9 +1,10 @@ import { ValidationException } from '../exception/validation.exception' +import { Strings } from '../../../utils/strings' export class EmailValidator { public static validate(email: string | undefined): void | ValidationException { if (!email || !(/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/).test(email)) { - throw new ValidationException(`Email "${email}" does not have a valid format!`) + throw new ValidationException(Strings.ERROR_MESSAGE.VALIDATE.INVALID_EMAIL.replace('{0}', email)) } } } diff --git a/src/application/domain/validator/email.welcome.validator.ts b/src/application/domain/validator/email.welcome.validator.ts index b8b0744..f458d41 100644 --- a/src/application/domain/validator/email.welcome.validator.ts +++ b/src/application/domain/validator/email.welcome.validator.ts @@ -1,5 +1,6 @@ import { ValidationException } from '../exception/validation.exception' import { EmailToValidator } from './email.to.validator' +import { Strings } from '../../../utils/strings' export class EmailWelcomeValidator { public static validate(email: any): void | ValidationException { @@ -12,8 +13,10 @@ export class EmailWelcomeValidator { if (!email.action_url) fields.push('action_url') if (fields.length > 0) { - throw new ValidationException('Required fields were not provided...', - 'Email validation: '.concat(fields.join(', ')).concat(' is required!')) + throw new ValidationException( + Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS, + Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS_DESC.replace('{0}', fields.join(', ')) + ) } } } diff --git a/src/application/domain/validator/user.validator.ts b/src/application/domain/validator/user.validator.ts index a3a713b..b7813bc 100644 --- a/src/application/domain/validator/user.validator.ts +++ b/src/application/domain/validator/user.validator.ts @@ -1,6 +1,7 @@ import { User } from '../model/user' import { ValidationException } from '../exception/validation.exception' import { ObjectIdValidator } from './object.id.validator' +import { Strings } from '../../../utils/strings' export class UserValidator { public static validate(item: User): void | ValidationException { @@ -10,9 +11,11 @@ export class UserValidator { else ObjectIdValidator.validate(item.id) if (!item.type) fields.push('type') - if (fields.length) { - throw new ValidationException('Required fields were not provided...', - 'User validation: '.concat(fields.join(', ')).concat(' required!')) + if (fields.length > 0) { + throw new ValidationException( + Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS, + Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS_DESC.replace('{0}', fields.join(', ')) + ) } } } diff --git a/src/infrastructure/repository/email.repository.ts b/src/infrastructure/repository/email.repository.ts index 3b6a5ff..96c3797 100644 --- a/src/infrastructure/repository/email.repository.ts +++ b/src/infrastructure/repository/email.repository.ts @@ -193,6 +193,24 @@ export class EmailRepository extends BaseRepository implemen } private getEmailTemplateInstance(): any { + const emailTemplatesPath = process.env.EMAIL_TEMPLATES_PATH + if (emailTemplatesPath) { + try { + const data: any = fs.readdirSync(emailTemplatesPath) + if (data && data.find(item => item === 'reset-password') && data.find(item => item === 'updated-password') + && data.find(item => item === 'welcome')) { + return new Template({ + transport: this.smtpTransport, + send: true, + preview: false, + views: { root: path.resolve(emailTemplatesPath) } + }) + } + } catch (err) { + this.logger.error(`The custom templates could not be accessed successfully, so the default will be used. ` + .concat(err.message)) + } + } return new Template({ transport: this.smtpTransport, send: true, diff --git a/src/infrastructure/repository/push.repository.ts b/src/infrastructure/repository/push.repository.ts index badac98..2fe7147 100644 --- a/src/infrastructure/repository/push.repository.ts +++ b/src/infrastructure/repository/push.repository.ts @@ -114,6 +114,12 @@ export class PushRepository extends BaseRepository implements Strings.FIREBASE_ADMIN_ERROR.INVALID_TOKEN.replace(': {0}', recipient ? `: ${recipient}` : '.'), Strings.FIREBASE_ADMIN_ERROR.INVALID_TOKEN_DESC) }, + 'messaging/invalid-argument': () => { + return new FirebaseClientException( + HttpStatus.UNAUTHORIZED, + Strings.FIREBASE_ADMIN_ERROR.INVALID_TOKEN.replace(': {0}', recipient ? `: ${recipient}` : '.'), + Strings.FIREBASE_ADMIN_ERROR.INVALID_TOKEN_DESC) + }, 'messaging/registration-token-not-registered': () => { return new FirebaseClientException( HttpStatus.UNAUTHORIZED, diff --git a/src/utils/strings.ts b/src/utils/strings.ts index 22f4487..1038f56 100644 --- a/src/utils/strings.ts +++ b/src/utils/strings.ts @@ -48,7 +48,17 @@ export abstract class Strings { AT_LEAST_ONE_RECIPIENT: 'At least one recipient is required.', AT_LEAST_ONE_RECIPIENT_DESC: 'Please enter at least one user id for direct notifications or at least one topic name for topic notifications.', USER_HAS_NO_PUSH_TOKEN: 'Some user ids do not have saved push tokens for any type of client: {0}.', - USER_HAS_NO_PUSH_TOKEN_DESC: 'Please submit a valid user id and try again.' + USER_HAS_NO_PUSH_TOKEN_DESC: 'Please submit a valid user id and try again.', + INVALID_EMAIL: 'Email "{0}" does not have a valid format!', + INVALID_TO: 'The "to" field is not in valid format!', + INVALID_TO_DESC: 'The {0} attribute is required.', + EMPTY_ATTACHMENTS: 'At least one file is required in attachments', + EMPTY_TO: 'The to field requires at least one recipient with an email address!', + REQUIRED_REPLY_EMAIL: 'The reply field requires that the object have email!', + REQUIRED_TO_EMAIL: 'The to field requires an array of recipients with a email address!', + REQUIRED_CC_EMAIL: 'The cc field requires an array of recipients with a email address!', + REQUIRED_BCC_EMAIL: 'The bcc field requires an array of recipients with a email address!', + REQUIRED_ATTACHMENTS_PATH: 'The attachment field requires a variety of attachments with at least the file path or URL.' } } diff --git a/test/mocks/generator.mock.ts b/test/mocks/generator.mock.ts index d821059..e66a25c 100644 --- a/test/mocks/generator.mock.ts +++ b/test/mocks/generator.mock.ts @@ -20,6 +20,16 @@ export class GeneratorMock { return randS } + public static generateUserType(): string { + const userTypes = { + 0: 'admin', + 1: 'health_professional', + 2: 'patient' + } + + return userTypes[Math.floor((Math.random() * 3))] // 0-2 + } + public static async generateEmailTemp(email): Promise { return new Promise((resolve, reject) => { const options = { diff --git a/test/mocks/models/default.entity.mock.ts b/test/mocks/models/default.entity.mock.ts index d0e1f91..7825032 100644 --- a/test/mocks/models/default.entity.mock.ts +++ b/test/mocks/models/default.entity.mock.ts @@ -5,6 +5,72 @@ import { ChoiceTypes } from '../../../src/application/domain/utils/choice.types' export abstract class DefaultEntityMock { // MODELS + public static readonly ADDRESS: any = { + name: 'Default Sender', + email: 'default_email@mail.com' + } + + public static readonly FROM_ADDRESS: any = { + name: 'Default From Sender', + email: 'default_from_email@mail.com' + } + + public static readonly TO_ADDRESS: any = { + name: 'Default To Sender', + email: 'default_to_email@mail.com' + } + + public static readonly ATTACHMENT: any = { + filename: 'Default Filename', + path: 'path/default_attachment', + content_type: 'default_content_type' + } + + public static readonly EMAIL: any = { + id: GeneratorMock.generateObjectId(), + from: DefaultEntityMock.FROM_ADDRESS, + reply: DefaultEntityMock.ADDRESS, + to: [DefaultEntityMock.TO_ADDRESS], + cc: [DefaultEntityMock.TO_ADDRESS], + bcc: [DefaultEntityMock.TO_ADDRESS], + subject: 'Default Subject', + text: 'Default Text', + html: 'Default HTML', + attachments: [DefaultEntityMock.ATTACHMENT], + created_at: new Date().toISOString(), + user_id: GeneratorMock.generateObjectId(), + template: 'Default Template', + link: 'Default Link' + } + + public static readonly PILOT_STUDY_DATA_EMAIL: any = { + to: DefaultEntityMock.ADDRESS, + attachments: [DefaultEntityMock.ATTACHMENT], + pilot_study: 'Default Pilot', + request_date: new Date().toISOString(), + action_url: 'https://localhost', + lang: 'pt-BR' + } + + public static readonly RESET_PASSWORD_EMAIL: any = { + to: DefaultEntityMock.ADDRESS, + action_url: 'https://localhost', + lang: 'pt-BR' + } + + public static readonly UPDATE_PASSWORD_EMAIL: any = { + to: DefaultEntityMock.ADDRESS, + action_url: 'https://localhost', + lang: 'pt-BR' + } + + public static readonly WELCOME_EMAIL: any = { + to: DefaultEntityMock.ADDRESS, + action_url: 'https://localhost', + password: 'user_pass', + lang: 'pt-BR' + } + public static readonly PUSH_MESSAGE: any = { type: 'notification-type', pt: { @@ -33,4 +99,9 @@ export abstract class DefaultEntityMock { message: DefaultEntityMock.PUSH_MESSAGE, created_at: '2020-11-18T02:40:10.752Z' } + + public static readonly USER: any = { + id: GeneratorMock.generateObjectId(), + type: GeneratorMock.generateUserType() + } } diff --git a/test/mocks/models/email.mock.ts b/test/mocks/models/email.mock.ts index dfce6a4..3e468c7 100644 --- a/test/mocks/models/email.mock.ts +++ b/test/mocks/models/email.mock.ts @@ -1,18 +1,23 @@ import { Email } from '../../../src/application/domain/model/email' import { Address } from '../../../src/application/domain/model/address' import { GeneratorMock } from '../generator.mock' +import { Attachment } from '../../../src/application/domain/model/attachment' +import { DefaultEntityMock } from './default.entity.mock' export class EmailMock { public generate(): Email { const email: Email = new Email() email.id = GeneratorMock.generateObjectId() - email.from = new Address('NOTIFICATION/HANIoT', process.env.SMTP_USER) - email.reply = new Address('NOTIFICATION/HANIoT', process.env.SMTP_USER) + email.from = new Address('Default From Sender', 'default_from_email@mail.com') + email.reply = new Address('Default Sender', 'default_email@mail.com') email.to = new Array(new Address(`Test ${email.id}`, `${email.id}@mail.com`)) - email.subject = GeneratorMock.generateLoremIpsum(Math.floor(Math.random() * 100)) - email.text = GeneratorMock.generateLoremIpsum(Math.floor(Math.random() * 500)) - email.html = GeneratorMock.generateLoremIpsum(Math.floor(Math.random() * 2000)) + email.cc = new Array(new Address(`Test ${email.id}`, `${email.id}@mail.com`)) + email.bcc = new Array(new Address(`Test ${email.id}`, `${email.id}@mail.com`)) + email.subject = GeneratorMock.generateLoremIpsum(Math.floor(Math.random() * 100) + 1) + email.text = GeneratorMock.generateLoremIpsum(Math.floor(Math.random() * 500) + 1) + email.html = GeneratorMock.generateLoremIpsum(Math.floor(Math.random() * 2000) + 1) + email.attachments = [new Attachment().fromJSON(DefaultEntityMock.ATTACHMENT)] email.createdAt = new Date().toISOString() email.userId = GeneratorMock.generateObjectId() diff --git a/test/mocks/models/user.mock.ts b/test/mocks/models/user.mock.ts new file mode 100644 index 0000000..5f3c5d5 --- /dev/null +++ b/test/mocks/models/user.mock.ts @@ -0,0 +1,13 @@ +import { User } from '../../../src/application/domain/model/user' +import { GeneratorMock } from '../generator.mock' + +export class UserMock { + + public generate(type?: string): User { + const user: User = new User() + user.id = GeneratorMock.generateObjectId() + user.type = type ? type : GeneratorMock.generateUserType() + + return user + } +} diff --git a/test/unit/mappers/email.entity.mapper.spec.ts b/test/unit/mappers/email.entity.mapper.spec.ts new file mode 100644 index 0000000..5858062 --- /dev/null +++ b/test/unit/mappers/email.entity.mapper.spec.ts @@ -0,0 +1,95 @@ +import { assert } from 'chai' +import { Email } from '../../../src/application/domain/model/email' +import { EmailEntityMapper } from '../../../src/infrastructure/entity/mapper/email.entity.mapper' +import { EmailEntity } from '../../../src/infrastructure/entity/email.entity' +import { EmailMock } from '../../mocks/models/email.mock' +import { DefaultEntityMock } from '../../mocks/models/default.entity.mock' + +describe('MAPPERS: EmailEntityMapper', () => { + const emailTokenEntityMapper: EmailEntityMapper = new EmailEntityMapper() + + // Create Email model. + const email: Email = new EmailMock().generate() + + // Create Email JSON. + const emailJSON: any = DefaultEntityMock.EMAIL + + describe('transform(item: any)', () => { + context('when the parameter is of type Email', () => { + it('should return an EmailEntity from a complete Email', () => { + const result: EmailEntity = emailTokenEntityMapper.transform(email) + + assert.propertyVal(result, 'id', email.id) + assert.propertyVal(result.from, 'name', email.from.name) + assert.propertyVal(result.from, 'email', email.from.email) + assert.propertyVal(result.reply, 'name', email.reply?.name) + assert.propertyVal(result.reply, 'email', email.reply?.email) + assert.propertyVal(result.to[0], 'name', email.to[0].name) + assert.propertyVal(result.to[0], 'email', email.to[0].email) + assert.propertyVal(result.cc![0], 'name', email.cc![0].name) + assert.propertyVal(result.cc![0], 'email', email.cc![0].email) + assert.propertyVal(result.bcc![0], 'name', email.bcc![0].name) + assert.propertyVal(result.bcc![0], 'email', email.bcc![0].email) + assert.propertyVal(result, 'subject', email.subject) + assert.propertyVal(result, 'text', email.text) + assert.propertyVal(result, 'html', email.html) + assert.propertyVal(result.attachments![0], 'filename', email.attachments![0].filename) + assert.propertyVal(result.attachments![0], 'path', email.attachments![0].path) + assert.propertyVal(result.attachments![0], 'content_type', email.attachments![0].contentType) + assert.propertyVal(result, 'user_id', email.userId) + }) + + it('should return an empty EmailEntity from empty Email', () => { + const result: EmailEntity = emailTokenEntityMapper.transform(new Email()) + + assert.isEmpty(result.to) + assert.isEmpty(result.cc) + assert.isEmpty(result.bcc) + assert.isEmpty(result.attachments) + }) + }) + + context('when the parameter is a JSON', () => { + it('should return an Email from a complete JSON', () => { + const result: Email = emailTokenEntityMapper.transform(emailJSON) + + assert.propertyVal(result, 'id', emailJSON.id) + assert.propertyVal(result, 'template', 'default') + assert.propertyVal(result.from, 'name', emailJSON.from.name) + assert.propertyVal(result.from, 'email', emailJSON.from.email) + assert.propertyVal(result.reply, 'name', emailJSON.reply.name) + assert.propertyVal(result.reply, 'email', emailJSON.reply.email) + assert.propertyVal(result.to[0], 'name', emailJSON.to[0].name) + assert.propertyVal(result.to[0], 'email', emailJSON.to[0].email) + assert.propertyVal(result.cc![0], 'name', emailJSON.cc[0].name) + assert.propertyVal(result.cc![0], 'email', emailJSON.cc[0].email) + assert.propertyVal(result.bcc![0], 'name', emailJSON.bcc[0].name) + assert.propertyVal(result.bcc![0], 'email', emailJSON.bcc[0].email) + assert.propertyVal(result, 'subject', emailJSON.subject) + assert.propertyVal(result, 'text', emailJSON.text) + assert.propertyVal(result, 'html', emailJSON.html) + assert.propertyVal(result, 'createdAt', emailJSON.created_at) + assert.propertyVal(result.attachments![0], 'filename', emailJSON.attachments[0].filename) + assert.propertyVal(result.attachments![0], 'path', emailJSON.attachments[0].path) + assert.propertyVal(result.attachments![0], 'contentType', emailJSON.attachments[0].content_type) + assert.propertyVal(result, 'userId', emailJSON.user_id) + }) + + it('should return an Email with some attributes equal to undefined from an empty JSON', () => { + const result: Email = emailTokenEntityMapper.transform({}) + + assert.isUndefined(result.id) + assert.propertyVal(result, 'template', 'default') + }) + }) + + context('when the parameter is undefined', () => { + it('should return an Email with some attributes equal to undefined from undefined json', () => { + const result: Email = emailTokenEntityMapper.transform(undefined) + + assert.isUndefined(result.id) + assert.propertyVal(result, 'template', 'default') + }) + }) + }) +}) diff --git a/test/unit/models/address.model.spec.ts b/test/unit/models/address.model.spec.ts new file mode 100644 index 0000000..dbe87c7 --- /dev/null +++ b/test/unit/models/address.model.spec.ts @@ -0,0 +1,72 @@ +import { assert } from 'chai' +import { Address } from '../../../src/application/domain/model/address' +import { DefaultEntityMock } from '../../mocks/models/default.entity.mock' + +describe('MODELS: Address', () => { + const addressJSON: any = JSON.parse(JSON.stringify(DefaultEntityMock.ADDRESS)) + + describe('fromJSON()', () => { + context('when a json is passed', () => { + it('should return an Address from a complete json', () => { + const result: Address = new Address().fromJSON(addressJSON) + + assert.propertyVal(result, 'name', addressJSON.name) + assert.propertyVal(result, 'email', addressJSON.email) + }) + + it('should return an Address with some attributes equal to undefined from an empty json', () => { + const result: Address = new Address().fromJSON({}) + + assert.isEmpty(result) + }) + }) + + context('when the parameter is undefined', () => { + it('should return an Address with some attributes equal to undefined from an undefined json', () => { + const result: Address = new Address().fromJSON(undefined) + + assert.isEmpty(result) + }) + }) + + context('when the json is a string', () => { + it('should return an Address from a complete json', () => { + const result: Address = new Address().fromJSON(JSON.stringify(addressJSON)) + + assert.propertyVal(result, 'name', addressJSON.name) + assert.propertyVal(result, 'email', addressJSON.email) + }) + + it('should return an Address with some attributes equal to undefined from an empty string', () => { + const result: Address = new Address().fromJSON(JSON.stringify('')) + + assert.isEmpty(result) + }) + + it('should return an Address with some attributes equal to undefined from an invalid string', () => { + const result: Address = new Address().fromJSON('d52215d412') + + assert.isEmpty(result) + }) + }) + }) + + describe('toJSON()', () => { + context('when toJSON() is executed', () => { + it('should return a JSON from a complete Address', () => { + const address: Address = new Address(addressJSON.name, addressJSON.email) + const result: any = address.toJSON() + + assert.propertyVal(result, 'name', addressJSON.name) + assert.propertyVal(result, 'email', addressJSON.email) + }) + + it('should return a JSON with all attributes equal to undefined from an incomplete Address', () => { + const result: any = new Address().toJSON() + + assert.isUndefined(result.id) + assert.isUndefined(result.type) + }) + }) + }) +}) diff --git a/test/unit/models/attachment.model.spec.ts b/test/unit/models/attachment.model.spec.ts new file mode 100644 index 0000000..e7caf7c --- /dev/null +++ b/test/unit/models/attachment.model.spec.ts @@ -0,0 +1,76 @@ +import { assert } from 'chai' +import { Attachment } from '../../../src/application/domain/model/attachment' +import { DefaultEntityMock } from '../../mocks/models/default.entity.mock' + +describe('MODELS: Attachment', () => { + const attachmentJSON: any = JSON.parse(JSON.stringify(DefaultEntityMock.ATTACHMENT)) + + describe('fromJSON()', () => { + context('when a json is passed', () => { + it('should return an Attachment from a complete json', () => { + const result: Attachment = new Attachment().fromJSON(attachmentJSON) + + assert.propertyVal(result, 'filename', attachmentJSON.filename) + assert.propertyVal(result, 'path', attachmentJSON.path) + assert.propertyVal(result, 'contentType', attachmentJSON.content_type) + }) + + it('should return an Attachment with some attributes equal to undefined from an empty json', () => { + const result: Attachment = new Attachment().fromJSON({}) + + assert.isEmpty(result) + }) + }) + + context('when the parameter is undefined', () => { + it('should return an Attachment with some attributes equal to undefined from an undefined json', () => { + const result: Attachment = new Attachment().fromJSON(undefined) + + assert.isEmpty(result) + }) + }) + + context('when the json is a string', () => { + it('should return an Attachment from a complete json', () => { + const result: Attachment = new Attachment().fromJSON(JSON.stringify(attachmentJSON)) + + assert.propertyVal(result, 'filename', attachmentJSON.filename) + assert.propertyVal(result, 'path', attachmentJSON.path) + assert.propertyVal(result, 'contentType', attachmentJSON.content_type) + }) + + it('should return an Attachment with some attributes equal to undefined from an empty string', () => { + const result: Attachment = new Attachment().fromJSON(JSON.stringify('')) + + assert.isEmpty(result) + }) + + it('should return an Attachment with some attributes equal to undefined from an invalid string', () => { + const result: Attachment = new Attachment().fromJSON('d52215d412') + + assert.isEmpty(result) + }) + }) + }) + + describe('toJSON()', () => { + context('when toJSON() is executed', () => { + it('should return a JSON from a complete Attachment', () => { + const attachment: Attachment = new Attachment().fromJSON(attachmentJSON) + const result: any = attachment.toJSON() + + assert.propertyVal(result, 'filename', attachmentJSON.filename) + assert.propertyVal(result, 'path', attachmentJSON.path) + assert.propertyVal(result, 'content_type', attachmentJSON.content_type) + }) + + it('should return a JSON with all attributes equal to undefined from an incomplete Attachment', () => { + const result: any = new Attachment().toJSON() + + assert.isUndefined(result.filename) + assert.isUndefined(result.path) + assert.isUndefined(result.content_type) + }) + }) + }) +}) diff --git a/test/unit/models/email.model.spec.ts b/test/unit/models/email.model.spec.ts new file mode 100644 index 0000000..6e151a3 --- /dev/null +++ b/test/unit/models/email.model.spec.ts @@ -0,0 +1,130 @@ +import { assert } from 'chai' +import { Email } from '../../../src/application/domain/model/email' +import { DefaultEntityMock } from '../../mocks/models/default.entity.mock' + +describe('MODELS: Email', () => { + const emailJSON: any = JSON.parse(JSON.stringify(DefaultEntityMock.EMAIL)) + + describe('fromJSON()', () => { + context('when a json is passed', () => { + it('should return an Email from a complete json', () => { + const result: Email = new Email().fromJSON(emailJSON) + + assert.propertyVal(result, 'id', emailJSON.id) + assert.propertyVal(result, 'template', emailJSON.template) + assert.propertyVal(result.from, 'name', emailJSON.from.name) + assert.propertyVal(result.from, 'email', emailJSON.from.email) + assert.propertyVal(result.reply, 'name', emailJSON.reply.name) + assert.propertyVal(result.reply, 'email', emailJSON.reply.email) + assert.propertyVal(result.to[0], 'name', emailJSON.to[0].name) + assert.propertyVal(result.to[0], 'email', emailJSON.to[0].email) + assert.propertyVal(result.cc![0], 'name', emailJSON.cc[0].name) + assert.propertyVal(result.cc![0], 'email', emailJSON.cc[0].email) + assert.propertyVal(result.bcc![0], 'name', emailJSON.bcc[0].name) + assert.propertyVal(result.bcc![0], 'email', emailJSON.bcc[0].email) + assert.propertyVal(result, 'subject', emailJSON.subject) + assert.propertyVal(result, 'text', emailJSON.text) + assert.propertyVal(result, 'html', emailJSON.html) + assert.propertyVal(result, 'createdAt', emailJSON.created_at) + assert.propertyVal(result.attachments![0], 'filename', emailJSON.attachments[0].filename) + assert.propertyVal(result.attachments![0], 'path', emailJSON.attachments[0].path) + assert.propertyVal(result.attachments![0], 'contentType', emailJSON.attachments[0].content_type) + assert.propertyVal(result, 'userId', emailJSON.user_id) + assert.propertyVal(result, 'link', emailJSON.link) + }) + + it('should return an Email with some attributes equal to undefined from an empty json', () => { + const result: Email = new Email().fromJSON({}) + + assert.isUndefined(result.id) + assert.propertyVal(result, 'template', 'default') + }) + }) + + context('when the parameter is undefined', () => { + it('should return an Email with some attributes equal to undefined from an undefined json', () => { + const result: Email = new Email().fromJSON(undefined) + + assert.isUndefined(result.id) + assert.propertyVal(result, 'template', 'default') + }) + }) + + context('when the json is a string', () => { + it('should return an Email from a complete json', () => { + const result: Email = new Email().fromJSON(JSON.stringify(emailJSON)) + + assert.propertyVal(result, 'id', emailJSON.id) + assert.propertyVal(result, 'template', emailJSON.template) + assert.propertyVal(result.from, 'name', emailJSON.from.name) + assert.propertyVal(result.from, 'email', emailJSON.from.email) + assert.propertyVal(result.reply, 'name', emailJSON.reply.name) + assert.propertyVal(result.reply, 'email', emailJSON.reply.email) + assert.propertyVal(result.to[0], 'name', emailJSON.to[0].name) + assert.propertyVal(result.to[0], 'email', emailJSON.to[0].email) + assert.propertyVal(result.cc![0], 'name', emailJSON.cc[0].name) + assert.propertyVal(result.cc![0], 'email', emailJSON.cc[0].email) + assert.propertyVal(result.bcc![0], 'name', emailJSON.bcc[0].name) + assert.propertyVal(result.bcc![0], 'email', emailJSON.bcc[0].email) + assert.propertyVal(result, 'subject', emailJSON.subject) + assert.propertyVal(result, 'text', emailJSON.text) + assert.propertyVal(result, 'html', emailJSON.html) + assert.propertyVal(result, '_createdAt', emailJSON.created_at) + assert.propertyVal(result.attachments![0], 'filename', emailJSON.attachments[0].filename) + assert.propertyVal(result.attachments![0], 'path', emailJSON.attachments[0].path) + assert.propertyVal(result.attachments![0], 'contentType', emailJSON.attachments[0].content_type) + assert.propertyVal(result, 'userId', emailJSON.user_id) + assert.propertyVal(result, 'link', emailJSON.link) + }) + + it('should return an Email with some attributes equal to undefined from an empty string', () => { + const result: Email = new Email().fromJSON(JSON.stringify('')) + + assert.isUndefined(result.id) + assert.propertyVal(result, 'template', 'default') + }) + + it('should return an Email with some attributes equal to undefined from an invalid string', () => { + const result: Email = new Email().fromJSON('d52215d412') + + assert.isUndefined(result.id) + assert.propertyVal(result, 'template', 'default') + }) + }) + }) + + describe('toJSON()', () => { + context('when toJSON() is executed', () => { + it('should return a JSON from a complete Email', () => { + const email: Email = new Email().fromJSON(emailJSON) + const result: any = email.toJSON() + + assert.propertyVal(result, 'id', emailJSON.id) + assert.deepPropertyVal(result, 'reply', emailJSON.reply) + assert.deepPropertyVal(result, 'to', emailJSON.to) + assert.deepPropertyVal(result, 'cc', emailJSON.cc) + assert.deepPropertyVal(result, 'bcc', emailJSON.bcc) + assert.propertyVal(result, 'subject', emailJSON.subject) + assert.propertyVal(result, 'text', emailJSON.text) + assert.propertyVal(result, 'html', emailJSON.html) + assert.deepPropertyVal(result, 'attachments', emailJSON.attachments) + assert.propertyVal(result, 'created_at', emailJSON.created_at) + }) + + it('should return a JSON with all attributes equal to undefined from an incomplete Email', () => { + const result: any = new Email().toJSON() + + assert.isUndefined(result.id) + assert.isUndefined(result.reply) + assert.isEmpty(result.to) + assert.isEmpty(result.cc) + assert.isEmpty(result.bcc) + assert.isUndefined(result.subject) + assert.isUndefined(result.text) + assert.isUndefined(result.html) + assert.isEmpty(result.attachments) + assert.isUndefined(result.created_at) + }) + }) + }) +}) diff --git a/test/unit/models/user.model.spec.ts b/test/unit/models/user.model.spec.ts new file mode 100644 index 0000000..4e7adec --- /dev/null +++ b/test/unit/models/user.model.spec.ts @@ -0,0 +1,72 @@ +import { assert } from 'chai' +import { User } from '../../../src/application/domain/model/user' +import { DefaultEntityMock } from '../../mocks/models/default.entity.mock' + +describe('MODELS: User', () => { + const userJSON: any = JSON.parse(JSON.stringify(DefaultEntityMock.USER)) + + describe('fromJSON()', () => { + context('when a json is passed', () => { + it('should return an User from a complete json', () => { + const result: User = new User().fromJSON(userJSON) + + assert.propertyVal(result, 'id', userJSON.id) + assert.propertyVal(result, 'type', userJSON.type) + }) + + it('should return an User with some attributes equal to undefined from an empty json', () => { + const result: User = new User().fromJSON({}) + + assert.isUndefined(result.id) + }) + }) + + context('when the parameter is undefined', () => { + it('should return an User with some attributes equal to undefined from an undefined json', () => { + const result: User = new User().fromJSON(undefined) + + assert.isUndefined(result.id) + }) + }) + + context('when the json is a string', () => { + it('should return an User from a complete json', () => { + const result: User = new User().fromJSON(JSON.stringify(userJSON)) + + assert.propertyVal(result, 'id', userJSON.id) + assert.propertyVal(result, 'type', userJSON.type) + }) + + it('should return an User with some attributes equal to undefined from an empty string', () => { + const result: User = new User().fromJSON(JSON.stringify('')) + + assert.isUndefined(result.id) + }) + + it('should return an User with some attributes equal to undefined from an invalid string', () => { + const result: User = new User().fromJSON('d52215d412') + + assert.isUndefined(result.id) + }) + }) + }) + + describe('toJSON()', () => { + context('when toJSON() is executed', () => { + it('should return a JSON from a complete User', () => { + const user: User = new User().fromJSON(userJSON) + const result: any = user.toJSON() + + assert.propertyVal(result, 'id', userJSON.id) + assert.propertyVal(result, 'type', userJSON.type) + }) + + it('should return a JSON with all attributes equal to undefined from an incomplete User', () => { + const result: any = new User().toJSON() + + assert.isUndefined(result.id) + assert.isUndefined(result.type) + }) + }) + }) +}) diff --git a/test/unit/validators/email.pilot.study.data.validator.spec.ts b/test/unit/validators/email.pilot.study.data.validator.spec.ts new file mode 100644 index 0000000..5f0dbfc --- /dev/null +++ b/test/unit/validators/email.pilot.study.data.validator.spec.ts @@ -0,0 +1,78 @@ +import { assert } from 'chai' +import { DefaultEntityMock } from '../../mocks/models/default.entity.mock' +import { EmailPilotStudyDataValidator } from '../../../src/application/domain/validator/email.pilot.study.data.validator' +import { ValidationException } from '../../../src/application/domain/exception/validation.exception' +import { Strings } from '../../../src/utils/strings' + +describe('VALIDATORS: EmailPilotStudyDataValidator', () => { + let pilotStudyDataEmail: any = JSON.parse(JSON.stringify(DefaultEntityMock.PILOT_STUDY_DATA_EMAIL)) + + afterEach(() => { + pilotStudyDataEmail = JSON.parse(JSON.stringify(DefaultEntityMock.PILOT_STUDY_DATA_EMAIL)) + }) + + context('when the pilot study data email is valid', () => { + it('should return undefined when the validation was successful', () => { + try { + const result = EmailPilotStudyDataValidator.validate(pilotStudyDataEmail) + assert.isUndefined(result) + } catch (err) { + assert.fail(err) + } + }) + }) + + context('when the pilot study data email is incomplete', () => { + it('should throw ValidationException for an incomplete pilot study data email (missing attachments fields)', () => { + try { + pilotStudyDataEmail.attachments = [{}] + EmailPilotStudyDataValidator.validate(pilotStudyDataEmail) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS) + assert.propertyVal(err, 'description', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS_DESC + .replace('{0}', 'attachments.filename, attachments.path, attachments.content_type')) + } + }) + + it('should throw ValidationException for an incomplete pilot study data email (missing all fields)', () => { + try { + EmailPilotStudyDataValidator.validate({}) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS) + assert.propertyVal(err, 'description', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS_DESC + .replace('{0}', 'to, pilot_study, request_date, action_url, attachments')) + } + }) + }) + + context('when the attachments array of the pilot study data email is empty', () => { + it('should throw a ValidationException for empty attachments array', () => { + try { + pilotStudyDataEmail.attachments = [] + EmailPilotStudyDataValidator.validate(pilotStudyDataEmail) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.EMPTY_ATTACHMENTS) + } + }) + }) + + context('when the \'to\' email from the pilot study data email is invalid', () => { + it('should throw a ValidationException for invalid email', () => { + try { + pilotStudyDataEmail.to.email = 'invalid_email@mailcom' + EmailPilotStudyDataValidator.validate(pilotStudyDataEmail) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.INVALID_EMAIL + .replace('{0}', 'invalid_email@mailcom')) + } + }) + }) +}) diff --git a/test/unit/validators/email.reset.password.validator.spec.ts b/test/unit/validators/email.reset.password.validator.spec.ts new file mode 100644 index 0000000..78a9aaa --- /dev/null +++ b/test/unit/validators/email.reset.password.validator.spec.ts @@ -0,0 +1,65 @@ +import { assert } from 'chai' +import { DefaultEntityMock } from '../../mocks/models/default.entity.mock' +import { EmailResetPasswordValidator } from '../../../src/application/domain/validator/email.reset.password.validator' +import { ValidationException } from '../../../src/application/domain/exception/validation.exception' +import { Strings } from '../../../src/utils/strings' + +describe('VALIDATORS: EmailResetPasswordValidator', () => { + let resetPasswordEmail: any = JSON.parse(JSON.stringify(DefaultEntityMock.RESET_PASSWORD_EMAIL)) + + afterEach(() => { + resetPasswordEmail = JSON.parse(JSON.stringify(DefaultEntityMock.RESET_PASSWORD_EMAIL)) + }) + + context('when the reset password email is valid', () => { + it('should return undefined when the validation was successful', () => { + try { + const result = EmailResetPasswordValidator.validate(resetPasswordEmail) + assert.isUndefined(result) + } catch (err) { + assert.fail(err) + } + }) + }) + + context('when the reset password email is incomplete', () => { + it('should throw ValidationException for an incomplete reset password email (missing to)', () => { + try { + resetPasswordEmail.to = undefined + EmailResetPasswordValidator.validate(resetPasswordEmail) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS) + assert.propertyVal(err, 'description', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS_DESC + .replace('{0}', 'to')) + } + }) + + it('should throw ValidationException for an incomplete reset password email (missing all fields)', () => { + try { + EmailResetPasswordValidator.validate({}) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS) + assert.propertyVal(err, 'description', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS_DESC + .replace('{0}', 'to, action_url')) + } + }) + }) + + context('when the \'to\' email from the reset password email is invalid', () => { + it('should throw a ValidationException for invalid email', () => { + try { + resetPasswordEmail.to.email = 'invalid_email@mailcom' + EmailResetPasswordValidator.validate(resetPasswordEmail) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.INVALID_EMAIL + .replace('{0}', 'invalid_email@mailcom')) + } + }) + }) +}) diff --git a/test/unit/validators/email.send.validator.spec.ts b/test/unit/validators/email.send.validator.spec.ts new file mode 100644 index 0000000..a8aecc5 --- /dev/null +++ b/test/unit/validators/email.send.validator.spec.ts @@ -0,0 +1,171 @@ +import { assert } from 'chai' +import { EmailSendValidator } from '../../../src/application/domain/validator/email.send.validator' +import { ValidationException } from '../../../src/application/domain/exception/validation.exception' +import { Strings } from '../../../src/utils/strings' +import { Email } from '../../../src/application/domain/model/email' +import { EmailMock } from '../../mocks/models/email.mock' +import { Attachment } from '../../../src/application/domain/model/attachment' + +describe('VALIDATORS: EmailSendValidator', () => { + let email: Email = new EmailMock().generate() + + afterEach(() => { + email = new EmailMock().generate() + }) + + context('when the email is valid', () => { + it('should return undefined when the validation was successful', () => { + try { + const result = EmailSendValidator.validate(email) + assert.isUndefined(result) + } catch (err) { + assert.fail(err) + } + }) + }) + + context('when the email is incomplete', () => { + it('should throw ValidationException for an incomplete email (missing subject)', () => { + try { + email.subject = undefined! + EmailSendValidator.validate(email) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS) + assert.propertyVal(err, 'description', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS_DESC + .replace('{0}', 'subject')) + } + }) + + it('should throw ValidationException for an incomplete email (missing reply.email)', () => { + try { + email.reply!.email = undefined! + EmailSendValidator.validate(email) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_REPLY_EMAIL) + } + }) + + it('should throw ValidationException for an incomplete email (missing to.email)', () => { + try { + email.to[0].email = undefined! + EmailSendValidator.validate(email) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_TO_EMAIL) + } + }) + + it('should throw ValidationException for an incomplete email (missing cc.email)', () => { + try { + email.cc![0].email = undefined! + EmailSendValidator.validate(email) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_CC_EMAIL) + } + }) + + it('should throw ValidationException for an incomplete email (missing bcc.email)', () => { + try { + email.bcc![0].email = undefined! + EmailSendValidator.validate(email) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_BCC_EMAIL) + } + }) + + it('should throw ValidationException for an incomplete email (missing attachments.path)', () => { + try { + email.attachments![0] = new Attachment() + EmailSendValidator.validate(email) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_ATTACHMENTS_PATH) + } + }) + + it('should throw ValidationException for an incomplete email (missing all fields)', () => { + try { + EmailSendValidator.validate(new Email()) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS) + assert.propertyVal(err, 'description', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS_DESC + .replace('{0}', 'subject, to')) + } + }) + }) + + context('when the \'to\' array of the email is empty', () => { + it('should throw a ValidationException for empty \'to\' array', () => { + try { + email.to = [] + EmailSendValidator.validate(email) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.EMPTY_TO) + } + }) + }) + + context('when the email is invalid', () => { + it('should throw a ValidationException for invalid reply email', () => { + try { + email.reply!.email = 'invalid_email@mailcom' + EmailSendValidator.validate(email) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.INVALID_EMAIL + .replace('{0}', 'invalid_email@mailcom')) + } + }) + + it('should throw a ValidationException for invalid \'to\' email', () => { + try { + email.to[0].email = 'invalid_email@mailcom' + EmailSendValidator.validate(email) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.INVALID_EMAIL + .replace('{0}', 'invalid_email@mailcom')) + } + }) + + it('should throw a ValidationException for invalid \'cc\' email', () => { + try { + email.cc![0].email = 'invalid_email@mailcom' + EmailSendValidator.validate(email) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.INVALID_EMAIL + .replace('{0}', 'invalid_email@mailcom')) + } + }) + + it('should throw a ValidationException for invalid \'bcc\' email', () => { + try { + email.bcc![0].email = 'invalid_email@mailcom' + EmailSendValidator.validate(email) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.INVALID_EMAIL + .replace('{0}', 'invalid_email@mailcom')) + } + }) + }) +}) diff --git a/test/unit/validators/email.to.validator.spec.ts b/test/unit/validators/email.to.validator.spec.ts new file mode 100644 index 0000000..0cd8c55 --- /dev/null +++ b/test/unit/validators/email.to.validator.spec.ts @@ -0,0 +1,64 @@ +import { assert } from 'chai' +import { DefaultEntityMock } from '../../mocks/models/default.entity.mock' +import { EmailToValidator } from '../../../src/application/domain/validator/email.to.validator' +import { ValidationException } from '../../../src/application/domain/exception/validation.exception' +import { Strings } from '../../../src/utils/strings' + +describe('VALIDATORS: EmailToValidator', () => { + let emailTo: any = JSON.parse(JSON.stringify(DefaultEntityMock.ADDRESS)) + + afterEach(() => { + emailTo = JSON.parse(JSON.stringify(DefaultEntityMock.ADDRESS)) + }) + + context('when the email \'to\' is valid', () => { + it('should return undefined when the validation was successful', () => { + try { + const result = EmailToValidator.validate(emailTo) + assert.isUndefined(result) + } catch (err) { + assert.fail(err) + } + }) + }) + + context('when the email \'to\' is incomplete', () => { + it('should throw ValidationException for an incomplete email \'to\' (missing name)', () => { + try { + emailTo.name = undefined + EmailToValidator.validate(emailTo) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.INVALID_TO) + assert.propertyVal(err, 'description', Strings.ERROR_MESSAGE.VALIDATE.INVALID_TO_DESC.replace('{0}', 'name')) + } + }) + + it('should throw ValidationException for an incomplete email \'to\' (missing email)', () => { + try { + emailTo.email = undefined + EmailToValidator.validate(emailTo) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.INVALID_TO) + assert.propertyVal(err, 'description', Strings.ERROR_MESSAGE.VALIDATE.INVALID_TO_DESC.replace('{0}', 'email')) + } + }) + }) + + context('when the \'to\' email is invalid', () => { + it('should throw a ValidationException for invalid email', () => { + try { + emailTo.email = 'invalid_email@mailcom' + EmailToValidator.validate(emailTo) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.INVALID_EMAIL + .replace('{0}', 'invalid_email@mailcom')) + } + }) + }) +}) diff --git a/test/unit/validators/email.update.password.validator.spec.ts b/test/unit/validators/email.update.password.validator.spec.ts new file mode 100644 index 0000000..20a5efd --- /dev/null +++ b/test/unit/validators/email.update.password.validator.spec.ts @@ -0,0 +1,53 @@ +import { assert } from 'chai' +import { DefaultEntityMock } from '../../mocks/models/default.entity.mock' +import { EmailUpdatePasswordValidator } from '../../../src/application/domain/validator/email.update.password.validator' +import { ValidationException } from '../../../src/application/domain/exception/validation.exception' +import { Strings } from '../../../src/utils/strings' + +describe('VALIDATORS: EmailUpdatePasswordValidator', () => { + let updatePasswordEmail: any = JSON.parse(JSON.stringify(DefaultEntityMock.UPDATE_PASSWORD_EMAIL)) + + afterEach(() => { + updatePasswordEmail = JSON.parse(JSON.stringify(DefaultEntityMock.UPDATE_PASSWORD_EMAIL)) + }) + + context('when the update password email is valid', () => { + it('should return undefined when the validation was successful', () => { + try { + const result = EmailUpdatePasswordValidator.validate(updatePasswordEmail) + assert.isUndefined(result) + } catch (err) { + assert.fail(err) + } + }) + }) + + context('when the update password email is incomplete', () => { + it('should throw ValidationException for an incomplete update password email (missing to)', () => { + try { + updatePasswordEmail.to = undefined + EmailUpdatePasswordValidator.validate(updatePasswordEmail) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS) + assert.propertyVal(err, 'description', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS_DESC + .replace('{0}', 'to')) + } + }) + }) + + context('when the \'to\' email from the update password email is invalid', () => { + it('should throw a ValidationException for invalid email', () => { + try { + updatePasswordEmail.to.email = 'invalid_email@mailcom' + EmailUpdatePasswordValidator.validate(updatePasswordEmail) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.INVALID_EMAIL + .replace('{0}', 'invalid_email@mailcom')) + } + }) + }) +}) diff --git a/test/unit/validators/email.validator.spec.ts b/test/unit/validators/email.validator.spec.ts new file mode 100644 index 0000000..d4b6d22 --- /dev/null +++ b/test/unit/validators/email.validator.spec.ts @@ -0,0 +1,70 @@ +import { assert } from 'chai' +import { EmailValidator } from '../../../src/application/domain/validator/email.validator' +import { ValidationException } from '../../../src/application/domain/exception/validation.exception' +import { Strings } from '../../../src/utils/strings' + +describe('VALIDATORS: EmailValidator', () => { + let email: string = 'valid_email@mail.com' + + afterEach(() => { + email = 'valid_email@mail.com' + }) + + context('when the Email is valid', () => { + it('should return undefined when the validation was successful', () => { + try { + const result = EmailValidator.validate(email) + assert.isUndefined(result) + } catch (err) { + assert.fail(err) + } + }) + }) + + context('when the email is invalid', () => { + it('should throw ValidationException for invalid email: undefined', () => { + try { + email = undefined! + EmailValidator.validate(email) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.INVALID_EMAIL.replace('{0}', undefined)) + } + }) + + it('should throw ValidationException for invalid email: null', () => { + try { + email = null! + EmailValidator.validate(email) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.INVALID_EMAIL.replace('{0}', null)) + } + }) + + it('should throw ValidationException for invalid email: empty', () => { + try { + email = '' + EmailValidator.validate(email) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.INVALID_EMAIL.replace('{0}', '')) + } + }) + + it('should throw ValidationException for invalid email', () => { + try { + email = 'invalid_email@mailcom' + EmailValidator.validate(email) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.INVALID_EMAIL + .replace('{0}', 'invalid_email@mailcom')) + } + }) + }) +}) diff --git a/test/unit/validators/email.welcome.validator.spec.ts b/test/unit/validators/email.welcome.validator.spec.ts new file mode 100644 index 0000000..daef108 --- /dev/null +++ b/test/unit/validators/email.welcome.validator.spec.ts @@ -0,0 +1,65 @@ +import { assert } from 'chai' +import { DefaultEntityMock } from '../../mocks/models/default.entity.mock' +import { EmailWelcomeValidator } from '../../../src/application/domain/validator/email.welcome.validator' +import { ValidationException } from '../../../src/application/domain/exception/validation.exception' +import { Strings } from '../../../src/utils/strings' + +describe('VALIDATORS: EmailWelcomeValidator', () => { + let welcomeEmail: any = JSON.parse(JSON.stringify(DefaultEntityMock.WELCOME_EMAIL)) + + afterEach(() => { + welcomeEmail = JSON.parse(JSON.stringify(DefaultEntityMock.WELCOME_EMAIL)) + }) + + context('when the welcome email is valid', () => { + it('should return undefined when the validation was successful', () => { + try { + const result = EmailWelcomeValidator.validate(welcomeEmail) + assert.isUndefined(result) + } catch (err) { + assert.fail(err) + } + }) + }) + + context('when the welcome email is incomplete', () => { + it('should throw ValidationException for an incomplete welcome email (missing to)', () => { + try { + welcomeEmail.to = undefined + EmailWelcomeValidator.validate(welcomeEmail) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS) + assert.propertyVal(err, 'description', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS_DESC + .replace('{0}', 'to')) + } + }) + + it('should throw ValidationException for an incomplete welcome email (missing all fields)', () => { + try { + EmailWelcomeValidator.validate({}) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS) + assert.propertyVal(err, 'description', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS_DESC + .replace('{0}', 'to, action_url')) + } + }) + }) + + context('when the \'to\' email from the welcome email is invalid', () => { + it('should throw a ValidationException for invalid email', () => { + try { + welcomeEmail.to.email = 'invalid_email@mailcom' + EmailWelcomeValidator.validate(welcomeEmail) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.INVALID_EMAIL + .replace('{0}', 'invalid_email@mailcom')) + } + }) + }) +}) diff --git a/test/unit/validators/user.validator.spec.ts b/test/unit/validators/user.validator.spec.ts new file mode 100644 index 0000000..96b06c4 --- /dev/null +++ b/test/unit/validators/user.validator.spec.ts @@ -0,0 +1,67 @@ +import { assert } from 'chai' +import { ValidationException } from '../../../src/application/domain/exception/validation.exception' +import { Strings } from '../../../src/utils/strings' +import { User } from '../../../src/application/domain/model/user' +import { UserValidator } from '../../../src/application/domain/validator/user.validator' +import { UserMock } from '../../mocks/models/user.mock' + +describe('VALIDATORS: UserValidator', () => { + let user: User = new UserMock().generate() + + afterEach(() => { + user = new UserMock().generate() + }) + + context('when the User is valid', () => { + it('should return undefined when the validation was successful', () => { + try { + const result = UserValidator.validate(user) + assert.isUndefined(result) + } catch (err) { + assert.fail(err) + } + }) + }) + + context('when the User is incomplete', () => { + it('should throw ValidationException for an incomplete User (missing id)', () => { + try { + user.id = undefined + UserValidator.validate(user) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS) + assert.propertyVal(err, 'description', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS_DESC + .replace('{0}', 'id')) + } + }) + + + it('should throw ValidationException for an incomplete User (missing all fields)', () => { + try { + UserValidator.validate(new User()) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS) + assert.propertyVal(err, 'description', Strings.ERROR_MESSAGE.VALIDATE.REQUIRED_FIELDS_DESC + .replace('{0}', 'id, type')) + } + }) + }) + + context('when the User id is invalid', () => { + it('should throw ValidationException for invalid ObjectId: 123', () => { + try { + user.id = '123' + UserValidator.validate(user) + assert.fail() + } catch (err) { + assert.instanceOf(err, ValidationException) + assert.propertyVal(err, 'message', Strings.ERROR_MESSAGE.VALIDATE.UUID_NOT_VALID_FORMAT) + assert.propertyVal(err, 'description', Strings.ERROR_MESSAGE.VALIDATE.UUID_NOT_VALID_FORMAT_DESC) + } + }) + }) +})