esercizio

This commit is contained in:
Dmitri 2025-11-16 18:24:18 +01:00
parent 82c87e9358
commit 7986151af4
Signed by: kanopo
GPG Key ID: 759ADD40E3132AC7
7 changed files with 170 additions and 17 deletions

56
package-lock.json generated
View File

@ -225,6 +225,7 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.2.tgz", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.2.tgz",
"integrity": "sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==", "integrity": "sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"@ampproject/remapping": "^2.1.0", "@ampproject/remapping": "^2.1.0",
"@babel/code-frame": "^7.18.6", "@babel/code-frame": "^7.18.6",
@ -1524,6 +1525,7 @@
"version": "9.2.0", "version": "9.2.0",
"resolved": "https://registry.npmjs.org/@nestjs/common/-/common-9.2.0.tgz", "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-9.2.0.tgz",
"integrity": "sha512-Ndcqak/ETYi+n1c5lFRPbxKLyUuM6DIOxcvfEFGfi0f6ad4dWDXRDx7z/n8V0l8+Y8djvvOHgf3t0e93w963Qg==", "integrity": "sha512-Ndcqak/ETYi+n1c5lFRPbxKLyUuM6DIOxcvfEFGfi0f6ad4dWDXRDx7z/n8V0l8+Y8djvvOHgf3t0e93w963Qg==",
"peer": true,
"dependencies": { "dependencies": {
"iterare": "1.2.1", "iterare": "1.2.1",
"tslib": "2.4.1", "tslib": "2.4.1",
@ -1557,6 +1559,7 @@
"resolved": "https://registry.npmjs.org/@nestjs/core/-/core-9.2.0.tgz", "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-9.2.0.tgz",
"integrity": "sha512-eVN7aXAavV+ImVt8mO+rQ5YyUP6lJtQKUtQHxHKzz6Wg+9Y67WWZS2uDcDX5NNcNijbWky5bqad86fgcK9Oqig==", "integrity": "sha512-eVN7aXAavV+ImVt8mO+rQ5YyUP6lJtQKUtQHxHKzz6Wg+9Y67WWZS2uDcDX5NNcNijbWky5bqad86fgcK9Oqig==",
"hasInstallScript": true, "hasInstallScript": true,
"peer": true,
"dependencies": { "dependencies": {
"@nuxtjs/opencollective": "0.3.2", "@nuxtjs/opencollective": "0.3.2",
"fast-safe-stringify": "2.1.1", "fast-safe-stringify": "2.1.1",
@ -1594,6 +1597,7 @@
"version": "9.2.0", "version": "9.2.0",
"resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-9.2.0.tgz", "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-9.2.0.tgz",
"integrity": "sha512-J1+nnzjC9ATSb0jSHBqAE6D4o+PIbGPItEfYTOZ0rkE5bvqnRfgO4q94SXhfri+5PaNx2vM8tOZsKaD0QmQRGQ==", "integrity": "sha512-J1+nnzjC9ATSb0jSHBqAE6D4o+PIbGPItEfYTOZ0rkE5bvqnRfgO4q94SXhfri+5PaNx2vM8tOZsKaD0QmQRGQ==",
"peer": true,
"dependencies": { "dependencies": {
"body-parser": "1.20.1", "body-parser": "1.20.1",
"cors": "2.8.5", "cors": "2.8.5",
@ -2022,7 +2026,8 @@
"version": "16.18.3", "version": "16.18.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.3.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.3.tgz",
"integrity": "sha512-jh6m0QUhIRcZpNv7Z/rpN+ZWXOicUUQbSoWks7Htkbb9IjFQj4kzcX/xFCkjstCj5flMsN8FiSvt+q+Tcs4Llg==", "integrity": "sha512-jh6m0QUhIRcZpNv7Z/rpN+ZWXOicUUQbSoWks7Htkbb9IjFQj4kzcX/xFCkjstCj5flMsN8FiSvt+q+Tcs4Llg==",
"dev": true "dev": true,
"peer": true
}, },
"node_modules/@types/parse-json": { "node_modules/@types/parse-json": {
"version": "4.0.0", "version": "4.0.0",
@ -2142,6 +2147,7 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.44.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.44.0.tgz",
"integrity": "sha512-H7LCqbZnKqkkgQHaKLGC6KUjt3pjJDx8ETDqmwncyb6PuoigYajyAwBGz08VU/l86dZWZgI4zm5k2VaKqayYyA==", "integrity": "sha512-H7LCqbZnKqkkgQHaKLGC6KUjt3pjJDx8ETDqmwncyb6PuoigYajyAwBGz08VU/l86dZWZgI4zm5k2VaKqayYyA==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "5.44.0", "@typescript-eslint/scope-manager": "5.44.0",
"@typescript-eslint/types": "5.44.0", "@typescript-eslint/types": "5.44.0",
@ -2466,6 +2472,7 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
"integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
"dev": true, "dev": true,
"peer": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
@ -2886,6 +2893,7 @@
"url": "https://tidelift.com/funding/github/npm/browserslist" "url": "https://tidelift.com/funding/github/npm/browserslist"
} }
], ],
"peer": true,
"dependencies": { "dependencies": {
"caniuse-lite": "^1.0.30001400", "caniuse-lite": "^1.0.30001400",
"electron-to-chromium": "^1.4.251", "electron-to-chromium": "^1.4.251",
@ -3053,6 +3061,7 @@
"url": "https://paulmillr.com/funding/" "url": "https://paulmillr.com/funding/"
} }
], ],
"peer": true,
"dependencies": { "dependencies": {
"anymatch": "~3.1.2", "anymatch": "~3.1.2",
"braces": "~3.0.2", "braces": "~3.0.2",
@ -3096,12 +3105,14 @@
"node_modules/class-transformer": { "node_modules/class-transformer": {
"version": "0.5.1", "version": "0.5.1",
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
"integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==" "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==",
"peer": true
}, },
"node_modules/class-validator": { "node_modules/class-validator": {
"version": "0.13.2", "version": "0.13.2",
"resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.13.2.tgz", "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.13.2.tgz",
"integrity": "sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw==", "integrity": "sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw==",
"peer": true,
"dependencies": { "dependencies": {
"libphonenumber-js": "^1.9.43", "libphonenumber-js": "^1.9.43",
"validator": "^13.7.0" "validator": "^13.7.0"
@ -3600,6 +3611,7 @@
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.28.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.28.0.tgz",
"integrity": "sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==", "integrity": "sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"@eslint/eslintrc": "^1.3.3", "@eslint/eslintrc": "^1.3.3",
"@humanwhocodes/config-array": "^0.11.6", "@humanwhocodes/config-array": "^0.11.6",
@ -4966,6 +4978,7 @@
"resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz", "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz",
"integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==", "integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"@jest/core": "^28.1.3", "@jest/core": "^28.1.3",
"@jest/types": "^28.1.3", "@jest/types": "^28.1.3",
@ -6666,6 +6679,7 @@
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.0.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.0.tgz",
"integrity": "sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA==", "integrity": "sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA==",
"dev": true, "dev": true,
"peer": true,
"bin": { "bin": {
"prettier": "bin-prettier.js" "prettier": "bin-prettier.js"
}, },
@ -6881,7 +6895,8 @@
"node_modules/reflect-metadata": { "node_modules/reflect-metadata": {
"version": "0.1.13", "version": "0.1.13",
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
"integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==",
"peer": true
}, },
"node_modules/regexpp": { "node_modules/regexpp": {
"version": "3.2.0", "version": "3.2.0",
@ -7042,6 +7057,7 @@
"version": "7.5.7", "version": "7.5.7",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz",
"integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==",
"peer": true,
"dependencies": { "dependencies": {
"tslib": "^2.1.0" "tslib": "^2.1.0"
} }
@ -7093,6 +7109,7 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0", "fast-json-stable-stringify": "^2.0.0",
@ -7807,6 +7824,7 @@
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
"integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"@cspotcode/source-map-support": "^0.8.0", "@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7", "@tsconfig/node10": "^1.0.7",
@ -7979,6 +7997,7 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz",
"integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==",
"dev": true, "dev": true,
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@ -8549,6 +8568,7 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.2.tgz", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.2.tgz",
"integrity": "sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==", "integrity": "sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==",
"dev": true, "dev": true,
"peer": true,
"requires": { "requires": {
"@ampproject/remapping": "^2.1.0", "@ampproject/remapping": "^2.1.0",
"@babel/code-frame": "^7.18.6", "@babel/code-frame": "^7.18.6",
@ -9555,6 +9575,7 @@
"version": "9.2.0", "version": "9.2.0",
"resolved": "https://registry.npmjs.org/@nestjs/common/-/common-9.2.0.tgz", "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-9.2.0.tgz",
"integrity": "sha512-Ndcqak/ETYi+n1c5lFRPbxKLyUuM6DIOxcvfEFGfi0f6ad4dWDXRDx7z/n8V0l8+Y8djvvOHgf3t0e93w963Qg==", "integrity": "sha512-Ndcqak/ETYi+n1c5lFRPbxKLyUuM6DIOxcvfEFGfi0f6ad4dWDXRDx7z/n8V0l8+Y8djvvOHgf3t0e93w963Qg==",
"peer": true,
"requires": { "requires": {
"iterare": "1.2.1", "iterare": "1.2.1",
"tslib": "2.4.1", "tslib": "2.4.1",
@ -9565,6 +9586,7 @@
"version": "9.2.0", "version": "9.2.0",
"resolved": "https://registry.npmjs.org/@nestjs/core/-/core-9.2.0.tgz", "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-9.2.0.tgz",
"integrity": "sha512-eVN7aXAavV+ImVt8mO+rQ5YyUP6lJtQKUtQHxHKzz6Wg+9Y67WWZS2uDcDX5NNcNijbWky5bqad86fgcK9Oqig==", "integrity": "sha512-eVN7aXAavV+ImVt8mO+rQ5YyUP6lJtQKUtQHxHKzz6Wg+9Y67WWZS2uDcDX5NNcNijbWky5bqad86fgcK9Oqig==",
"peer": true,
"requires": { "requires": {
"@nuxtjs/opencollective": "0.3.2", "@nuxtjs/opencollective": "0.3.2",
"fast-safe-stringify": "2.1.1", "fast-safe-stringify": "2.1.1",
@ -9579,6 +9601,7 @@
"version": "9.2.0", "version": "9.2.0",
"resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-9.2.0.tgz", "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-9.2.0.tgz",
"integrity": "sha512-J1+nnzjC9ATSb0jSHBqAE6D4o+PIbGPItEfYTOZ0rkE5bvqnRfgO4q94SXhfri+5PaNx2vM8tOZsKaD0QmQRGQ==", "integrity": "sha512-J1+nnzjC9ATSb0jSHBqAE6D4o+PIbGPItEfYTOZ0rkE5bvqnRfgO4q94SXhfri+5PaNx2vM8tOZsKaD0QmQRGQ==",
"peer": true,
"requires": { "requires": {
"body-parser": "1.20.1", "body-parser": "1.20.1",
"cors": "2.8.5", "cors": "2.8.5",
@ -9943,7 +9966,8 @@
"version": "16.18.3", "version": "16.18.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.3.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.3.tgz",
"integrity": "sha512-jh6m0QUhIRcZpNv7Z/rpN+ZWXOicUUQbSoWks7Htkbb9IjFQj4kzcX/xFCkjstCj5flMsN8FiSvt+q+Tcs4Llg==", "integrity": "sha512-jh6m0QUhIRcZpNv7Z/rpN+ZWXOicUUQbSoWks7Htkbb9IjFQj4kzcX/xFCkjstCj5flMsN8FiSvt+q+Tcs4Llg==",
"dev": true "dev": true,
"peer": true
}, },
"@types/parse-json": { "@types/parse-json": {
"version": "4.0.0", "version": "4.0.0",
@ -10047,6 +10071,7 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.44.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.44.0.tgz",
"integrity": "sha512-H7LCqbZnKqkkgQHaKLGC6KUjt3pjJDx8ETDqmwncyb6PuoigYajyAwBGz08VU/l86dZWZgI4zm5k2VaKqayYyA==", "integrity": "sha512-H7LCqbZnKqkkgQHaKLGC6KUjt3pjJDx8ETDqmwncyb6PuoigYajyAwBGz08VU/l86dZWZgI4zm5k2VaKqayYyA==",
"dev": true, "dev": true,
"peer": true,
"requires": { "requires": {
"@typescript-eslint/scope-manager": "5.44.0", "@typescript-eslint/scope-manager": "5.44.0",
"@typescript-eslint/types": "5.44.0", "@typescript-eslint/types": "5.44.0",
@ -10294,7 +10319,8 @@
"version": "8.8.1", "version": "8.8.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
"integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
"dev": true "dev": true,
"peer": true
}, },
"acorn-import-assertions": { "acorn-import-assertions": {
"version": "1.8.0", "version": "1.8.0",
@ -10604,6 +10630,7 @@
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz",
"integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==",
"dev": true, "dev": true,
"peer": true,
"requires": { "requires": {
"caniuse-lite": "^1.0.30001400", "caniuse-lite": "^1.0.30001400",
"electron-to-chromium": "^1.4.251", "electron-to-chromium": "^1.4.251",
@ -10711,6 +10738,7 @@
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
"dev": true, "dev": true,
"peer": true,
"requires": { "requires": {
"anymatch": "~3.1.2", "anymatch": "~3.1.2",
"braces": "~3.0.2", "braces": "~3.0.2",
@ -10743,12 +10771,14 @@
"class-transformer": { "class-transformer": {
"version": "0.5.1", "version": "0.5.1",
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
"integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==" "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==",
"peer": true
}, },
"class-validator": { "class-validator": {
"version": "0.13.2", "version": "0.13.2",
"resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.13.2.tgz", "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.13.2.tgz",
"integrity": "sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw==", "integrity": "sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw==",
"peer": true,
"requires": { "requires": {
"libphonenumber-js": "^1.9.43", "libphonenumber-js": "^1.9.43",
"validator": "^13.7.0" "validator": "^13.7.0"
@ -11130,6 +11160,7 @@
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.28.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.28.0.tgz",
"integrity": "sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==", "integrity": "sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==",
"dev": true, "dev": true,
"peer": true,
"requires": { "requires": {
"@eslint/eslintrc": "^1.3.3", "@eslint/eslintrc": "^1.3.3",
"@humanwhocodes/config-array": "^0.11.6", "@humanwhocodes/config-array": "^0.11.6",
@ -12145,6 +12176,7 @@
"resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz", "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz",
"integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==", "integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==",
"dev": true, "dev": true,
"peer": true,
"requires": { "requires": {
"@jest/core": "^28.1.3", "@jest/core": "^28.1.3",
"@jest/types": "^28.1.3", "@jest/types": "^28.1.3",
@ -13414,7 +13446,8 @@
"version": "2.8.0", "version": "2.8.0",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.0.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.0.tgz",
"integrity": "sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA==", "integrity": "sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA==",
"dev": true "dev": true,
"peer": true
}, },
"prettier-linter-helpers": { "prettier-linter-helpers": {
"version": "1.0.0", "version": "1.0.0",
@ -13572,7 +13605,8 @@
"reflect-metadata": { "reflect-metadata": {
"version": "0.1.13", "version": "0.1.13",
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
"integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==",
"peer": true
}, },
"regexpp": { "regexpp": {
"version": "3.2.0", "version": "3.2.0",
@ -13675,6 +13709,7 @@
"version": "7.5.7", "version": "7.5.7",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz",
"integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==",
"peer": true,
"requires": { "requires": {
"tslib": "^2.1.0" "tslib": "^2.1.0"
} }
@ -13705,6 +13740,7 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true, "dev": true,
"peer": true,
"requires": { "requires": {
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0", "fast-json-stable-stringify": "^2.0.0",
@ -14234,6 +14270,7 @@
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
"integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
"dev": true, "dev": true,
"peer": true,
"requires": { "requires": {
"@cspotcode/source-map-support": "^0.8.0", "@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7", "@tsconfig/node10": "^1.0.7",
@ -14353,7 +14390,8 @@
"version": "4.9.3", "version": "4.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz",
"integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==",
"dev": true "dev": true,
"peer": true
}, },
"universalify": { "universalify": {
"version": "2.0.0", "version": "2.0.0",

View File

@ -1,14 +1,19 @@
import { Controller, Post, Body } from '@nestjs/common'; import { Controller, Post, Body } from '@nestjs/common';
import { InfoService } from './info.service'; import { InfoService } from './info.service';
import { UpdateInfoRequest } from './interfaces'; import { UpdateFormRequest, UpdateInfoRequest } from './interfaces';
import { BaseResponse } from '../interfaces'; import { BaseResponse } from '../interfaces';
@Controller('info') @Controller('info')
export class InfoController { export class InfoController {
constructor(private readonly infoService: InfoService) {} constructor(private readonly infoService: InfoService) { }
@Post('/validate') @Post('/validate')
getConfig(@Body() bodyRequest: UpdateInfoRequest): Promise<BaseResponse> { getConfig(@Body() bodyRequest: UpdateInfoRequest): Promise<BaseResponse> {
return this.infoService.validateInfo(bodyRequest); return this.infoService.validateInfo(bodyRequest);
} }
@Post('/validate-form')
getForm(@Body() bodyRequest: UpdateFormRequest): Promise<BaseResponse> {
return this.infoService.validateForm(bodyRequest);
}
} }

View File

@ -1,10 +1,11 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { InfoController } from './info.controller'; import { InfoController } from './info.controller';
import { InfoService } from './info.service'; import { InfoService } from './info.service';
import { IsAgeMatchingBirthDateConstraint } from './validators/age-match-date-birth';
@Module({ @Module({
imports: [], imports: [],
controllers: [InfoController], controllers: [InfoController],
providers: [InfoService], providers: [InfoService, IsAgeMatchingBirthDateConstraint],
}) })
export class InfoModule {} export class InfoModule { }

View File

@ -1,9 +1,9 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { plainToClass } from 'class-transformer'; import { plainToClass } from 'class-transformer';
import { validate } from 'class-validator'; import { validate } from 'class-validator';
import { UpdateInfoRequest as UpdateInfoRequestInterface } from './interfaces'; import { UpdateFormRequest, UpdateInfoRequest as UpdateInfoRequestInterface } from './interfaces';
import { BaseResponse } from '../interfaces'; import { BaseResponse } from '../interfaces';
import { UpdateInfoRequest } from './models'; import { UpdateFormValidator, UpdateInfoRequest } from './models';
@Injectable() @Injectable()
export class InfoService { export class InfoService {
@ -23,4 +23,21 @@ export class InfoService {
data, data,
}; };
} }
async validateForm(
rawData: UpdateFormRequest,
): Promise<BaseResponse> {
const data = plainToClass(UpdateFormValidator, rawData);
const validationErrors = await validate(data);
if (validationErrors.length > 0) {
return {
success: false,
errors: validationErrors,
};
}
return {
success: true,
data,
};
}
} }

View File

@ -1,3 +1,10 @@
export interface UpdateInfoRequest { export interface UpdateInfoRequest {
name: string; name: string;
} }
export interface UpdateFormRequest {
name: string
age: number
married?: boolean
dateOfBirth: Date
}

View File

@ -1,5 +1,7 @@
import { UpdateInfoRequest as UpdateInfoRequestInterface } from '../interfaces'; import { UpdateFormRequest, UpdateInfoRequest as UpdateInfoRequestInterface } from '../interfaces';
import { IsNotEmpty, IsString, MinLength } from 'class-validator'; import { IsDate, IsNotEmpty, IsNumber, IsString, Max, MaxLength, Min, MinLength } from 'class-validator';
import { Type } from 'class-transformer';
import { IsAgeMatchingBirthDate } from '../validators/age-match-date-birth';
export class UpdateInfoRequest implements UpdateInfoRequestInterface { export class UpdateInfoRequest implements UpdateInfoRequestInterface {
@IsNotEmpty() @IsNotEmpty()
@ -7,3 +9,25 @@ export class UpdateInfoRequest implements UpdateInfoRequestInterface {
@MinLength(3) @MinLength(3)
name: string; name: string;
} }
export class UpdateFormValidator implements UpdateFormRequest {
@IsNotEmpty()
@IsString()
@MinLength(5)
@MaxLength(50)
name: string;
@IsNotEmpty()
@IsNumber()
@Max(150)
@Min(1)
@IsAgeMatchingBirthDate({ message: "mismatch betwean date of birth and age" })
age: number
married?: boolean
@IsNotEmpty()
@Type(() => Date)
@IsDate()
dateOfBirth: Date
}

View File

@ -0,0 +1,61 @@
import {
ValidatorConstraint,
ValidatorConstraintInterface,
ValidationArguments,
registerDecorator,
ValidationOptions,
} from 'class-validator';
import { Injectable } from '@nestjs/common';
// Funzione helper per calcolare l'età
function calculateAge(birthDate: Date): number {
if (!birthDate || !(birthDate instanceof Date)) return -1;
const today = new Date();
let age = today.getFullYear() - birthDate.getFullYear();
const m = today.getMonth() - birthDate.getMonth();
if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
age--;
}
return age;
}
@ValidatorConstraint({ name: 'isAgeMatchingBirthDate', async: false })
@Injectable()
export class IsAgeMatchingBirthDateConstraint implements ValidatorConstraintInterface {
// Questo è il metodo che esegue la validazione
validate(age: number, args: ValidationArguments) {
// args.object è l'intero oggetto DTO che viene validato
const object = args.object as any;
const dateOfBirth = object.dateOfBirth;
// Se dateOfBirth non è una data valida, questo validatore non fallisce.
// Ci penseranno @IsDate e @IsNotEmpty a bloccare la richiesta prima.
if (!(dateOfBirth instanceof Date)) {
return true;
}
const calculatedAge = calculateAge(dateOfBirth);
return age === calculatedAge;
}
// Questo metodo fornisce il messaggio di errore di default
defaultMessage(args: ValidationArguments) {
const calculatedAge = calculateAge((args.object as any).dateOfBirth);
return `The provided age ($value) is incorrect. Based on the date of birth, it should be ${calculatedAge}.`;
}
}
export function IsAgeMatchingBirthDate(validationOptions?: ValidationOptions) {
return function(object: Object, propertyName: string) {
registerDecorator({
target: object.constructor,
propertyName: propertyName,
options: validationOptions,
constraints: [],
validator: IsAgeMatchingBirthDateConstraint,
});
};
}