From d17b5b74587e97169a6bb246f85f00103238355a Mon Sep 17 00:00:00 2001 From: Lena Rashkovan Date: Sun, 29 Oct 2023 16:43:38 +0100 Subject: [PATCH 01/21] feat(cli): update help --- Workflow.md | 4 ++-- package.json | 3 ++- src/cli/commands/help.command.ts | 10 +++------- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/Workflow.md b/Workflow.md index 4977046..5e7ae48 100644 --- a/Workflow.md +++ b/Workflow.md @@ -75,13 +75,13 @@ npm run mock:server #### Запустить генерацию моковых данных ```bash -npm run ts ./src/main.cli.ts -- --generate 100 ./mocks/mock-data.tsv http://localhost:3123/api +npm run cli -- --generate 100 ./mocks/mock-data.tsv http://localhost:3123/api ``` #### Наполнить базу моковыми данными ```bash -npm run ts ./src/main.cli.ts -- --import ./mocks/mock-data.tsv admin test 127.0.0.1 six-cities secret +npm run cli -- --import ./mocks/mock-data.tsv admin test 127.0.0.1 six-cities secret ``` diff --git a/package.json b/package.json index be3d408..c0ccbb7 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ "compile": "tsc -p tsconfig.json", "clean": "rimraf dist", "ts": "ts-node", - "mock:server": "json-server ./mocks/mock-server-data.json --port 3123" + "mock:server": "json-server ./mocks/mock-server-data.json --port 3123", + "cli": "ts-node ./src/main.cli.ts" }, "devDependencies": { "@types/convict": "6.1.4", diff --git a/src/cli/commands/help.command.ts b/src/cli/commands/help.command.ts index ee4445c..157fcea 100644 --- a/src/cli/commands/help.command.ts +++ b/src/cli/commands/help.command.ts @@ -10,20 +10,16 @@ export class HelpCommand implements Command { console.info(`Программа для подготовки данных для REST API сервера. ${chalk.bold('ПРИМЕР')} - ${chalk.bold('cli.js')} --${chalk.underline( - 'command', -)} [...${chalk.underline('arguments')}] + ${chalk.bold('cli.js')} --${chalk.underline('command')} [...${chalk.underline('arguments')}] ${chalk.bold('КОМАНДЫ')} ${chalk.bold('--version')} Выводит номер версии ${chalk.bold('--help')} Печатает этот текст - ${chalk.bold('--import')} ${chalk.underline('path')} + ${chalk.bold('--import')} ${chalk.underline('path')} ${chalk.underline('db_login')} ${chalk.underline('db_pass')} ${chalk.underline('db_host')} ${chalk.underline('db_name')} ${chalk.underline('salt')} Импортирует данные из TSV - ${chalk.bold('--generate')} ${chalk.underline('n')} ${chalk.underline( - 'path', -)} ${chalk.underline('url')} + ${chalk.bold('--generate')} ${chalk.underline('n')} ${chalk.underline('path')} ${chalk.underline('url')} Генерирует произвольное количество тестовых данных `); } From 8927795522e0fb337cd52e1e719fd30916a26075 Mon Sep 17 00:00:00 2001 From: Lena Rashkovan Date: Sun, 29 Oct 2023 16:54:10 +0100 Subject: [PATCH 02/21] chore(rest): add env example and update workflow --- .env.example | 10 ++++++++++ Workflow.md | 27 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..55541f1 --- /dev/null +++ b/.env.example @@ -0,0 +1,10 @@ +PORT=4000 +SALT=secret +DB_HOST=127.0.0.1 +DB_USER=admin +DB_PASSWORD=test +DB_NAME=six-cities +DB_MAX_RETRIES=3 +DB_RETRY_TIMEOUT=1000 +UPLOAD_DIRECTORY=upload +JWT_SECRET=super-secret! diff --git a/Workflow.md b/Workflow.md index 5e7ae48..e780b89 100644 --- a/Workflow.md +++ b/Workflow.md @@ -84,6 +84,33 @@ npm run cli -- --generate 100 ./mocks/mock-data.tsv http://localhost:3123/api npm run cli -- --import ./mocks/mock-data.tsv admin test 127.0.0.1 six-cities secret ``` +## REST API сервис + +### Переменные окружения + +```bash +PORT=4000 - Порт для входящих соединений + +SALT=secret - Соль для хэширования паролей + +DB_HOST=127.0.0.1 - IP-адрес сервера базы данных (MongoDB) + +DB_USER=admin - Имя пользователя для подключения к базе данных + +DB_PASSWORD=test - Пароль для подключения к базе данных + +DB_PORT=27017 - Порт для подключения к базе данных (MongoDB) + +DB_NAME=six-cities - Имя базы данных (MongoDB) + +DB_MAX_RETRIES=3 - Максильмальное число попыток переподключения к БД + +DB_RETRY_TIMEOUT=1000 - Число миллисекунд между попытками подключения к БД + +UPLOAD_DIRECTORY=upload - Директория для хранения загружаемых пользователями файлов + +JWT_SECRET=super-secret! - Секрет для подписи JWT-токена +``` ## Структура проекта From c8814d198e89c3b4d577261fc18dfd276dc27f28 Mon Sep 17 00:00:00 2001 From: Lena Rashkovan Date: Sun, 29 Oct 2023 17:08:55 +0100 Subject: [PATCH 03/21] chore(cli): update help --- src/cli/commands/help.command.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/commands/help.command.ts b/src/cli/commands/help.command.ts index 157fcea..d0cd573 100644 --- a/src/cli/commands/help.command.ts +++ b/src/cli/commands/help.command.ts @@ -10,7 +10,7 @@ export class HelpCommand implements Command { console.info(`Программа для подготовки данных для REST API сервера. ${chalk.bold('ПРИМЕР')} - ${chalk.bold('cli.js')} --${chalk.underline('command')} [...${chalk.underline('arguments')}] + ${chalk.bold('npm run cli')} -- --${chalk.underline('command')} [...${chalk.underline('arguments')}] ${chalk.bold('КОМАНДЫ')} ${chalk.bold('--version')} From 2eea468a5b694c00f42f7d914f962c8920a2ca27 Mon Sep 17 00:00:00 2001 From: Lena Rashkovan Date: Sun, 29 Oct 2023 17:11:15 +0100 Subject: [PATCH 04/21] docs: update Workflow --- Workflow.md | 114 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 76 insertions(+), 38 deletions(-) diff --git a/Workflow.md b/Workflow.md index e780b89..393d8ec 100644 --- a/Workflow.md +++ b/Workflow.md @@ -1,16 +1,82 @@ # Как работать над проектом -## Окружение +## Запуск проекта -Для удобства работы над проектом используются инструменты из **Node.js** и **npm**. Все необходимые настройки произведены. Убедитесь, что на рабочем компьютере установлен актуальный LTS релиз Node.js**. Актуальная версия **Node.js** указана в файле `package.json` в поле `node`. Затем, в терминале, перейдите в директорию с проектом и _единожды_ запустите команду: +Убедитесь, что на рабочем компьютере установлен актуальный LTS релиз **Node.js**. Актуальная версия **Node.js** указана в файле `package.json` в поле `node`. + +### Установите зависимости + +Выполните команду ```bash npm install ``` -Команда запустит процесс установки зависимостей проекта из **npm**. +### Разверните базу данных MongoDB + +В проекте используется база данных **MongoDB** версии 4.2. + +Если вы используете Docker, воспользуйтесь файлом `docker-compose.dev.yml`, расположенным в корне проекта, для быстрого разворачивания базы данных. + +### Наполните базу данных + +Запустите JSON-сервер с моковыми данными: + +```bash +npm run mock:server +``` + +Сгенерируйте нужное количество предложений об аренде: + +```bash +npm run cli -- --generate 100 ./mocks/mock-data.tsv http://localhost:3123/api +``` + +Импортируйте данные в базу данных, используя настройки подключения из файла `docker-compose`: + +```bash +npm run cli -- --import ./mocks/mock-data.tsv admin test 127.0.0.1 six-cities secret +``` + +### Настройте переменные окружения + +В корне проекта находится файл `.env.example`. Скопируйте его содержимое в файл `.env` и настройте значения переменных. -### Сценарии +#### Переменные окружения + +```bash +PORT=4000 - Порт для входящих соединений + +SALT=secret - Соль для хэширования паролей + +DB_HOST=127.0.0.1 - IP-адрес сервера базы данных (MongoDB) + +DB_USER=admin - Имя пользователя для подключения к базе данных + +DB_PASSWORD=test - Пароль для подключения к базе данных + +DB_PORT=27017 - Порт для подключения к базе данных (MongoDB) + +DB_NAME=six-cities - Имя базы данных (MongoDB) + +DB_MAX_RETRIES=3 - Максильмальное число попыток переподключения к БД + +DB_RETRY_TIMEOUT=1000 - Число миллисекунд между попытками подключения к БД + +UPLOAD_DIRECTORY=upload - Директория для хранения загружаемых пользователями файлов + +JWT_SECRET=super-secret! - Секрет для подписи JWT-токена +``` + +### Запустите проект + +Выполните команду + +```bash +npm start +``` + +## Сценарии В `package.json` предопределено несколько сценариев. @@ -66,50 +132,22 @@ npm start В процессе запуска проекта будет выполнен процесс «Сборки проекта» и запуска результирующего кода. -#### Запустить JSON-server с моковыми данными +#### Запустить проект в режиме разработки ```bash -npm run mock:server -``` - -#### Запустить генерацию моковых данных - -```bash -npm run cli -- --generate 100 ./mocks/mock-data.tsv http://localhost:3123/api +npm run start:dev ``` -#### Наполнить базу моковыми данными +#### Запустить JSON-server с моковыми данными ```bash -npm run cli -- --import ./mocks/mock-data.tsv admin test 127.0.0.1 six-cities secret +npm run mock:server ``` -## REST API сервис - -### Переменные окружения +#### Запустить консольную утилиту ```bash -PORT=4000 - Порт для входящих соединений - -SALT=secret - Соль для хэширования паролей - -DB_HOST=127.0.0.1 - IP-адрес сервера базы данных (MongoDB) - -DB_USER=admin - Имя пользователя для подключения к базе данных - -DB_PASSWORD=test - Пароль для подключения к базе данных - -DB_PORT=27017 - Порт для подключения к базе данных (MongoDB) - -DB_NAME=six-cities - Имя базы данных (MongoDB) - -DB_MAX_RETRIES=3 - Максильмальное число попыток переподключения к БД - -DB_RETRY_TIMEOUT=1000 - Число миллисекунд между попытками подключения к БД - -UPLOAD_DIRECTORY=upload - Директория для хранения загружаемых пользователями файлов - -JWT_SECRET=super-secret! - Секрет для подписи JWT-токена +npm run cli ``` ## Структура проекта From 198738cf27d567910af7f35558f49317b25cce3e Mon Sep 17 00:00:00 2001 From: Lena Rashkovan Date: Sun, 29 Oct 2023 17:36:06 +0100 Subject: [PATCH 05/21] feat(validate-dto): update error format --- src/shared/libs/rest/middleware/validate-dto.middleware.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/shared/libs/rest/middleware/validate-dto.middleware.ts b/src/shared/libs/rest/middleware/validate-dto.middleware.ts index 8915ebd..3250753 100644 --- a/src/shared/libs/rest/middleware/validate-dto.middleware.ts +++ b/src/shared/libs/rest/middleware/validate-dto.middleware.ts @@ -16,7 +16,12 @@ export class ValidateDtoMiddleware implements Middleware { const errors = await validate(dtoInstance); if (errors.length > 0) { - res.status(StatusCodes.BAD_REQUEST).send(errors); + res.status(StatusCodes.BAD_REQUEST).send({ + errors: errors.map((error) => ({ + field: error.property, + message: Object.values(error.constraints ?? {}).join(';') + })) + }); return; } From e69515f46149f0af43743b7185579d879557acf4 Mon Sep 17 00:00:00 2001 From: Lena Rashkovan Date: Sun, 29 Oct 2023 17:38:38 +0100 Subject: [PATCH 06/21] feat(spec): update createUser schema --- specification/project.spec.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/specification/project.spec.yml b/specification/project.spec.yml index 1099561..5d3d618 100644 --- a/specification/project.spec.yml +++ b/specification/project.spec.yml @@ -395,6 +395,10 @@ components: format: email required: true example: keks@htmlacademy.ru + avatarPath: + type: string + required: false + example: upload/ketUeXWH-AxExEduf3lSp.png name: type: string required: true @@ -403,7 +407,7 @@ components: type: string format: password required: true - example: 123456 + example: 12345678 type: type: string enum: @@ -411,10 +415,6 @@ components: - Pro required: true example: Pro - avatarPath: - type: string - required: false - example: https://s3.amazonaws.com/uifaces/faces/twitter/hugocornejo/128.jpg authorizeUser: type: object From 4356c2ff5ca43134929317ceb226d20621bc25cf Mon Sep 17 00:00:00 2001 From: Lena Rashkovan Date: Sun, 29 Oct 2023 17:39:06 +0100 Subject: [PATCH 07/21] feat(spec): update validationError schema --- specification/project.spec.yml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/specification/project.spec.yml b/specification/project.spec.yml index 5d3d618..1e8da44 100644 --- a/specification/project.spec.yml +++ b/specification/project.spec.yml @@ -374,18 +374,14 @@ components: validationError: type: object properties: - message: - type: string - description: A description of the validation error. - example: Password too short field: type: string description: The name of the field that failed validation. example: password - code: + message: type: string - description: An error code associated with the validation error. - example: validation.createUser.password.tooShort + description: A description of the validation error. + example: Password too short createUser: type: object From f9827e43811e070b1320e68165232e8f7156b825 Mon Sep 17 00:00:00 2001 From: Lena Rashkovan Date: Sun, 29 Oct 2023 17:49:03 +0100 Subject: [PATCH 08/21] feat(spec): describe /users/register --- specification/project.spec.yml | 48 ++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/specification/project.spec.yml b/specification/project.spec.yml index 1e8da44..dde2e44 100644 --- a/specification/project.spec.yml +++ b/specification/project.spec.yml @@ -38,9 +38,13 @@ paths: content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/validationError' + $ref: '#/components/schemas/validationError' + '403': + description: A logged in user can not register. + content: + application/json: + schema: + $ref: '#/components/schemas/generalError' '409': description: A user with this email already exists. content: @@ -59,7 +63,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/authorizeUser' + $ref: '#/components/schemas/loginUser' required: true responses: '200': @@ -374,14 +378,19 @@ components: validationError: type: object properties: - field: - type: string - description: The name of the field that failed validation. - example: password - message: - type: string - description: A description of the validation error. - example: Password too short + errors: + type: array + items: + type: object + properties: + field: + type: string + description: The name of the field that failed validation. + example: password + message: + type: string + description: A description of the validation error. + example: Password too short createUser: type: object @@ -412,31 +421,30 @@ components: required: true example: Pro - authorizeUser: + loginUser: type: object properties: login: type: string + required: true example: keks@htmlacademy.ru password: type: string - example: 123456 + required: true + example: 12345678 user: type: object properties: - id: - type: string - example: 6329c3d6a04ab1061c6425ea email: type: string example: keks@htmlacademy.ru + avatarPath: + type: string + example: upload/ketUeXWH-AxExEduf3lSp.png name: type: string example: Keks - avatarPath: - type: string - example: https://s3.amazonaws.com/uifaces/faces/twitter/hugocornejo/128.jpg type: type: string enum: From c28128eabf68d6d872ebe9830f04afada684b9d6 Mon Sep 17 00:00:00 2001 From: Lena Rashkovan Date: Sun, 29 Oct 2023 17:58:10 +0100 Subject: [PATCH 09/21] feat(spec): describe POST /users/login --- specification/project.spec.yml | 17 +++++++++++++++++ .../modules/auth/auth.exception-filter.ts | 6 ++---- src/shared/modules/user/rdo/logged-user.rdo.ts | 9 --------- src/shared/modules/user/user.controller.ts | 7 +------ 4 files changed, 20 insertions(+), 19 deletions(-) delete mode 100644 src/shared/modules/user/rdo/logged-user.rdo.ts diff --git a/specification/project.spec.yml b/specification/project.spec.yml index dde2e44..d445f74 100644 --- a/specification/project.spec.yml +++ b/specification/project.spec.yml @@ -11,6 +11,7 @@ tags: - name: offers - name: users - name: comments + - name: cities paths: /users/register: @@ -72,8 +73,24 @@ paths: text/plain: schema: type: string + '400': + description: Some of the provided information is not correct. + content: + application/json: + schema: + $ref: '#/components/schemas/validationError' '401': + description: A user is not authorized. + content: + application/json: + schema: + $ref: '#/components/schemas/generalError' + '404': description: A user with specified credentials was not found. + content: + application/json: + schema: + $ref: '#/components/schemas/generalError' get: tags: diff --git a/src/shared/modules/auth/auth.exception-filter.ts b/src/shared/modules/auth/auth.exception-filter.ts index 771dd03..78c5193 100644 --- a/src/shared/modules/auth/auth.exception-filter.ts +++ b/src/shared/modules/auth/auth.exception-filter.ts @@ -4,6 +4,7 @@ import { ExceptionFilter } from '../../libs/rest/index.js'; import { Logger } from '../../libs/logger/index.js'; import { Component } from '../../types/index.js'; import { BaseUserException } from './errors/index.js'; +import { createErrorObject } from '../../helpers/index.js'; @injectable() export class AuthExceptionFilter implements ExceptionFilter { @@ -22,9 +23,6 @@ export class AuthExceptionFilter implements ExceptionFilter { } this.logger.error(`[AuthModule] ${error.message}`, error); - res.status(error.httpStatusCode).json({ - type: 'AUTHORIZATION', - error: error.message, - }); + res.status(error.httpStatusCode).json(createErrorObject(error.message)); } } diff --git a/src/shared/modules/user/rdo/logged-user.rdo.ts b/src/shared/modules/user/rdo/logged-user.rdo.ts deleted file mode 100644 index 543bd7d..0000000 --- a/src/shared/modules/user/rdo/logged-user.rdo.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Expose } from 'class-transformer'; - -export class LoggedUserRdo { - @Expose() - public token: string; - - @Expose() - public email: string; -} diff --git a/src/shared/modules/user/user.controller.ts b/src/shared/modules/user/user.controller.ts index 7394955..0cf1c1d 100644 --- a/src/shared/modules/user/user.controller.ts +++ b/src/shared/modules/user/user.controller.ts @@ -19,7 +19,6 @@ import { UserService } from './user-service.interface.js'; import { CreateUserRequest } from './types/create-user-request.type.js'; import { LoginUserRequest } from './types/login-user-request.type.js'; import { UserRdo } from './rdo/user.rdo.js'; -import { LoggedUserRdo } from './rdo/logged-user.rdo.js'; import { CreateUserDto } from './dto/create-user.dto.js'; import { LoginUserDto } from './dto/login-user.dto.js'; import { FavoriteOfferDto } from './dto/favorite-offer.dto.js'; @@ -118,11 +117,7 @@ export class UserController extends BaseController { public async login({ body }: LoginUserRequest, res: Response): Promise { const user = await this.authService.verify(body); const token = await this.authService.authenticate(user); - const responseData = fillDTO(LoggedUserRdo, { - email: user.email, - token, - }); - this.ok(res, responseData); + this.ok(res, token); } public async checkToken( From 4bc156ddcd07faea69a359f2e10208244d0a91b6 Mon Sep 17 00:00:00 2001 From: Lena Rashkovan Date: Sun, 29 Oct 2023 17:59:58 +0100 Subject: [PATCH 10/21] feat(spec): describe GET /users/login --- specification/project.spec.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/specification/project.spec.yml b/specification/project.spec.yml index d445f74..c7ae6cb 100644 --- a/specification/project.spec.yml +++ b/specification/project.spec.yml @@ -106,6 +106,10 @@ paths: $ref: '#/components/schemas/user' '401': description: User session token is invalid. + content: + application/json: + schema: + $ref: '#/components/schemas/generalError' /users/{usedId}/avatar: post: @@ -390,7 +394,7 @@ components: error: type: string description: A description of the error. - example: User already exists + example: Error description validationError: type: object From 5b713ba26be33408317f0626da35daafe4b224f8 Mon Sep 17 00:00:00 2001 From: Lena Rashkovan Date: Sun, 29 Oct 2023 18:05:46 +0100 Subject: [PATCH 11/21] feat(spec): describe POST /users/avatar --- specification/project.spec.yml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/specification/project.spec.yml b/specification/project.spec.yml index c7ae6cb..fb67341 100644 --- a/specification/project.spec.yml +++ b/specification/project.spec.yml @@ -111,7 +111,7 @@ paths: schema: $ref: '#/components/schemas/generalError' - /users/{usedId}/avatar: + /users/avatar: post: tags: - users @@ -120,6 +120,21 @@ paths: responses: '201': description: Image has been uploaded. + content: + application/json: + schema: + type: object + properties: + filepath: + type: string + example: + upload/Uq-PzHXRZnm6NzYvfjFGA.png + '401': + description: A user is not authorized. + content: + application/json: + schema: + $ref: '#/components/schemas/generalError' /offers: get: From 31044ed2239c10a2b42a4120ac417c9c24b54f91 Mon Sep 17 00:00:00 2001 From: Lena Rashkovan Date: Sun, 29 Oct 2023 18:08:29 +0100 Subject: [PATCH 12/21] feat(spec): describe GET /users/favorites --- specification/project.spec.yml | 43 +++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/specification/project.spec.yml b/specification/project.spec.yml index fb67341..4fb6b34 100644 --- a/specification/project.spec.yml +++ b/specification/project.spec.yml @@ -130,7 +130,30 @@ paths: example: upload/Uq-PzHXRZnm6NzYvfjFGA.png '401': - description: A user is not authorized. + description: A user is not authorized to upload an avatar. + content: + application/json: + schema: + $ref: '#/components/schemas/generalError' + + /users/favorites: + get: + tags: + - users + - offers + summary: List of favorite offers + description: Returns all the offers that have been added to favorites list by a current user. + responses: + '200': + description: List of offers. + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/offerPreview' + '401': + description: User is not authorized to view favorite offers. content: application/json: schema: @@ -301,24 +324,6 @@ paths: '404': description: Offer with the given ID does not exist. - /offers/favorites: - get: - tags: - - offers - summary: List of favorite offers - description: Returns all the offers that have been added to favorites list by a current user. - responses: - '200': - description: List of offers. - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/offerPreview' - '401': - description: User is not authorized to view favorite offers. - /offers/{offerId}/favorite: put: tags: From bb246bcf21c1105e203e633a7a9e637e8558315c Mon Sep 17 00:00:00 2001 From: Lena Rashkovan Date: Sun, 29 Oct 2023 18:14:36 +0100 Subject: [PATCH 13/21] feat(spec): describe PUT /users/favorites --- specification/project.spec.yml | 64 +++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/specification/project.spec.yml b/specification/project.spec.yml index 4fb6b34..77c9b78 100644 --- a/specification/project.spec.yml +++ b/specification/project.spec.yml @@ -159,6 +159,34 @@ paths: schema: $ref: '#/components/schemas/generalError' + put: + tags: + - users + - offers + summary: Favorite the offer + description: Adds/removes an offer to/from the favorites list. + requestBody: + description: Information to mark an offer as favorite. + content: + application/json: + schema: + $ref: '#/components/schemas/favoriteOffer' + responses: + '204': + description: Offer's `favorite` status has been successfully updated + '400': + description: Some of the provided information is not correct. + content: + application/json: + schema: + $ref: '#/components/schemas/validationError' + '401': + description: User is not authorized to favorite offers. + content: + application/json: + schema: + $ref: '#/components/schemas/generalError' + /offers: get: tags: @@ -324,30 +352,6 @@ paths: '404': description: Offer with the given ID does not exist. - /offers/{offerId}/favorite: - put: - tags: - - offers - summary: Favorite the offer - description: Adds/removes an offer to/from the favorites list. - parameters: - - in: path - name: offerId - schema: - type: string - required: true - description: The ID of the offer. - requestBody: - content: - text/plain: - schema: - type: boolean - responses: - '204': - description: Offer's `favorite` status has been successfully updated - '401': - description: User is not authorized to favorite offers. - /offers/premium: get: tags: @@ -493,6 +497,18 @@ components: - Pro example: Pro + favoriteOffer: + type: object + properties: + offerId: + type: string + required: true + example: 6329c3d6a04ab1061c6425ea + isFavorite: + type: boolean + required: true + example: true + createOffer: type: object properties: From 8e94c41800194e1a46a934b63c25b3fcab6db5df Mon Sep 17 00:00:00 2001 From: Lena Rashkovan Date: Sun, 29 Oct 2023 18:38:05 +0100 Subject: [PATCH 14/21] feat(spec): describe GET /offers --- specification/project.spec.yml | 79 ++++++++++++++++++++++++---------- src/shared/helpers/parse.ts | 4 -- 2 files changed, 56 insertions(+), 27 deletions(-) diff --git a/specification/project.spec.yml b/specification/project.spec.yml index 77c9b78..7d4c13b 100644 --- a/specification/project.spec.yml +++ b/specification/project.spec.yml @@ -784,48 +784,34 @@ components: id: type: string example: 6329c3d6a04ab1061c6425ea - price: - type: number - format: float - example: 100 title: type: string example: Beautiful & luxurious studio at great location housingType: - type: string - enum: - - Apartment - - House - - Room - - Hotel - example: Apartment - isFavorite: - type: boolean - example: true + $ref: '#/components/schemas/housingType' postDate: type: string format: date-time example: 2023-10-11T13:15:56.868Z city: - type: string - enum: - - Amsterdam - - Brussels - - Cologne - - Dusseldorf - - Hamburg - - Paris - example: Amsterdam + $ref: '#/components/schemas/city' imagePreview: type: string example: https://s3.amasonaws.com/image-preview.png isPremium: type: boolean example: false + isFavorite: + type: boolean + example: true rating: type: number format: float example: 4.2 + price: + type: number + format: float + example: 100 commentAmount: type: integer example: 5 @@ -869,3 +855,50 @@ components: example: 4 author: $ref: '#/components/schemas/user' + + amenities: + type: array + items: + type: string + enum: + - Breakfast + - AirConditioning + - LaptopFriendlyWorkspace + - BabySeat + - Washer + - Towels + - Fridge + example: Fridge + + housingType: + type: string + enum: + - Apartment + - House + - Room + - Hotel + example: Apartment + + location: + type: object + properties: + latitude: + type: number + format: float + example: 48.85661 + longitude: + type: number + format: float + example: 2.351499 + + city: + type: object + properties: + id: + type: string + example: 6329c3d6a04ab1061c6425ea + name: + type: string + example: Amsterdam + location: + $ref: '#/components/schemas/location' diff --git a/src/shared/helpers/parse.ts b/src/shared/helpers/parse.ts index f45bc69..742c3f5 100644 --- a/src/shared/helpers/parse.ts +++ b/src/shared/helpers/parse.ts @@ -7,7 +7,3 @@ export function parseAsInteger(param: unknown): number | null { return Number.isInteger(parsedParam) ? parsedParam : null; } - -export function parseAsString(param: unknown): string | null { - return typeof param === 'string' ? param : null; -} From f05f03948a60e4c6b72333fe5197e1d7f26451be Mon Sep 17 00:00:00 2001 From: Lena Rashkovan Date: Sun, 29 Oct 2023 18:39:00 +0100 Subject: [PATCH 15/21] feat(spec): describe POST /offers --- specification/project.spec.yml | 78 +++++++++------------------------- 1 file changed, 20 insertions(+), 58 deletions(-) diff --git a/specification/project.spec.yml b/specification/project.spec.yml index 7d4c13b..767dcce 100644 --- a/specification/project.spec.yml +++ b/specification/project.spec.yml @@ -234,11 +234,13 @@ paths: content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/validationError' + $ref: '#/components/schemas/validationError' '401': description: User is not authorized to create offers. + content: + application/json: + schema: + $ref: '#/components/schemas/generalError' /offers/{offerId}: get: @@ -520,17 +522,11 @@ components: type: string required: true example: A quiet cozy and picturesque that hides behind a a river by the unique lightness of Amsterdam. - city: + postDate: type: string - enum: - - Amsterdam - - Brussels - - Cologne - - Dusseldorf - - Hamburg - - Paris + format: date-time required: true - example: Amsterdam + example: "2023-01-30T08:30:00Z" imagePreview: type: string required: true @@ -548,14 +544,7 @@ components: required: true example: true housingType: - type: string - enum: - - Apartment - - House - - Room - - Hotel - required: true - example: Apartment + $ref: '#/components/schemas/housingType' roomAmount: type: integer required: true @@ -599,6 +588,10 @@ components: type: string example: 6329c3d6a04ab1061c6425ea required: true + cityId: + type: string + example: 6329c3d6a04ab1061c6425ea + required: true updateOffer: type: object @@ -690,6 +683,9 @@ components: offer: type: object properties: + id: + type: string + example: 6329c3d6a04ab1061c6425ea title: type: string example: Beautiful & luxurious studio at great location @@ -701,15 +697,7 @@ components: format: date-time example: 2023-10-11T13:15:56.868Z city: - type: string - enum: - - Amsterdam - - Brussels - - Cologne - - Dusseldorf - - Hamburg - - Paris - example: Amsterdam + $ref: '#/components/schemas/city' imagePreview: type: string example: https://s3.amasonaws.com/image-preview.png @@ -731,13 +719,7 @@ components: format: float example: 4.2 housingType: - type: string - enum: - - Apartment - - House - - Room - - Hotel - example: Apartment + $ref: '#/components/schemas/housingType' roomAmount: type: integer example: 3 @@ -749,29 +731,9 @@ components: format: float example: 100 amenities: - type: array - items: - type: string - enum: - - Breakfast - - AirConditioning - - LaptopFriendlyWorkspace - - BabySeat - - Washer - - Towels - - Fridge - example: Fridge + $ref: '#/components/schemas/amenities' location: - type: object - properties: - latitude: - type: number - format: float - example: 48.85661 - longitude: - type: number - format: float - example: 2.351499 + $ref: '#/components/schemas/location' commentAmount: type: integer example: 5 From 159a4fd727e198dd0aefa89f436b46dd4249df9a Mon Sep 17 00:00:00 2001 From: Lena Rashkovan Date: Sun, 29 Oct 2023 18:41:50 +0100 Subject: [PATCH 16/21] feat(spec): describe POST /offers/:offerId --- specification/project.spec.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/specification/project.spec.yml b/specification/project.spec.yml index 767dcce..92f39dc 100644 --- a/specification/project.spec.yml +++ b/specification/project.spec.yml @@ -262,8 +262,18 @@ paths: application/json: schema: $ref: '#/components/schemas/offer' + '400': + description: Some of the provided information is not correct. + content: + application/json: + schema: + $ref: '#/components/schemas/validationError' '404': description: Offer with the given ID does not exist. + content: + application/json: + schema: + $ref: '#/components/schemas/generalError' patch: tags: From 15e7257c1accebe35e419043db03c2537c9b2976 Mon Sep 17 00:00:00 2001 From: Lena Rashkovan Date: Sun, 29 Oct 2023 18:45:28 +0100 Subject: [PATCH 17/21] feat(spec): describe PATCH /offers/:offerId --- specification/project.spec.yml | 73 +++++++++------------------------- 1 file changed, 19 insertions(+), 54 deletions(-) diff --git a/specification/project.spec.yml b/specification/project.spec.yml index 92f39dc..fc28ff1 100644 --- a/specification/project.spec.yml +++ b/specification/project.spec.yml @@ -306,15 +306,25 @@ paths: content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/validationError' + $ref: '#/components/schemas/validationError' '401': description: User is not authorized to edit offers. + content: + application/json: + schema: + $ref: '#/components/schemas/generalError' '403': description: User is not authorized to edit this offer. + content: + application/json: + schema: + $ref: '#/components/schemas/generalError' '404': description: Offer with the given ID does not exist. + content: + application/json: + schema: + $ref: '#/components/schemas/generalError' delete: tags: @@ -609,26 +619,12 @@ components: title: type: string example: Beautiful & luxurious studio at great location - required: false description: type: string example: A quiet cozy and picturesque that hides behind a a river by the unique lightness of Amsterdam. - required: false - city: - type: string - enum: - - Amsterdam - - Brussels - - Cologne - - Dusseldorf - - Hamburg - - Paris - example: Amsterdam - required: false imagePreview: type: string example: https://s3.amasonaws.com/image-preview.png - required: false images: type: array minItems: 6 @@ -636,59 +632,28 @@ components: items: type: string example: https://s3.amasonaws.com/full-image.png - required: false isPremium: type: boolean example: true - required: false housingType: - type: string - enum: - - Apartment - - House - - Room - - Hotel - example: Apartment - required: false + $ref: '#/components/schemas/housingType' roomAmount: type: integer example: 3 - required: false guestAmount: type: integer example: 5 - required: false price: type: number format: float example: 100 - required: false amenities: - type: array - items: - type: string - enum: - - Breakfast - - AirConditioning - - LaptopFriendlyWorkspace - - BabySeat - - Washer - - Towels - - Fridge - example: Fridge - required: false + $ref: '#/components/schemas/amenities' location: - type: object - properties: - latitude: - type: number - format: float - example: 48.85661 - longitude: - type: number - format: float - example: 2.351499 - required: false + $ref: '#/components/schemas/location' + cityId: + type: string + example: 6329c3d6a04ab1061c6425ea offer: type: object From f41dc59d44ce96ed9d68fd4a7c5e3dc8e72fa7aa Mon Sep 17 00:00:00 2001 From: Lena Rashkovan Date: Sun, 29 Oct 2023 18:47:19 +0100 Subject: [PATCH 18/21] feat(spec): describe DELETE /offers/:offerId --- specification/project.spec.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/specification/project.spec.yml b/specification/project.spec.yml index fc28ff1..5e7da68 100644 --- a/specification/project.spec.yml +++ b/specification/project.spec.yml @@ -341,12 +341,30 @@ paths: responses: '204': description: Offer has been successfully removed. + '400': + description: Some of the provided information is not correct. + content: + application/json: + schema: + $ref: '#/components/schemas/validationError' '401': description: User is not authorized to delete offers. + content: + application/json: + schema: + $ref: '#/components/schemas/generalError' '403': description: User is not authorized to delete this offer. + content: + application/json: + schema: + $ref: '#/components/schemas/generalError' '404': description: Offer with the given ID does not exist. + content: + application/json: + schema: + $ref: '#/components/schemas/generalError' /offers/{offerId}/comments: get: From f4643f3ef4b4b6330a1ea6c7612c710ee78c01cc Mon Sep 17 00:00:00 2001 From: Lena Rashkovan Date: Sun, 29 Oct 2023 18:49:43 +0100 Subject: [PATCH 19/21] feat(spec): describe GET /offers/:offerId/comments --- specification/project.spec.yml | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/specification/project.spec.yml b/specification/project.spec.yml index 5e7da68..97c18e6 100644 --- a/specification/project.spec.yml +++ b/specification/project.spec.yml @@ -342,7 +342,7 @@ paths: '204': description: Offer has been successfully removed. '400': - description: Some of the provided information is not correct. + description: offerId is not correct. content: application/json: schema: @@ -389,8 +389,18 @@ paths: type: array items: $ref: '#/components/schemas/comment' + '400': + description: offerId is not correct. + content: + application/json: + schema: + $ref: '#/components/schemas/validationError' '404': description: Offer with the given ID does not exist. + content: + application/json: + schema: + $ref: '#/components/schemas/generalError' /offers/premium: get: @@ -801,13 +811,13 @@ components: text: type: string example: Nice property! + rating: + type: integer + example: 4 postDate: type: string format: date-time example: 2023-10-11T13:15:56.868Z - rating: - type: integer - example: 4 author: $ref: '#/components/schemas/user' From ca5acc2a1dced7343001098cc1f10b6b3de33b6a Mon Sep 17 00:00:00 2001 From: Lena Rashkovan Date: Sun, 29 Oct 2023 18:53:16 +0100 Subject: [PATCH 20/21] feat(spec): describe POST /comments --- specification/project.spec.yml | 69 +++++++++++++++++----------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/specification/project.spec.yml b/specification/project.spec.yml index 97c18e6..1a44a16 100644 --- a/specification/project.spec.yml +++ b/specification/project.spec.yml @@ -402,35 +402,11 @@ paths: schema: $ref: '#/components/schemas/generalError' - /offers/premium: - get: - tags: - - offers - summary: List of premium offers - description: Returns a list of premium offers for a given city. - parameters: - - in: query - name: city - schema: - type: string - required: true - description: The city to get the premium offers for. - example: Paris - responses: - '200': - description: List of premium offers. - content: - application/json: - schema: - type: array - maxItems: 3 - items: - $ref: '#/components/schemas/offerPreview' - /comments: post: tags: - comments + - offers summary: Comment creation description: Adds a comments to a given offer. requestBody: @@ -452,13 +428,44 @@ paths: content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/validationError' + $ref: '#/components/schemas/validationError' '401': description: User is not authorized to add comments. + content: + application/json: + schema: + $ref: '#/components/schemas/generalError' '404': description: Offer with the given ID does not exist. + content: + application/json: + schema: + $ref: '#/components/schemas/generalError' + + /offers/premium: + get: + tags: + - offers + summary: List of premium offers + description: Returns a list of premium offers for a given city. + parameters: + - in: query + name: city + schema: + type: string + required: true + description: The city to get the premium offers for. + example: Paris + responses: + '200': + description: List of premium offers. + content: + application/json: + schema: + type: array + maxItems: 3 + items: + $ref: '#/components/schemas/offerPreview' components: schemas: @@ -786,8 +793,6 @@ components: properties: text: type: string - minLength: 5 - maxLength: 1024 required: true rating: type: integer @@ -797,10 +802,6 @@ components: type: string example: 6329c3d6a04ab1061c6425ea required: true - authorId: - type: string - example: 6329c3d6a04ab1061c6425ea - required: true comment: type: object From 0730435651a4b15902e297d0d262fb37a39378e5 Mon Sep 17 00:00:00 2001 From: Lena Rashkovan Date: Sun, 29 Oct 2023 18:57:24 +0100 Subject: [PATCH 21/21] feat(spec): describe GET /cities/:cityId/premium --- specification/project.spec.yml | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/specification/project.spec.yml b/specification/project.spec.yml index 1a44a16..8c04734 100644 --- a/specification/project.spec.yml +++ b/specification/project.spec.yml @@ -442,20 +442,20 @@ paths: schema: $ref: '#/components/schemas/generalError' - /offers/premium: + /cities/:cityId/premium: get: tags: + - cities - offers summary: List of premium offers description: Returns a list of premium offers for a given city. parameters: - - in: query - name: city + - in: path + name: cityId schema: type: string required: true description: The city to get the premium offers for. - example: Paris responses: '200': description: List of premium offers. @@ -463,9 +463,20 @@ paths: application/json: schema: type: array - maxItems: 3 items: $ref: '#/components/schemas/offerPreview' + '400': + description: cityId is not correct. + content: + application/json: + schema: + $ref: '#/components/schemas/validationError' + '404': + description: City with the given ID does not exist. + content: + application/json: + schema: + $ref: '#/components/schemas/generalError' components: schemas: