diff --git a/src/cli/cli-application.ts b/src/cli/cli-application.ts index 1dccb3c..f5313e7 100644 --- a/src/cli/cli-application.ts +++ b/src/cli/cli-application.ts @@ -1,5 +1,5 @@ import { parseArgv } from './utils/parser.js'; -import { ConsoleLogger, Logger } from '../shared/libs/logger/index.js'; +import { ConsoleLogger, Logger } from '../shared/libs/index.js'; import { Command } from './index.js'; export type CommandInfo = { name: string; description: string; params?: string[] }; diff --git a/src/cli/commands/command.interface.ts b/src/cli/commands/command.interface.ts index 00266bc..165ab82 100644 --- a/src/cli/commands/command.interface.ts +++ b/src/cli/commands/command.interface.ts @@ -1,4 +1,4 @@ -import { CommandInfo } from '../../cli/index.js'; +import { CommandInfo } from '../index.js'; export interface Command { /** @example --help */ diff --git a/src/cli/commands/help.command.ts b/src/cli/commands/help.command.ts index 313f297..6b4be55 100644 --- a/src/cli/commands/help.command.ts +++ b/src/cli/commands/help.command.ts @@ -1,5 +1,5 @@ import { Command, CommandInfo } from '../../cli/index.js'; -import { ConsoleLogger, Logger } from '../../shared/libs/logger/index.js'; +import { ConsoleLogger, Logger } from '../../shared/libs/index.js'; export class HelpCommand implements Command { readonly name = '--help'; diff --git a/src/cli/commands/import.command.ts b/src/cli/commands/import.command.ts index 23b183a..dd10552 100644 --- a/src/cli/commands/import.command.ts +++ b/src/cli/commands/import.command.ts @@ -5,8 +5,8 @@ import { declination, getFileName } from '../../shared/helpers/index.js'; import { DefaultOfferService, OfferModel, OfferService } from '../../shared/modules/offer/index.js'; import { DefaultUserService, UserModel, UserService } from '../../shared/modules/user/index.js'; -import { DatabaseClient, MongoDatabaseClient } from '../../shared/libs/database-client/index.js'; -import { ConsoleLogger, Logger } from '../../shared/libs/logger/index.js'; +import { DatabaseClient, MongoDatabaseClient } from '../../shared/libs/index.js'; +import { ConsoleLogger, Logger } from '../../shared/libs/index.js'; import { TSVOfferFileReader } from '../../shared/libs/index.js'; import { EventName } from '../../constants/index.js'; import { Offer } from '../../shared/types/index.js'; diff --git a/src/cli/commands/index.ts b/src/cli/commands/index.ts index f29ec4b..e484118 100644 --- a/src/cli/commands/index.ts +++ b/src/cli/commands/index.ts @@ -1,6 +1,6 @@ -export * from './command.interface.js'; +export { Command } from './command.interface.js'; -export * from './help.command.js'; -export * from './version.command.js'; -export * from './import.command.js'; -export * from './generate.command.js'; +export { HelpCommand } from './help.command.js'; +export { VersionCommand } from './version.command.js'; +export { ImportCommand } from './import.command.js'; +export { GenerateCommand } from './generate.command.js'; diff --git a/src/cli/commands/version.command.ts b/src/cli/commands/version.command.ts index 281e13b..b255b41 100644 --- a/src/cli/commands/version.command.ts +++ b/src/cli/commands/version.command.ts @@ -1,5 +1,5 @@ import { readFileSync } from 'node:fs'; -import { ConsoleLogger, Logger } from '../../shared/libs/logger/index.js'; +import { ConsoleLogger, Logger } from '../../shared/libs/index.js'; import { Command } from '../../cli/index.js'; export class VersionCommand implements Command { diff --git a/src/cli/index.ts b/src/cli/index.ts index cb57a21..6d428c5 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -1,4 +1,9 @@ -export * from './cli-application.js'; - -export * from './utils/index.js'; -export * from './commands/index.js'; +export { CommandInfo, CliApplication } from './cli-application.js'; +export { parseArgv } from './utils/index.js'; +export { + Command, + HelpCommand, + ImportCommand, + VersionCommand, + GenerateCommand, +} from './commands/index.js'; diff --git a/src/cli/utils/index.ts b/src/cli/utils/index.ts index 09040c9..c25a63c 100644 --- a/src/cli/utils/index.ts +++ b/src/cli/utils/index.ts @@ -1 +1 @@ -export * from './parser.js'; +export { parseArgv } from './parser.js'; diff --git a/src/constants/index.ts b/src/constants/index.ts index 76bc982..892a301 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -1,2 +1,2 @@ export * from './common.js'; -export * from './city.js'; +export { coordinatesCityMap } from './city.js'; diff --git a/src/rest/index.ts b/src/rest/index.ts index 5829d8c..5e51a1d 100644 --- a/src/rest/index.ts +++ b/src/rest/index.ts @@ -1 +1 @@ -export * from './rest.application.js'; +export { RestApplication } from './rest.application.js'; diff --git a/src/rest/rest.application.ts b/src/rest/rest.application.ts index 19c638a..802fce3 100644 --- a/src/rest/rest.application.ts +++ b/src/rest/rest.application.ts @@ -1,10 +1,11 @@ import { inject, injectable } from 'inversify'; import express, { Express } from 'express'; -import { Controller, ExceptionFilter, ParseTokenMiddleware } from '../shared/libs/rest/index.js'; -import { DatabaseClient } from '../shared/libs/database-client/index.js'; -import { Config, RestSchema } from '../shared/libs/config/index.js'; -import { Logger } from '../shared/libs/logger/index.js'; + +import { Logger } from '../shared/libs/index.js'; import { Component } from '../shared/types/index.js'; +import { DatabaseClient } from '../shared/libs/index.js'; +import { Config, RestSchema } from '../shared/libs/index.js'; +import { Controller, ExceptionFilter, ParseTokenMiddleware } from '../shared/libs/index.js'; @injectable() export class RestApplication { @@ -13,12 +14,18 @@ export class RestApplication { constructor( @inject(Component.Logger) private readonly logger: Logger, @inject(Component.Config) private readonly config: Config, - @inject(Component.DatabaseClient) private readonly databaseClient: DatabaseClient, - @inject(Component.ExceptionFilter) private readonly appExceptionFilter: ExceptionFilter, - @inject(Component.UserController) private readonly userController: Controller, - @inject(Component.OfferController) private readonly offerController: Controller, - @inject(Component.CommentController) private readonly commentController: Controller, - @inject(Component.AuthExceptionFilter) private readonly authExceptionFilter: ExceptionFilter + @inject(Component.DatabaseClient) + private readonly databaseClient: DatabaseClient, + @inject(Component.ExceptionFilter) + private readonly appExceptionFilter: ExceptionFilter, + @inject(Component.UserController) + private readonly userController: Controller, + @inject(Component.OfferController) + private readonly offerController: Controller, + @inject(Component.CommentController) + private readonly commentController: Controller, + @inject(Component.AuthExceptionFilter) + private readonly authExceptionFilter: ExceptionFilter ) { this.server = express(); } @@ -31,48 +38,50 @@ export class RestApplication { } private initServer() { - this.logger.info('Инициализация сервера…'); + this.logger.info('Try to init server…'); const port = this.config.get('PORT'); this.server.listen(port); - this.logger.info(`🚀 Сервер запущен: http://localhost:${port}`); + this.logger.info(`🚀 Server started on http://localhost:${port}`); } private initControllers() { - this.logger.info('Инициализация контроллеров'); + this.logger.info('Init controllers'); this.server.use('/users', this.userController.router); this.server.use('/offers', this.offerController.router); this.server.use('/comments', this.commentController.router); - // this.server.use('/category', this.categoryController.router); - this.logger.info('Инициализация контроллеров завершена'); + this.logger.info('Controller initialization completed'); } private initMiddleware() { - this.logger.info('Инициализация middleware-ов'); + this.logger.info('Init app-level middleware'); + const authenticateMiddleware = new ParseTokenMiddleware(this.config.get('JWT_SECRET')); this.server.use(express.json()); this.server.use('/upload', express.static(this.config.get('UPLOAD_DIRECTORY'))); this.server.use(authenticateMiddleware.execute.bind(authenticateMiddleware)); - this.logger.info('Инициализация middleware-ов завершена'); + this.logger.info('App-level middleware initialization completed'); } private initExceptionFilters() { - this.logger.info('Инициализация фильтров исключений'); + this.logger.info('Init exception filters'); this.server.use(this.authExceptionFilter.catch.bind(this.authExceptionFilter)); this.server.use(this.appExceptionFilter.catch.bind(this.appExceptionFilter)); - this.logger.info('Инициализация фильтров исключений завершена'); + this.logger.info('Exception filters initialization compleated'); } public async init() { - this.logger.info('Инициализация приложения'); - this.logger.info(`Получить значение $PORT из переменной окружения: ${this.config.get('PORT')}`); + this.logger.info('Application initialization'); + this.logger.info(`Get value from env $PORT: ${this.config.get('PORT')}`); await this.initDb(); this.initMiddleware(); + this.initControllers(); + this.initExceptionFilters(); this.initServer(); diff --git a/src/rest/rest.container.ts b/src/rest/rest.container.ts index 7a3950f..5fe904a 100644 --- a/src/rest/rest.container.ts +++ b/src/rest/rest.container.ts @@ -1,10 +1,10 @@ import { Container } from 'inversify'; -import { DatabaseClient, MongoDatabaseClient } from '../shared/libs/database-client/index.js'; -import { AppExceptionFilter, ExceptionFilter } from '../shared/libs/rest/index.js'; -import { Config, RestConfig, RestSchema } from '../shared/libs/config/index.js'; -import { Logger, PinoLogger } from '../shared/libs/logger/index.js'; -import { RestApplication } from './rest.application.js'; import { Component } from '../shared/types/index.js'; +import { RestApplication } from './rest.application.js'; +import { Logger, PinoLogger } from '../shared/libs/index.js'; +import { Config, RestConfig, RestSchema } from '../shared/libs/index.js'; +import { DatabaseClient, MongoDatabaseClient } from '../shared/libs/index.js'; +import { AppExceptionFilter, ExceptionFilter } from '../shared/libs/index.js'; export function createRestApplicationContainer() { const restApplicationContainer = new Container(); diff --git a/src/shared/helpers/index.ts b/src/shared/helpers/index.ts index 1916d66..5eb41ea 100644 --- a/src/shared/helpers/index.ts +++ b/src/shared/helpers/index.ts @@ -1,3 +1,3 @@ export * from './common.js'; -export * from './file-system.js'; -export * from './hash.js'; +export { getCurrentModuleDirectoryPath, getFileName } from './file-system.js'; +export { createSHA256 } from './hash.js'; diff --git a/src/shared/libs/config/index.ts b/src/shared/libs/config/index.ts index 200ec95..eb41d89 100644 --- a/src/shared/libs/config/index.ts +++ b/src/shared/libs/config/index.ts @@ -1,3 +1,3 @@ -export * from './config.interface.js'; -export * from './rest.config.js'; -export * from './rest.schema.js'; +export { Config } from './config.interface.js'; +export { RestConfig } from './rest.config.js'; +export { RestSchema } from './rest.schema.js'; diff --git a/src/shared/libs/config/rest.config.ts b/src/shared/libs/config/rest.config.ts index 1fc944e..6effa61 100644 --- a/src/shared/libs/config/rest.config.ts +++ b/src/shared/libs/config/rest.config.ts @@ -1,10 +1,9 @@ import { config } from 'dotenv'; -import { inject, injectable } from 'inversify'; - +import { Logger } from '../logger/index.js'; +import { Config } from './config.interface.js'; import { configRestSchema, RestSchema } from './rest.schema.js'; +import { inject, injectable } from 'inversify'; import { Component } from '../../types/index.js'; -import { Config } from './config.interface.js'; -import { Logger } from '../logger/index.js'; @injectable() export class RestConfig implements Config { @@ -14,14 +13,15 @@ export class RestConfig implements Config { const parsedOutput = config(); if (parsedOutput.error) { - throw new Error('Файл «.env» — не найден.'); + throw new Error("Can't read .env file. Perhaps the file does not exist."); } configRestSchema.load({}); configRestSchema.validate({ allowed: 'strict', output: this.logger.info }); this.config = configRestSchema.getProperties(); - this.logger.info('Файл «.env» — успешно проанализирован!'); + + this.logger.info('.env file was found and successfully parsed!'); } public get(key: T): RestSchema[T] { diff --git a/src/shared/libs/config/rest.schema.ts b/src/shared/libs/config/rest.schema.ts index 88bc9a4..45d3e3b 100644 --- a/src/shared/libs/config/rest.schema.ts +++ b/src/shared/libs/config/rest.schema.ts @@ -30,7 +30,7 @@ export const configRestSchema = convict({ }, DB_HOST: { doc: 'Host of the database server (MongoDB)', - format: 'ipaddress', + format: String, env: 'DB_HOST', default: '127.0.0.1', }, @@ -43,8 +43,8 @@ export const configRestSchema = convict({ DB_PASS: { doc: 'Password to connect to the database', format: String, - env: 'DB_PASSWORD', - default: '', + env: 'DB_PASS', + default: null, }, DB_PORT: { doc: 'Port to connect to the database', diff --git a/src/shared/libs/database-client/index.ts b/src/shared/libs/database-client/index.ts index e31e958..8961709 100644 --- a/src/shared/libs/database-client/index.ts +++ b/src/shared/libs/database-client/index.ts @@ -1,2 +1,2 @@ -export * from './database-client.interface.js'; -export * from './mongo.database-client.js'; +export { DatabaseClient } from './database-client.interface.js'; +export { MongoDatabaseClient } from './mongo.database-client.js'; diff --git a/src/shared/libs/database-client/mongo.database-client.ts b/src/shared/libs/database-client/mongo.database-client.ts index ede83a4..14c42f8 100644 --- a/src/shared/libs/database-client/mongo.database-client.ts +++ b/src/shared/libs/database-client/mongo.database-client.ts @@ -11,47 +11,41 @@ const RETRY_TIMEOUT = 1000; @injectable() export class MongoDatabaseClient implements DatabaseClient { private mongoose: typeof Mongoose; - private isConnectedToDatabase = false; + private isConnected = false; constructor(@inject(Component.Logger) private readonly logger: Logger) {} - public isConnected() { - return this.isConnectedToDatabase; - } - public async connect(uri: string): Promise { - if (this.isConnectedToDatabase) { - this.logger.warn('MongoDB клиент подключен'); + if (this.isConnected) { return; } - this.logger.info('Подключение к MongoDB…'); + this.logger.info('Trying to connect to MongoDB…'); let attempt = 0; while (attempt < RETRY_COUNT) { try { this.mongoose = await Mongoose.connect(uri); - this.isConnectedToDatabase = true; - this.logger.info('Соединение с базой данных установлено'); + this.isConnected = true; + this.logger.info('Database connection established'); return; } catch (error) { attempt++; - this.logger.error(error, `Не удалось подключиться к базе данных (Попытка ${attempt})`); + this.logger.error(`Failed to connect to the database. Attempt ${attempt}`, error as Error); await setTimeout(RETRY_TIMEOUT); } } - throw new Error(`Невозможно установить соединение с базой данных (${RETRY_COUNT} попыток)`); + throw new Error(`Unable to establish database connection after ${RETRY_COUNT} attempts`); } public async disconnect(): Promise { - if (!this.isConnectedToDatabase) { - this.logger.warn('MongoDB клиент не подключен'); + if (!this.isConnected) { return; } - await this.mongoose.disconnect(); - this.isConnectedToDatabase = false; - this.logger.info('Соединение с базой данных закрыто'); + await this.mongoose.disconnect?.(); + this.isConnected = false; + this.logger.info('Database connection closed.'); } } diff --git a/src/shared/libs/file-reader/index.ts b/src/shared/libs/file-reader/index.ts index 81e1095..bdec587 100644 --- a/src/shared/libs/file-reader/index.ts +++ b/src/shared/libs/file-reader/index.ts @@ -1,2 +1,2 @@ -export * from './file-reader.interface.js'; -export * from './tsv-offer-file-reader.js'; +export { FileReader } from './file-reader.interface.js'; +export { TSVOfferFileReader } from './tsv-offer-file-reader.js'; diff --git a/src/shared/libs/file-writer/index.ts b/src/shared/libs/file-writer/index.ts index 2ec20f9..d698227 100644 --- a/src/shared/libs/file-writer/index.ts +++ b/src/shared/libs/file-writer/index.ts @@ -1,2 +1,2 @@ -export * from './file-writer.interface.js'; -export * from './tsv-file-writer.js'; +export { FileWriter } from './file-writer.interface.js'; +export { TSVFileWriter } from './tsv-file-writer.js'; diff --git a/src/shared/libs/index.ts b/src/shared/libs/index.ts index 6d8d21a..4ab3d43 100644 --- a/src/shared/libs/index.ts +++ b/src/shared/libs/index.ts @@ -1,3 +1,26 @@ -export * from './file-reader/index.js'; -export * from './file-writer/index.js'; -export * from './offer-generator/index.js'; +export { DatabaseClient, MongoDatabaseClient } from './database-client/index.js'; +export { OfferGenerator, TSVOfferGenerator } from './offer-generator/index.js'; +export { FileReader, TSVOfferFileReader } from './file-reader/index.js'; +export { ConsoleLogger, Logger, PinoLogger } from './logger/index.js'; +export { RestSchema, RestConfig, Config } from './config/index.js'; +export { TSVFileWriter, FileWriter } from './file-writer/index.js'; + +export { + ValidateCityQueryMiddleware, + ValidateObjectIdMiddleware, + DocumentExistsMiddleware, + PrivateRouteMiddleware, + ValidateDtoMiddleware, + UploadFileMiddleware, + ParseTokenMiddleware, + AppExceptionFilter, + ExceptionFilter, + BaseController, + RequestParams, + RequestBody, + Controller, + Middleware, + HttpMethod, + HttpError, + Route, +} from './rest/index.js'; diff --git a/src/shared/libs/logger/console-logger.ts b/src/shared/libs/logger/console.logger.ts similarity index 100% rename from src/shared/libs/logger/console-logger.ts rename to src/shared/libs/logger/console.logger.ts diff --git a/src/shared/libs/logger/index.ts b/src/shared/libs/logger/index.ts index 2feb5ac..30c4933 100644 --- a/src/shared/libs/logger/index.ts +++ b/src/shared/libs/logger/index.ts @@ -1,3 +1,3 @@ -export * from './logger.interface.js'; -export * from './console-logger.js'; -export * from './pino.logger.js'; +export { Logger } from './logger.interface.js'; +export { PinoLogger } from './pino.logger.js'; +export { ConsoleLogger } from './console.logger.js'; diff --git a/src/shared/libs/offer-generator/index.ts b/src/shared/libs/offer-generator/index.ts index 659a07f..133232a 100644 --- a/src/shared/libs/offer-generator/index.ts +++ b/src/shared/libs/offer-generator/index.ts @@ -1,2 +1,2 @@ -export * from './offer-generator.interface.js'; -export * from './tsv-offer-generator.js'; +export { OfferGenerator } from './offer-generator.interface.js'; +export { TSVOfferGenerator } from './tsv-offer-generator.js'; diff --git a/src/shared/libs/rest/controller/base-controller.abstract.ts b/src/shared/libs/rest/controller/base-controller.abstract.ts index e9d9e8e..46624cd 100644 --- a/src/shared/libs/rest/controller/base-controller.abstract.ts +++ b/src/shared/libs/rest/controller/base-controller.abstract.ts @@ -1,11 +1,12 @@ import { Response, Router } from 'express'; import { injectable } from 'inversify'; -import asyncHandler from 'express-async-handler'; import { StatusCodes } from 'http-status-codes'; +import asyncHandler from 'express-async-handler'; import { Controller } from './controller.interface.js'; -import { HttpMethod, Route } from '../types/index.js'; +import { HttpMethod } from '../types/index.js'; import { Logger } from '../../logger/index.js'; +import { Route } from '../types/index.js'; @injectable() export abstract class BaseController implements Controller { @@ -38,11 +39,11 @@ export abstract class BaseController implements Controller { this._router[route.method](route.path, allHandlers); - this.logger.info(`Маршрут зарегистрирован: ${route.method.toUpperCase()} ${route.path}`); + this.logger.info(`Route registered: ${route.method.toUpperCase()} ${route.path}`); } - public send(res: Response, statusCode: number, data: T) { - res.type(this.DEFAULT_CONTENT_TYPE).status(statusCode).json(data); + public send(response: Response, statusCode: number, data: T) { + response.type(this.DEFAULT_CONTENT_TYPE).status(statusCode).json(data); } public created(response: Response, data: T): void { diff --git a/src/shared/libs/rest/controller/index.ts b/src/shared/libs/rest/controller/index.ts index b70d598..8a3314d 100644 --- a/src/shared/libs/rest/controller/index.ts +++ b/src/shared/libs/rest/controller/index.ts @@ -1,2 +1,2 @@ -export * from './base-controller.abstract.js'; -export * from './controller.interface.js'; +export { BaseController } from './base-controller.abstract.js'; +export { Controller } from './controller.interface.js'; diff --git a/src/shared/libs/rest/errors/index.ts b/src/shared/libs/rest/errors/index.ts index 0c80068..9d68c51 100644 --- a/src/shared/libs/rest/errors/index.ts +++ b/src/shared/libs/rest/errors/index.ts @@ -1 +1 @@ -export * from './http-error.js'; +export { HttpError } from './http-error.js'; diff --git a/src/shared/libs/rest/exception-filter/app-exception-filter.ts b/src/shared/libs/rest/exception-filter/app-exception-filter.ts index 6bc99b0..b4726dd 100644 --- a/src/shared/libs/rest/exception-filter/app-exception-filter.ts +++ b/src/shared/libs/rest/exception-filter/app-exception-filter.ts @@ -1,4 +1,4 @@ -import { NextFunction, Request, Response } from 'express'; +import { Request, Response, NextFunction } from 'express'; import { inject, injectable } from 'inversify'; import { ExceptionFilter } from './exception-filter.interface.js'; diff --git a/src/shared/libs/rest/exception-filter/index.ts b/src/shared/libs/rest/exception-filter/index.ts index 68a3d40..920984c 100644 --- a/src/shared/libs/rest/exception-filter/index.ts +++ b/src/shared/libs/rest/exception-filter/index.ts @@ -1,2 +1,2 @@ -export * from './exception-filter.interface.js'; -export * from './app-exception-filter.js'; +export { ExceptionFilter } from './exception-filter.interface.js'; +export { AppExceptionFilter } from './app-exception-filter.js'; diff --git a/src/shared/libs/rest/index.ts b/src/shared/libs/rest/index.ts index ca86680..963732b 100644 --- a/src/shared/libs/rest/index.ts +++ b/src/shared/libs/rest/index.ts @@ -1,5 +1,16 @@ -export * from './types/index.js'; -export * from './errors/index.js'; -export * from './controller/index.js'; -export * from './middleware/index.js'; -export * from './exception-filter/index.js'; +export { ValidateCityQueryMiddleware } from './middleware/validate-city-query.middlware.js'; +export { ValidateObjectIdMiddleware } from './middleware/validate-objectid.middleware.js'; +export { DocumentExistsMiddleware } from './middleware/document-exists.middleware.js'; +export { ExceptionFilter } from './exception-filter/exception-filter.interface.js'; +export { PrivateRouteMiddleware } from './middleware/private-route.middleware.js'; +export { AppExceptionFilter } from './exception-filter/app-exception-filter.js'; +export { ValidateDtoMiddleware } from './middleware/validate-dto.middleware.js'; +export { UploadFileMiddleware } from './middleware/upload-file.middleware.js'; +export { ParseTokenMiddleware } from './middleware/parse-token.middleware.js'; +export { BaseController } from './controller/base-controller.abstract.js'; +export { RequestBody, RequestParams } from './types/request.type.js'; +export { Controller } from './controller/controller.interface.js'; +export { Middleware } from './middleware/middleware.interface.js'; +export { HttpMethod } from './types/http-method.enum.js'; +export { Route } from './types/route.interface.js'; +export { HttpError } from './errors/index.js'; diff --git a/src/shared/libs/rest/middleware/document-exists.middleware.ts b/src/shared/libs/rest/middleware/document-exists.middleware.ts index 89ee3ae..303e580 100644 --- a/src/shared/libs/rest/middleware/document-exists.middleware.ts +++ b/src/shared/libs/rest/middleware/document-exists.middleware.ts @@ -1,8 +1,8 @@ import { NextFunction, Request, Response } from 'express'; import { StatusCodes } from 'http-status-codes'; -import { DocumentExists } from '../../../types/index.js'; import { Middleware } from './middleware.interface.js'; +import { DocumentExists } from '../../../types/index.js'; import { HttpError } from '../errors/index.js'; export class DocumentExistsMiddleware implements Middleware { @@ -12,18 +12,14 @@ export class DocumentExistsMiddleware implements Middleware { private readonly paramName: string ) {} - public async execute( - { params }: Request, - _response: Response, - next: NextFunction - ): Promise { + public async execute({ params }: Request, _response: Response, next: NextFunction): Promise { const documentId = params[this.paramName]; const exists = await this.service.exists(documentId); if (!exists) { throw new HttpError( StatusCodes.NOT_FOUND, - `${this.entityName} №${documentId} не найден.`, + `${this.entityName} with ${documentId} not found.`, 'DocumentExistsMiddleware' ); } diff --git a/src/shared/libs/rest/middleware/index.ts b/src/shared/libs/rest/middleware/index.ts index ddf731a..cf2d101 100644 --- a/src/shared/libs/rest/middleware/index.ts +++ b/src/shared/libs/rest/middleware/index.ts @@ -1,9 +1,9 @@ -export * from './middleware.interface.js'; -export * from './validate-dto.middleware.js'; -export * from './validate-objectid.middleware.js'; -export * from './document-exists.middleware.js'; -export * from './upload-file.middleware.js'; -export * from './parse-token.middleware.js'; -export * from './private-route.middleware.js'; -export * from './own-offer.middleware.js'; -export * from './validate-city-query.middlware.js'; +export { Middleware } from './middleware.interface.js'; +export { ValidateDtoMiddleware } from './validate-dto.middleware.js'; +export { ValidateObjectIdMiddleware } from './validate-objectid.middleware.js'; +export { DocumentExistsMiddleware } from './document-exists.middleware.js'; +export { UploadFileMiddleware } from './upload-file.middleware.js'; +export { ParseTokenMiddleware } from './parse-token.middleware.js'; +export { PrivateRouteMiddleware } from './private-route.middleware.js'; +export { OwnOfferMiddleware } from './own-offer.middleware.js'; +export { ValidateCityQueryMiddleware } from './validate-city-query.middlware.js'; diff --git a/src/shared/libs/rest/middleware/own-offer.middleware.ts b/src/shared/libs/rest/middleware/own-offer.middleware.ts index a445a90..bf90ed9 100644 --- a/src/shared/libs/rest/middleware/own-offer.middleware.ts +++ b/src/shared/libs/rest/middleware/own-offer.middleware.ts @@ -1,10 +1,9 @@ import { NextFunction, Request, Response } from 'express'; -import { DocumentType } from '@typegoose/typegoose'; -import { StatusCodes } from 'http-status-codes'; - -import { OfferEntity, OfferService } from '../../../modules/offer/index.js'; import { Middleware } from './middleware.interface.js'; import { HttpError } from '../errors/index.js'; +import { StatusCodes } from 'http-status-codes'; +import { OfferEntity, OfferService } from '../../../modules/offer/index.js'; +import { DocumentType } from '@typegoose/typegoose'; export class OwnOfferMiddleware implements Middleware { constructor(private readonly offerService: OfferService) {} @@ -17,7 +16,7 @@ export class OwnOfferMiddleware implements Middleware { const offer = (await this.offerService.findById(params.offerId)) as DocumentType; if (!(offer.author._id.toString() === tokenPayload.id)) { - throw new HttpError(StatusCodes.UNAUTHORIZED, 'Нет доступа', 'OfferController'); + throw new HttpError(StatusCodes.UNAUTHORIZED, 'Unauthorized', 'OfferController'); } return next(); diff --git a/src/shared/libs/rest/middleware/parse-token.middleware.ts b/src/shared/libs/rest/middleware/parse-token.middleware.ts index 276d8d3..bcfc342 100644 --- a/src/shared/libs/rest/middleware/parse-token.middleware.ts +++ b/src/shared/libs/rest/middleware/parse-token.middleware.ts @@ -1,8 +1,8 @@ import { NextFunction, Request, Response } from 'express'; import { jwtVerify } from 'jose'; import { StatusCodes } from 'http-status-codes'; + import { createSecretKey } from 'node:crypto'; -import { ENCODING } from '../../../../constants/index.js'; import { Middleware } from './middleware.interface.js'; import { HttpError } from '../errors/index.js'; @@ -33,17 +33,17 @@ export class ParseTokenMiddleware implements Middleware { const [, token] = authorizationHeader; try { - const { payload } = await jwtVerify(token, createSecretKey(this.jwtSecret, ENCODING)); + const { payload } = await jwtVerify(token, createSecretKey(this.jwtSecret, 'utf-8')); if (!isTokenPayload(payload)) { - throw new Error('Не корректный токен'); + throw new Error('Bad token'); } request.tokenPayload = { ...payload }; return next(); } catch { return next( - new HttpError(StatusCodes.UNAUTHORIZED, 'Неверный токен', 'AuthenticateMiddleware') + new HttpError(StatusCodes.UNAUTHORIZED, 'Invalid token', 'AuthenticateMiddleware') ); } } diff --git a/src/shared/libs/rest/middleware/upload-file.middleware.ts b/src/shared/libs/rest/middleware/upload-file.middleware.ts index e298cdb..da7ac67 100644 --- a/src/shared/libs/rest/middleware/upload-file.middleware.ts +++ b/src/shared/libs/rest/middleware/upload-file.middleware.ts @@ -1,6 +1,7 @@ import { NextFunction, Request, Response } from 'express'; import multer, { diskStorage } from 'multer'; import { extension } from 'mime-types'; + import { randomUUID } from 'node:crypto'; import { Middleware } from './middleware.interface.js'; diff --git a/src/shared/libs/rest/middleware/validate-city-query.middlware.ts b/src/shared/libs/rest/middleware/validate-city-query.middlware.ts index 58a43c1..8ec50ee 100644 --- a/src/shared/libs/rest/middleware/validate-city-query.middlware.ts +++ b/src/shared/libs/rest/middleware/validate-city-query.middlware.ts @@ -1,7 +1,7 @@ import { NextFunction, Request, Response } from 'express'; -import { StatusCodes } from 'http-status-codes'; import { Middleware } from './middleware.interface.js'; import { HttpError } from '../errors/index.js'; +import { StatusCodes } from 'http-status-codes'; import { City } from '../../../types/index.js'; export class ValidateCityQueryMiddleware implements Middleware { @@ -13,7 +13,7 @@ export class ValidateCityQueryMiddleware implements Middleware { if (!Object.values(City).includes(city as City)) { throw new HttpError( StatusCodes.BAD_REQUEST, - `Город ${params.city} не поддерживается`, + `The city ${params.city} is not supported`, 'OfferController' ); } diff --git a/src/shared/libs/rest/middleware/validate-dto.middleware.ts b/src/shared/libs/rest/middleware/validate-dto.middleware.ts index 826535b..fbb0576 100644 --- a/src/shared/libs/rest/middleware/validate-dto.middleware.ts +++ b/src/shared/libs/rest/middleware/validate-dto.middleware.ts @@ -12,10 +12,10 @@ export class ValidateDtoMiddleware implements Middleware { ) {} public async execute(request: Request, response: Response, next: NextFunction): Promise { - const dtoInstance = plainToInstance(this.dto, request[this.type], { + const plain = request[this.type]; + const dtoInstance = plainToInstance(this.dto, plain, { excludeExtraneousValues: true, }); - const errors = await validate(dtoInstance); if (errors.length > 0) { diff --git a/src/shared/libs/rest/middleware/validate-objectid.middleware.ts b/src/shared/libs/rest/middleware/validate-objectid.middleware.ts index 99bf207..2425978 100644 --- a/src/shared/libs/rest/middleware/validate-objectid.middleware.ts +++ b/src/shared/libs/rest/middleware/validate-objectid.middleware.ts @@ -1,9 +1,8 @@ -import { Types } from 'mongoose'; -import { StatusCodes } from 'http-status-codes'; import { NextFunction, Request, Response } from 'express'; - import { Middleware } from './middleware.interface.js'; +import { Types } from 'mongoose'; import { HttpError } from '../errors/index.js'; +import { StatusCodes } from 'http-status-codes'; export class ValidateObjectIdMiddleware implements Middleware { constructor(private param: string) {} @@ -14,7 +13,7 @@ export class ValidateObjectIdMiddleware implements Middleware { if (!Types.ObjectId.isValid(objectId)) { throw new HttpError( StatusCodes.BAD_REQUEST, - `${objectId} недействительный идентификатор`, + `${objectId} is invalid ObjectID`, 'ValidateObjectIdMiddleware' ); } diff --git a/src/shared/libs/rest/types/index.ts b/src/shared/libs/rest/types/index.ts index e766aa2..2cab710 100644 --- a/src/shared/libs/rest/types/index.ts +++ b/src/shared/libs/rest/types/index.ts @@ -1,3 +1,3 @@ -export * from './request.type.js'; -export * from './http-method.enum.js'; -export * from './route.interface.js'; +export { RequestBody, RequestParams } from './request.type.js'; +export { HttpMethod } from './http-method.enum.js'; +export { Route } from './route.interface.js'; diff --git a/src/shared/modules/auth/auth.constant.ts b/src/shared/modules/auth/auth.constant.ts new file mode 100644 index 0000000..269747d --- /dev/null +++ b/src/shared/modules/auth/auth.constant.ts @@ -0,0 +1,2 @@ +export const JWT_ALGORITHM = 'HS256'; +export const JWT_EXPIRED = '2d'; diff --git a/src/shared/modules/auth/auth.container.ts b/src/shared/modules/auth/auth.container.ts index 4195d13..b0cbcfb 100644 --- a/src/shared/modules/auth/auth.container.ts +++ b/src/shared/modules/auth/auth.container.ts @@ -1,10 +1,10 @@ import { Container } from 'inversify'; -import { AuthExceptionFilter } from './auth.exception-filter.js'; -import { DefaultAuthService } from './default-auth.service.js'; -import { ExceptionFilter } from '../../libs/rest/index.js'; import { AuthService } from './auth-service.interface.js'; import { Component } from '../../types/index.js'; +import { DefaultAuthService } from './default-auth.service.js'; +import { ExceptionFilter } from '../../libs/index.js'; +import { AuthExceptionFilter } from './auth.exception-filter.js'; export function createAuthContainer() { const authContainer = new Container(); diff --git a/src/shared/modules/auth/auth.exception-filter.ts b/src/shared/modules/auth/auth.exception-filter.ts index 158891f..058f4af 100644 --- a/src/shared/modules/auth/auth.exception-filter.ts +++ b/src/shared/modules/auth/auth.exception-filter.ts @@ -1,10 +1,9 @@ -import { NextFunction, Request, Response } from 'express'; import { inject, injectable } from 'inversify'; - import { ExceptionFilter } from '../../libs/rest/index.js'; -import { BaseUserException } from './errors/index.js'; -import { Logger } from '../../libs/logger/index.js'; import { Component } from '../../types/index.js'; +import { Logger } from '../../libs/logger/index.js'; +import { Request, Response, NextFunction } from 'express'; +import { BaseUserException } from './errors/index.js'; @injectable() export class AuthExceptionFilter implements ExceptionFilter { diff --git a/src/shared/modules/auth/default-auth.service.ts b/src/shared/modules/auth/default-auth.service.ts index 2d1d505..60ccb1e 100644 --- a/src/shared/modules/auth/default-auth.service.ts +++ b/src/shared/modules/auth/default-auth.service.ts @@ -1,18 +1,14 @@ import { inject, injectable } from 'inversify'; import { createSecretKey } from 'node:crypto'; -import { SignJWT } from 'jose'; - +import { AuthService } from './auth-service.interface.js'; +import { Component } from '../../types/index.js'; +import { Logger } from '../../libs/logger/index.js'; import { LoginUserDto, UserEntity, UserService } from '../user/index.js'; import { Config, RestSchema } from '../../libs/config/index.js'; +import { TokenPayload } from './types/token-payload.js'; +import { SignJWT } from 'jose'; +import { JWT_ALGORITHM, JWT_EXPIRED } from './auth.constant.js'; import { AuthIncorrectException } from './errors/index.js'; -import { AuthService } from './auth-service.interface.js'; -import { ENCODING } from '../../../constants/index.js'; -import { Logger } from '../../libs/logger/index.js'; -import { Component } from '../../types/index.js'; -import { TokenPayload } from './types/index.js'; - -export const JWT_ALGORITHM = 'HS256'; -export const JWT_EXPIRED = '2d'; @injectable() export class DefaultAuthService implements AuthService { @@ -24,8 +20,12 @@ export class DefaultAuthService implements AuthService { public async authenticate(user: UserEntity): Promise { const jwtSecret = this.config.get('JWT_SECRET'); - const secretKey = createSecretKey(jwtSecret, ENCODING); - const tokenPayload: TokenPayload = { email: user.email, name: user.name, id: user.id }; + const secretKey = createSecretKey(jwtSecret, 'utf-8'); + const tokenPayload: TokenPayload = { + email: user.email, + name: user.name, + id: user.id, + }; this.logger.info(`Create token for ${user.email}`); return new SignJWT(tokenPayload) @@ -38,12 +38,12 @@ export class DefaultAuthService implements AuthService { public async verify(dto: LoginUserDto): Promise { const user = await this.userService.findByEmail(dto.email); if (!user) { - this.logger.warn(`Пользователь с ${dto.email} не найден`); + this.logger.warn(`User with ${dto.email} not found`); throw new AuthIncorrectException(); } if (!user.verifyPassword(dto.password, this.config.get('SALT'))) { - this.logger.warn(`Неправильный пароль для ${dto.email}`); + this.logger.warn(`Incorrect password for ${dto.email}`); throw new AuthIncorrectException(); } diff --git a/src/shared/modules/auth/errors/auth-incorrect.exception.ts b/src/shared/modules/auth/errors/auth-incorrect.exception.ts index 3f9960e..e7a51b9 100644 --- a/src/shared/modules/auth/errors/auth-incorrect.exception.ts +++ b/src/shared/modules/auth/errors/auth-incorrect.exception.ts @@ -3,6 +3,6 @@ import { BaseUserException } from './base-user.exception.js'; export class AuthIncorrectException extends BaseUserException { constructor() { - super(StatusCodes.UNAUTHORIZED, 'Неправильный логин или пароль пользователя'); + super(StatusCodes.UNAUTHORIZED, 'Incorrect user email or password'); } } diff --git a/src/shared/modules/auth/errors/index.ts b/src/shared/modules/auth/errors/index.ts index a09541f..c413fea 100644 --- a/src/shared/modules/auth/errors/index.ts +++ b/src/shared/modules/auth/errors/index.ts @@ -1,2 +1,2 @@ -export * from './base-user.exception.js'; -export * from './auth-incorrect.exception.js'; +export { BaseUserException } from './base-user.exception.js'; +export { AuthIncorrectException } from './auth-incorrect.exception.js'; diff --git a/src/shared/modules/auth/index.ts b/src/shared/modules/auth/index.ts index 882670c..4596891 100644 --- a/src/shared/modules/auth/index.ts +++ b/src/shared/modules/auth/index.ts @@ -1,4 +1,4 @@ -export * from './auth-service.interface.js'; -export * from './default-auth.service.js'; -export * from './auth.container.js'; -export * from './types/index.js'; +export { AuthService } from './auth-service.interface.js'; +export { TokenPayload } from './types/token-payload.js'; +export { createAuthContainer } from './auth.container.js'; +export { DefaultAuthService } from './default-auth.service.js'; diff --git a/src/shared/modules/auth/types/index.ts b/src/shared/modules/auth/types/index.ts index ebde34d..9985b47 100644 --- a/src/shared/modules/auth/types/index.ts +++ b/src/shared/modules/auth/types/index.ts @@ -1 +1 @@ -export * from './token-payload.js'; +export { TokenPayload } from './token-payload.js'; diff --git a/src/shared/modules/category/category.container.ts b/src/shared/modules/category/category.container.ts index 35703d6..1c72e1c 100644 --- a/src/shared/modules/category/category.container.ts +++ b/src/shared/modules/category/category.container.ts @@ -5,7 +5,7 @@ import { DefaultCategoryService } from './default-category.service.js'; import { CategoryEntity, CategoryModel } from './category.entity.js'; import { CategoryService } from './category-service.interface.js'; import { CategoryController } from './category.controller.js'; -import { Controller } from '../../libs/rest/index.js'; +import { Controller } from '../../libs/index.js'; import { Component } from '../../types/index.js'; export function createCategoryContainer() { diff --git a/src/shared/modules/category/default-category.service.ts b/src/shared/modules/category/default-category.service.ts index d7040c4..9f40400 100644 --- a/src/shared/modules/category/default-category.service.ts +++ b/src/shared/modules/category/default-category.service.ts @@ -3,7 +3,7 @@ import { DocumentType, types } from '@typegoose/typegoose'; import { CategoryService } from './category-service.interface.js'; import { Component } from '../../types/index.js'; -import { Logger } from '../../libs/logger/index.js'; +import { Logger } from '../../libs/index.js'; import { CategoryEntity } from './category.entity.js'; import { CreateCategoryDto } from './dto/create-category.dto.js'; diff --git a/src/shared/modules/category/index.ts b/src/shared/modules/category/index.ts index a1b9d77..929466b 100644 --- a/src/shared/modules/category/index.ts +++ b/src/shared/modules/category/index.ts @@ -1,5 +1,5 @@ -export * from './category.entity.js'; -export * from './dto/create-category.dto.js'; -export * from './category-service.interface.js'; -export * from './default-category.service.js'; -export * from './category.container.js'; +export { CategoryEntity, CategoryModel } from './category.entity.js'; +export { CreateCategoryDto } from './dto/create-category.dto.js'; +export { CategoryService } from './category-service.interface.js'; +export { DefaultCategoryService } from './default-category.service.js'; +export { createCategoryContainer } from './category.container.js'; diff --git a/src/shared/modules/comment/comment.constant.ts b/src/shared/modules/comment/comment.constant.ts new file mode 100644 index 0000000..45239e9 --- /dev/null +++ b/src/shared/modules/comment/comment.constant.ts @@ -0,0 +1 @@ +export const DEFAULT_COMMENT_COUNT = 50; diff --git a/src/shared/modules/comment/comment.container.ts b/src/shared/modules/comment/comment.container.ts index b290ef6..0b09818 100644 --- a/src/shared/modules/comment/comment.container.ts +++ b/src/shared/modules/comment/comment.container.ts @@ -1,12 +1,11 @@ -import { types } from '@typegoose/typegoose'; import { Container } from 'inversify'; - +import { CommentService } from './comment-service.interface.js'; +import { Component } from '../../types/index.js'; import { DefaultCommentService } from './default-comment.service.js'; +import { types } from '@typegoose/typegoose'; import { CommentEntity, CommentModel } from './comment.entity.js'; -import { CommentService } from './comment-service.interface.js'; +import { Controller } from '../../libs/index.js'; import { CommentController } from './comment.controller.js'; -import { Controller } from '../../libs/rest/index.js'; -import { Component } from '../../types/index.js'; export function createCommentContainer() { const commentContainer = new Container(); diff --git a/src/shared/modules/comment/comment.controller.ts b/src/shared/modules/comment/comment.controller.ts index e75698b..fa1ae5e 100644 --- a/src/shared/modules/comment/comment.controller.ts +++ b/src/shared/modules/comment/comment.controller.ts @@ -8,22 +8,23 @@ import { ValidateDtoMiddleware, ValidateObjectIdMiddleware, } from '../../libs/rest/index.js'; -import { fillDTO } from '../../helpers/index.js'; import { Component } from '../../types/index.js'; - -import { CommentService } from './comment-service.interface.js'; -import { CreateCommentDto } from './dto/create-comment.dto.js'; import { Logger } from '../../libs/logger/index.js'; +import { CommentService } from './comment-service.interface.js'; +import { OfferService } from '../offer/offer-service.interface.js'; +import { ParamOfferId } from './type/param-offerid.type.js'; +import { fillDTO } from '../../helpers/index.js'; import { CommentRdo } from './rdo/comment.rdo.js'; -import { OfferService } from '../offer/index.js'; -import { ParamOfferId } from './types/index.js'; +import { CreateCommentDto } from './dto/create-comment.dto.js'; @injectable() export class CommentController extends BaseController { constructor( @inject(Component.Logger) protected readonly logger: Logger, - @inject(Component.CommentService) protected readonly commentService: CommentService, - @inject(Component.OfferService) protected readonly offerService: OfferService + @inject(Component.CommentService) + protected readonly commentService: CommentService, + @inject(Component.OfferService) + protected readonly offerService: OfferService ) { super(logger); @@ -53,15 +54,15 @@ export class CommentController extends BaseController { ]); } - public async getByOfferId({ params }: Request, res: Response) { + public async getByOfferId({ params }: Request, response: Response) { const comments = await this.commentService.findByOfferId(params?.offerId); - this.ok(res, fillDTO(CommentRdo, comments)); + this.ok(response, fillDTO(CommentRdo, comments)); } public async create( { body, params, tokenPayload }: Request, - res: Response + response: Response ) { const result = await this.commentService.create({ ...body, @@ -69,6 +70,6 @@ export class CommentController extends BaseController { offer: params?.offerId, }); - this.created(res, fillDTO(CommentRdo, result)); + this.created(response, fillDTO(CommentRdo, result)); } } diff --git a/src/shared/modules/comment/comment.entity.ts b/src/shared/modules/comment/comment.entity.ts index f81bbb0..7e24479 100644 --- a/src/shared/modules/comment/comment.entity.ts +++ b/src/shared/modules/comment/comment.entity.ts @@ -1,23 +1,29 @@ -import { defaultClasses, getModelForClass, modelOptions, prop } from '@typegoose/typegoose'; -import { Comment } from '../../types/index.js'; +import { defaultClasses, getModelForClass, modelOptions, prop, Ref } from '@typegoose/typegoose'; +import { UserEntity } from '../user/index.js'; +import { OfferEntity } from '../offer/offer.entity.js'; +// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging export interface CommentEntity extends defaultClasses.Base {} @modelOptions({ - schemaOptions: { collection: 'comment', timestamps: true }, + schemaOptions: { + collection: 'comments', + timestamps: true, + }, }) -export class CommentEntity extends defaultClasses.TimeStamps implements Comment { - @prop({ required: true, trim: true }) - public text!: string; +// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging +export class CommentEntity extends defaultClasses.TimeStamps { + @prop({ trim: true, required: true }) + public text: string; @prop({ required: true }) - public publishedAt!: string; + public rating: number; - @prop({ required: true }) - public rating!: number; + @prop({ ref: UserEntity, required: true }) + public author: Ref; - @prop({ required: true }) - public authorId!: string; + @prop({ ref: OfferEntity, required: true }) + public offer: Ref; } export const CommentModel = getModelForClass(CommentEntity); diff --git a/src/shared/modules/comment/default-comment.service.ts b/src/shared/modules/comment/default-comment.service.ts index 984da2f..6eef78f 100644 --- a/src/shared/modules/comment/default-comment.service.ts +++ b/src/shared/modules/comment/default-comment.service.ts @@ -1,17 +1,16 @@ -import { types } from '@typegoose/typegoose'; import { inject, injectable } from 'inversify'; - import { CommentService } from './comment-service.interface.js'; -import { CreateCommentDto } from './dto/create-comment.dto.js'; import { Component, SortType } from '../../types/index.js'; +import { types } from '@typegoose/typegoose'; import { CommentEntity } from './comment.entity.js'; - -const DEFAULT_COMMENT_COUNT = 50; +import { CreateCommentDto } from './dto/create-comment.dto.js'; +import { DEFAULT_COMMENT_COUNT } from './comment.constant.js'; @injectable() export class DefaultCommentService implements CommentService { constructor( - @inject(Component.CommentModel) private readonly commentModel: types.ModelType + @inject(Component.CommentModel) + private readonly commentModel: types.ModelType ) {} public async create(dto: CreateCommentDto): Promise> { diff --git a/src/shared/modules/comment/dto/create-comment.messages.ts b/src/shared/modules/comment/dto/create-comment.messages.ts index 46c90a6..376666d 100644 --- a/src/shared/modules/comment/dto/create-comment.messages.ts +++ b/src/shared/modules/comment/dto/create-comment.messages.ts @@ -1,12 +1,12 @@ export const CreateCommentValidationMessage = { text: { - invalidFormat: 'Текст должен быть строкой', - minLength: 'Минимальная длина текста — 5', - maxLength: 'Максимальная длина текста — 1024', + invalidFormat: 'text must be a string', + minLength: 'Minimum text length must be 5', + maxLength: 'Maximum text length must be 1024', }, rating: { - invalidFormat: 'Рейтинг должен быть целым числом', - minValue: 'Минимальный рейтинг — 1', - maxValue: 'Максимальный рейтинг — 5', + invalidFormat: 'rating must be an integer', + minValue: 'Minimum rating is 1', + maxValue: 'Maximum rating is 5', }, }; diff --git a/src/shared/modules/comment/index.ts b/src/shared/modules/comment/index.ts index ac2a6dd..3a18cae 100644 --- a/src/shared/modules/comment/index.ts +++ b/src/shared/modules/comment/index.ts @@ -1,5 +1,4 @@ -export * from './comment.entity.js'; -export * from './dto/create-comment.dto.js'; -export * from './comment-service.interface.js'; -export * from './default-comment.service.js'; -export * from './comment.container.js'; +export { CommentService } from './comment-service.interface.js'; +export { createCommentContainer } from './comment.container.js'; +export { CommentEntity, CommentModel } from './comment.entity.js'; +export { DefaultCommentService } from './default-comment.service.js'; diff --git a/src/shared/modules/comment/type/param-offerid.type.ts b/src/shared/modules/comment/type/param-offerid.type.ts new file mode 100644 index 0000000..813fbe7 --- /dev/null +++ b/src/shared/modules/comment/type/param-offerid.type.ts @@ -0,0 +1,7 @@ +import { ParamsDictionary } from 'express-serve-static-core'; + +export type ParamOfferId = + | { + offerId: string; + } + | ParamsDictionary; diff --git a/src/shared/modules/comment/types/index.ts b/src/shared/modules/comment/types/index.ts index a1ce00c..b011271 100644 --- a/src/shared/modules/comment/types/index.ts +++ b/src/shared/modules/comment/types/index.ts @@ -1 +1 @@ -export * from './param-offerid.type.js'; +export { ParamOfferId } from './param-offerid.type.js'; diff --git a/src/shared/modules/offer/default-offer.service.ts b/src/shared/modules/offer/default-offer.service.ts index d98fecd..7320022 100644 --- a/src/shared/modules/offer/default-offer.service.ts +++ b/src/shared/modules/offer/default-offer.service.ts @@ -1,15 +1,15 @@ -import { types } from '@typegoose/typegoose'; import { inject, injectable } from 'inversify'; -import { Types } from 'mongoose'; -import { generalOfferAggregation, getIsFavoriteAggregation } from './offer.helpers.js'; - -import { Component, City, SortType } from '../../types/index.js'; import { OfferService } from './offer-service.interface.js'; +import { Component, SortType } from '../../types/index.js'; +import { Logger } from '../../libs/index.js'; +import { types } from '@typegoose/typegoose'; +import { OfferEntity } from './offer.entity.js'; import { CreateOfferDto } from './dto/create-offer.dto.js'; import { UpdateOfferDto } from './dto/update-offer.dto.js'; +import { City } from '../../types/index.js'; +import { Types } from 'mongoose'; import { UserEntity, UserService } from '../user/index.js'; -import { Logger } from '../../libs/logger/index.js'; -import { OfferEntity } from './offer.entity.js'; +import { generalOfferAggregation, getIsFavoriteAggregation } from './offer.helpers.js'; const DEFAULT_OFFER_COUNT = 60; const DEFAULT_PREMIUM_OFFER_COUNT = 3; @@ -37,7 +37,11 @@ export class DefaultOfferService implements OfferService { const favAggregation = getIsFavoriteAggregation(userId); const offerArray = await this.offerModel.aggregate | null>([ - { $match: { _id: new Types.ObjectId(offerId) } }, + { + $match: { + _id: new Types.ObjectId(offerId), + }, + }, ...generalOfferAggregation, ...favAggregation, ]); @@ -65,7 +69,11 @@ export class DefaultOfferService implements OfferService { return this.offerModel.aggregate([ { $match: { $expr: { $in: ['$_id', currentUser.favorites] } } }, ...generalOfferAggregation, - { $addFields: { isFavorite: true } }, + { + $addFields: { + isFavorite: true, + }, + }, { $limit: DEFAULT_OFFER_COUNT }, { $sort: { createdAt: SortType.Down } }, ]); @@ -89,7 +97,12 @@ export class DefaultOfferService implements OfferService { const favAggregation = getIsFavoriteAggregation(userId); return this.offerModel.aggregate([ - { $match: { city, isPremium: true } }, + { + $match: { + city, + isPremium: true, + }, + }, ...generalOfferAggregation, ...favAggregation, { $limit: DEFAULT_PREMIUM_OFFER_COUNT }, diff --git a/src/shared/modules/offer/dto/create-offer.dto.ts b/src/shared/modules/offer/dto/create-offer.dto.ts index eda99c4..30f311f 100644 --- a/src/shared/modules/offer/dto/create-offer.dto.ts +++ b/src/shared/modules/offer/dto/create-offer.dto.ts @@ -1,17 +1,17 @@ import { Expose } from 'class-transformer'; import { - IsArray, - IsBoolean, IsDateString, - IsEnum, - IsNumber, IsOptional, + IsBoolean, + MaxLength, + MinLength, + IsNumber, IsString, + IsArray, + IsEnum, Length, Max, - MaxLength, Min, - MinLength, } from 'class-validator'; import { City, OfferComfort, OfferType, User } from '../../../types/index.js'; import { CreateOfferValidationMessage } from './create-offer.messages.js'; diff --git a/src/shared/modules/offer/dto/update-offer.dto.ts b/src/shared/modules/offer/dto/update-offer.dto.ts index d1631de..94be87f 100644 --- a/src/shared/modules/offer/dto/update-offer.dto.ts +++ b/src/shared/modules/offer/dto/update-offer.dto.ts @@ -1,17 +1,17 @@ import { Expose } from 'class-transformer'; import { - IsArray, - IsBoolean, IsDateString, - IsEnum, - IsNumber, IsOptional, + IsBoolean, + MaxLength, + MinLength, + IsNumber, IsString, + IsArray, + IsEnum, Length, Max, - MaxLength, Min, - MinLength, } from 'class-validator'; import { City, OfferComfort, OfferType } from '../../../types/index.js'; import { UpdateOfferValidationMessage } from './update-offer.messages.js'; diff --git a/src/shared/modules/offer/index.ts b/src/shared/modules/offer/index.ts index 74f7732..b13b21c 100644 --- a/src/shared/modules/offer/index.ts +++ b/src/shared/modules/offer/index.ts @@ -1,7 +1,7 @@ -export * from './offer.entity.js'; -export * from './dto/create-offer.dto.js'; -export * from './offer-service.interface.js'; -export * from './default-offer.service.js'; -export * from './offer.controller.js'; -export * from './offer.container.js'; -export * from './rdo/offer.rdo.js'; +export { OfferEntity, OfferModel } from './offer.entity.js'; +export { CreateOfferDto } from './dto/create-offer.dto.js'; +export { OfferService } from './offer-service.interface.js'; +export { DefaultOfferService } from './default-offer.service.js'; +export { createOfferContainer } from './offer.container.js'; +export { OfferRdo } from './rdo/offer.rdo.js'; +export { CreateOfferValidationMessage } from './dto/create-offer.messages.js'; diff --git a/src/shared/modules/offer/offer.container.ts b/src/shared/modules/offer/offer.container.ts index 90fde8a..a2a0b1b 100644 --- a/src/shared/modules/offer/offer.container.ts +++ b/src/shared/modules/offer/offer.container.ts @@ -1,12 +1,11 @@ import { types } from '@typegoose/typegoose'; import { Container } from 'inversify'; - import { DefaultOfferService } from './default-offer.service.js'; import { OfferEntity, OfferModel } from './offer.entity.js'; import { OfferService } from './offer-service.interface.js'; import { OfferController } from './offer.controller.js'; -import { Controller } from '../../libs/rest/index.js'; import { Component } from '../../types/index.js'; +import { Controller } from '../../libs/index.js'; export function createOfferContainer() { const offerContainer = new Container(); diff --git a/src/shared/modules/offer/offer.controller.ts b/src/shared/modules/offer/offer.controller.ts index 2fd483a..5b9f1bc 100644 --- a/src/shared/modules/offer/offer.controller.ts +++ b/src/shared/modules/offer/offer.controller.ts @@ -1,43 +1,46 @@ -import { Request, Response } from 'express'; import { inject, injectable } from 'inversify'; +import { Request, Response } from 'express'; import { StatusCodes } from 'http-status-codes'; import { - BaseController, + ValidateCityQueryMiddleware, + ValidateObjectIdMiddleware, DocumentExistsMiddleware, - HttpError, - HttpMethod, PrivateRouteMiddleware, - ValidateCityQueryMiddleware, ValidateDtoMiddleware, - ValidateObjectIdMiddleware, -} from '../../libs/rest/index.js'; + BaseController, + HttpMethod, + HttpError, +} from '../../libs/index.js'; import { fillDTO } from '../../helpers/common.js'; import { Component } from '../../types/index.js'; +import { OwnOfferMiddleware } from '../../libs/rest/middleware/index.js'; import { GetOffersQueryDto } from './dto/get-offers-query.dto.js'; -import { OwnOfferMiddleware } from '../../libs/rest/index.js'; import { OfferService } from './offer-service.interface.js'; import { ParamOfferId } from './type/param-offerid.type.js'; import { UpdateOfferDto } from './dto/update-offer.dto.js'; import { CreateOfferDto } from './dto/create-offer.dto.js'; import { ParamCity } from './type/param-city.type.js'; import { CommentService } from '../comment/index.js'; -import { Logger } from '../../libs/logger/index.js'; import { UserService } from '../user/index.js'; import { OfferRdo } from './rdo/offer.rdo.js'; +import { Logger } from '../../libs/index.js'; import { City } from '../../types/index.js'; @injectable() export class OfferController extends BaseController { constructor( @inject(Component.Logger) protected readonly logger: Logger, - @inject(Component.OfferService) protected readonly offerService: OfferService, - @inject(Component.UserService) protected readonly userService: UserService, - @inject(Component.CommentService) protected readonly commentService: CommentService + @inject(Component.OfferService) + protected readonly offerService: OfferService, + @inject(Component.UserService) + protected readonly userService: UserService, + @inject(Component.CommentService) + protected readonly commentService: CommentService ) { super(logger); - this.logger.info('Регистрация маршрутов для OfferController…'); + this.logger.info('Register routes for OfferController…'); const offerIdMiddlewares = [ new ValidateObjectIdMiddleware('offerId'), @@ -107,12 +110,12 @@ export class OfferController extends BaseController { ]); } - public async show({ params, tokenPayload }: Request, res: Response) { + public async show({ params, tokenPayload }: Request, response: Response) { const { offerId } = params; const offer = await this.offerService.findById(offerId, tokenPayload?.id); - this.ok(res, fillDTO(OfferRdo, offer)); + this.ok(response, fillDTO(OfferRdo, offer)); } public async index( @@ -125,11 +128,11 @@ export class OfferController extends BaseController { Record, GetOffersQueryDto >, - res: Response + response: Response ) { const offers = await this.offerService.find(query?.count, tokenPayload?.id); - this.ok(res, fillDTO(OfferRdo, offers)); + this.ok(response, fillDTO(OfferRdo, offers)); } public async create( @@ -137,39 +140,36 @@ export class OfferController extends BaseController { body, tokenPayload, }: Request, Record, CreateOfferDto>, - res: Response + response: Response ) { - const result = await this.offerService.create({ - ...body, - author: tokenPayload.id, - }); + const result = await this.offerService.create({ ...body, author: tokenPayload.id }); const offer = await this.offerService.findById(result.id); - this.created(res, fillDTO(OfferRdo, offer)); + this.created(response, fillDTO(OfferRdo, offer)); } - public async delete({ params }: Request, res: Response): Promise { + public async delete({ params }: Request, response: Response): Promise { const { offerId } = params; const [deletedOffer] = await Promise.all([ this.offerService.deleteById(offerId), this.commentService.deleteByOfferId(offerId), ]); - this.noContent(res, `Offer with id ${deletedOffer?.id} was deleted`); + this.noContent(response, `Offer with id ${deletedOffer?.id} was deleted`); } public async update( { body, params }: Request, - res: Response + response: Response ): Promise { const result = await this.offerService.updateById(params.offerId, body); const updatedOffer = await this.offerService.findById(result?.id); - this.ok(res, fillDTO(OfferRdo, updatedOffer)); + this.ok(response, fillDTO(OfferRdo, updatedOffer)); } public async addToFavorite( { params, tokenPayload }: Request, - res: Response + response: Response ) { const result = await this.offerService.addToFavorite(params.offerId, tokenPayload.id); @@ -181,21 +181,21 @@ export class OfferController extends BaseController { ); } - this.created(res, `Offer with id "${params.offerId}" was added to favorites`); + this.created(response, `Offer with id "${params.offerId}" was added to favorites`); } - public async getPremiumOfferByCity({ params, tokenPayload }: Request, res: Response) { - const offers = await this.offerService.findPremiumByCity( - params?.city as City, - tokenPayload?.id - ); + public async getPremiumOfferByCity( + { params, tokenPayload }: Request, + response: Response + ) { + const offers = await this.offerService.findPremiumByCity(params?.city as City, tokenPayload?.id); - this.ok(res, fillDTO(OfferRdo, offers)); + this.ok(response, fillDTO(OfferRdo, offers)); } public async removeFromFavorite( { params, tokenPayload }: Request, - res: Response + response: Response ) { const result = await this.offerService.removeFromFavorite(params.offerId, tokenPayload.id); @@ -207,12 +207,12 @@ export class OfferController extends BaseController { ); } - this.noContent(res, `Offer with id "${params.offerId}" was removed from favorites`); + this.noContent(response, `Offer with id "${params.offerId}" was removed from favorites`); } - public async getFavorite({ tokenPayload }: Request, res: Response) { + public async getFavorite({ tokenPayload }: Request, response: Response) { const offers = await this.offerService.findFavorite(tokenPayload?.id); - this.ok(res, fillDTO(OfferRdo, offers)); + this.ok(response, fillDTO(OfferRdo, offers)); } } diff --git a/src/shared/modules/offer/offer.entity.ts b/src/shared/modules/offer/offer.entity.ts index 769543f..9560485 100644 --- a/src/shared/modules/offer/offer.entity.ts +++ b/src/shared/modules/offer/offer.entity.ts @@ -24,9 +24,6 @@ export class OfferEntity extends defaultClasses.TimeStamps { @prop({ required: true, default: false }) public isPremium: boolean; - @prop({ required: true }) - public rating: number; - @prop({ type: () => String, enum: OfferType, required: true }) public type: OfferType; @@ -45,7 +42,7 @@ export class OfferEntity extends defaultClasses.TimeStamps { @prop({ ref: UserEntity, required: true }) public author: Ref; - @prop({ type: () => Number, required: true }) + @prop({ type: () => [], required: true }) public coordinates: number[]; } diff --git a/src/shared/modules/offer/rdo/offer.rdo.ts b/src/shared/modules/offer/rdo/offer.rdo.ts index 625a566..ae76a4d 100644 --- a/src/shared/modules/offer/rdo/offer.rdo.ts +++ b/src/shared/modules/offer/rdo/offer.rdo.ts @@ -1,5 +1,5 @@ import { Expose, Type } from 'class-transformer'; -import { City, OfferComfort, OfferType, User } from '../../../types/index.js'; +import { City, OfferComfort, OfferType } from '../../../types/index.js'; import { UserRdo } from '../../user/index.js'; export class OfferRdo { @@ -27,9 +27,6 @@ export class OfferRdo { @Expose() isPremium: boolean; - @Expose() - isFavorite: boolean; - @Expose() commentsCount: number; @@ -53,8 +50,14 @@ export class OfferRdo { @Expose() @Type(() => UserRdo) - author: User; + author: UserRdo; + + @Expose() + latitude: number; + + @Expose() + longitude: number; @Expose() - coordinates: number[]; + isFavorite: boolean; } diff --git a/src/shared/modules/offer/type/param-city.type.ts b/src/shared/modules/offer/type/param-city.type.ts index 73ce791..65cc9da 100644 --- a/src/shared/modules/offer/type/param-city.type.ts +++ b/src/shared/modules/offer/type/param-city.type.ts @@ -1,3 +1,7 @@ import { ParamsDictionary } from 'express-serve-static-core'; -export type ParamCity = { city: string } | ParamsDictionary; +export type ParamCity = + | { + city: string; + } + | ParamsDictionary; diff --git a/src/shared/modules/offer/type/param-offerid.type.ts b/src/shared/modules/offer/type/param-offerid.type.ts index 7a46ae9..813fbe7 100644 --- a/src/shared/modules/offer/type/param-offerid.type.ts +++ b/src/shared/modules/offer/type/param-offerid.type.ts @@ -1,3 +1,7 @@ import { ParamsDictionary } from 'express-serve-static-core'; -export type ParamOfferId = { offerId: string } | ParamsDictionary; +export type ParamOfferId = + | { + offerId: string; + } + | ParamsDictionary; diff --git a/src/shared/modules/user/default-user.service.ts b/src/shared/modules/user/default-user.service.ts index fbe48ab..3f8856e 100644 --- a/src/shared/modules/user/default-user.service.ts +++ b/src/shared/modules/user/default-user.service.ts @@ -1,12 +1,11 @@ import { DocumentType, types } from '@typegoose/typegoose'; -import { inject, injectable } from 'inversify'; - -import { UserService } from './user-service.interface.js'; import { CreateUserDto } from './dto/create-user.dto.js'; -import { UpdateUserDto } from './dto/update-user.dto.js'; -import { Logger } from '../../libs/logger/index.js'; -import { Component } from '../../types/index.js'; +import { UserService } from './user-service.interface.js'; import { UserEntity } from './user.entity.js'; +import { inject, injectable } from 'inversify'; +import { Component } from '../../types/index.js'; +import { Logger } from '../../libs/logger/index.js'; +import { UpdateUserDto } from './dto/update-user.dto.js'; @injectable() export class DefaultUserService implements UserService { @@ -18,10 +17,10 @@ export class DefaultUserService implements UserService { public async create(dto: CreateUserDto, salt: string): Promise> { const user = new UserEntity(dto); - user.setPassword(dto.password, salt); + user.setPasswrod(dto.password, salt); const result = await this.userModel.create(user); - this.logger.info(`Новый пользователь создан: ${result.email}`); + this.logger.info(`New user created: ${result.email}`); return result; } diff --git a/src/shared/modules/user/dto/create-user.dto.ts b/src/shared/modules/user/dto/create-user.dto.ts index 05f520c..581d62f 100644 --- a/src/shared/modules/user/dto/create-user.dto.ts +++ b/src/shared/modules/user/dto/create-user.dto.ts @@ -1,7 +1,7 @@ -import { Expose } from 'class-transformer'; import { IsEmail, IsOptional, IsString, Length } from 'class-validator'; -import { CreateUserMessages } from './create-user.messages.js'; import { UserType } from '../../../types/index.js'; +import { CreateUserMessages } from './create-user.messages.js'; +import { Expose } from 'class-transformer'; export class CreateUserDto { @IsEmail({}, { message: CreateUserMessages.email.invalidFormat }) diff --git a/src/shared/modules/user/dto/create-user.messages.ts b/src/shared/modules/user/dto/create-user.messages.ts index 9d7135f..9c46307 100644 --- a/src/shared/modules/user/dto/create-user.messages.ts +++ b/src/shared/modules/user/dto/create-user.messages.ts @@ -1,17 +1,19 @@ export const CreateUserMessages = { - email: { invalidFormat: 'Введите действительный e-mail адрес' }, - + email: { + invalidFormat: 'email must be a valid address', + }, name: { - invalidFormat: 'Свойство name — обязательное', - lengthField: 'Минимальная длина — 1, максимальная — 15', + invalidFormat: 'name is required', + lengthField: 'min length is 1, max is 15', + }, + avatarPath: { + invalidFormat: 'avatarPath if present must be a string', + }, + type: { + invalid: 'type must be Regular or Pro', }, - - avatarPath: { invalidFormat: 'avatarPath, если он присутствует, должен быть строкой' }, - - type: { invalid: 'Свойство type должно иметь значения Regular или Pro' }, - password: { - invalidFormat: 'Свойство password — обязательное', - lengthField: 'Минимальная длина пароля — 6, максимальная — 12', + invalidFormat: 'password is required', + lengthField: 'min length for password is 6, max is 12', }, } as const; diff --git a/src/shared/modules/user/dto/login-user.dto.ts b/src/shared/modules/user/dto/login-user.dto.ts index 74af9d0..378ca3a 100644 --- a/src/shared/modules/user/dto/login-user.dto.ts +++ b/src/shared/modules/user/dto/login-user.dto.ts @@ -1,6 +1,6 @@ -import { Expose } from 'class-transformer'; import { IsEmail, IsString, Length } from 'class-validator'; import { CreateLoginUserMessage } from './login-user.messages.js'; +import { Expose } from 'class-transformer'; export class LoginUserDto { @IsEmail({}, { message: CreateLoginUserMessage.email.invalidFormat }) diff --git a/src/shared/modules/user/dto/login-user.messages.ts b/src/shared/modules/user/dto/login-user.messages.ts index dfec53b..df30147 100644 --- a/src/shared/modules/user/dto/login-user.messages.ts +++ b/src/shared/modules/user/dto/login-user.messages.ts @@ -1,8 +1,9 @@ export const CreateLoginUserMessage = { - email: { invalidFormat: 'Введите действительный e-mail адрес' }, - + email: { + invalidFormat: 'email must be a valid address', + }, password: { - invalidFormat: 'Свойство password — обязательное', - lengthField: 'Длина пароля должна быть от 6 до 12 символов', + invalidFormat: 'password is required', + lengthField: 'min length for password is 6, max is 12', }, } as const; diff --git a/src/shared/modules/user/dto/update-user.dto.ts b/src/shared/modules/user/dto/update-user.dto.ts index 084152a..2062a9b 100644 --- a/src/shared/modules/user/dto/update-user.dto.ts +++ b/src/shared/modules/user/dto/update-user.dto.ts @@ -2,6 +2,6 @@ import { UserType } from '../../../types/index.js'; export class UpdateUserDto { public name?: string; - public type?: UserType; public avatarPath?: string; + public type?: UserType; } diff --git a/src/shared/modules/user/index.ts b/src/shared/modules/user/index.ts index 84be06b..5e03c60 100644 --- a/src/shared/modules/user/index.ts +++ b/src/shared/modules/user/index.ts @@ -1,10 +1,8 @@ -export * from './user.entity.js'; -export * from './user-service.interface.js'; -export * from './default-user.service.js'; -export * from './user.controller.js'; -export * from './user.container.js'; - -export * from './dto/create-user.dto.js'; -export * from './dto/update-user.dto.js'; -export * from './dto/login-user.dto.js'; -export * from './rdo/user.rdo.js'; +export { UserEntity, UserModel } from './user.entity.js'; +export { CreateUserDto } from './dto/create-user.dto.js'; +export { UserService } from './user-service.interface.js'; +export { DefaultUserService } from './default-user.service.js'; +export { createUserContainer } from './user.container.js'; +export { UserController } from './user.controller.js'; +export { UserRdo } from './rdo/user.rdo.js'; +export { LoginUserDto } from './dto/login-user.dto.js'; diff --git a/src/shared/modules/user/user-service.interface.ts b/src/shared/modules/user/user-service.interface.ts index bca832a..ddf79d3 100644 --- a/src/shared/modules/user/user-service.interface.ts +++ b/src/shared/modules/user/user-service.interface.ts @@ -1,12 +1,12 @@ import { DocumentType } from '@typegoose/typegoose'; import { CreateUserDto } from './dto/create-user.dto.js'; -import { UpdateUserDto } from './dto/update-user.dto.js'; import { UserEntity } from './user.entity.js'; +import { UpdateUserDto } from './dto/update-user.dto.js'; export interface UserService { create(dto: CreateUserDto, salt: string): Promise>; - findById(id: string): Promise | null>; findByEmail(email: string): Promise | null>; + findById(id: string): Promise | null>; findOrCreate(dto: CreateUserDto, salt: string): Promise>; updateById(userId: string, dto: UpdateUserDto): Promise | null>; } diff --git a/src/shared/modules/user/user.container.ts b/src/shared/modules/user/user.container.ts index 3eb610a..705fb52 100644 --- a/src/shared/modules/user/user.container.ts +++ b/src/shared/modules/user/user.container.ts @@ -1,20 +1,17 @@ -import { types } from '@typegoose/typegoose'; import { Container } from 'inversify'; - -import { DefaultUserService } from './default-user.service.js'; import { UserService } from './user-service.interface.js'; +import { Component } from '../../types/index.js'; +import { DefaultUserService } from './default-user.service.js'; +import { types } from '@typegoose/typegoose'; import { UserEntity, UserModel } from './user.entity.js'; -import { Controller } from '../../libs/rest/index.js'; +import { Controller } from '../../libs/index.js'; import { UserController } from './user.controller.js'; -import { Component } from '../../types/index.js'; export function createUserContainer() { const userContainer = new Container(); userContainer.bind(Component.UserService).to(DefaultUserService).inSingletonScope(); - userContainer.bind>(Component.UserModel).toConstantValue(UserModel); - userContainer.bind(Component.UserController).to(UserController).inSingletonScope(); return userContainer; diff --git a/src/shared/modules/user/user.controller.ts b/src/shared/modules/user/user.controller.ts index b5bc4c7..3d2f103 100644 --- a/src/shared/modules/user/user.controller.ts +++ b/src/shared/modules/user/user.controller.ts @@ -1,6 +1,5 @@ import { inject, injectable } from 'inversify'; import { Request, Response } from 'express'; -import { StatusCodes } from 'http-status-codes'; import { BaseController, HttpError, @@ -8,31 +7,33 @@ import { UploadFileMiddleware, ValidateDtoMiddleware, ValidateObjectIdMiddleware, -} from '../../libs/rest/index.js'; +} from '../../libs/index.js'; +import { Component } from '../../types/index.js'; +import { Logger } from '../../libs/index.js'; +import { UserService } from './user-service.interface.js'; +import { Config, RestSchema } from '../../libs/index.js'; +import { StatusCodes } from 'http-status-codes'; import { fillDTO } from '../../helpers/common.js'; -import { Component, UserType } from '../../types/index.js'; - +import { UserRdo } from './rdo/user.rdo.js'; import { LoginUserRequest } from './type/login-user-request.type.js'; -import { Config, RestSchema } from '../../libs/config/index.js'; -import { UserService } from './user-service.interface.js'; import { CreateUserDto } from './dto/create-user.dto.js'; -import { LoggedUserRdo } from './rdo/logged-user.rdo.js'; import { LoginUserDto } from './dto/login-user.dto.js'; -import { Logger } from '../../libs/logger/index.js'; import { AuthService } from '../auth/index.js'; -import { UserRdo } from './rdo/user.rdo.js'; +import { LoggedUserRdo } from './rdo/logged-user.rdo.js'; +import { UserType } from '../../types/index.js'; @injectable() export class UserController extends BaseController { constructor( @inject(Component.Logger) protected readonly logger: Logger, - @inject(Component.Config) private readonly configService: Config, @inject(Component.UserService) private readonly userService: UserService, + @inject(Component.Config) + private readonly configService: Config, @inject(Component.AuthService) private readonly authService: AuthService ) { super(logger); - this.logger.info('Регистрация маршрутов для UserController…'); + this.logger.info('Register routes for UserController…'); this.addRoutes([ { @@ -64,10 +65,7 @@ export class UserController extends BaseController { } public async create( - { - body, - tokenPayload, - }: Request, Record, CreateUserDto>, + { body, tokenPayload }: Request, Record, CreateUserDto>, response: Response ): Promise { if (tokenPayload) { @@ -83,7 +81,7 @@ export class UserController extends BaseController { if (existingUser) { throw new HttpError( StatusCodes.CONFLICT, - `Пользователь с e-mail «${body.email}» существует.`, + `User with email «${body.email}» exists.`, 'UserController' ); } @@ -98,21 +96,26 @@ export class UserController extends BaseController { public async login({ body }: LoginUserRequest, response: Response) { const user = await this.authService.verify(body); const token = await this.authService.authenticate(user); - const responseData = fillDTO(LoggedUserRdo, { email: user.email, token }); + const responseData = fillDTO(LoggedUserRdo, { + email: user.email, + token, + }); this.ok(response, responseData); } public async uploadAvatar(request: Request, response: Response) { - this.created(response, { filepath: request.file?.path }); + this.created(response, { + filepath: request.file?.path, + }); } - public async checkAuthenticate({ tokenPayload }: Request, response: Response) { + public async checkAuthenticate({ tokenPayload }: Request, rresponses: Response) { const user = await this.userService.findByEmail(tokenPayload?.email); if (!user) { throw new HttpError(StatusCodes.UNAUTHORIZED, 'Unauthorized', 'UserController'); } - this.ok(response, fillDTO(UserRdo, user)); + this.ok(rresponses, fillDTO(UserRdo, user)); } } diff --git a/src/shared/modules/user/user.entity.ts b/src/shared/modules/user/user.entity.ts index 3e5b9f8..2cb6979 100644 --- a/src/shared/modules/user/user.entity.ts +++ b/src/shared/modules/user/user.entity.ts @@ -1,11 +1,18 @@ -import { Types } from 'mongoose'; import { defaultClasses, getModelForClass, modelOptions, prop } from '@typegoose/typegoose'; import { User, UserType } from '../../types/index.js'; import { createSHA256 } from '../../helpers/index.js'; +import { Types } from 'mongoose'; +// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging export interface UserEntity extends defaultClasses.Base {} -@modelOptions({ schemaOptions: { collection: 'users', timestamps: true } }) +@modelOptions({ + schemaOptions: { + collection: 'users', + timestamps: true, + }, +}) +// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging export class UserEntity extends defaultClasses.TimeStamps implements User { @prop({ required: true }) public name: string; @@ -19,12 +26,14 @@ export class UserEntity extends defaultClasses.TimeStamps implements User { @prop({ required: true, default: UserType.Regular }) public type: UserType; - /** Пароль - * @desc Мин. 6 символов, макс. - 12 */ @prop({ required: true }) private password?: string; - @prop({ type: Types.ObjectId, required: true, default: [] }) + @prop({ + type: Types.ObjectId, + required: true, + default: [], + }) public favorites: Types.ObjectId[]; constructor(userData: User) { @@ -36,7 +45,7 @@ export class UserEntity extends defaultClasses.TimeStamps implements User { this.type = userData.type; } - public setPassword(password: string, salt: string) { + public setPasswrod(password: string, salt: string) { this.password = createSHA256(password, salt); } diff --git a/src/shared/types/common.type.ts b/src/shared/types/common.type.ts deleted file mode 100644 index e7527b7..0000000 --- a/src/shared/types/common.type.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** Сущность */ -export interface Entity { - id: string; - - /** Дата создания */ - createdAt: string; - - /** Дата изменения */ - updatedAt: string; -} diff --git a/src/shared/types/index.ts b/src/shared/types/index.ts index 64780fc..7c21f9e 100644 --- a/src/shared/types/index.ts +++ b/src/shared/types/index.ts @@ -1,12 +1,16 @@ -export * from './document-exists.interface.js'; +export { DocumentExists } from './document-exists.interface.js'; -export * from './category.type.js'; -export * from './comment.type.js'; -export * from './common.type.js'; -export * from './offer.type.js'; -export * from './user.type.js'; +export { OfferType, OfferComfort, City, Offer } from './offer.type.js'; +export { ChalkColorMethod, Comment } from './comment.type.js'; +export { User, UserType } from './user.type.js'; +export { Category } from './category.type.js'; -export * from './component.enum.js'; -export * from './sort-type.enum.js'; +export { Component } from './component.enum.js'; +export { SortType } from './sort-type.enum.js'; -export * from './mock-server-data.type.js'; +export { + StringBool, + MockTableData, + MockServerData, + MockTableRawData, +} from './mock-server-data.type.js';