diff --git a/.http b/.http new file mode 100644 index 0000000..c721d93 --- /dev/null +++ b/.http @@ -0,0 +1,57 @@ +### use REST Client plugin for VSCode https://marketplace.visualstudio.com/items?itemName=humao.rest-client +@host = http://localhost:4005 +@user = test_user +@auth = 7b5da8a1-b64c-43ea-90f3-cdd3da507504 +@storage_id = 67c420ab38fafe445411e76a + +### Auth +POST {{host}}/auth HTTP/1.1 +content-type: application/json + +{ + "login": "{{user}}" +} + +### Get storages list +GET {{host}}/storages HTTP/1.1 +content-type: application/json +Authorization: {{auth}} + +{ + "login": "test_user" +} + +### Create storage +POST {{host}}/storages HTTP/1.1 +content-type: application/json +Authorization: {{auth}} + +{ + "data": { + "users": ["ivan", "maria"], + "count": 2 + }, + "storageName": "users" +} + +### Get storage +GET {{host}}/storages/{{storage_id}} HTTP/1.1 +content-type: application/json +Authorization: {{auth}} + +### Update storage +PUT {{host}}/storages/{{storage_id}} HTTP/1.1 +content-type: application/json +Authorization: {{auth}} + +{ + "data": { + "users": ["ivan", "maria", "fedor"], + "count": 3 + } +} + +### Remove image +DELETE {{host}}/storages/{{storage_id}} HTTP/1.1 +content-type: application/json +Authorization: {{auth}} diff --git a/src/api.responses.ts b/src/api.responses.ts index 5645f32..a35a4bc 100644 --- a/src/api.responses.ts +++ b/src/api.responses.ts @@ -16,7 +16,13 @@ export const AUTH_ERROR: ApiResponseOptions = { export const GET_STORAGES_LIST_SUCCESS: ApiResponseOptions = { status: 200, - description: 'Список всех картинок', + description: 'Список всех storage пользователя', type: StorageResponse, isArray: true, }; + +export const MANIPULATE_STORAGE_SUCCESS: ApiResponseOptions = { + status: 200, + description: 'Storage', + type: StorageResponse, +}; diff --git a/src/app.controller.ts b/src/app.controller.ts index 8c98866..3baf36a 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -1,15 +1,24 @@ import { Controller, + Delete, Get, Header, HttpCode, Options, Post, + Put, Req, } from '@nestjs/common'; import { Request } from 'express'; import { AppService } from './app.service'; -import { ApiBody, ApiResponse, ApiSecurity, ApiTags } from '@nestjs/swagger'; +import { + ApiBody, + ApiExcludeEndpoint, + ApiParam, + ApiResponse, + ApiSecurity, + ApiTags, +} from '@nestjs/swagger'; import { ALLOW_CREDENTIALS, ALLOW_HEADERS, @@ -20,10 +29,11 @@ import { import { AUTH_ERROR, AUTH_SUCCESS, + MANIPULATE_STORAGE_SUCCESS, GET_STORAGES_LIST_SUCCESS, } from './api.responses'; -import { AuthRequest } from './schemas'; -import { Storage } from './types'; +import { AuthRequest, StorageCreateRequest } from './schemas'; +import { Storage, StorageCreate, StorageList, StorageUpdate } from './types'; @Controller() @ApiTags('storage-app') @@ -48,14 +58,89 @@ export class AppController { @Header(...ALLOW_ORIGIN_ALL) @ApiResponse(GET_STORAGES_LIST_SUCCESS) @ApiResponse(AUTH_ERROR) - async getStorageList(@Req() request: Request): Promise { + async getStorageList(@Req() request: Request): Promise { const { login } = await this.appService.checkRequest( request.headers.authorization, ); return this.appService.getStorageList(login); } - @Options(['', '/auth']) + @Get('/storages/:id') + @ApiSecurity('apiKey') + @ApiParam({ + name: 'id', + description: 'id storage', + }) + @Header(...ALLOW_ORIGIN_ALL) + @ApiResponse(MANIPULATE_STORAGE_SUCCESS) + @ApiResponse(AUTH_ERROR) + async getImageById( + @Req() request: Request<{ id: string }>, + ): Promise { + const { login } = await this.appService.checkRequest( + request.headers.authorization, + ); + return this.appService.getStorageById(login, request.params.id); + } + + @Post('/storages') + @ApiSecurity('apiKey') + @ApiBody({ + type: StorageCreateRequest, + description: 'Объект создания storage', + }) + @Header(...ALLOW_ORIGIN_ALL) + @ApiResponse(MANIPULATE_STORAGE_SUCCESS) + @ApiResponse(AUTH_ERROR) + async createImage( + @Req() request: Request, + ): Promise { + const { login } = await this.appService.checkRequest( + request.headers.authorization, + ); + return this.appService.addStorage(login, request.body); + } + + @Put('/storages/:id') + @ApiSecurity('apiKey') + @ApiParam({ + name: 'id', + description: 'id storage', + }) + @Header(...ALLOW_ORIGIN_ALL) + @ApiResponse(MANIPULATE_STORAGE_SUCCESS) + @ApiResponse(AUTH_ERROR) + async toggleLike( + @Req() request: Request<{ id: string }, null, StorageUpdate>, + ): Promise { + const { login } = await this.appService.checkRequest( + request.headers.authorization, + ); + return this.appService.updateStorage( + login, + request.params.id, + request.body, + ); + } + + @Delete('/storages/:id') + @ApiSecurity('apiKey') + @ApiParam({ + name: 'id', + description: 'id картинки', + }) + @Header(...ALLOW_ORIGIN_ALL) + @ApiResponse(MANIPULATE_STORAGE_SUCCESS) + @ApiResponse(AUTH_ERROR) + async deleteImage(@Req() request: Request<{ id: string }>): Promise { + const { login } = await this.appService.checkRequest( + request.headers.authorization, + ); + return this.appService.deleteStorageById(login, request.params.id); + } + + @ApiExcludeEndpoint() + @Options(['', '/auth', '/storages', '/storages/:id']) @Header(...ALLOW_ORIGIN_ALL) @Header(...ALLOW_METHOD) @Header(...ALLOW_CREDENTIALS) diff --git a/src/app.service.ts b/src/app.service.ts index e8aea0e..d2b61fb 100644 --- a/src/app.service.ts +++ b/src/app.service.ts @@ -6,7 +6,13 @@ import { import { InjectModel } from '@nestjs/mongoose'; import { StorageDocument, UserDocument } from './schemas'; import { Model } from 'mongoose'; -import { User, Storage, StorageCreate, StorageUpdate } from './types'; +import { + User, + Storage, + StorageCreate, + StorageUpdate, + StorageList, +} from './types'; import { v4 } from 'uuid'; import { DB_STORAGES, DB_USERS } from './consts'; @@ -46,12 +52,12 @@ export class AppService { return newUser.token; } - async getStorageList(login: string): Promise { + async getStorageList(login: string): Promise { const storageList = await this.storageModel.find().exec(); - const preparedList = storageList.map(({ data, _id, user }) => ({ - data, + const preparedList = storageList.map(({ _id, user, storageName }) => ({ id: _id as string, user, + storageName, })); return preparedList.filter(({ user }) => user === login); @@ -63,6 +69,7 @@ export class AppService { return { data: searchStorage.data, id: searchStorage._id as string, + storageName: searchStorage.storageName, user: searchStorage.user, }; } @@ -73,6 +80,7 @@ export class AppService { const Model = this.storageModel; const storageModel = new Model({ data: storage.data, + storageName: storage.storageName, user: login, }); try { @@ -86,6 +94,7 @@ export class AppService { return { data: newStorage.data, user: newStorage.user, + storageName: newStorage.storageName, id: newStorage._id as string, }; } @@ -101,13 +110,17 @@ export class AppService { throw new BadRequestException(`Storage с id - "${id}" не найден`); } + const updatedStorageName = storage.storageName ?? searchStorage.storageName; + await searchStorage.updateOne({ data: storage.data, + storageName: updatedStorageName, }); return { data: storage.data, user: searchStorage.user, + storageName: updatedStorageName, id: searchStorage._id as string, }; } @@ -124,6 +137,7 @@ export class AppService { return { data: searchStorage.data, user: searchStorage.user, + storageName: searchStorage.storageName, id: searchStorage._id as string, }; } diff --git a/src/main.ts b/src/main.ts index e23ca32..87c91f9 100644 --- a/src/main.ts +++ b/src/main.ts @@ -22,7 +22,7 @@ async function bootstrap() { SwaggerModule.setup('api', app, document); - await app.listen(process.env.PORT ?? 3000); + await app.listen(4005); } void bootstrap(); diff --git a/src/schemas.ts b/src/schemas.ts index d1cafa2..e3db43b 100644 --- a/src/schemas.ts +++ b/src/schemas.ts @@ -1,7 +1,7 @@ import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import { ApiProperty } from '@nestjs/swagger'; import { Document } from 'mongoose'; -import { Storage } from './types'; +import { Storage, StorageCreate } from './types'; export class AuthRequest { @ApiProperty() @@ -31,6 +31,12 @@ export class StorageDocument extends Document { }) data: object; + @Prop({ + type: String, + required: true, + }) + storageName: string; + @Prop({ type: String, required: true, @@ -48,6 +54,17 @@ export class StorageResponse implements Storage { @ApiProperty() user: string; + @ApiProperty() + storageName: string; + @ApiProperty() id: string; } + +export class StorageCreateRequest implements StorageCreate { + @ApiProperty() + data: object; + + @ApiProperty() + storageName: string; +} diff --git a/src/types.ts b/src/types.ts index 09242d9..e4b6727 100644 --- a/src/types.ts +++ b/src/types.ts @@ -5,14 +5,23 @@ export type User = { export type Storage = { data: object; + storageName: string; user: string; id: string; }; +export type StorageList = Array<{ + user: string; + storageName: string; + id: string; +}>; + export type StorageCreate = { data: object; + storageName: string; }; export type StorageUpdate = { data: object; + storageName?: string; };