diff --git a/server/package-lock.json b/server/package-lock.json index dd4fdc7..d2dd937 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -1979,14 +1979,14 @@ "license": "MIT" }, "node_modules/@stylistic/eslint-plugin": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.2.0.tgz", - "integrity": "sha512-RCEdbREv9EBiToUBQTlRhVYKG093I6ZnnQ990j08eJ6uRZh71DXkOnoxtTLfDQ6utVCVQzrhZFHZP0zfrfOIjA==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.3.1.tgz", + "integrity": "sha512-Ykums1VYonM0TgkD0VteVq9mrlO2FhF48MDJnPyv3MktIB2ydtuhlO0AfWm7xnW1kyf5bjOqA6xc7JjviuVTxg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/types": "^8.37.0", + "@typescript-eslint/types": "^8.41.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "estraverse": "^5.3.0", @@ -1999,6 +1999,20 @@ "eslint": ">=9.0.0" } }, + "node_modules/@stylistic/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.42.0.tgz", + "integrity": "sha512-LdtAWMiFmbRLNP7JNeY0SqEtJvGMYSzfiWBSmx+VSZ1CH+1zyl8Mmw1TT39OrtsRvIYShjJWzTDMPWZJCpwBlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@stylistic/eslint-plugin/node_modules/picomatch": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", @@ -2664,6 +2678,131 @@ "typescript": ">=4.8.4 <6.0.0" } }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.42.0.tgz", + "integrity": "sha512-9KChw92sbPTYVFw3JLRH1ockhyR3zqqn9lQXol3/YbI6jVxzWoGcT3AsAW0mu1MY0gYtsXnUGV/AKpkAj5tVlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.42.0", + "@typescript-eslint/typescript-estree": "8.42.0", + "@typescript-eslint/utils": "8.42.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/project-service": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.42.0.tgz", + "integrity": "sha512-vfVpLHAhbPjilrabtOSNcUDmBboQNrJUiNAGoImkZKnMjs2TIcWG33s4Ds0wY3/50aZmTMqJa6PiwkwezaAklg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.42.0", + "@typescript-eslint/types": "^8.42.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.42.0.tgz", + "integrity": "sha512-kHeFUOdwAJfUmYKjR3CLgZSglGHjbNTi1H8sTYRYV2xX6eNz4RyJ2LIgsDLKf8Yi0/GL1WZAC/DgZBeBft8QAQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.42.0.tgz", + "integrity": "sha512-LdtAWMiFmbRLNP7JNeY0SqEtJvGMYSzfiWBSmx+VSZ1CH+1zyl8Mmw1TT39OrtsRvIYShjJWzTDMPWZJCpwBlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.42.0.tgz", + "integrity": "sha512-ku/uYtT4QXY8sl9EDJETD27o3Ewdi72hcXg1ah/kkUgBvAYHLwj2ofswFFNXS+FL5G+AGkxBtvGt8pFBHKlHsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.42.0", + "@typescript-eslint/tsconfig-utils": "8.42.0", + "@typescript-eslint/types": "8.42.0", + "@typescript-eslint/visitor-keys": "8.42.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.42.0.tgz", + "integrity": "sha512-3WbiuzoEowaEn8RSnhJBrxSwX8ULYE9CXaPepS2C2W3NSA5NNIvBaslpBSBElPq0UGr0xVJlXFWOAKIkyylydQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.42.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/types": { "version": "8.39.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.39.0.tgz", @@ -2708,16 +2847,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.39.0.tgz", - "integrity": "sha512-4GVSvNA0Vx1Ktwvf4sFE+exxJ3QGUorQG1/A5mRfRNZtkBT2xrA/BCO2H0eALx/PnvCS6/vmYwRdDA41EoffkQ==", + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.42.0.tgz", + "integrity": "sha512-JnIzu7H3RH5BrKC4NoZqRfmjqCIS1u3hGZltDYJgkVdqAezl4L9d1ZLw+36huCujtSBSAirGINF/S4UxOcR+/g==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.39.0", - "@typescript-eslint/types": "8.39.0", - "@typescript-eslint/typescript-estree": "8.39.0" + "@typescript-eslint/scope-manager": "8.42.0", + "@typescript-eslint/types": "8.42.0", + "@typescript-eslint/typescript-estree": "8.42.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2731,6 +2870,124 @@ "typescript": ">=4.8.4 <6.0.0" } }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/project-service": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.42.0.tgz", + "integrity": "sha512-vfVpLHAhbPjilrabtOSNcUDmBboQNrJUiNAGoImkZKnMjs2TIcWG33s4Ds0wY3/50aZmTMqJa6PiwkwezaAklg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.42.0", + "@typescript-eslint/types": "^8.42.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.42.0.tgz", + "integrity": "sha512-51+x9o78NBAVgQzOPd17DkNTnIzJ8T/O2dmMBLoK9qbY0Gm52XJcdJcCl18ExBMiHo6jPMErUQWUv5RLE51zJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.42.0", + "@typescript-eslint/visitor-keys": "8.42.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.42.0.tgz", + "integrity": "sha512-kHeFUOdwAJfUmYKjR3CLgZSglGHjbNTi1H8sTYRYV2xX6eNz4RyJ2LIgsDLKf8Yi0/GL1WZAC/DgZBeBft8QAQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.42.0.tgz", + "integrity": "sha512-LdtAWMiFmbRLNP7JNeY0SqEtJvGMYSzfiWBSmx+VSZ1CH+1zyl8Mmw1TT39OrtsRvIYShjJWzTDMPWZJCpwBlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.42.0.tgz", + "integrity": "sha512-ku/uYtT4QXY8sl9EDJETD27o3Ewdi72hcXg1ah/kkUgBvAYHLwj2ofswFFNXS+FL5G+AGkxBtvGt8pFBHKlHsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.42.0", + "@typescript-eslint/tsconfig-utils": "8.42.0", + "@typescript-eslint/types": "8.42.0", + "@typescript-eslint/visitor-keys": "8.42.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.42.0.tgz", + "integrity": "sha512-3WbiuzoEowaEn8RSnhJBrxSwX8ULYE9CXaPepS2C2W3NSA5NNIvBaslpBSBElPq0UGr0xVJlXFWOAKIkyylydQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.42.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/visitor-keys": { "version": "8.39.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.39.0.tgz", @@ -5320,56 +5577,6 @@ } } }, - "node_modules/eslint-config-ksv741/node_modules/@typescript-eslint/scope-manager": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.37.0.tgz", - "integrity": "sha512-0vGq0yiU1gbjKob2q691ybTg9JX6ShiVXAAfm2jGf3q0hdP6/BruaFjL/ManAR/lj05AvYCH+5bbVo0VtzmjOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/visitor-keys": "8.37.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-config-ksv741/node_modules/@typescript-eslint/types": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.37.0.tgz", - "integrity": "sha512-ax0nv7PUF9NOVPs+lmQ7yIE7IQmAf8LGcXbMvHX5Gm+YJUYNAl340XkGnrimxZ0elXyoQJuN5sbg6C4evKA4SQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-config-ksv741/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.37.0.tgz", - "integrity": "sha512-YzfhzcTnZVPiLfP/oeKtDp2evwvHLMe0LOy7oe+hb9KKIumLNohYS9Hgp1ifwpu42YWxhZE8yieggz6JpqO/1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.37.0", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/eslint-config-ksv741/node_modules/globals": { "version": "16.3.0", "resolved": "https://registry.npmjs.org/globals/-/globals-16.3.0.tgz", @@ -5383,212 +5590,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-config-ksv741/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/eslint-config-ksv741/node_modules/typescript-eslint": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.37.0.tgz", - "integrity": "sha512-TnbEjzkE9EmcO0Q2zM+GE8NQLItNAJpMmED1BdgoBMYNdqMhzlbqfdSwiRlAzEK2pA9UzVW0gzaaIzXWg2BjfA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.37.0", - "@typescript-eslint/parser": "8.37.0", - "@typescript-eslint/typescript-estree": "8.37.0", - "@typescript-eslint/utils": "8.37.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/eslint-config-ksv741/node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.37.0.tgz", - "integrity": "sha512-jsuVWeIkb6ggzB+wPCsR4e6loj+rM72ohW6IBn2C+5NCvfUVY8s33iFPySSVXqtm5Hu29Ne/9bnA0JmyLmgenA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.37.0", - "@typescript-eslint/type-utils": "8.37.0", - "@typescript-eslint/utils": "8.37.0", - "@typescript-eslint/visitor-keys": "8.37.0", - "graphemer": "^1.4.0", - "ignore": "^7.0.0", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.37.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/eslint-config-ksv741/node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.37.0.tgz", - "integrity": "sha512-SPkXWIkVZxhgwSwVq9rqj/4VFo7MnWwVaRNznfQDc/xPYHjXnPfLWn+4L6FF1cAz6e7dsqBeMawgl7QjUMj4Ow==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/typescript-estree": "8.37.0", - "@typescript-eslint/utils": "8.37.0", - "debug": "^4.3.4", - "ts-api-utils": "^2.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/eslint-config-ksv741/node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.37.0.tgz", - "integrity": "sha512-kVIaQE9vrN9RLCQMQ3iyRlVJpTiDUY6woHGb30JDkfJErqrQEmtdWH3gV0PBAfGZgQXoqzXOO0T3K6ioApbbAA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.37.0", - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/typescript-estree": "8.37.0", - "@typescript-eslint/visitor-keys": "8.37.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/eslint-config-ksv741/node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.37.0.tgz", - "integrity": "sha512-zuWDMDuzMRbQOM+bHyU4/slw27bAUEcKSKKs3hcv2aNnc/tvE/h7w60dwVw8vnal2Pub6RT1T7BI8tFZ1fE+yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.37.0", - "@typescript-eslint/tsconfig-utils": "8.37.0", - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/visitor-keys": "8.37.0", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^2.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/eslint-config-ksv741/node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.37.0.tgz", - "integrity": "sha512-BIUXYsbkl5A1aJDdYJCBAo8rCEbAvdquQ8AnLb6z5Lp1u3x5PNgSSx9A/zqYc++Xnr/0DVpls8iQ2cJs/izTXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.37.0", - "@typescript-eslint/types": "^8.37.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/eslint-config-ksv741/node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.37.0.tgz", - "integrity": "sha512-1/YHvAVTimMM9mmlPvTec9NP4bobA1RkDbMydxG8omqwJJLEW/Iy2C4adsAESIXU3WGLXFHSZUU+C9EoFWl4Zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/eslint-config-ksv741/node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.37.0.tgz", - "integrity": "sha512-TSFvkIW6gGjN2p6zbXo20FzCABbyUAuq6tBvNRGsKdsSQ6a7rnV6ADfZ7f4iI3lIiXc4F4WWvtUfDw9CJ9pO5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.37.0", - "@typescript-eslint/types": "8.37.0", - "@typescript-eslint/typescript-estree": "8.37.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, "node_modules/eslint-import-context": { "version": "0.1.9", "resolved": "https://registry.npmjs.org/eslint-import-context/-/eslint-import-context-0.1.9.tgz", @@ -10961,6 +10962,213 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.42.0.tgz", + "integrity": "sha512-ozR/rQn+aQXQxh1YgbCzQWDFrsi9mcg+1PM3l/z5o1+20P7suOIaNg515bpr/OYt6FObz/NHcBstydDLHWeEKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.42.0", + "@typescript-eslint/parser": "8.42.0", + "@typescript-eslint/typescript-estree": "8.42.0", + "@typescript-eslint/utils": "8.42.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.42.0.tgz", + "integrity": "sha512-Aq2dPqsQkxHOLfb2OPv43RnIvfj05nw8v/6n3B2NABIPpHnjQnaLo9QGMTvml+tv4korl/Cjfrb/BYhoL8UUTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.42.0", + "@typescript-eslint/type-utils": "8.42.0", + "@typescript-eslint/utils": "8.42.0", + "@typescript-eslint/visitor-keys": "8.42.0", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.42.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.42.0.tgz", + "integrity": "sha512-r1XG74QgShUgXph1BYseJ+KZd17bKQib/yF3SR+demvytiRXrwd12Blnz5eYGm8tXaeRdd4x88MlfwldHoudGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.42.0", + "@typescript-eslint/types": "8.42.0", + "@typescript-eslint/typescript-estree": "8.42.0", + "@typescript-eslint/visitor-keys": "8.42.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/project-service": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.42.0.tgz", + "integrity": "sha512-vfVpLHAhbPjilrabtOSNcUDmBboQNrJUiNAGoImkZKnMjs2TIcWG33s4Ds0wY3/50aZmTMqJa6PiwkwezaAklg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.42.0", + "@typescript-eslint/types": "^8.42.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.42.0.tgz", + "integrity": "sha512-51+x9o78NBAVgQzOPd17DkNTnIzJ8T/O2dmMBLoK9qbY0Gm52XJcdJcCl18ExBMiHo6jPMErUQWUv5RLE51zJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.42.0", + "@typescript-eslint/visitor-keys": "8.42.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.42.0.tgz", + "integrity": "sha512-kHeFUOdwAJfUmYKjR3CLgZSglGHjbNTi1H8sTYRYV2xX6eNz4RyJ2LIgsDLKf8Yi0/GL1WZAC/DgZBeBft8QAQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.42.0.tgz", + "integrity": "sha512-LdtAWMiFmbRLNP7JNeY0SqEtJvGMYSzfiWBSmx+VSZ1CH+1zyl8Mmw1TT39OrtsRvIYShjJWzTDMPWZJCpwBlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.42.0.tgz", + "integrity": "sha512-ku/uYtT4QXY8sl9EDJETD27o3Ewdi72hcXg1ah/kkUgBvAYHLwj2ofswFFNXS+FL5G+AGkxBtvGt8pFBHKlHsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.42.0", + "@typescript-eslint/tsconfig-utils": "8.42.0", + "@typescript-eslint/types": "8.42.0", + "@typescript-eslint/visitor-keys": "8.42.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.42.0.tgz", + "integrity": "sha512-3WbiuzoEowaEn8RSnhJBrxSwX8ULYE9CXaPepS2C2W3NSA5NNIvBaslpBSBElPq0UGr0xVJlXFWOAKIkyylydQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.42.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/uid": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz", diff --git a/server/package.json b/server/package.json index 5c52a79..4b11e4b 100644 --- a/server/package.json +++ b/server/package.json @@ -53,5 +53,9 @@ "ts-node": "10.9.2", "tsconfig-paths": "4.2.0", "typescript": "5.9.2" + }, + "overrides": { + "@stylistic/eslint-plugin": "5.3.1", + "typescript-eslint": "8.42.0" } } diff --git a/server/prisma/schema.prisma b/server/prisma/schema.prisma index 8ffb950..150c937 100644 --- a/server/prisma/schema.prisma +++ b/server/prisma/schema.prisma @@ -26,6 +26,7 @@ model User { createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") expensesLists ExpenseList[] + BankCard BankCard[] @@map("users") } @@ -57,3 +58,26 @@ model ExpenseItem { @@map("expenses_items") } + +model BankAccount { + id String @id @default(uuid()) + balance Float @default(0) + cards BankCard[] + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + @@map("bank_accounts") +} + +model BankCard { + id String @id @default(uuid()) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + userId String + name String + bankAccount BankAccount @relation(fields: [bankAccountId], references: [id], onDelete: Cascade) + bankAccountId String + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + @@map("bank_cards") +} diff --git a/server/src/modules/app.module.ts b/server/src/modules/app.module.ts index 1aa348c..48626b1 100644 --- a/server/src/modules/app.module.ts +++ b/server/src/modules/app.module.ts @@ -2,6 +2,8 @@ import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { AuthModule } from './auth/auth.module'; +import { BankAccountModule } from './bank-account/bank-account.module'; +import { BankCardModule } from './bank-card/bank-card.module'; import { ExpensesModule } from './expenses/expenses.module'; import { PrismaModule } from './prisma/prisma.module'; @@ -13,6 +15,8 @@ import { PrismaModule } from './prisma/prisma.module'; PrismaModule, AuthModule, ExpensesModule, + BankAccountModule, + BankCardModule, ], }) export class AppModule {} diff --git a/server/src/modules/bank-account/bank-account.module.ts b/server/src/modules/bank-account/bank-account.module.ts new file mode 100644 index 0000000..f00667a --- /dev/null +++ b/server/src/modules/bank-account/bank-account.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; + +import { BankAccountService } from './bank-account.service'; + +@Module({ + providers: [BankAccountService], + exports: [BankAccountService], +}) +export class BankAccountModule {} diff --git a/server/src/modules/bank-account/bank-account.service.ts b/server/src/modules/bank-account/bank-account.service.ts new file mode 100644 index 0000000..78750dc --- /dev/null +++ b/server/src/modules/bank-account/bank-account.service.ts @@ -0,0 +1,46 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { BankAccount } from '@prisma/client'; + +import { PrismaService } from '@/modules/prisma/prisma.service'; + +import { CreateBankAccountDto } from './dto'; + +@Injectable() +export class BankAccountService { + constructor(private readonly prismaService: PrismaService) {} + + async createBankAccount(dto: CreateBankAccountDto) { + const { balance } = dto; + + return this.prismaService.bankAccount.create({ + data: { + balance, + }, + }); + } + + async getBankAccountById(id: BankAccount['id']) { + const bankAccount = await this.prismaService.bankAccount.findUnique({ where: { id } }); + + if (!bankAccount) { + throw new NotFoundException('Счет не найден'); + } + + return bankAccount; + } + + async getBalance(id: BankAccount['id']) { + const account = await this.getBankAccountById(id); + + return account.balance; + } + + async changeBalance(id: BankAccount['id'], amount: number) { + const account = await this.getBankAccountById(id); + + return this.prismaService.bankAccount.update({ + where: { id: account.id }, + data: { balance: amount }, + }); + } +} diff --git a/server/src/modules/bank-account/dto/CreateBankAccountDto.ts b/server/src/modules/bank-account/dto/CreateBankAccountDto.ts new file mode 100644 index 0000000..d53d33a --- /dev/null +++ b/server/src/modules/bank-account/dto/CreateBankAccountDto.ts @@ -0,0 +1,16 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { + IsNumber, + IsOptional, +} from 'class-validator'; + +export class CreateBankAccountDto { + @ApiProperty({ + description: 'Баланс', + example: 100.95, + type: Number, + }) + @IsNumber({ maxDecimalPlaces: 2 }, { message: 'Баланс должен быть числом' }) + @IsOptional() + balance?: number; +} diff --git a/server/src/modules/bank-account/dto/index.ts b/server/src/modules/bank-account/dto/index.ts new file mode 100644 index 0000000..aca8aad --- /dev/null +++ b/server/src/modules/bank-account/dto/index.ts @@ -0,0 +1 @@ +export { CreateBankAccountDto } from './CreateBankAccountDto'; diff --git a/server/src/modules/bank-card/bank-card.controller.ts b/server/src/modules/bank-card/bank-card.controller.ts new file mode 100644 index 0000000..14af562 --- /dev/null +++ b/server/src/modules/bank-card/bank-card.controller.ts @@ -0,0 +1,70 @@ +import { + Body, + Controller, + Delete, + Get, + Param, + Patch, + Post, +} from '@nestjs/common'; +import { BankCard, User } from '@prisma/client'; + +import { CreateBankCardDto, EditBankCardDto } from '@/modules/bank-card/dto'; +import { Authorized } from '@/shared/decorators'; + +import { BankCardService } from './bank-card.service'; +import { + CreateBankCard, + DeleteBankCard, + EditBankCard, + GetAllBankCard, + GetBankCard, +} from './decorators'; + +@Controller('bank-card') +export class BankCardController { + constructor(private readonly bankCardService: BankCardService) {} + + @CreateBankCard() + @Post() + async createBankCard( + @Authorized('userId') userId: User['id'], + @Body() dto: CreateBankCardDto, + ) { + return this.bankCardService.createBankCard(userId, dto); + } + + @EditBankCard() + @Patch(':id') + async editBankCard( + @Authorized('userId') userId: User['id'], + @Param('id') id: BankCard['id'], + @Body() dto: EditBankCardDto, + ) { + return this.bankCardService.editBankCard(userId, id, dto); + } + + @GetBankCard() + @Get(':id') + async getBankCardById( + @Authorized('userId') userId: User['id'], + @Param('id') id: BankCard['id'], + ) { + return this.bankCardService.getBankCardById(userId, id); + } + + @DeleteBankCard() + @Delete(':id') + async deleteBankCardById( + @Authorized('userId') userId: User['id'], + @Param('id') id: BankCard['id'], + ) { + return this.bankCardService.deleteBankCard(userId, id); + } + + @GetAllBankCard() + @Get() + async getBankCards(@Authorized('userId') userId: User['id']) { + return this.bankCardService.getBankCardsByUserId(userId); + } +} diff --git a/server/src/modules/bank-card/bank-card.module.ts b/server/src/modules/bank-card/bank-card.module.ts new file mode 100644 index 0000000..81a78b4 --- /dev/null +++ b/server/src/modules/bank-card/bank-card.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; + +import { BankAccountModule } from '@/modules/bank-account/bank-account.module'; + +import { BankCardController } from './bank-card.controller'; +import { BankCardService } from './bank-card.service'; + +@Module({ + controllers: [BankCardController], + providers: [BankCardService], + imports: [BankAccountModule], +}) +export class BankCardModule {} diff --git a/server/src/modules/bank-card/bank-card.service.ts b/server/src/modules/bank-card/bank-card.service.ts new file mode 100644 index 0000000..1d951d6 --- /dev/null +++ b/server/src/modules/bank-card/bank-card.service.ts @@ -0,0 +1,102 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { BankAccount, BankCard, User } from '@prisma/client'; + +import { BankAccountService } from '@/modules/bank-account/bank-account.service'; +import { PrismaService } from '@/modules/prisma/prisma.service'; + +import { BankCardDto, CreateBankCardDto, EditBankCardDto } from './dto'; + +@Injectable() +export class BankCardService { + constructor( + private readonly prismaService: PrismaService, + private readonly bankAccountService: BankAccountService, + ) {} + + async createBankCard(userId: User['id'], dto: CreateBankCardDto): Promise { + const { name, balance } = dto; + + const bankAccount = await this.bankAccountService.createBankAccount({ + balance, + }); + + const card = await this.prismaService.bankCard.create({ + data: { + name, + user: { + connect: { id: userId }, + }, + bankAccount: { + connect: { id: bankAccount.id }, + }, + }, + include: { bankAccount: true }, + }); + + return this.toDto(card); + } + + async getBankCardById(userId: User['id'], bankCardId: BankCard['id']): Promise { + const card = await this.prismaService.bankCard.findUnique({ + where: { id: bankCardId }, + include: { bankAccount: true }, + }); + + if (card?.userId !== userId) { + throw new NotFoundException('Карта не найдена'); + } + + return this.toDto(card); + } + + async getBankCardsByUserId(userId: User['id']): Promise { + const cards = await this.prismaService.bankCard.findMany({ + where: { userId }, + include: { bankAccount: true }, + orderBy: { createdAt: 'asc' }, + }); + + return cards.map((card) => this.toDto(card)); + } + + async editBankCard(userId: User['id'], bankCardId: BankCard['id'], dto: EditBankCardDto): Promise { + const { name, balance } = dto; + const card = await this.getBankCardById(userId, bankCardId); + + const updatedCard = await this.prismaService.bankCard.update({ + where: { id: card.id }, + data: { + name: name ?? card.name, + bankAccount: { + update: { + balance: balance ?? card.balance, + }, + }, + }, + include: { bankAccount: true }, + }); + + return this.toDto(updatedCard); + } + + async deleteBankCard(userId: User['id'], bankCardId: BankCard['id']): Promise { + const card = await this.getBankCardById(userId, bankCardId); + + const deletedCard = await this.prismaService.bankCard.delete({ + where: { id: card.id }, + include: { bankAccount: true }, + }); + + return this.toDto(deletedCard); + } + + toDto(card: BankCard & { bankAccount: BankAccount }): BankCardDto { + return { + id: card.id, + name: card.name, + balance: card.bankAccount.balance, + createdAt: card.createdAt, + updatedAt: card.updatedAt, + }; + } +} diff --git a/server/src/modules/bank-card/decorators/create-bank-card.decorator.ts b/server/src/modules/bank-card/decorators/create-bank-card.decorator.ts new file mode 100644 index 0000000..01fa74e --- /dev/null +++ b/server/src/modules/bank-card/decorators/create-bank-card.decorator.ts @@ -0,0 +1,24 @@ +import { applyDecorators } from '@nestjs/common'; +import { ApiBearerAuth, ApiOkResponse, ApiOperation } from '@nestjs/swagger'; + +import { Authorization } from '@/shared/decorators'; + +import { BankCardDto } from '../dto'; + +function Documentation() { + return applyDecorators( + ApiOperation({ + summary: 'Создать карту', + description: 'Создать банковскую карту', + }), + ApiBearerAuth(), + ApiOkResponse({ description: 'Успешно создана банковская карта', type: BankCardDto }), + ); +} + +export function CreateBankCard() { + return applyDecorators( + Authorization(), + Documentation(), + ); +} diff --git a/server/src/modules/bank-card/decorators/delete-bank-card.decorator.ts b/server/src/modules/bank-card/decorators/delete-bank-card.decorator.ts new file mode 100644 index 0000000..174a38b --- /dev/null +++ b/server/src/modules/bank-card/decorators/delete-bank-card.decorator.ts @@ -0,0 +1,32 @@ +import { applyDecorators } from '@nestjs/common'; +import { + ApiBearerAuth, + ApiNotFoundResponse, + ApiOkResponse, + ApiOperation, + ApiParam, +} from '@nestjs/swagger'; + +import { Authorization } from '@/shared/decorators'; + +import { BankCardDto } from '../dto'; + +function Documentation() { + return applyDecorators( + ApiOperation({ + summary: 'Удалить карту', + description: 'Удалить банковскую карту', + }), + ApiBearerAuth(), + ApiParam({ name: 'id', type: String, description: 'ID карты' }), + ApiNotFoundResponse({ description: 'Карта не найдена' }), + ApiOkResponse({ description: 'Успешно удалена банковская карта', type: BankCardDto }), + ); +} + +export function DeleteBankCard() { + return applyDecorators( + Authorization(), + Documentation(), + ); +} diff --git a/server/src/modules/bank-card/decorators/edit-bank-card.decorator.ts b/server/src/modules/bank-card/decorators/edit-bank-card.decorator.ts new file mode 100644 index 0000000..9bdbe46 --- /dev/null +++ b/server/src/modules/bank-card/decorators/edit-bank-card.decorator.ts @@ -0,0 +1,32 @@ +import { applyDecorators } from '@nestjs/common'; +import { + ApiBearerAuth, + ApiNotFoundResponse, + ApiOkResponse, + ApiOperation, + ApiParam, +} from '@nestjs/swagger'; + +import { Authorization } from '@/shared/decorators'; + +import { BankCardDto } from '../dto'; + +function Documentation() { + return applyDecorators( + ApiOperation({ + summary: 'Редактировать карту', + description: 'Редактировать банковскую карту', + }), + ApiBearerAuth(), + ApiParam({ name: 'id', type: String, description: 'ID карты' }), + ApiNotFoundResponse({ description: 'Карта не найдена' }), + ApiOkResponse({ description: 'Успешно отредактирована банковская карта', type: BankCardDto }), + ); +} + +export function EditBankCard() { + return applyDecorators( + Authorization(), + Documentation(), + ); +} diff --git a/server/src/modules/bank-card/decorators/get-all-bank-card.decorator.ts b/server/src/modules/bank-card/decorators/get-all-bank-card.decorator.ts new file mode 100644 index 0000000..960fa87 --- /dev/null +++ b/server/src/modules/bank-card/decorators/get-all-bank-card.decorator.ts @@ -0,0 +1,24 @@ +import { applyDecorators } from '@nestjs/common'; +import { ApiBearerAuth, ApiOkResponse, ApiOperation } from '@nestjs/swagger'; + +import { Authorization } from '@/shared/decorators'; + +import { BankCardDto } from '../dto'; + +function Documentation() { + return applyDecorators( + ApiOperation({ + summary: 'Найти все карты', + description: 'Найти все банковсие карты', + }), + ApiBearerAuth(), + ApiOkResponse({ description: 'Успешно найдены банковские карты', type: [BankCardDto] }), + ); +} + +export function GetAllBankCard() { + return applyDecorators( + Authorization(), + Documentation(), + ); +} diff --git a/server/src/modules/bank-card/decorators/get-bank-card.decorator.ts b/server/src/modules/bank-card/decorators/get-bank-card.decorator.ts new file mode 100644 index 0000000..0e60f59 --- /dev/null +++ b/server/src/modules/bank-card/decorators/get-bank-card.decorator.ts @@ -0,0 +1,32 @@ +import { applyDecorators } from '@nestjs/common'; +import { + ApiBearerAuth, + ApiNotFoundResponse, + ApiOkResponse, + ApiOperation, + ApiParam, +} from '@nestjs/swagger'; + +import { Authorization } from '@/shared/decorators'; + +import { BankCardDto } from '../dto'; + +function Documentation() { + return applyDecorators( + ApiOperation({ + summary: 'Найти карту', + description: 'Найти банковскую карту', + }), + ApiBearerAuth(), + ApiParam({ name: 'id', type: String, description: 'ID карты' }), + ApiNotFoundResponse({ description: 'Карта не найдена' }), + ApiOkResponse({ description: 'Успешно найдена банковская карта', type: BankCardDto }), + ); +} + +export function GetBankCard() { + return applyDecorators( + Authorization(), + Documentation(), + ); +} diff --git a/server/src/modules/bank-card/decorators/index.ts b/server/src/modules/bank-card/decorators/index.ts new file mode 100644 index 0000000..a485b8a --- /dev/null +++ b/server/src/modules/bank-card/decorators/index.ts @@ -0,0 +1,5 @@ +export { CreateBankCard } from './create-bank-card.decorator'; +export { EditBankCard } from './edit-bank-card.decorator'; +export { GetBankCard } from './get-bank-card.decorator'; +export { DeleteBankCard } from './delete-bank-card.decorator'; +export { GetAllBankCard } from './get-all-bank-card.decorator'; diff --git a/server/src/modules/bank-card/dto/bank-card.dto.ts b/server/src/modules/bank-card/dto/bank-card.dto.ts new file mode 100644 index 0000000..73dd9d5 --- /dev/null +++ b/server/src/modules/bank-card/dto/bank-card.dto.ts @@ -0,0 +1,35 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export class BankCardDto { + @ApiProperty({ + description: 'ID', + type: String, + }) + id: string; + + @ApiProperty({ + description: 'Название карты', + example: 'Карта Сбербанка', + type: String, + }) + name: string; + + @ApiProperty({ + description: 'Баланс карты', + example: 100.95, + type: Number, + }) + balance: number; + + @ApiProperty({ + description: 'Дата создания', + type: Date, + }) + createdAt: Date; + + @ApiProperty({ + description: 'Дата обновления', + type: Date, + }) + updatedAt: Date; +} diff --git a/server/src/modules/bank-card/dto/create-bank-card.dto.ts b/server/src/modules/bank-card/dto/create-bank-card.dto.ts new file mode 100644 index 0000000..dc6277a --- /dev/null +++ b/server/src/modules/bank-card/dto/create-bank-card.dto.ts @@ -0,0 +1,27 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { + IsNotEmpty, + IsNumber, + IsOptional, + IsString, +} from 'class-validator'; + +export class CreateBankCardDto { + @ApiProperty({ + description: 'Название карты', + example: 'Карта Сбербанка', + type: String, + }) + @IsString({ message: 'Название карты должно быть строкой' }) + @IsNotEmpty({ message: 'Название карты обязательно к заполнению' }) + name: string; + + @ApiProperty({ + description: 'Баланс карты', + example: 100.95, + type: Number, + }) + @IsNumber({ maxDecimalPlaces: 2 }, { message: 'Баланс карты должен быть числом' }) + @IsOptional() + balance?: number; +} diff --git a/server/src/modules/bank-card/dto/edit-bank-card.dto.ts b/server/src/modules/bank-card/dto/edit-bank-card.dto.ts new file mode 100644 index 0000000..bd5706c --- /dev/null +++ b/server/src/modules/bank-card/dto/edit-bank-card.dto.ts @@ -0,0 +1,26 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { + IsNumber, + IsOptional, + IsString, +} from 'class-validator'; + +export class EditBankCardDto { + @ApiProperty({ + description: 'Название карта', + example: 'Карта Сбербанка', + type: String, + }) + @IsString({ message: 'Название карты должно быть строкой' }) + @IsOptional() + name?: string; + + @ApiProperty({ + description: 'Баланс карты', + example: 100.95, + type: Number, + }) + @IsNumber({ maxDecimalPlaces: 2 }, { message: 'Баланс карты должен быть числом' }) + @IsOptional() + balance?: number; +} diff --git a/server/src/modules/bank-card/dto/index.ts b/server/src/modules/bank-card/dto/index.ts new file mode 100644 index 0000000..a246d20 --- /dev/null +++ b/server/src/modules/bank-card/dto/index.ts @@ -0,0 +1,3 @@ +export { CreateBankCardDto } from './create-bank-card.dto'; +export { EditBankCardDto } from './edit-bank-card.dto'; +export { BankCardDto } from './bank-card.dto';