From d28cdd64104537f93a3020db8d21ab9a0f2105f1 Mon Sep 17 00:00:00 2001 From: Nekitech Date: Sun, 7 Apr 2024 18:24:37 +0300 Subject: [PATCH] fix --- Makefile | 15 +- docker-compose.yml | 8 +- docker/Dockerfile | 6 - package-lock.json | 201 +++++++++++++++++- package.json | 4 +- src/app.ts | 13 ++ src/app/repositories/BookingRepo.ts | 5 +- src/app/repositories/dto/addBookingDto.ts | 20 +- .../services/BookingService/BookingService.ts | 24 ++- .../controllers/Booking/BookingController.ts | 38 ++-- .../Equipment/EquipmentController.ts | 18 +- .../db/mappers/Booking/BookingMapper.ts | 14 -- .../PostgresQL/BookingRepoImplement.ts | 23 +- src/infrastructure/helpers/Time.ts | 33 +++ .../routes/rest/BookingRoutes.ts | 2 +- .../routes/rest/EquipmentsRoutes.ts | 3 +- src/infrastructure/shared/types/Booking.ts | 5 + .../validations/Booking/BookingValidations.ts | 40 ++++ 18 files changed, 412 insertions(+), 60 deletions(-) delete mode 100644 src/infrastructure/db/mappers/Booking/BookingMapper.ts create mode 100644 src/infrastructure/validations/Booking/BookingValidations.ts diff --git a/Makefile b/Makefile index 5c5535e..45d8ea0 100644 --- a/Makefile +++ b/Makefile @@ -1,19 +1,24 @@ -doc_back_build: +docker_build_backend: docker-compose up -d --build reeq-backend --wait watch: docker compose watch docker_build: docker-compose up -d --build --wait +docker_create_volume: + docker volume create db_volume +build: docker_create_volume docker_build run_db_push + +run_db_push: + npx prisma db push + +run_migrations: + npx prisma migrate deploy ## Для загрузки дампа ## заходим в контейнер базы и пишем # pg_dump -U < reeq-db.dump # - - - - # Windows prisma_add_migrate : docker-compose exec reeq-backend sh -c 'npx prisma migrate dev --name %migration_name%' diff --git a/docker-compose.yml b/docker-compose.yml index 112ad93..f4d73f9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,9 +10,9 @@ services: ports: - "${DB_EXTERNAL_PORT}:${DB_PORT}" environment: - - POSTGRES_PASSWORD=${DB_PASSWORD} - - POSTGRES_USER=${DB_USER} - - POSTGRES_DB=${DB_NAME} + - POSTGRES_PASSWORD=${DB_PASSWORD} + - POSTGRES_USER=${DB_USER} + - POSTGRES_DB=${DB_NAME} networks: - reeq-network reeq-backend: @@ -31,6 +31,8 @@ services: - action: rebuild path: ./prisma target: /usr/src/reeq-backend/prisma + - action: rebuild + path: .env build: context: ./ dockerfile: docker/Dockerfile diff --git a/docker/Dockerfile b/docker/Dockerfile index 40bcb47..06a9166 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -18,17 +18,11 @@ RUN npm ci #prisma init RUN npx prisma generate -ENV DATABASE_URL="postgresql://postgres:postgres@db:5437/reeq-db?schema=public" - ## Push prisma schema to database #RUN npx prisma db push # Copy folder project COPY . . -## Build -#RUN npm run build - -EXPOSE 3005 CMD ["npm", "run", "dev"] diff --git a/package-lock.json b/package-lock.json index bb2832a..5cafc25 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,8 +24,10 @@ "express-validator": "^7.0.1", "jsonwebtoken": "^9.0.2", "module-alias": "^2.2.3", + "moment": "^2.30.1", "multer": "^1.4.5-lts.1", - "pg": "^8.11.3" + "pg": "^8.11.3", + "socket.io": "^4.7.5" }, "devDependencies": { "@types/cors": "^2.8.16", @@ -318,6 +320,11 @@ "@prisma/debug": "5.7.1" } }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -367,6 +374,11 @@ "@types/node": "*" } }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, "node_modules/@types/cookie-parser": { "version": "1.4.6", "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.6.tgz", @@ -379,7 +391,6 @@ "version": "2.8.17", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", - "dev": true, "dependencies": { "@types/node": "*" } @@ -697,6 +708,14 @@ } ] }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, "node_modules/bcrypt": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz", @@ -1237,6 +1256,55 @@ "node": ">= 0.8" } }, + "node_modules/engine.io": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", + "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", + "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -2247,6 +2315,14 @@ "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.3.tgz", "integrity": "sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q==" }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -3148,6 +3224,107 @@ "node": ">=8" } }, + "node_modules/socket.io": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", + "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.4.tgz", + "integrity": "sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==", + "dependencies": { + "debug": "~4.3.4", + "ws": "~8.11.0" + } + }, + "node_modules/socket.io-adapter/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-adapter/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/spawn-command": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz", @@ -3713,6 +3890,26 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, + "node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/xml2js": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", diff --git a/package.json b/package.json index 71e145f..58d1916 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,9 @@ "express-validator": "^7.0.1", "jsonwebtoken": "^9.0.2", "module-alias": "^2.2.3", + "moment": "^2.30.1", "multer": "^1.4.5-lts.1", - "pg": "^8.11.3" + "pg": "^8.11.3", + "socket.io": "^4.7.5" } } diff --git a/src/app.ts b/src/app.ts index a79c774..6cdbc36 100644 --- a/src/app.ts +++ b/src/app.ts @@ -12,10 +12,14 @@ import {bookingRoutes} from "./infrastructure/routes/rest/BookingRoutes"; import {uploadRoutes} from "./infrastructure/routes/rest/UploadRoutes"; import bodyParser from "body-parser"; import multer from "multer"; +import {Server} from "socket.io"; +import * as http from "node:http"; dotenv.config(); const app = express(); const router = express.Router(); +const server = new http.Server(app) + app.use(express.json()) app.use(cookieParser()) app.use(multer().any()); @@ -42,6 +46,15 @@ app.use("/api", router) app.use(ErrorMiddleware) const port = process.env.PORT; + +// Websocket init + +const io = new Server(server) +io.on('connection', (socket) => { + console.log('a user connected'); +}); + + app.get('/api', (req, res) => { res.send('Express + TypeScript Server'); }); diff --git a/src/app/repositories/BookingRepo.ts b/src/app/repositories/BookingRepo.ts index ecae3a0..cac0951 100644 --- a/src/app/repositories/BookingRepo.ts +++ b/src/app/repositories/BookingRepo.ts @@ -1,11 +1,12 @@ import {Booking} from "../models/Booking/Booking"; -import {addBookingDto} from "./dto/addBookingDto"; +import {addBookingDto, getBookingByParamsDtoType} from "./dto/addBookingDto"; import {updateBookingDto} from "./dto/updateBookingDto"; export interface BookingRepo { - getById(id: number): Promise getByFilter(date: string, skip: number| undefined, take: number| undefined): Promise add(booking: addBookingDto): Promise update(booking: updateBookingDto): Promise> getByField(fields: object): Promise<{}[]> + getByParams(params: getBookingByParamsDtoType, include: object): any + getListsTimeReservation(equipment_id: number): any } \ No newline at end of file diff --git a/src/app/repositories/dto/addBookingDto.ts b/src/app/repositories/dto/addBookingDto.ts index 3e592e3..cca2d58 100644 --- a/src/app/repositories/dto/addBookingDto.ts +++ b/src/app/repositories/dto/addBookingDto.ts @@ -1,3 +1,21 @@ import {Booking} from "../../models/Booking/Booking"; +import {getBookingByParams} from "../../../infrastructure/shared/types/Booking"; -export type addBookingDto = Omit \ No newline at end of file +export type addBookingDto = Omit + +type InputObj = { + [key: string]: Number | String +} + +export const getBookingByParamsDto = (params: getBookingByParams) => { + let returnObj: InputObj = {} + for (const key in params) { + if(Object.prototype.hasOwnProperty.call(params, key)) { + returnObj[key] = Number(params[key]) + } + } + + return returnObj +} + +export type getBookingByParamsDtoType = ReturnType \ No newline at end of file diff --git a/src/app/services/BookingService/BookingService.ts b/src/app/services/BookingService/BookingService.ts index 3bf777f..2e11989 100644 --- a/src/app/services/BookingService/BookingService.ts +++ b/src/app/services/BookingService/BookingService.ts @@ -1,6 +1,6 @@ import {BookingRepo} from "../../repositories/BookingRepo"; import {postgresBookingRepository} from "../../../infrastructure/db/repository/PostgresQL/BookingRepoImplement"; -import {addBookingDto} from "../../repositories/dto/addBookingDto"; +import {addBookingDto, getBookingByParamsDtoType} from "../../repositories/dto/addBookingDto"; import {EquipmentRepo} from "../../repositories/EquipmentRepo"; import {postgresEquipmentRepository} from "../../../infrastructure/db/repository/PostgresQL/EquipmentRepoImplement"; import {EquipmentStatus} from "../../../infrastructure/shared/types/Equipment"; @@ -39,8 +39,26 @@ export class BookingService { return addedBooking } - async getBookingByUserId(userId: number) { - return this.bookingRepo.getById(userId) + async getBookingByParams(params: getBookingByParamsDtoType) { + return this.bookingRepo.getByParams(params, { + equipments: true, + users: true + }) + } + + async getListUsersForEquipment(equipment_id: number) { + return this.bookingRepo.getByParams({ + equipment_id + }, { + users: { + select: { + id: true, + first_name: true, + second_name: true, + email: true + } + } + }) } async closeBooking(bookingId: number, equipmentId: number) { diff --git a/src/infrastructure/controllers/Booking/BookingController.ts b/src/infrastructure/controllers/Booking/BookingController.ts index 1dace0c..7f80294 100644 --- a/src/infrastructure/controllers/Booking/BookingController.ts +++ b/src/infrastructure/controllers/Booking/BookingController.ts @@ -1,10 +1,13 @@ import {bookingService, BookingService} from "../../../app/services/BookingService/BookingService"; import {NextFunction, Request, Response} from "express"; import * as console from "console"; +import {getBookingByParams} from "../../shared/types/Booking"; +import {getBookingByParamsDto} from "../../../app/repositories/dto/addBookingDto"; +import {bookingValidations, BookingValidations} from "../../validations/Booking/BookingValidations"; export class BookingController { - constructor(private bookingService: BookingService) { + constructor(private bookingService: BookingService, private validation: BookingValidations) { } async getBookings(req: Request, res: Response, next: NextFunction) { @@ -25,23 +28,32 @@ export class BookingController { async createBooking(req: Request, res: Response, next: NextFunction) { try { const bookingInfo = req.body - const createdBooking = await this.bookingService.CreateBooking(bookingInfo) - res.send({ - msg: `Оборудование ${createdBooking.equipments?.name} успешно забронировано`, - data: createdBooking - }) + const {equipment_id, time_from, time_to, date} = bookingInfo + const isValidTime = await this.validation.validationTimeReservationForm(equipment_id, time_from, time_to, date) + + if(isValidTime) { + const createdBooking = await this.bookingService.CreateBooking(bookingInfo) + res.send({ + msg: `Оборудование ${createdBooking.equipments?.name} успешно забронировано`, + data: createdBooking + }) + } else { + res.send({ + msg: 'Вы выбрали невалидное время, оно пересекается с другими бронями для данного оборудования', + err: new Error("dontValidTimeInterval").message + }) + } } catch (e) { next(e) } } - - async getBookingByUserId(req: Request, res: Response, next: NextFunction) { + + async getBookingByParams(req: Request, res: Response, next: NextFunction) { try { - const userId = Number(req.params.userId) - console.log(req.params.userId, userId) - const listBookings = await this.bookingService.getBookingByUserId(userId) + const params = getBookingByParamsDto(req.query); + const listBookings = await this.bookingService.getBookingByParams(params) res.send({ - msg: `Бронирования юзера успешно получены`, + msg: 'Бронирования успешно получены!', data: listBookings }) } catch (e) { @@ -77,4 +89,4 @@ export class BookingController { } -export const bookingController = new BookingController(bookingService) \ No newline at end of file +export const bookingController = new BookingController(bookingService, bookingValidations) \ No newline at end of file diff --git a/src/infrastructure/controllers/Equipment/EquipmentController.ts b/src/infrastructure/controllers/Equipment/EquipmentController.ts index f263ed2..d47238c 100644 --- a/src/infrastructure/controllers/Equipment/EquipmentController.ts +++ b/src/infrastructure/controllers/Equipment/EquipmentController.ts @@ -1,10 +1,11 @@ import {NextFunction, Request, Response} from "express"; import {equipmentService, EquipmentService} from "../../../app/services/EquipmentService/EquipmentService"; import {EquipmentStatus} from "../../shared/types/Equipment"; +import {bookingService, BookingService} from "../../../app/services/BookingService/BookingService"; export class EquipmentController { - constructor(public equipmentService: EquipmentService) { + constructor(public equipmentService: EquipmentService, private bookingService: BookingService) { } async getAllEquipments(req: Request, res: Response, next: NextFunction) { @@ -70,7 +71,20 @@ export class EquipmentController { next(e) } } + + async getUsersEquipment(req: Request, res: Response, next: NextFunction) { + try { + const equipment_id = Number(req.params.equipment_id) + const listUsers = await this.bookingService.getListUsersForEquipment(equipment_id) + res.send({ + msg: `Список юзеров, забронировавших текущее оборудование, получен`, + data: listUsers + }) + } catch (e: any) { + next(e) + } + } } -export const equipmentsController = new EquipmentController(equipmentService) +export const equipmentsController = new EquipmentController(equipmentService, bookingService) diff --git a/src/infrastructure/db/mappers/Booking/BookingMapper.ts b/src/infrastructure/db/mappers/Booking/BookingMapper.ts deleted file mode 100644 index 78bb973..0000000 --- a/src/infrastructure/db/mappers/Booking/BookingMapper.ts +++ /dev/null @@ -1,14 +0,0 @@ -import {addBookingDto} from "../../../../app/repositories/dto/addBookingDto"; - -class BookingMapper { - constructor() { - } - - public CreateBookingMap(createBooking: addBookingDto) { - createBooking.date_from = new Date(createBooking.date_from) - createBooking.date_to = new Date(createBooking.date_to) - return createBooking - } -} - -export const bookingMapper = new BookingMapper() \ No newline at end of file diff --git a/src/infrastructure/db/repository/PostgresQL/BookingRepoImplement.ts b/src/infrastructure/db/repository/PostgresQL/BookingRepoImplement.ts index a97f2fa..faff34c 100644 --- a/src/infrastructure/db/repository/PostgresQL/BookingRepoImplement.ts +++ b/src/infrastructure/db/repository/PostgresQL/BookingRepoImplement.ts @@ -1,22 +1,33 @@ import {BookingRepo} from "../../../../app/repositories/BookingRepo"; import {Booking} from "../../../../app/models/Booking/Booking"; -import {addBookingDto} from "../../../../app/repositories/dto/addBookingDto"; +import {addBookingDto, getBookingByParamsDtoType} from "../../../../app/repositories/dto/addBookingDto"; import {prisma} from "../../orm/prisma/PrismaClient"; import {updateBookingDto} from "../../../../app/repositories/dto/updateBookingDto"; -import * as console from "console"; class BookingRepoImplement implements BookingRepo { - async getById(id: number){ + + async getListsTimeReservation(equipment_id: number) { return prisma.booking.findMany({ where: { - user_id: id + equipment_id, }, - include: { - equipments: true + select: { + date: true, + time_to: true, + time_from: true } }) } + + async getByParams(params: getBookingByParamsDtoType, include: object) { + return prisma.booking.findMany({ + where: { + ...params + }, + include, + }) + } async getByFilter(date: string, skip: number, take: number): Promise { diff --git a/src/infrastructure/helpers/Time.ts b/src/infrastructure/helpers/Time.ts index 7caab9d..ac5a808 100644 --- a/src/infrastructure/helpers/Time.ts +++ b/src/infrastructure/helpers/Time.ts @@ -1,3 +1,4 @@ +import moment from 'moment' export const convertToMilliseconds = (value: number, format: string) => { switch (format) { case 'd': @@ -9,4 +10,36 @@ export const convertToMilliseconds = (value: number, format: string) => { case 'sec': return value * 1000 } +} + + +/** + * Определяет, пересекаются ли диапазоны времени + * @param range1 + * @param range2 + */ +export function rangesIntersect(range1: any, range2: any) { + const [start1, end1] = range1.map((value: string) => moment(value, 'YYYY-MM-DD HH:mm')); + const [start2, end2] = range2.map((value: string) => moment(value, 'YYYY-MM-DD HH:mm')); + + // Проверяем пересечение по времени и дате + return ( + (end1.isSameOrBefore(start2)) || + (start1.isSameOrAfter(end2)) + ); +} + +/** + * Форматирует дату и диапазон времени в формат [date time_from, date time_to] + * @param date + * @param time_from + * @param time_to + */ +export function formatDateTime(date: Date, time_from: string, time_to: string) { + const format_date = date.toISOString().split('T')[0]; + + const formattedTo = `${format_date} ${time_to}`; + const formattedFrom = `${format_date} ${time_from}`; + + return [formattedFrom, formattedTo]; } \ No newline at end of file diff --git a/src/infrastructure/routes/rest/BookingRoutes.ts b/src/infrastructure/routes/rest/BookingRoutes.ts index 3275ec7..4ff8ee9 100644 --- a/src/infrastructure/routes/rest/BookingRoutes.ts +++ b/src/infrastructure/routes/rest/BookingRoutes.ts @@ -10,7 +10,7 @@ export class BookingRoutes implements Routes { initRoutes(router: Router) { router.get(`${this.initRoutePath}s`, this.bookingController.getBookings.bind(this.bookingController)) router.post(`${this.initRoutePath}/create`, this.bookingController.createBooking.bind(this.bookingController)) - router.get(`${this.initRoutePath}/:userId`, this.bookingController.getBookingByUserId.bind(this.bookingController)) + router.get(`${this.initRoutePath}`, this.bookingController.getBookingByParams.bind(this.bookingController)) router.patch(`${this.initRoutePath}/close`, this.bookingController.closeBooking.bind(this.bookingController)) router.get(`${this.initRoutePath}_dates`, this.bookingController.getBookingDateLists.bind(this.bookingController)) } diff --git a/src/infrastructure/routes/rest/EquipmentsRoutes.ts b/src/infrastructure/routes/rest/EquipmentsRoutes.ts index 27b5329..510f408 100644 --- a/src/infrastructure/routes/rest/EquipmentsRoutes.ts +++ b/src/infrastructure/routes/rest/EquipmentsRoutes.ts @@ -4,7 +4,7 @@ import {Routes} from "./Routes"; class EquipmentsRoutes implements Routes { - constructor(readonly equipmentsController: EquipmentController, public initRoutePath: string) { + constructor(private equipmentsController: EquipmentController, public initRoutePath: string) { } initRoutes(router: Router) { @@ -13,6 +13,7 @@ class EquipmentsRoutes implements Routes { router.get(`${this.initRoutePath}/:id`, this.equipmentsController.getEquipmentById.bind(this.equipmentsController)) router.patch(`${this.initRoutePath}`, this.equipmentsController.updateEquipment.bind(this.equipmentsController)) router.delete(`${this.initRoutePath}/:id`, this.equipmentsController.deleteEquipment.bind(this.equipmentsController)) + router.get(`${this.initRoutePath}/users_equipment/:equipment_id`, this.equipmentsController.getUsersEquipment.bind(this.equipmentsController)) } } diff --git a/src/infrastructure/shared/types/Booking.ts b/src/infrastructure/shared/types/Booking.ts index e002389..330e499 100644 --- a/src/infrastructure/shared/types/Booking.ts +++ b/src/infrastructure/shared/types/Booking.ts @@ -3,3 +3,8 @@ export enum BookingStatus { COMPLETE = "COMPLETE", EXPIRED = "EXPIRED" } + + +export interface getBookingByParams { + [key: string]: any; +} \ No newline at end of file diff --git a/src/infrastructure/validations/Booking/BookingValidations.ts b/src/infrastructure/validations/Booking/BookingValidations.ts new file mode 100644 index 0000000..6c7a305 --- /dev/null +++ b/src/infrastructure/validations/Booking/BookingValidations.ts @@ -0,0 +1,40 @@ +import {BookingService} from "../../../app/services/BookingService/BookingService"; +import {BookingRepo} from "../../../app/repositories/BookingRepo"; +import {postgresBookingRepository} from "../../db/repository/PostgresQL/BookingRepoImplement"; +import {formatDateTime, rangesIntersect} from "../../helpers/Time"; + +export class BookingValidations { + + constructor(private bookingRepo: BookingRepo) { + } + + /** + * Проверяет выбранный юзером диапазон дат на пересечение с уже существующими бронями пользователей на данное оборудование + * @param equipment_id + * @param time_from + * @param time_to + * @param date + */ + public async validationTimeReservationForm( + equipment_id: number, + time_from: string, + time_to: string, + date: string) { + + const list = await this.bookingRepo.getListsTimeReservation(equipment_id) + const checkedRange = formatDateTime(new Date(date), time_from, time_to) + const formatList = list.map((value: any) => { + const {date, time_from, time_to} = value + return formatDateTime(date, time_from, time_to) + }) + + for (const range of formatList) { + if(!rangesIntersect(checkedRange, range)) { + return false + } + } + return true + } +} + +export const bookingValidations = new BookingValidations(postgresBookingRepository) \ No newline at end of file