add service and first method to controller

This commit is contained in:
Николай Вигдоров
2025-03-01 23:54:08 +03:00
parent 83ad4d43cd
commit 12b3d5b23c
10 changed files with 632 additions and 17 deletions

287
package-lock.json generated
View File

@ -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",

View File

@ -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",

22
src/api.responses.ts Normal file
View File

@ -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,
};

View File

@ -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<null, null, { login: string }>,
): Promise<string> {
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<Storage[]> {
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<string> {
return await Promise.resolve('');
}
}

View File

@ -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],
})

View File

@ -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<UserDocument>,
@InjectModel(StorageDocument.name, DB_STORAGES)
private storageModel: Model<StorageDocument>,
) {}
async checkRequest(token?: string): Promise<User> {
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<string> {
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<Storage[]> {
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<Storage> {
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<Storage> {
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<Storage> {
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<Storage> {
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,
};
}
}

24
src/consts.ts Normal file
View File

@ -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',
];

View File

@ -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();

53
src/schemas.ts Normal file
View File

@ -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;
}

18
src/types.ts Normal file
View File

@ -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;
};