From 12b3d5b23c9a682359c95c2254a3568cd0ac43a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B8=D0=BA=D0=BE=D0=BB=D0=B0=D0=B9=20=D0=92=D0=B8?= =?UTF-8?q?=D0=B3=D0=B4=D0=BE=D1=80=D0=BE=D0=B2?= Date: Sat, 1 Mar 2025 23:54:08 +0300 Subject: [PATCH] add service and first method to controller --- package-lock.json | 287 ++++++++++++++++++++++++++++++++++++++++-- package.json | 6 +- src/api.responses.ts | 22 ++++ src/app.controller.ts | 64 +++++++++- src/app.module.ts | 25 +++- src/app.service.ts | 128 ++++++++++++++++++- src/consts.ts | 24 ++++ src/main.ts | 22 +++- src/schemas.ts | 53 ++++++++ src/types.ts | 18 +++ 10 files changed, 632 insertions(+), 17 deletions(-) create mode 100644 src/api.responses.ts create mode 100644 src/consts.ts create mode 100644 src/schemas.ts create mode 100644 src/types.ts diff --git a/package-lock.json b/package-lock.json index 01d246d..6f5fac2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,9 +11,13 @@ "dependencies": { "@nestjs/common": "^11.0.1", "@nestjs/core": "^11.0.1", + "@nestjs/mongoose": "^11.0.1", "@nestjs/platform-express": "^11.0.1", + "@nestjs/swagger": "^11.0.6", + "mongoose": "^8.11.0", "reflect-metadata": "^0.2.2", - "rxjs": "^7.8.1" + "rxjs": "^7.8.1", + "uuid": "^11.1.0" }, "devDependencies": { "@eslint/eslintrc": "^3.2.0", @@ -1778,6 +1782,19 @@ "node": ">=8" } }, + "node_modules/@microsoft/tsdoc": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.15.1.tgz", + "integrity": "sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==" + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.2.0.tgz", + "integrity": "sha512-+ywrb0AqkfaYuhHs6LxKWgqbh3I72EpEgESCw37o+9qPx9WTCkgDm2B+eMrwehGtHBWHFU4GXvnSCNiFhhausg==", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, "node_modules/@napi-rs/nice": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.0.1.tgz", @@ -2179,6 +2196,36 @@ } } }, + "node_modules/@nestjs/mapped-types": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.1.0.tgz", + "integrity": "sha512-W+n+rM69XsFdwORF11UqJahn4J3xi4g/ZEOlJNL6KoW5ygWSmBB2p0S2BZ4FQeS/NDH72e6xIcu35SfJnE8bXw==", + "peerDependencies": { + "@nestjs/common": "^10.0.0 || ^11.0.0", + "class-transformer": "^0.4.0 || ^0.5.0", + "class-validator": "^0.13.0 || ^0.14.0", + "reflect-metadata": "^0.1.12 || ^0.2.0" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, + "node_modules/@nestjs/mongoose": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@nestjs/mongoose/-/mongoose-11.0.1.tgz", + "integrity": "sha512-Nsw/eW5ZptIgwv3gPumKe6UtZu/0HZqixwkkO8Hqn6wZyrLeaTpBFi/z3DGY36dp66uPw14huradDY7OTPDYJA==", + "peerDependencies": { + "@nestjs/common": "^10.0.0 || ^11.0.0", + "@nestjs/core": "^10.0.0 || ^11.0.0", + "mongoose": "^7.0.0 || ^8.0.0", + "rxjs": "^7.0.0" + } + }, "node_modules/@nestjs/platform-express": { "version": "11.0.11", "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.0.11.tgz", @@ -2291,6 +2338,38 @@ "tslib": "^2.1.0" } }, + "node_modules/@nestjs/swagger": { + "version": "11.0.6", + "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-11.0.6.tgz", + "integrity": "sha512-W/0aQWiEfEcXKd/dYO0DbVpYhlKNVMAhO4haahUyrYe20eXaaDY0T5exA2U8IsCcXZePWZuodRUiiXo8jcMYbA==", + "dependencies": { + "@microsoft/tsdoc": "0.15.1", + "@nestjs/mapped-types": "2.1.0", + "js-yaml": "4.1.0", + "lodash": "4.17.21", + "path-to-regexp": "8.2.0", + "swagger-ui-dist": "5.19.0" + }, + "peerDependencies": { + "@fastify/static": "^8.0.0", + "@nestjs/common": "^11.0.1", + "@nestjs/core": "^11.0.1", + "class-transformer": "*", + "class-validator": "*", + "reflect-metadata": "^0.1.12 || ^0.2.0" + }, + "peerDependenciesMeta": { + "@fastify/static": { + "optional": true + }, + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, "node_modules/@nestjs/testing": { "version": "11.0.11", "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-11.0.11.tgz", @@ -2380,6 +2459,12 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@scarf/scarf": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", + "integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==", + "hasInstallScript": true + }, "node_modules/@sec-ant/readable-stream": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", @@ -3003,6 +3088,19 @@ "@types/superagent": "^8.1.0" } }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" + }, + "node_modules/@types/whatwg-url": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "dependencies": { + "@types/webidl-conversions": "*" + } + }, "node_modules/@types/yargs": { "version": "17.0.33", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", @@ -3748,8 +3846,7 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/array-timsort": { "version": "1.0.3", @@ -4111,6 +4208,14 @@ "node-int64": "^0.4.0" } }, + "node_modules/bson": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.3.tgz", + "integrity": "sha512-MTxGsqgYTwfshYWTRdmZRC+M7FnG1b4y7RO7p2k3X24Wq0yv1m77Wsj0BzlPzd/IowgESfsruQCUToa7vbOpPQ==", + "engines": { + "node": ">=16.20.1" + } + }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -7266,7 +7371,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -7340,6 +7444,14 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/kareem": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz", + "integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -7422,8 +7534,7 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash.memoize": { "version": "4.1.2", @@ -7541,6 +7652,11 @@ "node": ">= 4.0.0" } }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" + }, "node_modules/merge-descriptors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", @@ -7692,6 +7808,100 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mongodb": { + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.13.1.tgz", + "integrity": "sha512-gdq40tX8StmhP6akMp1pPoEVv+9jTYFSrga/g23JxajPAQhH39ysZrHGzQCSd9PEOnuEQEdjIWqxO7ZSwC0w7Q==", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.9", + "bson": "^6.10.3", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.632.0", + "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz", + "integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==", + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^14.1.0 || ^13.0.0" + } + }, + "node_modules/mongoose": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.11.0.tgz", + "integrity": "sha512-xaQSuaLk2JKmXI5zDVVWXVCQTnWhAe8MFOijMnwOuP/wucKVphd3f+ouDKivCDMGjYBDrR7dtoyV0U093xbKqA==", + "dependencies": { + "bson": "^6.10.1", + "kareem": "2.6.3", + "mongodb": "~6.13.0", + "mpath": "0.9.0", + "mquery": "5.0.0", + "ms": "2.1.3", + "sift": "17.1.3" + }, + "engines": { + "node": ">=16.20.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mongoose" + } + }, + "node_modules/mpath": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", + "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mquery": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", + "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", + "dependencies": { + "debug": "4.x" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -8356,7 +8566,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, "engines": { "node": ">=6" } @@ -8957,6 +9166,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/sift": { + "version": "17.1.3", + "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz", + "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==" + }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -9036,6 +9250,14 @@ "node": ">=0.10.0" } }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -9361,6 +9583,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swagger-ui-dist": { + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.19.0.tgz", + "integrity": "sha512-bSVZeYaqanMFeW5ZY3+EejFbsjkjazYxm1I7Lz3xayYz5XU3m2aUzvuPC0jI95WCQdduszHYV3ER4buQoy8DXA==", + "dependencies": { + "@scarf/scarf": "=1.4.0" + } + }, "node_modules/symbol-observable": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", @@ -9668,6 +9898,17 @@ "url": "https://github.com/sponsors/Borewit" } }, + "node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -10037,6 +10278,18 @@ "node": ">= 0.4.0" } }, + "node_modules/uuid": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", @@ -10108,6 +10361,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, "node_modules/webpack": { "version": "5.98.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz", @@ -10285,6 +10546,18 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/whatwg-url": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.1.tgz", + "integrity": "sha512-mDGf9diDad/giZ/Sm9Xi2YcyzaFpbdLpJPr+E9fSkyQ7KpQD4SdFcugkRQYzhmfI4KeV4Qpnn2sKPdo+kmsgRQ==", + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 205f2fa..16ac086 100644 --- a/package.json +++ b/package.json @@ -22,9 +22,13 @@ "dependencies": { "@nestjs/common": "^11.0.1", "@nestjs/core": "^11.0.1", + "@nestjs/mongoose": "^11.0.1", "@nestjs/platform-express": "^11.0.1", + "@nestjs/swagger": "^11.0.6", + "mongoose": "^8.11.0", "reflect-metadata": "^0.2.2", - "rxjs": "^7.8.1" + "rxjs": "^7.8.1", + "uuid": "^11.1.0" }, "devDependencies": { "@eslint/eslintrc": "^3.2.0", diff --git a/src/api.responses.ts b/src/api.responses.ts new file mode 100644 index 0000000..5645f32 --- /dev/null +++ b/src/api.responses.ts @@ -0,0 +1,22 @@ +import { ApiResponseOptions } from '@nestjs/swagger'; +import { StorageResponse } from './schemas'; + +export const AUTH_SUCCESS: ApiResponseOptions = { + status: 200, + description: 'Токен пользователя', + type: String, +}; + +export const AUTH_ERROR: ApiResponseOptions = { + status: 406, + description: + 'Ошибка, при попытке получить доступ к данным без токена или с не корректным токеном', + type: Error, +}; + +export const GET_STORAGES_LIST_SUCCESS: ApiResponseOptions = { + status: 200, + description: 'Список всех картинок', + type: StorageResponse, + isArray: true, +}; diff --git a/src/app.controller.ts b/src/app.controller.ts index cce879e..8c98866 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -1,12 +1,68 @@ -import { Controller, Get } from '@nestjs/common'; +import { + Controller, + Get, + Header, + HttpCode, + Options, + Post, + Req, +} from '@nestjs/common'; +import { Request } from 'express'; import { AppService } from './app.service'; +import { ApiBody, ApiResponse, ApiSecurity, ApiTags } from '@nestjs/swagger'; +import { + ALLOW_CREDENTIALS, + ALLOW_HEADERS, + ALLOW_METHOD, + ALLOW_ORIGIN_ALL, + CONTENT_LENGTH, +} from './consts'; +import { + AUTH_ERROR, + AUTH_SUCCESS, + GET_STORAGES_LIST_SUCCESS, +} from './api.responses'; +import { AuthRequest } from './schemas'; +import { Storage } from './types'; @Controller() +@ApiTags('storage-app') export class AppController { constructor(private readonly appService: AppService) {} - @Get() - getHello(): string { - return this.appService.getHello(); + @Post('/auth') + @ApiBody({ + type: AuthRequest, + description: 'Объект с логином пользователя', + }) + @Header(...ALLOW_ORIGIN_ALL) + @ApiResponse(AUTH_SUCCESS) + authUser( + @Req() request: Request, + ): Promise { + return this.appService.authUser(request.body.login); + } + + @Get('/storages') + @ApiSecurity('apiKey') + @Header(...ALLOW_ORIGIN_ALL) + @ApiResponse(GET_STORAGES_LIST_SUCCESS) + @ApiResponse(AUTH_ERROR) + async getStorageList(@Req() request: Request): Promise { + const { login } = await this.appService.checkRequest( + request.headers.authorization, + ); + return this.appService.getStorageList(login); + } + + @Options(['', '/auth']) + @Header(...ALLOW_ORIGIN_ALL) + @Header(...ALLOW_METHOD) + @Header(...ALLOW_CREDENTIALS) + @Header(...CONTENT_LENGTH) + @Header(...ALLOW_HEADERS) + @HttpCode(204) + async options(): Promise { + return await Promise.resolve(''); } } diff --git a/src/app.module.ts b/src/app.module.ts index 8662803..32e56ac 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,9 +1,32 @@ import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; +import { MongooseModule } from '@nestjs/mongoose'; +import { DB_STORAGES, DB_USERS, MONGO_URL } from './consts'; +import { + StorageDocument, + StorageScheme, + UserDocument, + UserScheme, +} from './schemas'; @Module({ - imports: [], + imports: [ + MongooseModule.forRoot(`${MONGO_URL}/${DB_USERS}`, { + connectionName: DB_USERS, + }), + MongooseModule.forRoot(`${MONGO_URL}/${DB_STORAGES}`, { + connectionName: DB_STORAGES, + }), + MongooseModule.forFeature( + [{ name: UserDocument.name, schema: UserScheme }], + DB_USERS, + ), + MongooseModule.forFeature( + [{ name: StorageDocument.name, schema: StorageScheme }], + DB_STORAGES, + ), + ], controllers: [AppController], providers: [AppService], }) diff --git a/src/app.service.ts b/src/app.service.ts index 927d7cc..e8aea0e 100644 --- a/src/app.service.ts +++ b/src/app.service.ts @@ -1,8 +1,130 @@ -import { Injectable } from '@nestjs/common'; +import { + BadRequestException, + Injectable, + NotAcceptableException, +} from '@nestjs/common'; +import { InjectModel } from '@nestjs/mongoose'; +import { StorageDocument, UserDocument } from './schemas'; +import { Model } from 'mongoose'; +import { User, Storage, StorageCreate, StorageUpdate } from './types'; +import { v4 } from 'uuid'; +import { DB_STORAGES, DB_USERS } from './consts'; @Injectable() export class AppService { - getHello(): string { - return 'Hello World!'; + constructor( + @InjectModel(UserDocument.name, DB_USERS) + private userModel: Model, + @InjectModel(StorageDocument.name, DB_STORAGES) + private storageModel: Model, + ) {} + + async checkRequest(token?: string): Promise { + const userList = await this.userModel.find().exec(); + const searchUser = userList.find((user) => user.token === token); + if (searchUser) { + return { + login: searchUser.login, + token: searchUser.token, + }; + } + throw new NotAcceptableException(`Доступ запрещен`); + } + + async authUser(login: string): Promise { + const userList = await this.userModel.find().exec(); + const searchUser = userList.find((user) => user.login === login); + if (searchUser) { + return searchUser.token; + } + const Model = this.userModel; + const userModel = new Model({ + login, + token: v4(), + }); + const newUser = await userModel.save(); + return newUser.token; + } + + async getStorageList(login: string): Promise { + const storageList = await this.storageModel.find().exec(); + const preparedList = storageList.map(({ data, _id, user }) => ({ + data, + id: _id as string, + user, + })); + + return preparedList.filter(({ user }) => user === login); + } + + async getStorageById(login: string, id: string): Promise { + const searchStorage = await this.storageModel.findById(id); + if (searchStorage && searchStorage.user === login) { + return { + data: searchStorage.data, + id: searchStorage._id as string, + user: searchStorage.user, + }; + } + throw new BadRequestException(`Storage с id - "${id}" не найдена`); + } + + async addStorage(login: string, storage: StorageCreate): Promise { + const Model = this.storageModel; + const storageModel = new Model({ + data: storage.data, + user: login, + }); + try { + await storageModel.validate(); + } catch (e) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + throw new BadRequestException(e.message); + } + + const newStorage = await storageModel.save(); + return { + data: newStorage.data, + user: newStorage.user, + id: newStorage._id as string, + }; + } + + async updateStorage( + login: string, + id: string, + storage: StorageUpdate, + ): Promise { + const searchStorage = await this.storageModel.findById(id); + + if (!searchStorage || searchStorage.user !== login) { + throw new BadRequestException(`Storage с id - "${id}" не найден`); + } + + await searchStorage.updateOne({ + data: storage.data, + }); + + return { + data: storage.data, + user: searchStorage.user, + id: searchStorage._id as string, + }; + } + + async deleteStorageById(login: string, id: string): Promise { + const searchStorage = await this.storageModel.findById(id); + if (!searchStorage || searchStorage.user !== login) { + throw new BadRequestException(`Storage с id - "${id}" не найден`); + } + const Model = this.storageModel; + + await Model.findByIdAndDelete(id); + + return { + data: searchStorage.data, + user: searchStorage.user, + id: searchStorage._id as string, + }; } } diff --git a/src/consts.ts b/src/consts.ts new file mode 100644 index 0000000..40721d8 --- /dev/null +++ b/src/consts.ts @@ -0,0 +1,24 @@ +export const MONGO_URL = 'mongodb://localhost:27017'; + +export const APP_CONTROLLER = 'storage-app'; + +export const DB_USERS = 'storage-back-users'; +export const DB_STORAGES = 'storage-back-storages'; + +export const ALLOW_ORIGIN_ALL: [string, string] = [ + 'Access-Control-Allow-Origin', + '*', +]; +export const ALLOW_CREDENTIALS: [string, string] = [ + 'Access-Control-Allow-Credentials', + 'true', +]; +export const CONTENT_LENGTH: [string, string] = ['Content-Length', '0']; +export const ALLOW_METHOD: [string, string] = [ + 'Access-Control-Allow-Methods', + 'GET,HEAD,PUT,PATCH,POST,DELETE', +]; +export const ALLOW_HEADERS: [string, string] = [ + 'Access-Control-Allow-Headers', + 'Version, Authorization, Content-Type, Api-Name, x-turbo-id, x-turbo-compression, chrome-proxy, chrome-proxy-ect', +]; diff --git a/src/main.ts b/src/main.ts index f76bc8d..e23ca32 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,8 +1,28 @@ import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; +import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; +import { APP_CONTROLLER } from './consts'; async function bootstrap() { const app = await NestFactory.create(AppModule); + + const options = new DocumentBuilder() + .addSecurity('apiKey', { + type: 'apiKey', + in: 'header', + name: 'Authorization', + }) + .setTitle('Storage API') + .setDescription('API для работы с хранилищами') + .setVersion('1.0.0') + .addTag(APP_CONTROLLER) + .build(); + + const document = SwaggerModule.createDocument(app, options); + + SwaggerModule.setup('api', app, document); + await app.listen(process.env.PORT ?? 3000); } -bootstrap(); + +void bootstrap(); diff --git a/src/schemas.ts b/src/schemas.ts new file mode 100644 index 0000000..d1cafa2 --- /dev/null +++ b/src/schemas.ts @@ -0,0 +1,53 @@ +import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; +import { ApiProperty } from '@nestjs/swagger'; +import { Document } from 'mongoose'; +import { Storage } from './types'; + +export class AuthRequest { + @ApiProperty() + login: string; +} + +@Schema() +export class UserDocument extends Document { + @Prop({ + type: String, + required: true, + }) + login: string; + + @Prop({ + type: String, + required: true, + }) + token: string; +} + +@Schema() +export class StorageDocument extends Document { + @Prop({ + type: Object, + required: true, + }) + data: object; + + @Prop({ + type: String, + required: true, + }) + user: string; +} + +export const StorageScheme = SchemaFactory.createForClass(StorageDocument); +export const UserScheme = SchemaFactory.createForClass(UserDocument); + +export class StorageResponse implements Storage { + @ApiProperty() + data: object; + + @ApiProperty() + user: string; + + @ApiProperty() + id: string; +} diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..09242d9 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,18 @@ +export type User = { + login: string; + token: string; +}; + +export type Storage = { + data: object; + user: string; + id: string; +}; + +export type StorageCreate = { + data: object; +}; + +export type StorageUpdate = { + data: object; +};